|
|
@ -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 |
|
|
|
} |
|
|
|