Commit 10a9d599 authored by Bruce Flynn's avatar Bruce Flynn
Browse files

support remote path from URL, make URL and arg not option

parent dc293c4e
......@@ -9,6 +9,7 @@ import (
"io/ioutil"
url_ "net/url"
"os"
"path/filepath"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
......@@ -33,7 +34,7 @@ type result struct {
}
type sftpAPI struct {
url url_.URL
url *url_.URL
client *sftp.Client
cfg ssh.ClientConfig
req io.Reader
......@@ -125,8 +126,16 @@ func (s sftpAPI) textCommands() <-chan command {
return ch
}
func (s sftpAPI) rempath(path string) string {
if !filepath.IsAbs(path) {
return filepath.Join(s.url.Path, path)
}
return path
}
// args: source, dest as abs paths
func (s sftpAPI) doPut(source, dest string) error {
dest = s.rempath(dest)
fout, err := s.client.Create(dest)
if err != nil {
return errors.Wrapf(err, "can't create %s", dest)
......@@ -148,6 +157,8 @@ func (s sftpAPI) doPut(source, dest string) error {
// args: source, dest as abs paths
func (s sftpAPI) doGet(source, dest string) error {
source = s.rempath(source)
fin, err := s.client.Open(source)
if err != nil {
return errors.Wrapf(err, "can't read %s", source)
......@@ -177,6 +188,7 @@ type stat struct {
func (s sftpAPI) doListdir(path string) ([]stat, error) {
stats := []stat{}
path = s.rempath(path)
infos, err := s.client.ReadDir(path)
if err != nil {
return stats, err
......@@ -191,7 +203,7 @@ func (s sftpAPI) doListdir(path string) ([]stat, error) {
// args: abspath
func (s sftpAPI) doDelete(path string) error {
return s.client.Remove(path)
return s.client.Remove(s.rempath(path))
}
func (s *sftpAPI) ensureConnected() error {
......@@ -287,32 +299,28 @@ func (s sftpAPI) close() {
}
}
func cleanURL(url string) (url_.URL, error) {
newURL := url_.URL{
Scheme: "sftp",
}
// cleanURL takes an input url and makes sure it has a default user and port
func cleanURL(url string) (*url_.URL, error) {
u, err := url_.Parse(url)
if len(url) == 0 || err != nil {
return newURL, err
return &url_.URL{}, err
}
if u.Scheme != "sftp" {
debug("URL does not have scheme sftp, ignoring")
}
newURL.Path = u.Path
username := u.User.Username()
if len(username) == 0 {
username = os.Getenv("USER")
}
newURL.User = url_.User(username)
u.User = url_.User(username)
host := u.Hostname()
if len(u.Port()) != 0 {
host += ":" + u.Port()
} else {
host += ":22"
if len(u.Port()) == 0 {
u.Host += ":22"
}
newURL.Host = host
return newURL, nil
return u, nil
}
func parseServerHostKey(fpath string) (ssh.PublicKey, error) {
......
......@@ -34,10 +34,14 @@ func main() {
log.SetOutput(os.Stderr)
pflag.Usage = func() {
fmt.Fprintf(os.Stderr, `%s [options]
fmt.Fprintf(os.Stderr, `%s [options] <url>
Mini in-process API to drive an SFTP connection.
Arguments:
url: SFTP base url sftp://[<user>@]<hostname>[:port][<basepath>]
Options:
`, os.Args[0])
......@@ -57,7 +61,6 @@ https://gitlab.ssec.wisc.edu/brucef/sftper
"you're super-duper sure you will have no strings with new lines. But, it sure is handy for testing.")
source = pflag.StringP("commands", "c", "-", "File where commands are read from.")
help = pflag.Bool("help", false, "Print help and exit")
urlArg = pflag.String("url", "", "SFTP base url sftp://[<user>@]<hostname>[:port]. Any provided path will be ignored")
// pflag.BoolVar(&verbose, "verbose", false, "Verbose output")
pKey = pflag.StringP("pkey", "i", defaultPrivateKey(), "Path to PEM formatted private key.")
hKey = pflag.StringP("hkey", "h", "", "Path to PEM formatted host public key. If not "+
......@@ -68,7 +71,7 @@ https://gitlab.ssec.wisc.edu/brucef/sftper
pflag.Parse()
if *help {
if *help || pflag.NArg() != 1 {
pflag.Usage()
os.Exit(2)
}
......@@ -83,7 +86,7 @@ https://gitlab.ssec.wisc.edu/brucef/sftper
}
}
sftp, err := newSftpApi(*urlArg, *pKey, *hKey, input, os.Stdout)
sftp, err := newSftpApi(pflag.Arg(0), *pKey, *hKey, input, os.Stdout)
if err != nil {
info("could not initialize api: %s", err)
os.Exit(2)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment