Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 115d35b

Browse files
committed
Add basic SCP protocol
1 parent 2d39caa commit 115d35b

File tree

11 files changed

+400
-29
lines changed

11 files changed

+400
-29
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ $ coder sync ~/Projects/cdr/enterprise my-env:~/enterprise
2020

2121
- The `coder login` flow will not work when the CLI is ran from a different network
2222
than the browser. #1
23+
- Windows doesn't work out of the box. The `scp` utility is required in PATH.

cmd/coder/login.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import (
1111
"go.coder.com/cli"
1212
"go.coder.com/flog"
1313

14-
"cdr.dev/coder/internal/client"
15-
"cdr.dev/coder/internal/config"
16-
"cdr.dev/coder/internal/loginsrv"
14+
"cdr.dev/coder-cli/internal/client"
15+
"cdr.dev/coder-cli/internal/config"
16+
"cdr.dev/coder-cli/internal/loginsrv"
1717
)
1818

1919
type loginCmd struct {

cmd/coder/logout.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"go.coder.com/cli"
88
"go.coder.com/flog"
99

10-
"cdr.dev/coder/internal/config"
10+
"cdr.dev/coder-cli/internal/config"
1111
)
1212

1313
type logoutCmd struct {

cmd/coder/main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package main
33
import (
44
"github.com/spf13/pflag"
55
"go.coder.com/cli"
6+
"log"
7+
"os"
8+
"net/http"
9+
_ "net/http/pprof"
610
)
711

812
type rootCmd struct {
@@ -24,10 +28,15 @@ func (r *rootCmd) Subcommands() []cli.Command {
2428
return []cli.Command{
2529
loginCmd{},
2630
logoutCmd{},
27-
syncCmd{},
31+
&syncCmd{},
2832
}
2933
}
3034

3135
func main() {
36+
if os.Getenv("PPROF") != "" {
37+
go func() {
38+
log.Println(http.ListenAndServe("localhost:6060", nil))
39+
}()
40+
}
3241
cli.RunRoot(&rootCmd{})
3342
}

cmd/coder/sync.go

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,41 @@
11
package main
22

33
import (
4+
"context"
5+
"crypto/rand"
6+
"io"
7+
"io/ioutil"
48
"os"
59
"strings"
610

11+
"github.com/cheggaaa/pb/v3"
712
"github.com/spf13/pflag"
813
"go.coder.com/cli"
914
"go.coder.com/flog"
1015

11-
"cdr.dev/coder/internal/client"
12-
"cdr.dev/coder/internal/sync"
16+
"cdr.dev/coder-cli/internal/client"
17+
"cdr.dev/coder-cli/internal/sync"
18+
"cdr.dev/coder-cli/wush"
1319
)
1420

1521
type syncCmd struct {
22+
init bool
23+
benchSize int64
1624
}
1725

18-
func (cmd syncCmd) Spec() cli.CommandSpec {
26+
func (cmd *syncCmd) Spec() cli.CommandSpec {
1927
return cli.CommandSpec{
2028
Name: "sync",
2129
Usage: "[local directory] [<env name>:<remote directory>]",
2230
Desc: "establish a one way directory sync to a remote environment",
2331
}
2432
}
2533

34+
func (cmd *syncCmd) RegisterFlags(fl *pflag.FlagSet) {
35+
fl.BoolVarP(&cmd.init, "init", "i", false, "do inititial transfer and exit")
36+
fl.Int64Var(&cmd.benchSize, "bench", 0, "bench test the wush endpoint")
37+
}
38+
2639
// userOrgs gets a list of orgs the user is apart of.
2740
func userOrgs(user *client.User, orgs []client.Org) []client.Org {
2841
var uo []client.Org
@@ -39,7 +52,7 @@ outer:
3952
return uo
4053
}
4154

42-
func (cmd syncCmd) findEnv(client *client.Client, name string) client.Environment {
55+
func (cmd *syncCmd) findEnv(client *client.Client, name string) client.Environment {
4356
me, err := client.Me()
4457
if err != nil {
4558
flog.Fatal("get self: %+v", err)
@@ -72,8 +85,27 @@ func (cmd syncCmd) findEnv(client *client.Client, name string) client.Environmen
7285
panic("unreachable")
7386
}
7487

75-
//noinspection GoImportUsedAsName
76-
func (cmd syncCmd) Run(fl *pflag.FlagSet) {
88+
func (cmd *syncCmd) bench(client *client.Client, env client.Environment) {
89+
conn, err := client.Wush(env, "cat")
90+
if err != nil {
91+
flog.Fatal("wush failed: %v", err)
92+
}
93+
wc := wush.Dial(context.Background(), conn)
94+
bar := pb.New64(cmd.benchSize)
95+
bar.Start()
96+
go io.Copy(ioutil.Discard, wc.Stdout)
97+
io.Copy(
98+
bar.NewProxyWriter(wc.Stdin),
99+
io.LimitReader(rand.Reader, cmd.benchSize),
100+
)
101+
wc.Stdin.Close()
102+
code, err := wc.Wait()
103+
if err != nil || code != 0 {
104+
flog.Error("bench: (code %v) %v", code, err)
105+
}
106+
}
107+
108+
func (cmd *syncCmd) Run(fl *pflag.FlagSet) {
77109
var (
78110
local = fl.Arg(0)
79111
remote = fl.Arg(1)
@@ -97,14 +129,21 @@ func (cmd syncCmd) Run(fl *pflag.FlagSet) {
97129
flog.Fatal("remote misformmated")
98130
}
99131
var (
100-
envName = remoteTokens[0]
101-
remotePAth = remoteTokens[1]
132+
envName = remoteTokens[0]
133+
remoteDir = remoteTokens[1]
102134
)
103135

104136
env := cmd.findEnv(client, envName)
105-
_ = remotePAth
137+
138+
if cmd.benchSize > 0 {
139+
cmd.bench(client, env)
140+
return
141+
}
106142

107143
s := sync.Sync{
144+
Init: cmd.init,
145+
RemoteDir: remoteDir,
146+
LocalDir: local,
108147
Client: client,
109148
Environment: env,
110149
}

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
module cdr.dev/coder
1+
module cdr.dev/coder-cli
22

33
go 1.14
44

55
require (
6+
github.com/cheggaaa/pb/v3 v3.0.4
7+
github.com/dustin/go-humanize v1.0.0
68
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
79
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
10+
github.com/rjeczalik/notify v0.9.2
811
github.com/spf13/pflag v1.0.5
912
go.coder.com/cli v0.4.0
1013
go.coder.com/flog v0.0.0-20190906214207-47dd47ea0512
14+
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
1115
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
1216
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
1317
nhooyr.io/websocket v1.8.5

go.sum

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
2+
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
3+
github.com/cheggaaa/pb v1.0.28 h1:kWGpdAcSp3MxMU9CCHOwz/8V0kCHN4+9yQm2MzWuI98=
4+
github.com/cheggaaa/pb v2.0.7+incompatible h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU=
5+
github.com/cheggaaa/pb/v3 v3.0.4 h1:QZEPYOj2ix6d5oEg63fbHmpolrnNiwjUsk+h74Yt4bM=
6+
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw=
7+
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
8+
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
19
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
210
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
311
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
@@ -12,17 +20,32 @@ github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eT
1220
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
1321
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
1422
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
23+
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
24+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
1525
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
1626
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
27+
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
28+
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
29+
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
30+
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
31+
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
1732
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
1833
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
34+
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
35+
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
1936
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
2037
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
2138
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
2239
go.coder.com/cli v0.4.0 h1:PruDGwm/CPFndyK/eMowZG3vzg5CgohRWeXWCTr3zi8=
2340
go.coder.com/cli v0.4.0/go.mod h1:hRTOURCR3LJF1FRW9arecgrzX+AHG7mfYMwThPIgq+w=
2441
go.coder.com/flog v0.0.0-20190906214207-47dd47ea0512 h1:DjCS6dRQh+1PlfiBmnabxfdrzenb0tAwJqFxDEH/s9g=
2542
go.coder.com/flog v0.0.0-20190906214207-47dd47ea0512/go.mod h1:83JsYgXYv0EOaXjIMnaZ1Fl6ddNB3fJnDZ/8845mUJ8=
43+
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
44+
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
45+
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
46+
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
47+
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
48+
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2649
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
2750
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2851
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

internal/client/env.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,10 @@ func (c Client) Wush(env Environment, cmd string, args ...string) (*websocket.Co
3737
query.Set("tty", "false")
3838
query.Set("stdin", "true")
3939

40-
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
40+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
4141
defer cancel()
4242

4343
fullURL := u.String() + "?" + query.Encode()
44-
println(fullURL)
4544

4645
conn, resp, err := websocket.Dial(ctx, fullURL,
4746
&websocket.DialOptions{
@@ -51,7 +50,10 @@ func (c Client) Wush(env Environment, cmd string, args ...string) (*websocket.Co
5150
},
5251
)
5352
if err != nil {
54-
return nil, bodyError(resp)
53+
if resp != nil {
54+
return nil, bodyError(resp)
55+
}
56+
return nil, err
5557
}
5658
return conn, nil
5759
}

internal/sync/debugwriter.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package sync
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
)
8+
9+
type debugWriter struct {
10+
Prefix string
11+
W io.Writer
12+
}
13+
14+
func (w debugWriter) Write(p []byte) (n int, err error) {
15+
if os.Getenv("DEBUG") == "" {
16+
return len(p), nil
17+
}
18+
_, err = fmt.Fprintf(w.W, "%v: %q\n", w.Prefix, p)
19+
return len(p), err
20+
}
21+

0 commit comments

Comments
 (0)