feat: support scp publishing

See https://git.vvvvvvaria.org/decentral1se/distribusi-go/issues/4
This commit is contained in:
decentral1se 2022-02-06 03:31:47 +01:00
parent c77022b97f
commit bba820173d
Signed by: decentral1se
GPG Key ID: 03789458B3D0C410
4 changed files with 145 additions and 0 deletions

View File

@ -119,6 +119,16 @@ ls /tmp/ | grep -i distribusi
distribusi-go-20-25-492637114356
```
If you have SSH access to a server, you can publish your files with `-P/--publish`.
It works just like [scp] does:
```
./distribusi -p <path> -P <server>:<remote-path>
```
See [this short guide](#ssh-guide-for-the-publishing) for help with SSH issues.
:v:
## Hacking
@ -154,6 +164,42 @@ Binaries are in `dist/`.
[`LICENSE`](./LICENSE)
## Tips
### SSH guide for `-P/--publish`
If you already know & use `scp` then `-P/--publish` should Just Work :tm: If
not, read on for some tips on how to configure your SSH client to help
`distribusi-go` make SSH connections successfully.
The simplest way to make sure `distribusi` can make an SSH connection with your
server is to match a `~/.ssh/config` entry with the `-P <server>:...` server
value you pass on the command-line.
If you want to run `./distribusi -p <path> -P varia.zone:/var/www/`, then a
matching `~/.ssh/config` entry might look like this:
```ssh
Host varia.zone
Hostname varia.zone
User decentral1se
Port 22
IdentityFile ~/.ssh/<ssh-secret-key-part>
```
This tells `distribusi-go` everything it needs to know to make a successful SSH
connection. Run with `-d/--debug` for extra help figuring out what connection
details are being used.
If you have a secret protected SSH key then make sure you've got a running
`ssh-agent` and have added the key with the following:
```
eval $(ssh-agent -k)
ssh-add ~/.ssh/<ssh-secret-key-part>
ssh-add -L # see loaded keys
```
[Go]: https://go.dev
[Pillow]: https://pillow.readthedocs.io/en/stable/installation.html#external-libraries
[distribusi]: https://git.vvvvvvaria.org/varia/distribusi
@ -165,3 +211,4 @@ Binaries are in `dist/`.
[the entire listing]: https://vvvvvvaria.org/~decentral1se/distribusi-go/
[this book]: https://www.gopl.io/
[this ticket]: https://git.vvvvvvaria.org/decentral1se/distribusi-go/issues/1
[scp]: https://linux.die.net/man/1/scp

View File

@ -11,6 +11,7 @@ import (
"io"
"io/fs"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
@ -25,9 +26,13 @@ import (
"github.com/disintegration/imaging"
"github.com/gabriel-vasile/mimetype"
"github.com/k0kubun/go-ansi"
"github.com/kevinburke/ssh_config"
"github.com/povsister/scp"
"github.com/schollz/progressbar/v3"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
// Version is the current version of distribusi-go.
@ -211,6 +216,12 @@ Example:
Usage: "path to distribusify",
Required: true,
},
&cli.StringFlag{
Name: "publish",
Aliases: []string{"P"},
Usage: `publish to a server using scp (e.g. "varia.zone:public_html")`,
Required: false,
},
&cli.BoolFlag{
Name: "serve",
Aliases: []string{"s"},
@ -253,6 +264,10 @@ Example:
return nil
},
Action: func(c *cli.Context) error {
if c.Bool("serve") && c.String("publish") != "" {
logrus.Fatal("woops, can't publish & serve at the same time?")
}
root, err := filepath.Abs(c.String("path"))
if err != nil {
logrus.Fatal(err)
@ -300,6 +315,16 @@ Example:
fmt.Println("done!")
}
pubTarget := c.String("publish")
if pubTarget != "" {
logrus.Debugf("attempting to publish files to %s", pubTarget)
if err := scpPublish(c, root, pubTarget); err != nil {
ch <- err
return
}
}
ch <- nil
return
}()
@ -879,3 +904,67 @@ func mkProgressBar(c *cli.Context) *progressbar.ProgressBar {
return bar
}
// scpPublish initates a scp-like publishing interface. We do our best here to
// simply work with existing local work station SSH client configurations. It
// is mostly up to folks to configure their own shit. We don't do anything
// fancy here.
func scpPublish(c *cli.Context, root, pubTarget string) error {
split := strings.Split(pubTarget, ":")
server, remotePath := split[0], split[1]
logrus.Debugf("parsed server: %s remotePath: %s from %s", server, remotePath, pubTarget)
if hostname := ssh_config.Get(server, "Hostname"); hostname == "" {
return fmt.Errorf("missing Hostname entry for %s in ~/.ssh/config, cannot continue", server)
}
user := ssh_config.Get(server, "User")
port := ssh_config.Get(server, "Port")
logrus.Debugf("read user: %s, port: %s for %s in ~/.ssh/config", user, port, server)
sshConf := &ssh.ClientConfig{
User: user,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), // awful, i know
Timeout: 5 * time.Second,
}
identityFile := ssh_config.Get(server, "IdentityFile")
if identityFile != "" && identityFile != "~/.ssh/identity" {
sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
return err
}
agentCl := agent.NewClient(sshAgent)
authMethod := ssh.PublicKeysCallback(agentCl.Signers)
sshConf.Auth = []ssh.AuthMethod{authMethod}
logrus.Debugf("read identityFile: %s for %s in ~/.ssh/config, using ssh-agent for auth", identityFile, server)
}
logrus.Debug("attempting to construct SSH client for publishing logic")
serverAndPort := fmt.Sprintf("%s:%s", server, port)
scpClient, err := scp.NewClient(serverAndPort, sshConf, &scp.ClientOption{})
if err != nil {
return err
}
defer scpClient.Close()
opts := &scp.DirTransferOption{
Context: c.Context,
Timeout: 10 * time.Minute,
}
fmt.Printf(fmt.Sprintf("publishing %s to %s...", filepath.Base(root), server))
if err := scpClient.CopyDirToRemote(root, remotePath, opts); err != nil {
return err
}
fmt.Println(" done!")
return nil
}

2
go.mod
View File

@ -16,9 +16,11 @@ require (
require (
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/povsister/scp v0.0.0-20210427074412-33febfd9f13e // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect

7
go.sum
View File

@ -16,6 +16,8 @@ github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0Fn
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
@ -24,6 +26,8 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2Em
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/povsister/scp v0.0.0-20210427074412-33febfd9f13e h1:VtsDti2SgX7M7jy0QAyGgb162PeHLrOaNxmcYOtaGsY=
github.com/povsister/scp v0.0.0-20210427074412-33febfd9f13e/go.mod h1:i1Au86ZXK0ZalQNyBp2njCcyhSCR/QP/AMfILip+zNI=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
@ -40,10 +44,12 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -58,6 +64,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=