From bd46e98e70d6ddf76fed65f53ebf37264d5180b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20GUILLAUME?= Date: Fri, 25 Apr 2025 15:19:55 +0200 Subject: [PATCH] removing unsed deps. adding more subcommands --- go.mod | 2 - gshare.go | 340 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 212 insertions(+), 130 deletions(-) diff --git a/go.mod b/go.mod index 1b5342c..fd2e62c 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,6 @@ require ( github.com/alexflint/go-arg v1.5.1 // indirect github.com/alexflint/go-scalar v1.2.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/emersion/go-webdav v0.6.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/studio-b12/gowebdav v0.10.0 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/gshare.go b/gshare.go index 91e6c74..37b78e8 100644 --- a/gshare.go +++ b/gshare.go @@ -1,174 +1,258 @@ package main import ( - "fmt" - log "github.com/sirupsen/logrus" - "os" - "errors" - "strings" - "gopkg.in/yaml.v3" - "github.com/studio-b12/gowebdav" - "github.com/alexflint/go-arg" - "github.com/dustin/go-humanize" + "fmt" + log "github.com/sirupsen/logrus" + "os" + "io" + "errors" + "strings" + "path/filepath" + "gopkg.in/yaml.v3" + "github.com/studio-b12/gowebdav" + "github.com/alexflint/go-arg" + "github.com/dustin/go-humanize" ) type NextcloudServers struct { - Configs []NextcloudServer `nextcloud` + Configs []NextcloudServer `nextcloud` } type NextcloudServer struct { - Uuid string - Name string - Url string - Username string - Token string + Uuid string + Name string + Url string + Username string + Token string } type LsCmd struct { - Remote string `arg:"positional" help:"remote folder" default:"/"` - Detailed bool `arg:"-d,--details",default:"false"` - Recurse bool `arg:"-r,--recurse",default:"false"` + Remote string `arg:"positional" help:"remote folder" default:"/"` + Detailed bool `arg:"-d,--details",default:"false"` + Recurse bool `arg:"-r,--recurse",default:"false"` } type RmCmd struct { - Remote string `arg:"positional,required"` - Force bool `arg:"-f,--force",default:"false"` - Recurse bool `arg:"-r,--recurse",default:"false"` + Remote string `arg:"positional,required"` + Force bool `arg:"-f,--force",default:"false"` + Recurse bool `arg:"-r,--recurse",default:"false"` } type UploadCmd struct { - Local string `arg:"positional,required"` - Remote string `arg:"positional"` - Force bool `arg:"-f,--force",default:"false"` + Local string `arg:"positional,required"` + Remote string `arg:"positional"` } type DownloadCmd struct { - Remote string `arg:"positional"` - Local string `arg:"positional"` - Force bool `arg:"-f,--force",default:"false"` + Remote string `arg:"positional"` + Local string `arg:"positional"` } type ShareCmd struct { - Remote string `arg:"positional"` - Name string `arg:"-n,--name"` + Remote string `arg:"positional"` + Name string `arg:"-n,--name"` } type args struct { - Servername string `arg:"--server"` - Ls *LsCmd `arg:"subcommand:ls"` - Rm *RmCmd `arg:"subcommand:rm"` - Upload *UploadCmd `arg:"subcommand:upload"` - Download *DownloadCmd `arg:"subcommand:download"` - Share *ShareCmd `arg:"subcommand:share"` + Servername string `arg:"--server"` + Ls *LsCmd `arg:"subcommand:ls"` + Rm *RmCmd `arg:"subcommand:rm"` + Upload *UploadCmd `arg:"subcommand:upload"` + Download *DownloadCmd `arg:"subcommand:download"` + Share *ShareCmd `arg:"subcommand:share"` } func (args) Version() string { - return "1.0.0" + return "1.0.0" +} + +func check(e error) { + if e != nil { + log.Fatal(e) + } } func loadConfig(name string) (NextcloudServer, error) { - var err_msg string - var config_err NextcloudServer - var filename = os.Args[0] - f, err := os.ReadFile("~/.config/gshare/config.yaml") - if err != nil { - log.Fatal(err) - } - var config NextcloudServers - if err := yaml.Unmarshal([]byte(f), &config); err != nil { - log.Fatal(err) - } - switch size := len(config.Configs); size { - case 0: - err_msg = fmt.Sprintf("No server configured. You should configure one with %s config add", filename) - log.Fatal(err_msg) - return config_err, errors.New(err_msg) - case 1: - log.Debug("Only one server configured") - return config.Configs[0], nil - default: - if len(name) == 0 { - err_msg = fmt.Sprintf("Multiple servers configured. You should specify a server name with %s --server servername %s", filename) - err_msg = "You should specify a server name with --server servername" - log.Fatal(err_msg) - return config_err, errors.New(err_msg) - } - } - for _, s := range config.Configs { - if s.Name == name { - return s, nil - } - } - err_msg = fmt.Sprintf("Could not find requested server with name %s", name) - log.Fatal(err_msg) - return config_err, errors.New(err_msg) + var err_msg string + var config_err NextcloudServer + var filename = os.Args[0] + //f, err := os.ReadFile("~/.config/gshare/config.yaml") + f, err := os.ReadFile("config.yaml") + check(err) + var config NextcloudServers + err = yaml.Unmarshal([]byte(f), &config) + check(err) + switch size := len(config.Configs); size { + case 0: + err_msg = fmt.Sprintf("No server configured. You should configure one with %s config add", filename) + log.Fatal(err_msg) + return config_err, errors.New(err_msg) + case 1: + log.Debug("Only one server configured") + return config.Configs[0], nil + default: + if len(name) == 0 { + err_msg = fmt.Sprintf("Multiple servers configured. You should specify a server name with %s --server servername %s", filename) + err_msg = "You should specify a server name with --server servername" + log.Fatal(err_msg) + return config_err, errors.New(err_msg) + } + } + for _, s := range config.Configs { + if s.Name == name { + return s, nil + } + } + err_msg = fmt.Sprintf("Could not find requested server with name %s", name) + log.Fatal(err_msg) + return config_err, errors.New(err_msg) } func listDir(c gowebdav.Client, dir string, details bool, recurse bool, recursecount int) { - files, err := c.ReadDir(dir) - if err != nil { - log.Fatal(err) - } - if recursecount == 0 { - fmt.Println(dir) - } - for i, file := range files { - var pfx = strings.Repeat("|", recursecount) - var sfx = "|-" - if details { - var ftype = "[File]" - var size = "" - if file.IsDir() { - ftype = "[Dir]" - } else { - size = humanize.Bytes(uint64(file.Size())) - } - if i == len(files) - 1 { - sfx = "\\-" - } - fmt.Println(fmt.Sprintf("%s%s %s %s %s", pfx, sfx, ftype, file.Name(), size)) - } else { - fmt.Println(fmt.Sprintf("%s%s %s", pfx, sfx, file.Name())) - } - if recurse { - if file.IsDir() { - new_dir := fmt.Sprintf("%s/%s", dir, file.Name()) - listDir(c, new_dir, details, recurse, recursecount+1) - } - } - } + files, err := c.ReadDir(dir) + check(err) + if recursecount == 0 { + fmt.Println(dir) + } + for i, file := range files { + var pfx = strings.Repeat("|", recursecount) + var sfx = "|-" + if details { + var ftype = "[File]" + var size = "" + if file.IsDir() { + ftype = "[Dir]" + } else { + size = humanize.Bytes(uint64(file.Size())) + } + if i == len(files) - 1 { + sfx = "\\-" + } + fmt.Println(fmt.Sprintf("%s%s %s %s %s", pfx, sfx, ftype, file.Name(), size)) + } else { + fmt.Println(fmt.Sprintf("%s%s %s", pfx, sfx, file.Name())) + } + if recurse { + if file.IsDir() { + new_dir := fmt.Sprintf("%s/%s", dir, file.Name()) + listDir(c, new_dir, details, recurse, recursecount+1) + } + } + } } func Remove(c gowebdav.Client, dir string, force bool, recurse bool) { - fmt.Println(fmt.Sprintf("%s, %t, %t", dir, force, recurse)) - c.Remove(dir) + log.Info(fmt.Sprintf("Removing remote file or directory : %s", dir)) + c.Remove(dir) +} + +func Upload(c gowebdav.Client, local_dir string, remote_dir string) { + _path, _ := os.Stat(local_dir) + _info := os.FileInfo(_path) + var l_t_r []string + if _info.IsDir() { + if local_dir[len(local_dir)-1:] != "/" { + local_dir = fmt.Sprintf("%s/", local_dir) + } + } + l_t_r = strings.Split(local_dir, "/") + log.Info(fmt.Sprintf("Creating directory : %s", remote_dir)) + var err = c.Mkdir(remote_dir, 0644) + check(err) + + err = filepath.Walk(local_dir, func(path string, info os.FileInfo, err error) error { + check(err) + var l_t_r_2 string + if _info.IsDir() { + l_t_r_2 = strings.Join(strings.Split(path, "/")[len(l_t_r)-2:], "/") + } else { + l_t_r_2 = strings.Join(strings.Split(path, "/")[len(l_t_r)-1:], "/") + } + l_t_r_3 := []string{remote_dir, l_t_r_2} + local_to_remote := strings.Join(l_t_r_3, "/") + if info.IsDir() { + log.Info(fmt.Sprintf("Creating directory : %s", local_to_remote)) + c.Mkdir(local_to_remote, 0644) + } else { + file, err := os.Open(path) + defer file.Close() + check(err) + log.Info(fmt.Sprintf("Uploading file %s into %s", path, local_to_remote)) + c.WriteStream(local_to_remote, file, 0644) + } + return nil + }) + check(err) +} + +func Download(c gowebdav.Client, remote_dir string, local_dir string, inrecurse bool) { + remote_info, err := c.Stat(remote_dir) + check(err) + if remote_info.IsDir() { + if remote_dir[len(remote_dir)-1:] != "/" { + remote_dir = fmt.Sprintf("%s/", remote_dir) + } + } + var r_t_l = strings.Split(remote_dir, "/") + var r_t_l_2 string + if remote_info.IsDir() { + r_t_l_2 = strings.Join(strings.Split(remote_dir, "/")[len(r_t_l)-2:], "/") + } else { + r_t_l_2 = strings.Join(strings.Split(remote_dir, "/")[len(r_t_l)-1:], "/") + } + r_t_l_3 := []string{local_dir, r_t_l_2} + remote_to_local := strings.ReplaceAll(strings.Join(r_t_l_3, "/"), "//", "/") + if remote_info.IsDir() { + os.MkdirAll(remote_to_local, 0644) + files, err := c.ReadDir(remote_dir) + check(err) + for _, file := range files { + Download(c, fmt.Sprintf("%s%s", remote_dir, file.Name()), remote_to_local, true) + } + } else { + log.Info(fmt.Sprintf("Downloading remote file %s to %s", remote_dir, remote_to_local)) + reader, err := c.ReadStream(remote_dir) + check(err) + file, err := os.Create(remote_to_local) + check(err) + defer file.Close() + io.Copy(file, reader) + } } func nextcloudConnect(config NextcloudServer) gowebdav.Client { - baseUrl := fmt.Sprintf("%s/remote.php/dav/files/%s", config.Url, config.Username) - c := gowebdav.NewClient(baseUrl, config.Username, config.Token) - return *c + baseUrl := fmt.Sprintf("%s/remote.php/dav/files/%s", config.Url, config.Username) + c := gowebdav.NewClient(baseUrl, config.Username, config.Token) + return *c } func main() { - var args args - p := arg.MustParse(&args) - if p.Subcommand() == nil { - p.Fail("missing subcommand") - } - - config, err := loadConfig(args.Servername) - if err != nil { - log.Fatal(err) - } - switch { - case args.Ls != nil: - c := nextcloudConnect(config) - c.Connect() - listDir(c, args.Ls.Remote, args.Ls.Detailed, args.Ls.Recurse, 0) - case args.Rm != nil: - c := nextcloudConnect(config) - c.Connect() - Remove(c, args.Rm.Remote, args.Rm.Force, args.Rm.Recurse) - } + var args args + p := arg.MustParse(&args) + if p.Subcommand() == nil { + p.Fail("missing subcommand") + } + config, err := loadConfig(args.Servername) + check(err) + switch { + case args.Ls != nil: + c := nextcloudConnect(config) + c.Connect() + listDir(c, args.Ls.Remote, args.Ls.Detailed, args.Ls.Recurse, 0) + case args.Rm != nil: + c := nextcloudConnect(config) + c.Connect() + Remove(c, args.Rm.Remote, args.Rm.Force, args.Rm.Recurse) + case args.Upload != nil: + c := nextcloudConnect(config) + c.Connect() + Upload(c, args.Upload.Local, args.Upload.Remote) + case args.Download != nil: + c := nextcloudConnect(config) + c.Connect() + Download(c, args.Download.Remote, args.Download.Local, false) + case args.Share != nil: + fmt.Println("Not yet implemented.") + fmt.Println("You should use nextcloud directly to create the share for now.") + } }