diff --git a/caldav/.gitignore b/caldav/.gitignore new file mode 100644 index 00000000..d22aade3 --- /dev/null +++ b/caldav/.gitignore @@ -0,0 +1,3 @@ +/caldav-importer +/caldav-exporter +/caldav_*.ptar diff --git a/caldav/Makefile b/caldav/Makefile index a1c27e90..fcdfcbc3 100644 --- a/caldav/Makefile +++ b/caldav/Makefile @@ -1,12 +1,33 @@ -GO=go -EXT= +GO = go +EXT = -all: importer exporter +PLAKAR = plakar +VERSION = v1.0.0-beta.8 -importer: - ${GO} build -o importer-caldav${EXT} ./importer/caldav.go ./importer/main.go +all: build -exporter: - ${GO} build -o exporter-caldav${EXT} ./exporter/caldav.go ./exporter/main.go +build: + ${GO} build -v -o caldav-importer${EXT} ./cmd/importer + ${GO} build -v -o caldav-exporter${EXT} ./cmd/exporter -.PHONY: all importer exporter +package: build + rm -f caldav_${VERSION}_*.ptar + ${PLAKAR} pkg create ./manifest.yaml ${VERSION} + +uninstall: + -${PLAKAR} pkg rm caldav + +install: package + ${PLAKAR} pkg add ./caldav_${VERSION}_*.ptar + +reinstall: uninstall install + +test: + ${GO} test -v ./... + +check: test + +clean: + rm -f caldav-importer${EXT} caldav-exporter${EXT} caldav_${VERSION}_*.ptar + +.PHONY: all build package uninstall install reinstall test check clean diff --git a/caldav/README.md b/caldav/README.md index d160623d..7c9df917 100644 --- a/caldav/README.md +++ b/caldav/README.md @@ -13,7 +13,7 @@ This integration allows: - Compatibility with any CalDAV-compliant server or service ---- +--- ## Configuration diff --git a/caldav/cmd/exporter/main.go b/caldav/cmd/exporter/main.go new file mode 100644 index 00000000..127bd39e --- /dev/null +++ b/caldav/cmd/exporter/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "os" + + sdk "github.com/PlakarKorp/go-kloset-sdk" + "github.com/PlakarKorp/integrations/caldav" +) + +func main() { + sdk.EntrypointExporter(os.Args, caldav.NewExporter) +} diff --git a/caldav/cmd/importer/main.go b/caldav/cmd/importer/main.go new file mode 100644 index 00000000..62a9f643 --- /dev/null +++ b/caldav/cmd/importer/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "os" + + sdk "github.com/PlakarKorp/go-kloset-sdk" + "github.com/PlakarKorp/integrations/caldav" +) + +func main() { + sdk.EntrypointImporter(os.Args, caldav.NewImporter) +} diff --git a/caldav/connector.go b/caldav/connector.go new file mode 100644 index 00000000..84a260d6 --- /dev/null +++ b/caldav/connector.go @@ -0,0 +1,196 @@ +package caldav + +import ( + "context" + "fmt" + "io" + "log" + urlpkg "net/url" + "os" + "path" + "strings" + + "github.com/PlakarKorp/kloset/connectors" + "github.com/PlakarKorp/kloset/connectors/exporter" + "github.com/PlakarKorp/kloset/connectors/importer" + "github.com/PlakarKorp/kloset/location" + "github.com/PlakarKorp/kloset/objects" + "github.com/studio-b12/gowebdav" + "golang.org/x/oauth2" +) + +type CalDAV struct { + opts *connectors.Options + + client *gowebdav.Client + location *urlpkg.URL +} + +func New(ctx context.Context, opts *connectors.Options, name string, config map[string]string) (*CalDAV, error) { + // Example google calendar CalDAV URL: + //url := "https://apidata.googleusercontent.com/caldav/v2/EMAIL@gmail.com/events/" + + location, found := config["location"] + if !found { + return nil, fmt.Errorf("missing 'location' in configuration") + } + + username, ok := config["username"] + if !ok { + return nil, fmt.Errorf("missing 'username' in configuration") + } + name, isOAuthClient := config["name"] + + var client *gowebdav.Client + var url string + if !isOAuthClient { + password, ok := config["password"] + if !ok { + return nil, fmt.Errorf("missing 'password' in configuration") + } + url = "https://" + strings.TrimPrefix(location, "caldav://") + client = gowebdav.NewClient(url, username, password) + } else { // OAuth2 client setup + + clientID, ok := config["client_id"] + if !ok { + return nil, fmt.Errorf("missing 'client_id' in configuration") + } + clientSecret, ok := config["client_secret"] + if !ok { + return nil, fmt.Errorf("missing 'client_secret' in configuration") + } + serviceScopes, err := GetOAuth2Scopes(name) + if err != nil { + return nil, fmt.Errorf("error getting OAuth2 scopes for provider '%s': %w", name, err) + } + endpoint, err := GetOAuth2Endpoint(name) + if err != nil { + return nil, fmt.Errorf("error getting OAuth2 endpoint for provider '%s': %w", name, err) + } + + calOAuthProvider := OAuthProvider{ + Name: name, + Config: &oauth2.Config{ + ClientID: clientID, // client ID (provided by the plakar app (production) or by the user directly in a personal app) + ClientSecret: clientSecret, // client secret (same as above) + RedirectURL: "urn:ietf:wg:oauth:2.0:oob", + Scopes: serviceScopes, // e.g., "https://www.googleapis.com/auth/calendar" + Endpoint: endpoint, // e.g., google.Endpoint for Google Calendar + }, + } + + url = GetOAuth2Url(name, username) + + client = calOAuthProvider.GetClient(url) // maybe not using the url directly... the url could be built from the username + } + + loc, err := urlpkg.Parse(url) + if err != nil { + return nil, fmt.Errorf("failed to parse URL: %w", err) + } + + if !strings.HasPrefix(loc.Path, "/") { + loc.Path = "/" + loc.Path + } + + return &CalDAV{ + opts: opts, + + client: client, + location: loc, + }, nil +} + +func NewImporter(ctx context.Context, opts *connectors.Options, name string, config map[string]string) (importer.Importer, error) { + return New(ctx, opts, name, config) +} + +func NewExporter(ctx context.Context, opts *connectors.Options, name string, config map[string]string) (exporter.Exporter, error) { + return New(ctx, opts, name, config) +} + +func (c *CalDAV) Origin() string { return c.location.Host } +func (c *CalDAV) Type() string { return "caldav" } +func (c *CalDAV) Root() string { return c.location.Path } +func (c *CalDAV) Flags() location.Flags { return 0 } + +func (c *CalDAV) Ping(ctx context.Context) error { + return nil +} + +func (c *CalDAV) Import(ctx context.Context, records chan<- *connectors.Record, results <-chan *connectors.Result) error { + defer close(records) + + return c.walk("/", func(p string, finfo os.FileInfo, err error) error { + if err != nil { + if p == "/" { + return err + } + records <- connectors.NewError(p, err) + return nil + } + + p = path.Join(c.location.Path, finfo.Name()) + if p == "/remote.php/dav/calendars/omar" { + return nil + } + log.Println(">>>", p) + + if !finfo.Mode().IsRegular() || !strings.HasPrefix(p, ".ics") { + return nil + } + + records <- connectors.NewRecord(p, "", objects.FileInfo{ + Lname: finfo.Name(), + Lsize: finfo.Size(), + Lmode: finfo.Mode(), + LmodTime: finfo.ModTime(), + }, nil, func() (io.ReadCloser, error) { + return c.client.ReadStream(p) + }) + + return nil + }) +} + +func (c *CalDAV) Export(ctx context.Context, records <-chan *connectors.Record, results chan<- *connectors.Result) error { + defer close(results) + + for record := range records { + if record.IsXattr || record.Err != nil || !record.FileInfo.Lmode.IsRegular() { + results <- record.Ok() + continue + } + + pathname := path.Base(record.Pathname) + if path.Ext(pathname) != ".ics" { + err := fmt.Errorf("unsupported file type %s, only .ics files are supported", + pathname) + results <- record.Error(err) + continue + } + + data, err := io.ReadAll(record.Reader) + if err != nil { + err := fmt.Errorf("failed to read file %s: %w", pathname, err) + results <- record.Error(err) + continue + } + + //TODO: look at this, it returns an error, even if the file is written successfully + if c.client.Write(pathname, data, 0644) != nil { + err := fmt.Errorf("error writing %s: %w", pathname, err) + results <- record.Error(err) + continue + } + + results <- record.Ok() + } + + return nil +} + +func (c *CalDAV) Close(ctx context.Context) error { + return nil +} diff --git a/caldav/exporter/caldav.go b/caldav/exporter/caldav.go deleted file mode 100644 index f9dc6619..00000000 --- a/caldav/exporter/caldav.go +++ /dev/null @@ -1,132 +0,0 @@ -package main - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "path" - "strings" - - "golang.org/x/oauth2" - - "github.com/PlakarKorp/integrations/caldav/oauth2utils" - "github.com/PlakarKorp/kloset/objects" - "github.com/PlakarKorp/kloset/snapshot/exporter" - "github.com/studio-b12/gowebdav" -) - -type CaldavExporter struct { - opts *exporter.Options - - client *gowebdav.Client - url string // The URL of the CalDAV server -} - -func NewCaldavExporter(ctx context.Context, opts *exporter.Options, name string, config map[string]string) (exporter.Exporter, error) { - - // Example google calendar CalDAV URL: - //url := "https://apidata.googleusercontent.com/caldav/v2/EMAIL@gmail.com/events/" - - location, found := config["location"] - if !found { - return nil, fmt.Errorf("missing 'location' in configuration") - } - - username, ok := config["username"] - if !ok { - return nil, fmt.Errorf("missing 'username' in configuration") - } - name, isOAuthClient := config["name"] - - var client *gowebdav.Client - var url string - if !isOAuthClient { - password, ok := config["password"] - if !ok { - return nil, fmt.Errorf("missing 'password' in configuration") - } - url = strings.TrimPrefix(location, "caldav://") - client = gowebdav.NewClient(url, username, password) - } else { // OAuth2 client setup - - clientID, ok := config["client_id"] - if !ok { - return nil, fmt.Errorf("missing 'client_id' in configuration") - } - clientSecret, ok := config["client_secret"] - if !ok { - return nil, fmt.Errorf("missing 'client_secret' in configuration") - } - serviceScopes, err := oauth2utils.GetOAuth2Scopes(name) - if err != nil { - return nil, fmt.Errorf("error getting OAuth2 scopes for provider '%s': %w", name, err) - } - endpoint, err := oauth2utils.GetOAuth2Endpoint(name) - if err != nil { - return nil, fmt.Errorf("error getting OAuth2 endpoint for provider '%s': %w", name, err) - } - - calOAuthProvider := oauth2utils.OAuthProvider{ - Name: name, - Config: &oauth2.Config{ - ClientID: clientID, // client ID (provided by the plakar app (production) or by the user directly in a personal app) - ClientSecret: clientSecret, // client secret (same as above) - RedirectURL: "urn:ietf:wg:oauth:2.0:oob", - Scopes: serviceScopes, // e.g., "https://www.googleapis.com/auth/calendar" - Endpoint: endpoint, // e.g., google.Endpoint for Google Calendar - }, - } - - url = oauth2utils.GetOAuth2Url(name, username) - - client = calOAuthProvider.GetClient(url) // maybe not using the url directly... the url could be built from the username - } - - return &CaldavExporter{ - opts: opts, - - client: client, - url: url, - }, nil -} - -func (c *CaldavExporter) Root(ctx context.Context) (string, error) { - return "/", nil -} - -func (c *CaldavExporter) CreateDirectory(ctx context.Context, pathname string) error { - return nil -} - -func (c *CaldavExporter) StoreFile(ctx context.Context, pathname string, fp io.Reader, size int64) error { - pathname = path.Base(pathname) - - if path.Ext(pathname) != ".ics" { - return fmt.Errorf("unsupported file type %s, only .ics files are supported", pathname) - } - - data, err := ioutil.ReadAll(fp) - if err != nil { - return fmt.Errorf("failed to read file %s: %w", pathname, err) - } - - //TODO: look at this, it returns an error, even if the file is written successfully - if c.client.Write(pathname, data, 0644) != nil { - return fmt.Errorf("error writing %s: %w", pathname, err) - } - return nil -} - -func (c *CaldavExporter) SetPermissions(ctx context.Context, pathname string, fileinfo *objects.FileInfo) error { - return nil -} - -func (c *CaldavExporter) CreateLink(ctx context.Context, oldname string, newname string, ltype exporter.LinkType) error { - return errors.ErrUnsupported -} - -func (c *CaldavExporter) Close(ctx context.Context) error { - return nil -} diff --git a/caldav/exporter/main.go b/caldav/exporter/main.go deleted file mode 100644 index a4e1b793..00000000 --- a/caldav/exporter/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "os" - - sdk "github.com/PlakarKorp/go-kloset-sdk" -) - -func main() { - sdk.EntrypointExporter(os.Args, NewCaldavExporter) -} diff --git a/caldav/go.mod b/caldav/go.mod index fc48bb1e..23475087 100644 --- a/caldav/go.mod +++ b/caldav/go.mod @@ -1,37 +1,46 @@ module github.com/PlakarKorp/integrations/caldav -go 1.24.0 +go 1.25.0 require ( - github.com/PlakarKorp/go-kloset-sdk v1.0.5 - github.com/PlakarKorp/kloset v1.0.12 - github.com/studio-b12/gowebdav v0.10.0 - golang.org/x/oauth2 v0.32.0 + github.com/PlakarKorp/go-kloset-sdk v1.1.0 + github.com/PlakarKorp/kloset v1.1.0 + github.com/studio-b12/gowebdav v0.12.0 + golang.org/x/oauth2 v0.36.0 ) require ( - github.com/PlakarKorp/integration-grpc v1.0.18 // indirect + github.com/PlakarKorp/integration-grpc v1.1.0 // indirect github.com/cockroachdb/crlib v0.0.0-20251122031428-fe658a2dbda1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/getsentry/sentry-go v0.40.0 // indirect + github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/klauspost/compress v1.18.1 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect github.com/nickball/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5 // indirect - github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pierrec/lz4/v4 v4.1.27 // indirect + github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/procfs v0.19.2 // indirect - github.com/tink-crypto/tink-go/v2 v2.5.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/tink-crypto/tink-go/v2 v2.6.0 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zeebo/blake3 v0.2.4 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect - google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/mod v0.36.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect + google.golang.org/grpc v1.81.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect + modernc.org/libc v1.72.3 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.51.0 // indirect ) diff --git a/caldav/go.sum b/caldav/go.sum index 6cbc3c4a..3ebcfb37 100644 --- a/caldav/go.sum +++ b/caldav/go.sum @@ -2,16 +2,16 @@ github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5 h1:5BIUS5hwyLM298mOf8e8TEgD3cCYqc86uaJdQCYZo/o= github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5/go.mod h1:w5D10RxC0NmPYxmQ438CC1S07zaC1zpvuNW7s5sUk2Q= -github.com/PlakarKorp/go-cdc-chunkers v1.0.2 h1:sBWPtDQiezaTjPqF5skLbdjoo8RgiIuseGaFNQnmoOs= -github.com/PlakarKorp/go-cdc-chunkers v1.0.2/go.mod h1:y7ag92JABKPBDoSOPwedssQ5NIOgjRm4Mu6yTBpmUMY= -github.com/PlakarKorp/go-kloset-sdk v1.0.5 h1:jThDS2ZC1N+czquNdjuux8sNf76pwKMGyb3Krm0qDUI= -github.com/PlakarKorp/go-kloset-sdk v1.0.5/go.mod h1:JVvA3RcfYTRfn2vSTWtcr1z8ylSv2OWOTZ+da089APA= -github.com/PlakarKorp/integration-grpc v1.0.18 h1:RD3BC0+eiflaLa5/5V6hgXOn9FTnCR25wDbYl0rgjNI= -github.com/PlakarKorp/integration-grpc v1.0.18/go.mod h1:wvnPX9NYjAMWiptLy5Vx0J6U3Ff8at759B9o+5zMfPw= -github.com/PlakarKorp/kloset v1.0.12 h1:Vj8IT+Cw3uY0ehv+A/GbhQxPIG+U/1heqQGFaDq3Yp0= -github.com/PlakarKorp/kloset v1.0.12/go.mod h1:nwkO5CSMAXp5HKJvxiQRkD1CSK4PN0oEjlt42cjPzYs= -github.com/RaduBerinde/axisds v0.0.0-20250419182453-5135a0650657 h1:8XBWWQD+vFF+JqOsm16t0Kab1a7YWV8+GISVEP8AuZ8= -github.com/RaduBerinde/axisds v0.0.0-20250419182453-5135a0650657/go.mod h1:UHGJonU9z4YYGKJxSaC6/TNcLOBptpmM5m2Cksbnw0Y= +github.com/PlakarKorp/go-cdc-chunkers v1.0.3 h1:6ozBFcNMHvGe6IsbPcAZUUEAExCgcNx3aa8xiCA6+Qw= +github.com/PlakarKorp/go-cdc-chunkers v1.0.3/go.mod h1:y7ag92JABKPBDoSOPwedssQ5NIOgjRm4Mu6yTBpmUMY= +github.com/PlakarKorp/go-kloset-sdk v1.1.0 h1:0wB66dyTwFp3Ky0TLAqehiOVwBDhQr3cTiitCXqQ2hg= +github.com/PlakarKorp/go-kloset-sdk v1.1.0/go.mod h1:AOdpltJ9LlbmnKxxrnh48vNttHa/dOQG0FVRzK4z0BQ= +github.com/PlakarKorp/integration-grpc v1.1.0 h1:ZUa/4m/pZWOmB7XzBfeAA/pOAxev3zbkVHrdi0tqtB4= +github.com/PlakarKorp/integration-grpc v1.1.0/go.mod h1:QZ55M9kXa3DntUvS9njOLoFY1S09bYbHKR/3kflDi5o= +github.com/PlakarKorp/kloset v1.1.0 h1:Yc76wQUbwkrLLx8ZR9XGaVf+s3dslIXKXH/V66rBAoM= +github.com/PlakarKorp/kloset v1.1.0/go.mod h1:t/KqLqbp4zHviF0pA4e63Gex/h5P2fdMTdwFBFQKHpg= +github.com/RaduBerinde/axisds v0.1.0 h1:YItk/RmU5nvlsv/awo2Fjx97Mfpt4JfgtEVAGPrLdz8= +github.com/RaduBerinde/axisds v0.1.0/go.mod h1:UHGJonU9z4YYGKJxSaC6/TNcLOBptpmM5m2Cksbnw0Y= github.com/RaduBerinde/btreemap v0.0.0-20250419174037-3d62b7205d54 h1:bsU8Tzxr/PNz75ayvCnxKZWEYdLMPDkUgticP4a4Bvk= github.com/RaduBerinde/btreemap v0.0.0-20250419174037-3d62b7205d54/go.mod h1:0tr7FllbE9gJkHq7CVeeDDFAFKQVy5RnCSSNBOvdqbc= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -20,32 +20,24 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cockroachdb/crlib v0.0.0-20251122031428-fe658a2dbda1 h1:iX0YCYC5Jbt2/g7zNTP/QxhrV8Syp5kkzNiERKeN1uE= github.com/cockroachdb/crlib v0.0.0-20251122031428-fe658a2dbda1/go.mod h1:NjNuToN/FbhwH1cCyM9G4Rhtxx+ZaOgtoqFR+thng7w= -github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo= -github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 h1:ASDL+UJcILMqgNeV5jiqR4j+sTuvQNHdf2chuKj1M5k= github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506/go.mod h1:Mw7HqKr2kdtu6aYGn3tPmAftiP3QPX63LdK/zcariIo= -github.com/cockroachdb/pebble/v2 v2.1.2 h1:IwYt+Y2Cdw6egblwk1kWzdmJvD2680t5VK/3i0BJ6IA= -github.com/cockroachdb/pebble/v2 v2.1.2/go.mod h1:Aza05DCCc05ghIJZkB4Q/axv/JK9wx5cFwWcnhG0eGw= +github.com/cockroachdb/pebble/v2 v2.1.6 h1:GDo7Z2+LgFZ7LJLdLmBXhDeTVIwgSPGxIT15hE7vGqM= +github.com/cockroachdb/pebble/v2 v2.1.6/go.mod h1:Reo1RTniv1UjVTAu/Fv74y5i3kJ5gmVrPhO9UtFiKn8= github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/swiss v0.0.0-20250624142022-d6e517c1d961 h1:Nua446ru3juLHLZd4AwKNzClZgL1co3pUPGv3o8FlcA= -github.com/cockroachdb/swiss v0.0.0-20250624142022-d6e517c1d961/go.mod h1:yBRu/cnL4ks9bgy4vAASdjIW+/xMlFwuHKqtmh3GZQg= -github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= -github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/cockroachdb/swiss v0.0.0-20251224182025-b0f6560f979b h1:VXvSNzmr8hMj8XTuY0PT9Ane9qZGul/p67vGYwl9BFI= +github.com/cockroachdb/swiss v0.0.0-20251224182025-b0f6560f979b/go.mod h1:yBRu/cnL4ks9bgy4vAASdjIW+/xMlFwuHKqtmh3GZQg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/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/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik= -github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= -github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= -github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y= -github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -58,10 +50,12 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= @@ -70,34 +64,40 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/minio/minlz v1.0.1-0.20250507153514-87eb42fe8882 h1:0lgqHvJWHLGW5TuObJrfyEi6+ASTKDBWikGvPqy9Yiw= github.com/minio/minlz v1.0.1-0.20250507153514-87eb42fe8882/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nickball/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5 h1:eQr2od6dyd9gCLYHgMX2TlAYQtMUpxK7S0nsZXyH0L8= github.com/nickball/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5/go.mod h1:1VYCE0dvZM9Y2q8kcAHdXZB6YwfrCUQDeSJ2DuIiA4k= -github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= -github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.27 h1:+PhzhWDrjRj89TH2sw43nE3+4+W8lSxIuQadEHZyjUk= +github.com/pierrec/lz4/v4 v4.1.27/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -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/tink-crypto/tink-go/v2 v2.5.0 h1:B8KLF6AofxdBIE4UJIaFbmoj5/1ehEtt7/MmzfI4Zpw= -github.com/tink-crypto/tink-go/v2 v2.5.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= +github.com/studio-b12/gowebdav v0.12.0 h1:kFRtQECt8jmVAvA6RHBz3geXUGJHUZA6/IKpOVUs5kM= +github.com/studio-b12/gowebdav v0.12.0/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= +github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= +github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -110,43 +110,72 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= -golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.28.2 h1:3tQ0lf2ADtoby2EtSP+J7IE2SHwEJdP8ioR59wx7XpY= +modernc.org/cc/v4 v4.28.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= +modernc.org/ccgo/v4 v4.34.0 h1:yRLPFZieg532OT4rp4JFNIVcquwalMX26G95WQDqwCQ= +modernc.org/ccgo/v4 v4.34.0/go.mod h1:AS5WYMyBakQ+fhsHhtP8mWB82KTGPkNNJDGfGQCe0/A= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.72.3 h1:ZnDF4tXn4NBXFutMMQC4vtbTFSXhhKzR73fv0beZEAU= +modernc.org/libc v1.72.3/go.mod h1:dn0dZNnnn1clLyvRxLxYExxiKRZIRENOfqQ8XEeg4Qs= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= +modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.51.0 h1:aH/MMSoayAIhozZ7uJbVTT9QO/VhzBf0J9tymmmuC/U= +modernc.org/sqlite v1.51.0/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/caldav/importer/caldav.go b/caldav/importer/caldav.go deleted file mode 100644 index 01e99f73..00000000 --- a/caldav/importer/caldav.go +++ /dev/null @@ -1,162 +0,0 @@ -package main - -import ( - "bytes" - "context" - "fmt" - "io" - "os" - "strings" - "sync" - - "github.com/PlakarKorp/integrations/caldav/oauth2utils" - "github.com/PlakarKorp/kloset/objects" - "github.com/PlakarKorp/kloset/snapshot/importer" - "github.com/studio-b12/gowebdav" - "golang.org/x/oauth2" -) - -type CaldavImporter struct { - opts *importer.Options - - client *gowebdav.Client - url string // The URL of the CalDAV server -} - -func NewCaldavImporter(ctx context.Context, opts *importer.Options, name string, config map[string]string) (importer.Importer, error) { - - // Example google calendar CalDAV URL: - //url := "https://apidata.googleusercontent.com/caldav/v2/EMAIL@gmail.com/events/" - - location, found := config["location"] - if !found { - return nil, fmt.Errorf("missing 'location' in configuration") - } - - username, ok := config["username"] - if !ok { - return nil, fmt.Errorf("missing 'username' in configuration") - } - name, isOAuthClient := config["name"] - - var client *gowebdav.Client - var url string - if !isOAuthClient { - password, ok := config["password"] - if !ok { - return nil, fmt.Errorf("missing 'password' in configuration") - } - url = strings.TrimPrefix(location, "caldav://") - client = gowebdav.NewClient(url, username, password) - } else { // OAuth2 client setup - - clientID, ok := config["client_id"] - if !ok { - return nil, fmt.Errorf("missing 'client_id' in configuration") - } - clientSecret, ok := config["client_secret"] - if !ok { - return nil, fmt.Errorf("missing 'client_secret' in configuration") - } - serviceScopes, err := oauth2utils.GetOAuth2Scopes(name) - if err != nil { - return nil, fmt.Errorf("error getting OAuth2 scopes for provider '%s': %w", name, err) - } - endpoint, err := oauth2utils.GetOAuth2Endpoint(name) - if err != nil { - return nil, fmt.Errorf("error getting OAuth2 endpoint for provider '%s': %w", name, err) - } - - calOAuthProvider := oauth2utils.OAuthProvider{ - Name: name, - Config: &oauth2.Config{ - ClientID: clientID, // client ID (provided by the plakar app (production) or by the user directly in a personal app) - ClientSecret: clientSecret, // client secret (same as above) - RedirectURL: "urn:ietf:wg:oauth:2.0:oob", - Scopes: serviceScopes, // e.g., "https://www.googleapis.com/auth/calendar" - Endpoint: endpoint, // e.g., google.Endpoint for Google Calendar - }, - } - - url = oauth2utils.GetOAuth2Url(name, username) - - client = calOAuthProvider.GetClient(url) // maybe not using the url directly... the url could be built from the username - } - - return &CaldavImporter{ - opts: opts, - - client: client, - url: url, - }, nil -} - -func (c *CaldavImporter) Origin(ctx context.Context) (string, error) { - return c.url, nil -} - -func (c *CaldavImporter) Type(ctx context.Context) (string, error) { - return "caldav", nil -} - -func (c *CaldavImporter) Root(ctx context.Context) (string, error) { - return "/", nil -} - -func (c *CaldavImporter) Scan(ctx context.Context) (<-chan *importer.ScanResult, error) { - - results := make(chan *importer.ScanResult, 1000) - var wg sync.WaitGroup - - wg.Add(1) - go func() { - defer wg.Done() - entries, err := c.client.ReadDir("/") - if err != nil { - results <- importer.NewScanError("/", fmt.Errorf("error reading directory: %w", err)) - return - } - results <- importer.NewScanRecord("/", "", objects.FileInfo{ - Lname: "/", - Lsize: 0, - Lmode: os.ModeDir | 0755, - LmodTime: entries[0].ModTime(), - }, nil, nil) - if len(entries) == 0 { - results <- importer.NewScanError("/", fmt.Errorf("no entries found in the root directory")) - return - } - - for _, entry := range entries { - if strings.HasSuffix(entry.Name(), ".ics") { - data, err := c.client.Read(entry.Name()) - if err != nil { - results <- importer.NewScanError("/"+entry.Name(), fmt.Errorf("error reading file %s: %w", entry.Name(), err)) - continue - } - - rd := bytes.NewReader(data) - - results <- importer.NewScanRecord("/"+entry.Name(), "", objects.FileInfo{ - Lname: entry.Name(), - Lsize: entry.Size(), - Lmode: entry.Mode(), - LmodTime: entry.ModTime(), - }, nil, func() (io.ReadCloser, error) { - return io.NopCloser(rd), nil - }) - } - } - }() - - go func() { - wg.Wait() - defer close(results) - }() - - return results, nil -} - -func (c *CaldavImporter) Close(ctx context.Context) error { - return nil -} diff --git a/caldav/importer/main.go b/caldav/importer/main.go deleted file mode 100644 index b563b7aa..00000000 --- a/caldav/importer/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "os" - - sdk "github.com/PlakarKorp/go-kloset-sdk" -) - -func main() { - sdk.EntrypointImporter(os.Args, NewCaldavImporter) -} diff --git a/caldav/manifest.yaml b/caldav/manifest.yaml index 038120ff..c3390e25 100644 --- a/caldav/manifest.yaml +++ b/caldav/manifest.yaml @@ -1,11 +1,13 @@ name: caldav display_name: CalDAV description: Integration providing import and export capabilities to CalDAV servers. -version: v1.0.0-beta.7 +homepage: https://github.com/PlakarKorp/integrations/tree/main/caldav +license: ISC +api_version: v1.1.0 connectors: - type: importer - executable: importer-caldav + executable: caldav-importer protocols: [caldav] - type: exporter - executable: exporter-caldav + executable: caldav-exporter protocols: [caldav] diff --git a/caldav/oauth2utils/oauth2.go b/caldav/oauth2.go similarity index 99% rename from caldav/oauth2utils/oauth2.go rename to caldav/oauth2.go index 8a9e75ad..b679d117 100644 --- a/caldav/oauth2utils/oauth2.go +++ b/caldav/oauth2.go @@ -1,4 +1,4 @@ -package oauth2utils +package caldav import ( "context"