overhaul how commands are found/run
--- a/access/access.go Tue Jul 23 15:30:21 2019 -0500
+++ b/access/access.go Tue Jul 23 16:08:13 2019 -0500
@@ -38,7 +38,7 @@
groups map[string][]string
@@ -73,7 +73,7 @@
a.patterns = data.Patterns
@@ -83,7 +83,7 @@
func (a *Access) findUsers() []string {
users := map[string]bool{}
- for _, name := range a.global.Users() {
+ for _, name := range a.Global.Users() { // don't add groups to the users list
if _, found := a.groups[name]; found {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/commands.go Tue Jul 23 16:08:13 2019 -0500
@@ -0,0 +1,62 @@
+ "github.com/alecthomas/kong" + "github.com/kballard/go-shellquote" + "golang.org/x/crypto/ssh" + "bitbucket.org/rw_grim/hgkeeper/access" + Repo string `kong:"flag,short='R'"` + Stdio bool `kong:"flag,name='stdio'"` + Repo string `kong:"arg"` +type Command interface { + Run(conn ssh.Channel, serverConn *ssh.ServerConn, req *ssh.Request) error + CheckAccess(access access.Access, username string) bool +func parse(cmd string) (cli, string, error) { + args, err := shellquote.Split(cmd) + parser := kong.Must(&values) + ctx, err := parser.Parse(args) + return values, ctx.Command(), nil +func Find(cmd, reposPath string) (Command, error) { + values, pcmd, err := parse(cmd) + return NewServe(reposPath, values.Hg.Repo), nil + return NewInit(reposPath, values.Hg.Init.Repo), nil + return nil, fmt.Errorf("unknown command %s", cmd) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/commands_test.go Tue Jul 23 16:08:13 2019 -0500
@@ -0,0 +1,39 @@
+ "github.com/stretchr/testify/assert" +func TestRepoFromCommand(t *testing.T) { + assert := assert.New(t) + "hg -R foo serve --stdio", + NewServe("repos", "foo"), + "hg -R foo/bar serve --stdio", + NewServe("repos", "foo/bar"), + for _, testCase := range cases { + cmd, err := Find(testCase.input, "repos") + assert.Equal(cmd, testCase.expected) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/init.go Tue Jul 23 16:08:13 2019 -0500
@@ -0,0 +1,29 @@
+ "golang.org/x/crypto/ssh" + "bitbucket.org/rw_grim/hgkeeper/access" + "bitbucket.org/rw_grim/hgkeeper/hg" +func NewInit(reposPath, repoName string) *Init { + repoPath: filepath.Join(reposPath, repoName), +func (i *Init) Run(conn ssh.Channel, serverConn *ssh.ServerConn, req *ssh.Request) error { + return run(hg.Init(i.repoPath), conn, serverConn, req) +func (i *Init) CheckAccess(access access.Access, username string) bool { + return access.Global.CanInit(username) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/run.go Tue Jul 23 16:08:13 2019 -0500
@@ -0,0 +1,78 @@
+ log "github.com/sirupsen/logrus" + "golang.org/x/crypto/ssh" +func run(cmd *exec.Cmd, conn ssh.Channel, serverConn *ssh.ServerConn, req *ssh.Request) error { + if err := cmd.Wait(); err != nil { + "%s command %q failed: %v", + serverConn.RemoteAddr(), + strings.Join(cmd.Args, " "), + "%s command %s finished", + serverConn.RemoteAddr(), + strings.Join(cmd.Args, " "), + stdinWriter, err := cmd.StdinPipe() + stdoutReader, err := cmd.StdoutPipe() + stderrReader, err := cmd.StderrPipe() + // now wire up stdin/stdout/stderr + io.Copy(stdinWriter, conn) + io.Copy(conn, stdoutReader) + io.Copy(conn.Stderr(), stderrReader) + if err := cmd.Start(); err != nil { --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/serve.go Tue Jul 23 16:08:13 2019 -0500
@@ -0,0 +1,30 @@
+ "golang.org/x/crypto/ssh" + "bitbucket.org/rw_grim/hgkeeper/access" + "bitbucket.org/rw_grim/hgkeeper/hg" +func NewServe(reposPath, repoName string) *Serve { + repoPath: filepath.Join(reposPath, repoName), +func (s *Serve) Run(conn ssh.Channel, serverConn *ssh.ServerConn, req *ssh.Request) error { + return run(hg.Serve(s.repoPath), conn, serverConn, req) +func (s *Serve) CheckAccess(access access.Access, username string) bool { + return access.Global.CanRead(username) --- a/ssh/command.go Tue Jul 23 15:30:21 2019 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
- "github.com/alecthomas/kong"
- "github.com/kballard/go-shellquote"
- log "github.com/sirupsen/logrus"
- "golang.org/x/crypto/ssh"
- "bitbucket.org/rw_grim/hgkeeper/hg"
- Repo string `kong:"flag,short='R'"`
- Stdio bool `kong:"flag,name='stdio'"`
- Repo string `kong:"arg"`
-func NewCommand(path string, cmd *exec.Cmd) *Command {
-func (c *Command) run(conn ssh.Channel, serverConn *ssh.ServerConn, req *ssh.Request) error {
- if err := c.cmd.Wait(); err != nil {
- "%s command %q failed: %v",
- serverConn.RemoteAddr(),
- strings.Join(c.cmd.Args, " "),
- "%s command %s finished",
- serverConn.RemoteAddr(),
- strings.Join(c.cmd.Args, " "),
- stdinWriter, err := c.cmd.StdinPipe()
- stdoutReader, err := c.cmd.StdoutPipe()
- stderrReader, err := c.cmd.StderrPipe()
- // now wire up stdin/stdout/stderr
- io.Copy(stdinWriter, conn)
- io.Copy(conn, stdoutReader)
- io.Copy(conn.Stderr(), stderrReader)
- if err := c.cmd.Start(); err != nil {
-func parseCommand(cmd string) (cli, string, error) {
- args, err := shellquote.Split(cmd)
- parser := kong.Must(&values)
- ctx, err := parser.Parse(args)
- return values, ctx.Command(), nil
-func findCommand(cmd, reposPath string) (*Command, error) {
- values, pcmd, err := parseCommand(cmd)
- hg.Serve(filepath.Join(reposPath, values.Hg.Repo)),
- hg.Init(filepath.Join(reposPath, values.Hg.Init.Repo)),
- return nil, fmt.Errorf("unknown command %s", cmd)
--- a/ssh/command_test.go Tue Jul 23 15:30:21 2019 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
- "github.com/stretchr/testify/assert"
-func TestRepoFromCommand(t *testing.T) {
- assert := assert.New(t)
- Args: []string{"hg", "-R", "repos", "serve", "--stdio"},
- "hg -R foo serve --stdio",
- Args: []string{"hg", "-R", "repos/foo", "serve", "--stdio"},
- "hg -R foo/bar serve --stdio",
- Args: []string{"hg", "-R", "repos/foo/bar", "serve", "--stdio"},
- for _, testCase := range cases {
- cmd, err := findCommand(testCase.input, "repos")
- assert.Equal(cmd.cmd.Args, testCase.expected.Args)