From 4fd4391c6d669dcc5acfc00d4a6f3c9f9a1819e4 Mon Sep 17 00:00:00 2001 From: JEAN-FRANCOIS GUILLAUME Date: Fri, 25 Apr 2025 11:41:43 +0200 Subject: [PATCH] first pass --- .gitignore | 129 +++++++++++++++++++++++++++++++++++++++ README.md | 0 go.mod | 15 +++++ go.sum | 29 +++++++++ gshare.go | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 347 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 gshare.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0a266f --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +*.manifest +*.spec +pip-log.txt +pip-delete-this-directory.txt +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ +*.mo +*.pot +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal +instance/ +.webassets-cache +.scrapy +docs/_build/ +target/ +.ipynb_checkpoints +profile_default/ +ipython_config.py +.python-version +Pipfile.lock +celerybeat-schedule +*.sage.py +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +.spyderproject +.spyproject +.ropeproject +/site +.mypy_cache/ +.dmypy.json +dmypy.json +.pyre/ +.idea +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.idea/**/contentModel.xml +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml +.idea/**/gradle.xml +.idea/**/libraries +.idea/modules.xml +.idea/*.iml +.idea/modules +*.iml +*.ipr +cmake-build-*/ +.idea/**/mongoSettings.xml +*.iws +.idea +out/ +.idea_modules/ +atlassian-ide-plugin.xml +.idea/replstate.xml +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +.idea/httpRequests +.idea/caches/build_file_checksums.ser +*.[oa] +*~ +.idea +*.pyc +__pycache__ +*tmp.* +*.log +*.sqlite* +celerybeat-schedule +config.ini +*.sh +clam_uwsgi_dev.ini +docker/data/ldap +docker/data/ldap_config +docker/data/pgsql +docker/data/mysql/ +docker/data/slurm_jobdir/ +docker/data/statics +docker/data/uploads +docker/data/clam/STOR +celerybeat-schedule.db +setup.env +config.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1b5342c --- /dev/null +++ b/go.mod @@ -0,0 +1,15 @@ +module glicid/gshare + +go 1.23.5 + +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 + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8b064d4 --- /dev/null +++ b/go.sum @@ -0,0 +1,29 @@ +github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8Y= +github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8= +github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw= +github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emersion/go-ical v0.0.0-20240127095438-fc1c9d8fb2b6/go.mod h1:BEksegNspIkjCQfmzWgsgbu6KdeJ/4LwUZs7DMBzjzw= +github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= +github.com/emersion/go-webdav v0.6.0 h1:rbnBUEXvUM2Zk65Him13LwJOBY0ISltgqM5k6T5Lq4w= +github.com/emersion/go-webdav v0.6.0/go.mod h1:mI8iBx3RAODwX7PJJ7qzsKAKs/vY429YfS2/9wKnDbQ= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/studio-b12/gowebdav v0.10.0 h1:Yewz8FFiadcGEu4hxS/AAJQlHelndqln1bns3hcJIYc= +github.com/studio-b12/gowebdav v0.10.0/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= +github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gshare.go b/gshare.go new file mode 100644 index 0000000..91e6c74 --- /dev/null +++ b/gshare.go @@ -0,0 +1,174 @@ +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" +) + +type NextcloudServers struct { + Configs []NextcloudServer `nextcloud` +} + +type NextcloudServer struct { + 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"` +} + +type RmCmd struct { + 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"` +} + +type DownloadCmd struct { + Remote string `arg:"positional"` + Local string `arg:"positional"` + Force bool `arg:"-f,--force",default:"false"` +} + +type ShareCmd struct { + 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"` +} + +func (args) Version() string { + return "1.0.0" +} + +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) +} + +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) + } + } + } +} + +func Remove(c gowebdav.Client, dir string, force bool, recurse bool) { + fmt.Println(fmt.Sprintf("%s, %t, %t", dir, force, recurse)) + c.Remove(dir) +} + +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 +} + +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) + } +}