first pass

This commit is contained in:
Jean-François GUILLAUME 2025-04-25 11:41:43 +02:00
commit 4fd4391c6d
GPG key ID: 38751DAE145EFB5A
5 changed files with 347 additions and 0 deletions

129
.gitignore vendored Normal file
View file

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

0
README.md Normal file
View file

15
go.mod Normal file
View file

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

29
go.sum Normal file
View file

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

174
gshare.go Normal file
View file

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