grim/hgkeeper
Clone
Summary
Browse
Changes
Graph
access: Implement stubs
access-control
2019-05-04, Wagner Riffel
208e17128bb9
access: Implement stubs
package
ssh
import
(
"fmt"
"io"
"os/exec"
"path/filepath"
"strings"
"sync"
"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"
)
type
cli
struct
{
Hg
struct
{
Repo
string
`kong:"flag,short='R'"`
Serve
struct
{
Stdio
bool
`kong:"flag,name='stdio'"`
}
`kong:"cmd"`
Init
struct
{
Repo
string
`kong:"arg"`
}
`kong:"cmd"`
}
`kong:"cmd"`
}
type
Command
struct
{
path
string
cmd
*
exec
.
Cmd
}
func
NewCommand
(
path
string
,
cmd
*
exec
.
Cmd
)
*
Command
{
return
&
Command
{
path
:
path
,
cmd
:
cmd
,
}
}
func
(
c
*
Command
)
run
(
conn
ssh
.
Channel
,
serverConn
*
ssh
.
ServerConn
,
req
*
ssh
.
Request
)
error
{
teardown
:=
func
()
{
conn
.
Close
()
if
err
:=
c
.
cmd
.
Wait
();
err
!=
nil
{
log
.
Warnf
(
"%s command %q failed: %v"
,
serverConn
.
RemoteAddr
(),
strings
.
Join
(
c
.
cmd
.
Args
,
" "
),
err
,
)
req
.
Reply
(
false
,
nil
)
return
}
log
.
Debugf
(
"%s command %s finished"
,
serverConn
.
RemoteAddr
(),
strings
.
Join
(
c
.
cmd
.
Args
,
" "
),
)
req
.
Reply
(
true
,
nil
)
}
stdinWriter
,
err
:=
c
.
cmd
.
StdinPipe
()
if
err
!=
nil
{
return
err
}
stdoutReader
,
err
:=
c
.
cmd
.
StdoutPipe
()
if
err
!=
nil
{
return
err
}
stderrReader
,
err
:=
c
.
cmd
.
StderrPipe
()
if
err
!=
nil
{
return
err
}
var
once
sync
.
Once
// now wire up stdin/stdout/stderr
go
func
()
{
io
.
Copy
(
stdinWriter
,
conn
)
once
.
Do
(
teardown
)
}()
go
func
()
{
io
.
Copy
(
conn
,
stdoutReader
)
once
.
Do
(
teardown
)
}()
go
func
()
{
io
.
Copy
(
conn
.
Stderr
(),
stderrReader
)
once
.
Do
(
teardown
)
}()
if
err
:=
c
.
cmd
.
Start
();
err
!=
nil
{
req
.
Reply
(
false
,
nil
)
once
.
Do
(
teardown
)
return
err
}
return
nil
}
func
parseCommand
(
cmd
string
)
(
cli
,
string
,
error
)
{
values
:=
cli
{}
args
,
err
:=
shellquote
.
Split
(
cmd
)
if
err
!=
nil
{
return
values
,
""
,
err
}
parser
:=
kong
.
Must
(
&
values
)
ctx
,
err
:=
parser
.
Parse
(
args
)
if
err
!=
nil
{
return
values
,
""
,
err
}
return
values
,
ctx
.
Command
(),
nil
}
func
findCommand
(
cmd
,
reposPath
string
)
(
*
Command
,
error
)
{
values
,
pcmd
,
err
:=
parseCommand
(
cmd
)
if
err
!=
nil
{
return
nil
,
err
}
switch
pcmd
{
case
"hg serve"
:
return
NewCommand
(
values
.
Hg
.
Repo
,
hg
.
Serve
(
filepath
.
Join
(
reposPath
,
values
.
Hg
.
Repo
)),
),
nil
case
"hg init <repo>"
:
return
NewCommand
(
values
.
Hg
.
Init
.
Repo
,
hg
.
Init
(
filepath
.
Join
(
reposPath
,
values
.
Hg
.
Init
.
Repo
)),
),
nil
default
:
return
nil
,
fmt
.
Errorf
(
"unknown command %s"
,
cmd
)
}
}