removing unsed deps. adding more subcommands

This commit is contained in:
Jean-François GUILLAUME 2025-04-25 15:19:55 +02:00
parent 4fd4391c6d
commit bd46e98e70
2 changed files with 212 additions and 130 deletions

2
go.mod
View file

@ -6,8 +6,6 @@ require (
github.com/alexflint/go-arg v1.5.1 // indirect github.com/alexflint/go-arg v1.5.1 // indirect
github.com/alexflint/go-scalar v1.2.0 // indirect github.com/alexflint/go-scalar v1.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // 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/sirupsen/logrus v1.9.3 // indirect
github.com/studio-b12/gowebdav v0.10.0 // indirect github.com/studio-b12/gowebdav v0.10.0 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect

340
gshare.go
View file

@ -1,174 +1,258 @@
package main package main
import ( import (
"fmt" "fmt"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"os" "os"
"errors" "io"
"strings" "errors"
"gopkg.in/yaml.v3" "strings"
"github.com/studio-b12/gowebdav" "path/filepath"
"github.com/alexflint/go-arg" "gopkg.in/yaml.v3"
"github.com/dustin/go-humanize" "github.com/studio-b12/gowebdav"
"github.com/alexflint/go-arg"
"github.com/dustin/go-humanize"
) )
type NextcloudServers struct { type NextcloudServers struct {
Configs []NextcloudServer `nextcloud` Configs []NextcloudServer `nextcloud`
} }
type NextcloudServer struct { type NextcloudServer struct {
Uuid string Uuid string
Name string Name string
Url string Url string
Username string Username string
Token string Token string
} }
type LsCmd struct { type LsCmd struct {
Remote string `arg:"positional" help:"remote folder" default:"/"` Remote string `arg:"positional" help:"remote folder" default:"/"`
Detailed bool `arg:"-d,--details",default:"false"` Detailed bool `arg:"-d,--details",default:"false"`
Recurse bool `arg:"-r,--recurse",default:"false"` Recurse bool `arg:"-r,--recurse",default:"false"`
} }
type RmCmd struct { type RmCmd struct {
Remote string `arg:"positional,required"` Remote string `arg:"positional,required"`
Force bool `arg:"-f,--force",default:"false"` Force bool `arg:"-f,--force",default:"false"`
Recurse bool `arg:"-r,--recurse",default:"false"` Recurse bool `arg:"-r,--recurse",default:"false"`
} }
type UploadCmd struct { type UploadCmd struct {
Local string `arg:"positional,required"` Local string `arg:"positional,required"`
Remote string `arg:"positional"` Remote string `arg:"positional"`
Force bool `arg:"-f,--force",default:"false"`
} }
type DownloadCmd struct { type DownloadCmd struct {
Remote string `arg:"positional"` Remote string `arg:"positional"`
Local string `arg:"positional"` Local string `arg:"positional"`
Force bool `arg:"-f,--force",default:"false"`
} }
type ShareCmd struct { type ShareCmd struct {
Remote string `arg:"positional"` Remote string `arg:"positional"`
Name string `arg:"-n,--name"` Name string `arg:"-n,--name"`
} }
type args struct { type args struct {
Servername string `arg:"--server"` Servername string `arg:"--server"`
Ls *LsCmd `arg:"subcommand:ls"` Ls *LsCmd `arg:"subcommand:ls"`
Rm *RmCmd `arg:"subcommand:rm"` Rm *RmCmd `arg:"subcommand:rm"`
Upload *UploadCmd `arg:"subcommand:upload"` Upload *UploadCmd `arg:"subcommand:upload"`
Download *DownloadCmd `arg:"subcommand:download"` Download *DownloadCmd `arg:"subcommand:download"`
Share *ShareCmd `arg:"subcommand:share"` Share *ShareCmd `arg:"subcommand:share"`
} }
func (args) Version() string { 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) { func loadConfig(name string) (NextcloudServer, error) {
var err_msg string var err_msg string
var config_err NextcloudServer var config_err NextcloudServer
var filename = os.Args[0] var filename = os.Args[0]
f, err := os.ReadFile("~/.config/gshare/config.yaml") //f, err := os.ReadFile("~/.config/gshare/config.yaml")
if err != nil { f, err := os.ReadFile("config.yaml")
log.Fatal(err) check(err)
} var config NextcloudServers
var config NextcloudServers err = yaml.Unmarshal([]byte(f), &config)
if err := yaml.Unmarshal([]byte(f), &config); err != nil { check(err)
log.Fatal(err) switch size := len(config.Configs); size {
} case 0:
switch size := len(config.Configs); size { err_msg = fmt.Sprintf("No server configured. You should configure one with %s config add", filename)
case 0: log.Fatal(err_msg)
err_msg = fmt.Sprintf("No server configured. You should configure one with %s config add", filename) return config_err, errors.New(err_msg)
log.Fatal(err_msg) case 1:
return config_err, errors.New(err_msg) log.Debug("Only one server configured")
case 1: return config.Configs[0], nil
log.Debug("Only one server configured") default:
return config.Configs[0], nil if len(name) == 0 {
default: err_msg = fmt.Sprintf("Multiple servers configured. You should specify a server name with %s --server servername %s", filename)
if len(name) == 0 { err_msg = "You should specify a server name with --server servername"
err_msg = fmt.Sprintf("Multiple servers configured. You should specify a server name with %s --server servername %s", filename) log.Fatal(err_msg)
err_msg = "You should specify a server name with --server servername" return config_err, errors.New(err_msg)
log.Fatal(err_msg) }
return config_err, errors.New(err_msg) }
} for _, s := range config.Configs {
} if s.Name == name {
for _, s := range config.Configs { return s, nil
if s.Name == name { }
return s, nil }
} err_msg = fmt.Sprintf("Could not find requested server with name %s", name)
} log.Fatal(err_msg)
err_msg = fmt.Sprintf("Could not find requested server with name %s", name) return config_err, errors.New(err_msg)
log.Fatal(err_msg)
return config_err, errors.New(err_msg)
} }
func listDir(c gowebdav.Client, dir string, details bool, recurse bool, recursecount int) { func listDir(c gowebdav.Client, dir string, details bool, recurse bool, recursecount int) {
files, err := c.ReadDir(dir) files, err := c.ReadDir(dir)
if err != nil { check(err)
log.Fatal(err) if recursecount == 0 {
} fmt.Println(dir)
if recursecount == 0 { }
fmt.Println(dir) for i, file := range files {
} var pfx = strings.Repeat("|", recursecount)
for i, file := range files { var sfx = "|-"
var pfx = strings.Repeat("|", recursecount) if details {
var sfx = "|-" var ftype = "[File]"
if details { var size = ""
var ftype = "[File]" if file.IsDir() {
var size = "" ftype = "[Dir]"
if file.IsDir() { } else {
ftype = "[Dir]" size = humanize.Bytes(uint64(file.Size()))
} else { }
size = humanize.Bytes(uint64(file.Size())) if i == len(files) - 1 {
} sfx = "\\-"
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 %s %s", pfx, sfx, ftype, file.Name(), size)) fmt.Println(fmt.Sprintf("%s%s %s", pfx, sfx, file.Name()))
} else { }
fmt.Println(fmt.Sprintf("%s%s %s", pfx, sfx, file.Name())) if recurse {
} if file.IsDir() {
if recurse { new_dir := fmt.Sprintf("%s/%s", dir, file.Name())
if file.IsDir() { listDir(c, new_dir, details, recurse, recursecount+1)
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) { func Remove(c gowebdav.Client, dir string, force bool, recurse bool) {
fmt.Println(fmt.Sprintf("%s, %t, %t", dir, force, recurse)) log.Info(fmt.Sprintf("Removing remote file or directory : %s", dir))
c.Remove(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 { func nextcloudConnect(config NextcloudServer) gowebdav.Client {
baseUrl := fmt.Sprintf("%s/remote.php/dav/files/%s", config.Url, config.Username) baseUrl := fmt.Sprintf("%s/remote.php/dav/files/%s", config.Url, config.Username)
c := gowebdav.NewClient(baseUrl, config.Username, config.Token) c := gowebdav.NewClient(baseUrl, config.Username, config.Token)
return *c return *c
} }
func main() { func main() {
var args args var args args
p := arg.MustParse(&args) p := arg.MustParse(&args)
if p.Subcommand() == nil { if p.Subcommand() == nil {
p.Fail("missing subcommand") p.Fail("missing subcommand")
} }
config, err := loadConfig(args.Servername)
config, err := loadConfig(args.Servername) check(err)
if err != nil { switch {
log.Fatal(err) case args.Ls != nil:
} c := nextcloudConnect(config)
switch { c.Connect()
case args.Ls != nil: listDir(c, args.Ls.Remote, args.Ls.Detailed, args.Ls.Recurse, 0)
c := nextcloudConnect(config) case args.Rm != nil:
c.Connect() c := nextcloudConnect(config)
listDir(c, args.Ls.Remote, args.Ls.Detailed, args.Ls.Recurse, 0) c.Connect()
case args.Rm != nil: Remove(c, args.Rm.Remote, args.Rm.Force, args.Rm.Recurse)
c := nextcloudConnect(config) case args.Upload != nil:
c.Connect() c := nextcloudConnect(config)
Remove(c, args.Rm.Remote, args.Rm.Force, args.Rm.Recurse) 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.")
}
} }