From fd659be06d5666d74fc1f10695c68b2ac21d329e Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sat, 2 Aug 2025 20:02:55 +0530 Subject: [PATCH 01/12] added gcs filestore and some testcase --- pkg/gofr/datasource/file/gcs/file.go | 116 +++++ pkg/gofr/datasource/file/gcs/file_parse.go | 195 ++++++++ pkg/gofr/datasource/file/gcs/fs.go | 461 ++++++++++++++++++ pkg/gofr/datasource/file/gcs/fs_dir.go | 248 ++++++++++ pkg/gofr/datasource/file/gcs/fs_dir_test.go | 231 +++++++++ pkg/gofr/datasource/file/gcs/fs_test.go | 314 ++++++++++++ pkg/gofr/datasource/file/gcs/go.mod | 66 +++ pkg/gofr/datasource/file/gcs/go.sum | 169 +++++++ pkg/gofr/datasource/file/gcs/interface.go | 115 +++++ pkg/gofr/datasource/file/gcs/logger.go | 34 ++ .../datasource/file/gcs/mock_interface.go | 287 +++++++++++ 11 files changed, 2236 insertions(+) create mode 100644 pkg/gofr/datasource/file/gcs/file.go create mode 100644 pkg/gofr/datasource/file/gcs/file_parse.go create mode 100644 pkg/gofr/datasource/file/gcs/fs.go create mode 100644 pkg/gofr/datasource/file/gcs/fs_dir.go create mode 100644 pkg/gofr/datasource/file/gcs/fs_dir_test.go create mode 100644 pkg/gofr/datasource/file/gcs/fs_test.go create mode 100644 pkg/gofr/datasource/file/gcs/go.mod create mode 100644 pkg/gofr/datasource/file/gcs/go.sum create mode 100644 pkg/gofr/datasource/file/gcs/interface.go create mode 100644 pkg/gofr/datasource/file/gcs/logger.go create mode 100644 pkg/gofr/datasource/file/gcs/mock_interface.go diff --git a/pkg/gofr/datasource/file/gcs/file.go b/pkg/gofr/datasource/file/gcs/file.go new file mode 100644 index 000000000..392f542ce --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/file.go @@ -0,0 +1,116 @@ +package gcs + +import ( + "errors" + "io" + "time" + + "cloud.google.com/go/storage" +) + +type GCSFile struct { + conn gcsClient + writer *storage.Writer + name string + offset int64 + logger Logger + metrics Metrics + size int64 + contentType string + body io.ReadCloser + lastModified time.Time + isDir bool +} + +// ====== File interface methods ====== + +func (g *GCSFile) Read(p []byte) (int, error) { + if g.body == nil { + return 0, errors.New("GCS file body is nil") + } + return g.body.Read(p) +} +func (g *GCSFile) Write(p []byte) (int, error) { + bucketName := getBucketName(g.name) + + var msg string + + st := statusErr + + defer g.sendOperationStats(&FileLog{ + Operation: "WRITE", + Location: getLocation(bucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + n, err := g.writer.Write(p) + if err != nil { + g.logger.Errorf("failed to write: %v", err) + msg = err.Error() + return n, err + } + st = statusSuccess + msg = "Write successful" + return n, nil + +} + +func (g *GCSFile) Close() error { + bucketName := getBucketName(g.name) + var msg string + st := statusErr + + defer g.sendOperationStats(&FileLog{ + Operation: "CLOSE", + Location: getLocation(bucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + if g.writer != nil { + err := g.writer.Close() + if err != nil { + msg = err.Error() + return err + } + st = statusSuccess + msg = "Writer closed successfully" + return nil + } + + if g.body != nil { + err := g.body.Close() + if err != nil { + msg = err.Error() + return err + } + st = statusSuccess + msg = "Reader closed successfully" + return nil + } + st = statusSuccess + msg = "Writer closed successfully" + return nil +} + +func (g *GCSFile) Seek(offset int64, whence int) (int64, error) { + // Not supported: Seek requires reopening with range. + return 0, errors.New("Seek not supported on GCSFile") +} + +func (g *GCSFile) ReadAt(_ []byte, _ int64) (int, error) { + return 0, errors.New("ReadAt not supported on GCSFile") +} + +func (g *GCSFile) WriteAt(_ []byte, _ int64) (int, error) { + return 0, errors.New("WriteAt not supported on GCSFile (read-only)") +} + +func (g *GCSFile) sendOperationStats(fl *FileLog, startTime time.Time) { + duration := time.Since(startTime).Microseconds() + + fl.Duration = duration + + g.logger.Debug(fl) +} diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go new file mode 100644 index 000000000..0ae769e71 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -0,0 +1,195 @@ +package gcs + +import ( + "bufio" + "bytes" + "encoding/json" + "errors" + "io" + "io/fs" + "path" + "strings" + "time" + + file "gofr.dev/pkg/gofr/datasource/file" +) + +var ( + // errNotPointer is returned when Read method is called with a non-pointer argument. + errStringNotPointer = errors.New("input should be a pointer to a string") + ErrOutOfRange = errors.New("out of range") +) + +const ( + statusErr = "ERROR" + statusSuccess = "SUCCESS" +) + +// textReader implements RowReader for reading text files. +type textReader struct { + scanner *bufio.Scanner + logger Logger +} + +// jsonReader implements RowReader for reading JSON files. +type jsonReader struct { + decoder *json.Decoder + token json.Token +} + +func (f *GCSFile) ReadAll() (file.RowReader, error) { + bucketName := getBucketName(f.name) + location := path.Join(bucketName, f.name) + + defer f.sendOperationStats(&FileLog{ + Operation: "READALL", + Location: location, + }, time.Now()) + + if strings.HasSuffix(f.Name(), ".json") { + return f.createJSONReader(location) + } + + return f.createTextCSVReader(location) +} + +// createJSONReader creates a JSON reader for JSON files. +func (f *GCSFile) createJSONReader(location string) (file.RowReader, error) { + status := statusErr + + defer f.sendOperationStats(&FileLog{Operation: "JSON READER", Location: location, Status: &status}, time.Now()) + + buffer, err := io.ReadAll(f.body) + if err != nil { + f.logger.Errorf("ReadAll Failed: Unable to read json file: %v", err) + return nil, err + } + + reader := bytes.NewReader(buffer) + + decoder := json.NewDecoder(reader) + + // Peek the first JSON token to determine the type + // Note: This results in offset to move ahead, making it necessary to + // decode again if we are decoding a json object instead of array + token, err := decoder.Token() + if err != nil { + f.logger.Errorf("Error decoding token: %v", err) + return nil, err + } + + if d, ok := token.(json.Delim); ok && d == '[' { + status = statusSuccess + return &jsonReader{decoder: decoder, token: token}, err + } + + // Reading JSON object + decoder = json.NewDecoder(reader) + status = statusSuccess + + return &jsonReader{decoder: decoder}, nil +} + +// createTextCSVReader creates a text reader for reading text files. +func (f *GCSFile) createTextCSVReader(location string) (file.RowReader, error) { + status := statusErr + + defer f.sendOperationStats(&FileLog{Operation: "TEXT/CSV READER", Location: location, Status: &status}, time.Now()) + + buffer, err := io.ReadAll(f.body) + if err != nil { + f.logger.Errorf("ReadAll failed: Unable to read text file: %v", err) + return nil, err + } + + reader := bytes.NewReader(buffer) + status = statusSuccess + + return &textReader{ + scanner: bufio.NewScanner(reader), + logger: f.logger, + }, err +} + +func (j *jsonReader) Next() bool { + return j.decoder.More() +} + +// Scan decodes the next JSON object into the provided structure. +func (j *jsonReader) Scan(i any) error { + return j.decoder.Decode(&i) +} + +// Next checks if there is another line available in the text file. +func (f *textReader) Next() bool { + return f.scanner.Scan() +} + +// Scan scans the next line from the text file into the provided pointer to string. +func (f *textReader) Scan(i any) error { + if val, ok := i.(*string); ok { + *val = f.scanner.Text() + return nil + } + + return errStringNotPointer +} + +// ====== FileInfo interface methods ====== + +// func (g *GCSFile) Name() string { +// return g.name +// } + +// func (g *GCSFile) Size() int64 { +// return g.size +// } + +// func (g *GCSFile) ModTime() time.Time { +// return g.lastModified +// } + +// // func (g *GCSFile) Mode() os.FileMode { +// // return 0 +// // } + +// func (f *GCSFile) Mode() fs.FileMode { +// if f.isDir { +// return fs.ModeDir +// } +// return 0 +// } + +// func (g *GCSFile) IsDir() bool { +// return strings.HasSuffix(g.name, "/") +// } + +// func (f *GCSFile) Sys() interface{} { +// return nil +// } +func (g *GCSFile) Name() string { + return g.name +} + +func (g *GCSFile) Size() int64 { + return g.size +} + +func (g *GCSFile) ModTime() time.Time { + return g.lastModified +} + +func (f *GCSFile) Mode() fs.FileMode { + if f.isDir { + return fs.ModeDir + } + return 0 +} + +func (g *GCSFile) IsDir() bool { + return g.isDir +} + +func (f *GCSFile) Sys() interface{} { + return nil +} diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go new file mode 100644 index 000000000..9e2259909 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -0,0 +1,461 @@ +package gcs + +import ( + "context" + "errors" + "fmt" + "os" + "path" + "strings" + "time" + + "cloud.google.com/go/storage" + file "gofr.dev/pkg/gofr/datasource/file" + "google.golang.org/api/option" +) + +const ( + typeFile = "file" + typeDirectory = "directory" +) + +var ( + errIncorrectFileType = errors.New("incorrect file type") +) + +type client struct { + *storage.Client +} +type FileSystem struct { + GCSFile GCSFile + conn gcsClient + config *Config + logger Logger + metrics Metrics +} + +// Config represents the s3 configuration. +type Config struct { + BucketName string + CredentialsJSON string + ProjectID string +} + +// New initializes a new instance of FTP fileSystem with provided configuration. +func New(config *Config) file.FileSystemProvider { + return &FileSystem{config: config} +} + +func (f *FileSystem) Connect() { + var msg string + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "CONNECT", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + f.logger.Debugf("connecting to GCS bucket: %s", f.config.BucketName) + ctx := context.TODO() + client, err := storage.NewClient(ctx, option.WithCredentialsJSON([]byte(f.config.CredentialsJSON))) + + if err != nil { + f.logger.Errorf("Failed to connect to GCS: %v", err) + return + } + f.conn = &gcsClientImpl{ + client: client, + bucket: client.Bucket(f.config.BucketName), + } + st = statusSuccess + msg = "GCS Client connected." + f.logger.Logf("connected to GCS bucket %s", f.config.BucketName) +} + +// func (f *FileSystem) Create(name string) (file.File, error) { + +// var msg string + +// st := statusErr + +// defer f.sendOperationStats(&FileLog{ +// Operation: "CREATE FILE", +// Location: getLocation(f.config.BucketName), +// Status: &st, +// Message: &msg, +// }, time.Now()) + +// ctx := context.TODO() +// writer := f.conn.NewWriter(ctx, name) + +// // write empty data to simulate file +// if _, err := writer.Write([]byte{}); err != nil { +// fmt.Sprintf(err.Error()) +// return nil, err +// } +// err := writer.Close() +// if err != nil { +// return nil, err +// } +// st = statusSuccess +// msg = "File creation on GCS successful." + +// f.logger.Logf("File with name %s created.", name) + +// return f.Open(name) // re-open to return as file.File + +// } +// func (f *FileSystem) Create(name string) (file.File, error) { +// var msg string +// st := statusErr + +// defer f.sendOperationStats(&FileLog{ +// Operation: "CREATE FILE", +// Location: getLocation(f.config.BucketName), +// Status: &st, +// Message: &msg, +// }, time.Now()) + +// ctx := context.TODO() +// writer := f.conn.NewWriter(ctx, name) +// if _, err := writer.Write([]byte{}); err != nil { +// fmt.Sprintf(err.Error()) +// return nil, err +// } +// err := writer.Close() +// if err != nil { +// return nil, err +// } +// st = statusSuccess +// msg = "Write stream opened successfully" + +// return &GCSFile{ +// writer: writer, +// name: name, +// }, nil +// } +// func (f *FileSystem) Create(name string) (file.File, error) { +// var msg string +// st := statusErr + +// defer f.sendOperationStats(&FileLog{ +// Operation: "CREATE FILE", +// Location: getLocation(f.config.BucketName), +// Status: &st, +// Message: &msg, +// }, time.Now()) + +// ctx := context.TODO() + +// parentPath := path.Dir(name) + +// if parentPath != "." { +// objects, err := f.conn.ListObjects(ctx, parentPath+"/") +// if err != nil { +// return nil, err +// } +// if len(objects) == 0 { +// f.logger.Errorf("Parent path %q does not exist", parentPath) +// return nil, fmt.Errorf("%w: create parent path before creating a file", ErrOperationNotPermitted) +// } +// } + +// // Handle name conflict by checking existence and appending " copy" +// originalName := name +// index := 1 + +// for { +// objects, err := f.conn.ListObjects(ctx, name) +// if err != nil { +// return nil, err +// } +// if len(objects) == 0 { +// msg = "Write stream opened successfully" //addd a mesage "as already exit ,create file with copy" +// break // file doesn't exist, safe to use +// } +// name = generateCopyName(originalName, index) +// index++ +// } +// writer := f.conn.NewWriter(ctx, name) + +// st = statusSuccess +// msg = "Write stream opened successfully" + +// return &GCSFile{ +// conn: f.conn, +// writer: writer, +// name: name, +// contentType: writer.ContentType, +// size: writer.Size, +// lastModified: writer.Updated, +// logger: f.logger, +// metrics: f.metrics, +// }, nil +// } + +// func (f *FileSystem) Create(name string) (file.File, error) { +// var msg string +// st := statusErr + +// defer f.sendOperationStats(&FileLog{ +// Operation: "CREATE FILE", +// Location: getLocation(f.config.BucketName), +// Status: &st, +// Message: &msg, +// }, time.Now()) + +// ctx := context.TODO() + +// parentPath := path.Dir(name) + +// // 1. First check parent directory (or root) +// checkPath := "." +// if parentPath != "." { +// checkPath = parentPath + "/" +// } + +// _, err := f.conn.ListObjects(ctx, checkPath) +// if err != nil { +// return nil, err +// } + +// // 2. Handle name conflicts +// originalName := name +// index := 1 +// for { +// objects, err := f.conn.ListObjects(ctx, name) +// if err != nil { +// return nil, err +// } +// if len(objects) == 0 { +// break // file doesn't exist, safe to use +// } +// name = generateCopyName(originalName, index) +// index++ +// } + +// // 3. Create the file +// writer := f.conn.NewWriter(ctx, name) +// st = statusSuccess +// msg = "Write stream opened successfully" + +// return &GCSFile{ +// conn: f.conn, +// writer: writer, +// name: name, +// contentType: writer.ContentType, +// size: writer.Size, +// lastModified: writer.Updated, +// logger: f.logger, +// metrics: f.metrics, +// }, nil +// } +func (f *FileSystem) Create(name string) (file.File, error) { + var ( + msg string + st = statusErr + ) + + startTime := time.Now() + defer f.sendOperationStats(&FileLog{ + Operation: "CREATE FILE", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, startTime) + + ctx := context.Background() + + // 1. Check if parent directory exists + parentPath := path.Dir(name) + checkPath := "." + if parentPath != "." { + checkPath = parentPath + "/" + } + + if _, err := f.conn.ListObjects(ctx, checkPath); err != nil { + msg = "Parent directory does not exist" + return nil, err + } + + // 2. Resolve file name conflict + originalName := name + for index := 1; ; index++ { + objs, err := f.conn.ListObjects(ctx, name) + if err != nil { + msg = "Error checking existing objects" + return nil, err + } + if len(objs) == 0 { + break // Safe to use + } + name = generateCopyName(originalName, index) + } + + // 3. Open writer to create file + writer := f.conn.NewWriter(ctx, name) + + sw, ok := writer.(*storage.Writer) + if !ok { + msg = "Failed to assert writer to *storage.Writer" + return nil, errors.New(msg) + } + + st = statusSuccess + msg = "Write stream opened successfully" + + return &GCSFile{ + conn: f.conn, + writer: sw, + name: name, + contentType: sw.ContentType, + size: sw.Size, + lastModified: sw.Updated, + logger: f.logger, + metrics: f.metrics, + }, nil + +} + +func (f *FileSystem) Remove(name string) error { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "REMOVE FILE", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + err := f.conn.DeleteObject(ctx, name) + if err != nil { + f.logger.Errorf("Error while deleting file: %v", err) + return err + } + + st = statusSuccess + msg = "File deletion on GCS successful" + + f.logger.Logf("File with path %q deleted", name) + + return nil +} + +func (f *FileSystem) Open(name string) (file.File, error) { + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "OPEN FILE", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + reader, err := f.conn.NewReader(ctx, name) + + if err != nil { + if errors.Is(err, storage.ErrObjectNotExist) { + return nil, file.ErrFileNotFound + } + + f.logger.Errorf("failed to retrieve %q: %v", name, err) + + return nil, err + } + + attr, err := f.conn.StatObject(ctx, name) + if err != nil { + reader.Close() + return nil, err + } + st = statusSuccess + msg = fmt.Sprintf("File with path %q retrieved successfully", name) + + return &GCSFile{ + conn: f.conn, + name: name, + body: reader, + logger: f.logger, + metrics: f.metrics, + size: attr.Size, + contentType: attr.ContentType, + lastModified: attr.Updated, + }, nil +} + +func (f *FileSystem) Rename(oldname, newname string) error { + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "RENAME", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + if oldname == newname { + f.logger.Logf("%q & %q are same", oldname, newname) + return nil + } + + if path.Dir(oldname) != path.Dir(newname) { + f.logger.Errorf("%q & %q are not in same location", oldname, newname) + return fmt.Errorf("%w: renaming as well as moving file to different location is not allowed", ErrOperationNotPermitted) + } + // Copy old object to new + if err := f.conn.CopyObject(ctx, oldname, newname); err != nil { + msg = fmt.Sprintf("Error while copying file: %v", err) + return err + } + + // Delete old + err := f.conn.DeleteObject(ctx, oldname) + if err != nil { + msg = fmt.Sprintf("failed to remove old file %s", oldname) + return err + } + + st = statusSuccess + msg = "File renamed successfully" + + f.logger.Logf("File with path %q renamed to %q", oldname, newname) + + return nil +} +func (f *FileSystem) OpenFile(name string, _ int, _ os.FileMode) (file.File, error) { + return f.Open(name) +} + +// UseLogger sets the Logger interface for the FTP file system. +func (f *FileSystem) UseLogger(logger any) { + if l, ok := logger.(Logger); ok { + f.logger = l + } +} + +// UseMetrics sets the Metrics interface. +func (f *FileSystem) UseMetrics(metrics any) { + if m, ok := metrics.(Metrics); ok { + f.metrics = m + } +} +func generateCopyName(original string, count int) string { + ext := path.Ext(original) + base := strings.TrimSuffix(original, ext) + return fmt.Sprintf("%s copy %d%s", base, count, ext) +} diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go new file mode 100644 index 000000000..0f405afb7 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -0,0 +1,248 @@ +package gcs + +import ( + "context" + "errors" + "fmt" + "os" + "path" + "path/filepath" + "strings" + "time" + + file "gofr.dev/pkg/gofr/datasource/file" + "google.golang.org/api/googleapi" +) + +var ( + ErrOperationNotPermitted = errors.New("operation not permitted") +) + +func getBucketName(filePath string) string { + return strings.Split(filePath, string(filepath.Separator))[0] +} + +func getLocation(bucket string) string { + return path.Join(string(filepath.Separator), bucket) +} + +func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "MKDIR", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + if name == "" { + msg = fmt.Sprintf("directory name cannot be empty") + return errors.New("directory name cannot be empty") + } + + ctx := context.TODO() + objName := name + "/" + + writer := f.conn.NewWriter(ctx, objName) + defer writer.Close() + + _, err := writer.Write([]byte("dir")) // minimal content + if err != nil { + if err != nil { + msg = fmt.Sprintf("failed to create directory %q on GCS: %v", objName, err) + return err + } + } + st = statusSuccess + msg = fmt.Sprintf("Directories on path %q created successfully", name) + + f.logger.Logf("Created directories on path %q", name) + return err +} + +func (f *FileSystem) MkdirAll(path string, perm os.FileMode) error { + cleaned := strings.Trim(path, "/") + if cleaned == "" { + return nil // root directory + } + + dirs := strings.Split(cleaned, "/") + var currentPath string + + for _, dir := range dirs { + currentPath = pathJoin(currentPath, dir) + err := f.Mkdir(currentPath, perm) + if err != nil && !isAlreadyExistsError(err) { + return err + } + } + return nil +} +func pathJoin(parts ...string) string { + return path.Join(parts...) +} + +func isAlreadyExistsError(err error) bool { + // If using Google Cloud Storage SDK + if gErr, ok := err.(*googleapi.Error); ok { + return gErr.Code == 409 || gErr.Code == 412 // Conflict or Precondition Failed + } + // Fallback check + return strings.Contains(err.Error(), "already exists") +} +func (f *FileSystem) RemoveAll(path string) error { + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "REMOVEALL", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + objects, err := f.conn.ListObjects(ctx, path) + if err != nil { + msg = fmt.Sprintf("Error retrieving objects: %v", err) + return err + } + + for _, obj := range objects { + if err := f.conn.DeleteObject(ctx, obj); err != nil { + f.logger.Errorf("Error while deleting directory: %v", err) + return err + } + } + st = statusSuccess + msg = fmt.Sprintf("Directory with path %q, deleted successfully", path) + + f.logger.Logf("Directory %s deleted.", path) + return nil +} +func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "READDIR", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + objects, prefixes, err := f.conn.ListDir(ctx, dir) + if err != nil { + msg = fmt.Sprintf("Error retrieving objects: %v", err) + return nil, err + } + + var fileinfo []file.FileInfo + for _, p := range prefixes { + trimmedName := strings.TrimSuffix(p, "/") + dirName := path.Base(trimmedName) + fileinfo = append(fileinfo, &GCSFile{ + name: dirName, + isDir: true, + }) + } + + for _, o := range objects { + fileinfo = append(fileinfo, &GCSFile{ + name: path.Base(o.Name), + size: o.Size, + lastModified: o.Updated, + isDir: false, + }) + } + + st = statusSuccess + msg = fmt.Sprintf("Directory/Files in directory with path %q retrieved successfully", dir) + + f.logger.Logf("Reading directory/files from GCS at path %q successful.", dir) + return fileinfo, nil +} + +func (f *FileSystem) ChDir(_ string) error { + const op = "CHDIR" + st := statusErr + var msg = "Changing directory not supported" + + defer f.sendOperationStats(&FileLog{ + Operation: op, + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + f.logger.Errorf("%s: not supported in GCS", op) + + return errors.New("changing directory is not supported in GCS") +} +func (f *FileSystem) Getwd() (string, error) { + // Optional: If you track working directory, return it + // For now return root + const op = "GETWD" + st := statusSuccess + start := time.Now() + var msg = "Returning simulated root directory" + + defer f.sendOperationStats(&FileLog{ + Operation: op, + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, start) + return getLocation(f.config.BucketName), nil +} +func (f *FileSystem) Stat(name string) (file.FileInfo, error) { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "STAT", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + attr, err := f.conn.StatObject(ctx, name) + if err != nil { + f.logger.Errorf("Error returning file info: %v", err) + return nil, err + } + + st = statusSuccess + msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) + + return &GCSFile{ + // conn: f.conn, + name: name, + // body: reader, + logger: f.logger, + metrics: f.metrics, + size: attr.Size, + contentType: attr.ContentType, + lastModified: attr.Updated, + }, nil +} + +func (f *FileSystem) sendOperationStats(fl *FileLog, startTime time.Time) { + duration := time.Since(startTime).Microseconds() + + fl.Duration = duration + + f.logger.Debug(fl) +} diff --git a/pkg/gofr/datasource/file/gcs/fs_dir_test.go b/pkg/gofr/datasource/file/gcs/fs_dir_test.go new file mode 100644 index 000000000..558f41ee4 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs_dir_test.go @@ -0,0 +1,231 @@ +package gcs + +import ( + "bytes" + "fmt" + "testing" + + "cloud.google.com/go/storage" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" +) + +type fakeWriteCloser struct { + *bytes.Buffer +} + +func (fwc *fakeWriteCloser) Close() error { + return nil +} + +type errorWriterCloser struct{} + +func (e *errorWriterCloser) Write(p []byte) (int, error) { + return 0, fmt.Errorf("write error") +} + +func (e *errorWriterCloser) Close() error { + return fmt.Errorf("close error") +} + +type result struct { + Name string + Size int64 + IsDir bool +} + +func Test_Mkdir_GCS(t *testing.T) { + type testCase struct { + name string + dirName string + setupMocks func(mockGCS *MockgcsClient) + expectError bool + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{ + BucketName: "test-bucket", + CredentialsJSON: "fake-creds", + ProjectID: "test-project", + } + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debugf(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + + tests := []testCase{ + { + name: "successfully create directory", + dirName: "testDir", + setupMocks: func(m *MockgcsClient) { + buf := &bytes.Buffer{} + fakeWriter := &fakeWriteCloser{Buffer: buf} + m.EXPECT().NewWriter(gomock.Any(), "testDir/").Return(fakeWriter) + }, + expectError: false, + }, + { + name: "fail when directory name is empty", + dirName: "", + setupMocks: func(m *MockgcsClient) { + // No mock needed for empty dir + }, + expectError: true, + }, + { + name: "fail when GCS write fails", + dirName: "brokenDir", + setupMocks: func(m *MockgcsClient) { + errorWriter := &errorWriterCloser{} + m.EXPECT().NewWriter(gomock.Any(), "brokenDir/").Return(errorWriter) + }, + expectError: true, + }, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks(mockGCS) + + err := fs.Mkdir(tt.dirName, 0777) + + if tt.expectError { + require.Error(t, err, "Test %d (%s): expected an error", i, tt.name) + } else { + require.NoError(t, err, "Test %d (%s): expected no error", i, tt.name) + } + }) + } +} + +func Test_ReadDir_GCS(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{ + BucketName: "test-bucket", + } + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + + tests := []struct { + name string + dirPath string + expectedResults []result + setupMock func() + expectError bool + }{ + { + name: "Valid directory path with files and subdirectory", + dirPath: "abc/efg", + expectedResults: []result{ + {"hij", 0, true}, + {"file.txt", 1, false}, + }, + + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "abc/efg").Return( + []*storage.ObjectAttrs{ + {Name: "abc/efg/file.txt", Size: 1}, + }, + []string{ + "abc/efg/hij/", + }, + nil) + + }, + }, + { + name: "Valid directory path with only subdirectory", + dirPath: "abc", + expectedResults: []result{ + {"efg", 0, true}, + }, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "abc").Return( + []*storage.ObjectAttrs{}, + []string{"abc/efg/"}, + nil, + ) + }, + }, + { + name: "Directory not found", + dirPath: "does-not-exist", + expectedResults: nil, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "does-not-exist").Return(nil, nil, fmt.Errorf("directory not found")) + }, + expectError: true, + }, + { + name: "Empty directory", + dirPath: "empty", + expectedResults: []result{}, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "empty").Return([]*storage.ObjectAttrs{}, nil, nil) + }, + }, + { + name: "Directory with multiple files", + dirPath: "many/files", + expectedResults: []result{ + {"file1.txt", 1, false}, + {"file2.txt", 2, false}, + }, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "many/files").Return([]*storage.ObjectAttrs{ + {Name: "many/files/file1.txt", Size: 1}, + {Name: "many/files/file2.txt", Size: 2}, + }, nil, nil) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMock() + + entries, err := fs.ReadDir(tt.dirPath) + if tt.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, len(tt.expectedResults), len(entries)) + + for i, entry := range entries { + // fmt.Printf("DEBUG [%d] => Name: %s, IsDir: %v\n", i, entry.Name(), entry.IsDir()) + require.Equal(t, tt.expectedResults[i].Name, entry.Name(), "entry name mismatch") + require.Equal(t, tt.expectedResults[i].IsDir, entry.IsDir(), "entry type mismatch (file/dir)") + } + }) + } +} diff --git a/pkg/gofr/datasource/file/gcs/fs_test.go b/pkg/gofr/datasource/file/gcs/fs_test.go new file mode 100644 index 000000000..8e442494a --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs_test.go @@ -0,0 +1,314 @@ +package gcs + +import ( + "errors" + "testing" + + "cloud.google.com/go/storage" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" +) + +func Test_CreateFile(t *testing.T) { + type testCase struct { + name string + createPath string + setupMocks func(mockGCS *MockgcsClient) + expectError bool + isRoot bool + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{ + BucketName: "test-bucket", + CredentialsJSON: "fake-creds", + ProjectID: "test-project", + } + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + + tests := []testCase{ + { + name: "create file at root level", + createPath: "abc.txt", + setupMocks: func(m *MockgcsClient) { + m.EXPECT().ListObjects(gomock.Any(), ".").Return([]string{}, nil) + m.EXPECT().ListObjects(gomock.Any(), "abc.txt").Return([]string{}, nil) + m.EXPECT().NewWriter(gomock.Any(), "abc.txt").Return(&storage.Writer{}) + + }, + expectError: false, + isRoot: true, + }, + { + name: "fail when parent directory does not exist", + createPath: "abc/abc.txt", + setupMocks: func(m *MockgcsClient) { + m.EXPECT().ListObjects(gomock.Any(), "abc/").Return(nil, errors.New("errMock")) + }, + expectError: true, + isRoot: false, + }, + { + name: "create file inside existing directory", + createPath: "abc/efg.txt", + setupMocks: func(m *MockgcsClient) { + // parent path "abc/" exists + m.EXPECT().ListObjects(gomock.Any(), "abc/").Return([]string{"abc/.keep"}, nil) + // filename does not exist + m.EXPECT().ListObjects(gomock.Any(), "abc/efg.txt").Return([]string{}, nil) + m.EXPECT().NewWriter(gomock.Any(), "abc/efg.txt").Return(&storage.Writer{}) + }, + expectError: false, + isRoot: false, + }, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks(mockGCS) + + file, err := fs.Create(tt.createPath) + + if tt.expectError { + require.Error(t, err, "Test %d (%s): expected an error", i, tt.name) + return + } + + require.NoError(t, err, "Test %d (%s): expected no error", i, tt.name) + require.NotNil(t, file) + }) + } +} +func Test_Remove_GCS(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + fs := &FileSystem{ + conn: mockGCS, + logger: mockLogger, + config: &Config{BucketName: "test-bucket"}, + metrics: mockMetrics, + } + + // Expectations + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + + mockGCS.EXPECT(). + DeleteObject(gomock.Any(), "abc/a1.txt"). + Return(nil). + Times(1) + + err := fs.Remove("abc/a1.txt") + require.NoError(t, err) +} + +func TestRenameFile(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockConn := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{BucketName: "test-bucket"} + + fs := &FileSystem{ + conn: mockConn, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + tests := []struct { + name string + initialName string + newName string + setupMocks func() + expectedError bool + }{ + { + name: "Rename file to new name", + initialName: "dir/file.txt", + newName: "dir/file-renamed.txt", + setupMocks: func() { + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(nil) + mockConn.EXPECT().DeleteObject(gomock.Any(), "dir/file.txt").Return(nil) + }, + expectedError: false, + }, + { + name: "Rename file with copy failure", + initialName: "dir/file.txt", + newName: "dir/file-renamed.txt", + setupMocks: func() { + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(errors.New("copy failed")) + }, + expectedError: true, + }, + { + name: "Rename file with delete failure", + initialName: "dir/file.txt", + newName: "dir/file-renamed.txt", + setupMocks: func() { + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(nil) + mockConn.EXPECT().DeleteObject(gomock.Any(), "dir/file.txt").Return(errors.New("delete failed")) + }, + expectedError: true, + }, + { + name: "Rename file to same name", + initialName: "dir/file.txt", + newName: "dir/file.txt", + setupMocks: func() {}, // No calls expected + expectedError: false, + }, + { + name: "Rename file to different directory (not allowed)", + initialName: "dir1/file.txt", + newName: "dir2/file.txt", + setupMocks: func() {}, // No calls expected + expectedError: true, + }, + } + + // Set up logger mocks globally + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks() + err := fs.Rename(tt.initialName, tt.newName) + + if tt.expectedError { + require.Error(t, err, "Expected error but got none") + } else { + require.NoError(t, err, "Unexpected error: %v", err) + } + }) + } +} + +// func Test_OpenFile_GCS(t *testing.T) { +// ctrl := gomock.NewController(t) +// defer ctrl.Finish() + +// mockGCS := NewMockgcsClient(ctrl) +// mockLogger := NewMockLogger(ctrl) +// mockMetrics := NewMockMetrics(ctrl) + +// config := &Config{ +// BucketName: "test-bucket", +// CredentialsJSON: "fake-creds", +// ProjectID: "test-project", +// } + +// fs := &FileSystem{ +// conn: mockGCS, +// logger: mockLogger, +// config: config, +// metrics: mockMetrics, +// } + +// expectedContent := "Hello, GCS!" + +// // 👇 Create a mocked reader that returns your expected content +// mockReader := &storage.Reader{ +// reader: io.NopCloser(strings.NewReader("dummy data")), // or fakeReader +// } + +// // Set up expectations +// mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() +// mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() +// mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + +// mockGCS.EXPECT(). +// NewReader(gomock.Any(), "abc/a1.txt"). +// Return(mockReader, nil) + +// mockGCS.EXPECT(). +// StatObject(gomock.Any(), "abc/a1.txt"). +// Return(&storage.ObjectAttrs{}, nil) + +// // Act +// file, err := fs.OpenFile("abc/a1.txt", 0, os.ModePerm) +// require.NoError(t, err, "Failed to open file") + +// content := make([]byte, 200) +// n, err := file.Read(content) +// require.NoError(t, err, "Failed to read file content") + +// require.Equal(t, expectedContent, string(content[:n]), "File content does not match") +// } + +// func Test_OpenFile_GCS(t *testing.T) { +// ctrl := gomock.NewController(t) +// defer ctrl.Finish() + +// mockGCS := NewMockgcsClient(ctrl) +// mockLogger := NewMockLogger(ctrl) +// mockMetrics := NewMockMetrics(ctrl) + +// config := &Config{ +// BucketName: "test-bucket", +// CredentialsJSON: "fake-creds", +// ProjectID: "test-project", +// } + +// fs := &FileSystem{ +// conn: mockGCS, +// logger: mockLogger, +// config: config, +// metrics: mockMetrics, +// } + +// expectedContent := "Hello, GCS!" +// mockReader := ioutil.NopCloser(strings.NewReader(expectedContent)) + +// // Expect logger calls (optional but commonly included) +// mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() +// mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() +// mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + +// // Set up mock for GCS client +// mockGCS.EXPECT(). +// NewReader(gomock.Any(), "abc/a1.txt"). +// Return(mockReader, nil) + +// mockGCS.EXPECT(). +// StatObject(gomock.Any(), "abc/a1.txt"). +// Return(&storage.ObjectAttrs{}, nil) + +// // Act +// file, err := fs.OpenFile("abc/a1.txt", 0, os.ModePerm) +// require.NoError(t, err, "Failed to open file") + +// content := make([]byte, 200) +// n, err := file.Read(content) +// require.NoError(t, err, "Failed to read file content") + +// require.Equal(t, expectedContent, string(content[:n]), "File content does not match") +// } diff --git a/pkg/gofr/datasource/file/gcs/go.mod b/pkg/gofr/datasource/file/gcs/go.mod new file mode 100644 index 000000000..c4b2457e7 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/go.mod @@ -0,0 +1,66 @@ +module gofr.dev/pkg/gofr/datasource/file/gcs + +go 1.24.0 + +require ( + cloud.google.com/go/storage v1.55.0 + github.com/golang/mock v1.6.0 + github.com/stretchr/testify v1.10.0 + gofr.dev v1.42.2 + google.golang.org/api v0.238.0 +) + +require ( + cel.dev/expr v0.23.0 // indirect + cloud.google.com/go v0.121.1 // indirect + cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/iam v1.5.2 // indirect + cloud.google.com/go/monitoring v1.24.2 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect + github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/zeebo/errs v1.4.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.uber.org/mock v0.5.2 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/grpc v1.73.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/pkg/gofr/datasource/file/gcs/go.sum b/pkg/gofr/datasource/file/gcs/go.sum new file mode 100644 index 000000000..705df407e --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/go.sum @@ -0,0 +1,169 @@ +cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss= +cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= +cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= +cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= +cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= +cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= +cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2znf0= +cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY= +cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= +cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +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/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= +github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +gofr.dev v1.42.2 h1:cqWFwnYzaDyNZgMDxdwgb4Wk3/1kam0E+mpXOyeiU4Q= +gofr.dev v1.42.2/go.mod h1:viVap8+T4Uk6FbeK2brW3U8dau4R8xiGoo+/NyY7zrE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs= +google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +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/pkg/gofr/datasource/file/gcs/interface.go b/pkg/gofr/datasource/file/gcs/interface.go new file mode 100644 index 000000000..af61a8659 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/interface.go @@ -0,0 +1,115 @@ +//go:generate mockgen -source=interface.go -destination=mock_interface.go -package=gcs + +package gcs + +import ( + "context" + "fmt" + "io" + + "cloud.google.com/go/storage" + "google.golang.org/api/iterator" +) + +type Logger interface { + Debug(args ...any) + Debugf(pattern string, args ...any) + Logf(pattern string, args ...any) + Errorf(pattern string, args ...any) +} +type gcsClientImpl struct { + client *storage.Client + bucket *storage.BucketHandle +} + +type gcsClient interface { + // NewWriter(ctx context.Context, name string) *storage.Writer + NewWriter(ctx context.Context, name string) io.WriteCloser + NewReader(ctx context.Context, name string) (*storage.Reader, error) + DeleteObject(ctx context.Context, name string) error + CopyObject(ctx context.Context, src, dst string) error + ListObjects(ctx context.Context, prefix string) ([]string, error) + ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) + StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) + // GetSignedURL(ctx context.Context, object string, expiry time.Duration) (string, error) +} + +type Metrics interface { + NewHistogram(name, desc string, buckets ...float64) + RecordHistogram(ctx context.Context, name string, value float64, labels ...string) +} + +func (g *gcsClientImpl) NewWriter(ctx context.Context, name string) io.WriteCloser { + return g.bucket.Object(name).NewWriter(ctx) +} + +func (g *gcsClientImpl) NewReader(ctx context.Context, name string) (*storage.Reader, error) { + return g.bucket.Object(name).NewReader(ctx) +} + +func (g *gcsClientImpl) DeleteObject(ctx context.Context, name string) error { + attrs, err := g.bucket.Object(name).Attrs(ctx) + if err != nil { + return fmt.Errorf("failed to get object attributes: %w", err) + } + + err = g.bucket.Object(name).If(storage.Conditions{GenerationMatch: attrs.Generation}).Delete(ctx) + if err != nil { + return fmt.Errorf("failed to delete object: %w", err) + } + + return nil +} + +func (g *gcsClientImpl) CopyObject(ctx context.Context, src, dst string) error { + srcObj := g.bucket.Object(src) + dstObj := g.bucket.Object(dst) + _, err := dstObj.CopierFrom(srcObj).Run(ctx) + return err +} + +func (g *gcsClientImpl) ListObjects(ctx context.Context, prefix string) ([]string, error) { + var objects []string + it := g.bucket.Objects(ctx, &storage.Query{Prefix: prefix}) + for { + obj, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + objects = append(objects, obj.Name) + } + return objects, nil +} + +func (g *gcsClientImpl) ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) { + var attrs []*storage.ObjectAttrs + var prefixes []string + + it := g.bucket.Objects(ctx, &storage.Query{ + Prefix: prefix, + Delimiter: "/", + }) + + for { + obj, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, nil, err + } + if obj.Prefix != "" { + prefixes = append(prefixes, obj.Prefix) + } else { + attrs = append(attrs, obj) + } + } + return attrs, prefixes, nil +} + +func (g *gcsClientImpl) StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) { + return g.bucket.Object(name).Attrs(ctx) +} diff --git a/pkg/gofr/datasource/file/gcs/logger.go b/pkg/gofr/datasource/file/gcs/logger.go new file mode 100644 index 000000000..2a6e8e8dc --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/logger.go @@ -0,0 +1,34 @@ +package gcs + +import ( + "fmt" + "io" + "regexp" + "strings" +) + +// FileLog handles logging with different levels. +// In DEBUG MODE, this FileLog can be exported into a file while +// running the application or can be logged in the terminal. +type FileLog struct { + Operation string `json:"operation"` + Duration int64 `json:"duration"` + Status *string `json:"status"` + Location string `json:"location,omitempty"` + Message *string `json:"message,omitempty"` +} + +var regexpSpaces = regexp.MustCompile(`\s+`) + +func clean(query *string) string { + if query == nil { + return "" + } + + return strings.TrimSpace(regexpSpaces.ReplaceAllString(*query, " ")) +} + +func (fl *FileLog) PrettyPrint(writer io.Writer) { + fmt.Fprintf(writer, "\u001B[38;5;8m%-32s \u001B[38;5;148m%-6s\u001B[0m %8d\u001B[38;5;8mµs\u001B[0m %-10s \u001B[0m %-48s \n", + clean(&fl.Operation), "AWS_S3", fl.Duration, clean(fl.Status), clean(fl.Message)) +} diff --git a/pkg/gofr/datasource/file/gcs/mock_interface.go b/pkg/gofr/datasource/file/gcs/mock_interface.go new file mode 100644 index 000000000..31d3ba436 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/mock_interface.go @@ -0,0 +1,287 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: interface.go + +// Package gcs is a generated GoMock package. +package gcs + +import ( + context "context" + io "io" + reflect "reflect" + + storage "cloud.google.com/go/storage" + gomock "github.com/golang/mock/gomock" +) + +// MockLogger is a mock of Logger interface. +type MockLogger struct { + ctrl *gomock.Controller + recorder *MockLoggerMockRecorder +} + +// MockLoggerMockRecorder is the mock recorder for MockLogger. +type MockLoggerMockRecorder struct { + mock *MockLogger +} + +// NewMockLogger creates a new mock instance. +func NewMockLogger(ctrl *gomock.Controller) *MockLogger { + mock := &MockLogger{ctrl: ctrl} + mock.recorder = &MockLoggerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { + return m.recorder +} + +// Debug mocks base method. +func (m *MockLogger) Debug(args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debug", varargs...) +} + +// Debug indicates an expected call of Debug. +func (mr *MockLoggerMockRecorder) Debug(args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), args...) +} + +// Debugf mocks base method. +func (m *MockLogger) Debugf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debugf", varargs...) +} + +// Debugf indicates an expected call of Debugf. +func (mr *MockLoggerMockRecorder) Debugf(pattern interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...) +} + +// Errorf mocks base method. +func (m *MockLogger) Errorf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Errorf", varargs...) +} + +// Errorf indicates an expected call of Errorf. +func (mr *MockLoggerMockRecorder) Errorf(pattern interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) +} + +// Logf mocks base method. +func (m *MockLogger) Logf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Logf", varargs...) +} + +// Logf indicates an expected call of Logf. +func (mr *MockLoggerMockRecorder) Logf(pattern interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Logf", reflect.TypeOf((*MockLogger)(nil).Logf), varargs...) +} + +// MockgcsClient is a mock of gcsClient interface. +type MockgcsClient struct { + ctrl *gomock.Controller + recorder *MockgcsClientMockRecorder +} + +// MockgcsClientMockRecorder is the mock recorder for MockgcsClient. +type MockgcsClientMockRecorder struct { + mock *MockgcsClient +} + +// NewMockgcsClient creates a new mock instance. +func NewMockgcsClient(ctrl *gomock.Controller) *MockgcsClient { + mock := &MockgcsClient{ctrl: ctrl} + mock.recorder = &MockgcsClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockgcsClient) EXPECT() *MockgcsClientMockRecorder { + return m.recorder +} + +// CopyObject mocks base method. +func (m *MockgcsClient) CopyObject(ctx context.Context, src, dst string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyObject", ctx, src, dst) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyObject indicates an expected call of CopyObject. +func (mr *MockgcsClientMockRecorder) CopyObject(ctx, src, dst interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyObject", reflect.TypeOf((*MockgcsClient)(nil).CopyObject), ctx, src, dst) +} + +// DeleteObject mocks base method. +func (m *MockgcsClient) DeleteObject(ctx context.Context, name string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteObject", ctx, name) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteObject indicates an expected call of DeleteObject. +func (mr *MockgcsClientMockRecorder) DeleteObject(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObject", reflect.TypeOf((*MockgcsClient)(nil).DeleteObject), ctx, name) +} + +// ListDir mocks base method. +func (m *MockgcsClient) ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListDir", ctx, prefix) + ret0, _ := ret[0].([]*storage.ObjectAttrs) + ret1, _ := ret[1].([]string) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// ListDir indicates an expected call of ListDir. +func (mr *MockgcsClientMockRecorder) ListDir(ctx, prefix interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDir", reflect.TypeOf((*MockgcsClient)(nil).ListDir), ctx, prefix) +} + +// ListObjects mocks base method. +func (m *MockgcsClient) ListObjects(ctx context.Context, prefix string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListObjects", ctx, prefix) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListObjects indicates an expected call of ListObjects. +func (mr *MockgcsClientMockRecorder) ListObjects(ctx, prefix interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjects", reflect.TypeOf((*MockgcsClient)(nil).ListObjects), ctx, prefix) +} + +// NewReader mocks base method. +func (m *MockgcsClient) NewReader(ctx context.Context, name string) (*storage.Reader, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewReader", ctx, name) + ret0, _ := ret[0].(*storage.Reader) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewReader indicates an expected call of NewReader. +func (mr *MockgcsClientMockRecorder) NewReader(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewReader", reflect.TypeOf((*MockgcsClient)(nil).NewReader), ctx, name) +} + +// NewWriter mocks base method. +func (m *MockgcsClient) NewWriter(ctx context.Context, name string) io.WriteCloser { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewWriter", ctx, name) + ret0, _ := ret[0].(io.WriteCloser) + return ret0 +} + +// NewWriter indicates an expected call of NewWriter. +func (mr *MockgcsClientMockRecorder) NewWriter(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewWriter", reflect.TypeOf((*MockgcsClient)(nil).NewWriter), ctx, name) +} + +// StatObject mocks base method. +func (m *MockgcsClient) StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StatObject", ctx, name) + ret0, _ := ret[0].(*storage.ObjectAttrs) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StatObject indicates an expected call of StatObject. +func (mr *MockgcsClientMockRecorder) StatObject(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatObject", reflect.TypeOf((*MockgcsClient)(nil).StatObject), ctx, name) +} + +// MockMetrics is a mock of Metrics interface. +type MockMetrics struct { + ctrl *gomock.Controller + recorder *MockMetricsMockRecorder +} + +// MockMetricsMockRecorder is the mock recorder for MockMetrics. +type MockMetricsMockRecorder struct { + mock *MockMetrics +} + +// NewMockMetrics creates a new mock instance. +func NewMockMetrics(ctrl *gomock.Controller) *MockMetrics { + mock := &MockMetrics{ctrl: ctrl} + mock.recorder = &MockMetricsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMetrics) EXPECT() *MockMetricsMockRecorder { + return m.recorder +} + +// NewHistogram mocks base method. +func (m *MockMetrics) NewHistogram(name, desc string, buckets ...float64) { + m.ctrl.T.Helper() + varargs := []interface{}{name, desc} + for _, a := range buckets { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "NewHistogram", varargs...) +} + +// NewHistogram indicates an expected call of NewHistogram. +func (mr *MockMetricsMockRecorder) NewHistogram(name, desc interface{}, buckets ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{name, desc}, buckets...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewHistogram", reflect.TypeOf((*MockMetrics)(nil).NewHistogram), varargs...) +} + +// RecordHistogram mocks base method. +func (m *MockMetrics) RecordHistogram(ctx context.Context, name string, value float64, labels ...string) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, name, value} + for _, a := range labels { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "RecordHistogram", varargs...) +} + +// RecordHistogram indicates an expected call of RecordHistogram. +func (mr *MockMetricsMockRecorder) RecordHistogram(ctx, name, value interface{}, labels ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, name, value}, labels...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHistogram", reflect.TypeOf((*MockMetrics)(nil).RecordHistogram), varargs...) +} From 72430566d15d75a1d52c44d23de15a3d8853e718 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sat, 2 Aug 2025 20:09:42 +0530 Subject: [PATCH 02/12] Added GCS FIlestore --- go.work | 1 + go.work.sum | 49 +++--- pkg/gofr/datasource/file/gcs/file_parse.go | 32 ---- pkg/gofr/datasource/file/gcs/fs.go | 178 --------------------- pkg/gofr/datasource/file/gcs/fs_dir.go | 7 +- 5 files changed, 26 insertions(+), 241 deletions(-) diff --git a/go.work b/go.work index e2667a918..a0a16d53f 100644 --- a/go.work +++ b/go.work @@ -10,6 +10,7 @@ use ( ./pkg/gofr/datasource/dgraph ./pkg/gofr/datasource/elasticsearch ./pkg/gofr/datasource/file/ftp + ./pkg/gofr/datasource/file/gcs ./pkg/gofr/datasource/file/s3 ./pkg/gofr/datasource/file/sftp ./pkg/gofr/datasource/kv-store/badger diff --git a/go.work.sum b/go.work.sum index da01c42da..d5437c19a 100644 --- a/go.work.sum +++ b/go.work.sum @@ -108,6 +108,8 @@ cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9m cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= +cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.14.2/go.mod h1:mIat+Mf77W30eWQ/vrhjXsXaRh8Qfu4WiymR0hR6Uxk= cloud.google.com/go/automl v1.14.4 h1:vkD+hQ75SMINMgJBT/KDpFYvfQLzJbtIQZdw0AWq8Rs= @@ -388,6 +390,7 @@ cloud.google.com/go/gkemulticloud v1.5.3 h1:334aZmOzIt3LVBpguCof8IHaLaftcZlx+L0T cloud.google.com/go/gkemulticloud v1.5.3/go.mod h1:KPFf+/RcfvmuScqwS9/2MF5exZAmXSuoSLPuaQ98Xlk= cloud.google.com/go/grafeas v0.3.11 h1:CobnwnyeY1j1Defi5vbEircI+jfrk3ci5m004ZjiFP4= cloud.google.com/go/grafeas v0.3.11/go.mod h1:dcQyG2+T4tBgG0MvJAh7g2wl/xHV2w+RZIqivwuLjNg= +cloud.google.com/go/grafeas v0.3.15/go.mod h1:irwcwIQOBlLBotGdMwme8PipnloOPqILfIvMwlmu8Pk= cloud.google.com/go/gsuiteaddons v1.7.2/go.mod h1:GD32J2rN/4APilqZw4JKmwV84+jowYYMkEVwQEYuAWc= cloud.google.com/go/gsuiteaddons v1.7.3 h1:QafYhVhyFGpidBUUlVhy6lUHFogFOycVYm9DV7MinhA= cloud.google.com/go/gsuiteaddons v1.7.3/go.mod h1:0rR+LC21v1Sx1Yb6uohHI/F8DF3h2arSJSHvfi3GmyQ= @@ -426,9 +429,8 @@ cloud.google.com/go/lifesciences v0.10.3/go.mod h1:hnUUFht+KcZcliixAg+iOh88FUwAz cloud.google.com/go/lifesciences v0.10.6 h1:Vu7XF4s5KJ8+mSLIL4eaQM6JTyWXvSB54oqC+CUZH20= cloud.google.com/go/lifesciences v0.10.6/go.mod h1:1nnZwaZcBThDujs9wXzECnd1S5d+UiDkPuJWAmhRi7Q= cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM= -cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= -cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= cloud.google.com/go/managedidentities v1.7.2/go.mod h1:t0WKYzagOoD3FNtJWSWcU8zpWZz2i9cw2sKa9RiPx5I= cloud.google.com/go/managedidentities v1.7.3 h1:b9xGs24BIjfyvLgCtJoClOZpPi8d8owPgWe5JEINgaY= cloud.google.com/go/managedidentities v1.7.3/go.mod h1:H9hO2aMkjlpY+CNnKWRh+WoQiUIDO8457wWzUGsdtLA= @@ -467,8 +469,6 @@ cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6sr cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= cloud.google.com/go/monitoring v1.24.0 h1:csSKiCJ+WVRgNkRzzz3BPoGjFhjPY23ZTcaenToJxMM= cloud.google.com/go/monitoring v1.24.0/go.mod h1:Bd1PRK5bmQBQNnuGwHBfUamAV1ys9049oEPHnn4pcsc= -cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= -cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= cloud.google.com/go/networkconnectivity v1.15.2/go.mod h1:N1O01bEk5z9bkkWwXLKcN2T53QN49m/pSpjfUvlHDQY= cloud.google.com/go/networkconnectivity v1.16.1 h1:YsVhG71ZC4FkqCP2oCI55x/JeGFyd7738Lt8iNTrzJw= cloud.google.com/go/networkconnectivity v1.16.1/go.mod h1:GBC1iOLkblcnhcnfRV92j4KzqGBrEI6tT7LP52nZCTk= @@ -651,6 +651,7 @@ cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyX cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA= cloud.google.com/go/storagetransfer v1.11.2/go.mod h1:FcM29aY4EyZ3yVPmW5SxhqUdhjgPBUOFyy4rqiQbias= cloud.google.com/go/storagetransfer v1.12.1 h1:W3v9A7MGBN7H9sAFstyciwP/1XEQhUhZfrjclmDnpMs= cloud.google.com/go/storagetransfer v1.12.1/go.mod h1:hQqbfs8/LTmObJyCC0KrlBw8yBJ2bSFlaGila0qBMk4= @@ -684,8 +685,6 @@ cloud.google.com/go/tpu v1.8.3/go.mod h1:Do6Gq+/Jx6Xs3LcY2WhHyGwKDKVw++9jIJp+X+0 cloud.google.com/go/trace v1.11.2/go.mod h1:bn7OwXd4pd5rFuAnTrzBuoZ4ax2XQeG3qNgYmfCy0Io= cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= -cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= -cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= cloud.google.com/go/translate v1.12.2/go.mod h1:jjLVf2SVH2uD+BNM40DYvRRKSsuyKxVvs3YjTW/XSWY= cloud.google.com/go/translate v1.12.3 h1:XJ7LipYJi80BCgVk2lx1fwc7DIYM6oV2qx1G4IAGQ5w= @@ -766,8 +765,6 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 h1:f2Qw/Ehhimh5uO1fayV0QIW7DShEQqhtUfhYc+cBPlw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0/go.mod h1:2bIszWvQRlJVmJLiuLhukLImRjKPcYdzzsx6darK02A= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 h1:5IT7xOdq17MtcdtL/vtl6mGfzhaq4m4vpollPRmlsBQ= @@ -889,19 +886,11 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= -github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= -github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= -github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= -github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= -github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= -github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -909,8 +898,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= @@ -976,8 +963,6 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= -github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -1001,6 +986,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= @@ -1120,8 +1106,6 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= @@ -1153,8 +1137,6 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= -github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -1175,13 +1157,12 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8 github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= -github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1203,6 +1184,7 @@ go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8F go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0/go.mod h1:3qi2EEwMgB4xnKgPLqsDP3j9qxnHDZeHsnAxfjQqTko= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= @@ -1233,7 +1215,9 @@ go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxt go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= @@ -1255,6 +1239,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= @@ -1291,6 +1276,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -1319,6 +1305,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= @@ -1387,6 +1374,7 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1415,6 +1403,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1456,6 +1445,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= @@ -1493,6 +1483,9 @@ google.golang.org/api v0.219.0/go.mod h1:K6OmjGm+NtLrIkHxv1U3a0qIf/0JOvAHd5O/6Ao google.golang.org/api v0.222.0/go.mod h1:efZia3nXpWELrwMlN5vyQrD4GmJN1Vw0x68Et3r+a9c= google.golang.org/api v0.224.0/go.mod h1:3V39my2xAGkodXy0vEqcEtkqgw2GtrFL5WuBZlCTCOQ= google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ= +google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= +google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= +google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -1535,6 +1528,7 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= @@ -1587,6 +1581,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go index 0ae769e71..8b7738f96 100644 --- a/pkg/gofr/datasource/file/gcs/file_parse.go +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -135,38 +135,6 @@ func (f *textReader) Scan(i any) error { return errStringNotPointer } -// ====== FileInfo interface methods ====== - -// func (g *GCSFile) Name() string { -// return g.name -// } - -// func (g *GCSFile) Size() int64 { -// return g.size -// } - -// func (g *GCSFile) ModTime() time.Time { -// return g.lastModified -// } - -// // func (g *GCSFile) Mode() os.FileMode { -// // return 0 -// // } - -// func (f *GCSFile) Mode() fs.FileMode { -// if f.isDir { -// return fs.ModeDir -// } -// return 0 -// } - -// func (g *GCSFile) IsDir() bool { -// return strings.HasSuffix(g.name, "/") -// } - -// func (f *GCSFile) Sys() interface{} { -// return nil -// } func (g *GCSFile) Name() string { return g.name } diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go index 9e2259909..ae70727cd 100644 --- a/pkg/gofr/datasource/file/gcs/fs.go +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -74,184 +74,6 @@ func (f *FileSystem) Connect() { f.logger.Logf("connected to GCS bucket %s", f.config.BucketName) } -// func (f *FileSystem) Create(name string) (file.File, error) { - -// var msg string - -// st := statusErr - -// defer f.sendOperationStats(&FileLog{ -// Operation: "CREATE FILE", -// Location: getLocation(f.config.BucketName), -// Status: &st, -// Message: &msg, -// }, time.Now()) - -// ctx := context.TODO() -// writer := f.conn.NewWriter(ctx, name) - -// // write empty data to simulate file -// if _, err := writer.Write([]byte{}); err != nil { -// fmt.Sprintf(err.Error()) -// return nil, err -// } -// err := writer.Close() -// if err != nil { -// return nil, err -// } -// st = statusSuccess -// msg = "File creation on GCS successful." - -// f.logger.Logf("File with name %s created.", name) - -// return f.Open(name) // re-open to return as file.File - -// } -// func (f *FileSystem) Create(name string) (file.File, error) { -// var msg string -// st := statusErr - -// defer f.sendOperationStats(&FileLog{ -// Operation: "CREATE FILE", -// Location: getLocation(f.config.BucketName), -// Status: &st, -// Message: &msg, -// }, time.Now()) - -// ctx := context.TODO() -// writer := f.conn.NewWriter(ctx, name) -// if _, err := writer.Write([]byte{}); err != nil { -// fmt.Sprintf(err.Error()) -// return nil, err -// } -// err := writer.Close() -// if err != nil { -// return nil, err -// } -// st = statusSuccess -// msg = "Write stream opened successfully" - -// return &GCSFile{ -// writer: writer, -// name: name, -// }, nil -// } -// func (f *FileSystem) Create(name string) (file.File, error) { -// var msg string -// st := statusErr - -// defer f.sendOperationStats(&FileLog{ -// Operation: "CREATE FILE", -// Location: getLocation(f.config.BucketName), -// Status: &st, -// Message: &msg, -// }, time.Now()) - -// ctx := context.TODO() - -// parentPath := path.Dir(name) - -// if parentPath != "." { -// objects, err := f.conn.ListObjects(ctx, parentPath+"/") -// if err != nil { -// return nil, err -// } -// if len(objects) == 0 { -// f.logger.Errorf("Parent path %q does not exist", parentPath) -// return nil, fmt.Errorf("%w: create parent path before creating a file", ErrOperationNotPermitted) -// } -// } - -// // Handle name conflict by checking existence and appending " copy" -// originalName := name -// index := 1 - -// for { -// objects, err := f.conn.ListObjects(ctx, name) -// if err != nil { -// return nil, err -// } -// if len(objects) == 0 { -// msg = "Write stream opened successfully" //addd a mesage "as already exit ,create file with copy" -// break // file doesn't exist, safe to use -// } -// name = generateCopyName(originalName, index) -// index++ -// } -// writer := f.conn.NewWriter(ctx, name) - -// st = statusSuccess -// msg = "Write stream opened successfully" - -// return &GCSFile{ -// conn: f.conn, -// writer: writer, -// name: name, -// contentType: writer.ContentType, -// size: writer.Size, -// lastModified: writer.Updated, -// logger: f.logger, -// metrics: f.metrics, -// }, nil -// } - -// func (f *FileSystem) Create(name string) (file.File, error) { -// var msg string -// st := statusErr - -// defer f.sendOperationStats(&FileLog{ -// Operation: "CREATE FILE", -// Location: getLocation(f.config.BucketName), -// Status: &st, -// Message: &msg, -// }, time.Now()) - -// ctx := context.TODO() - -// parentPath := path.Dir(name) - -// // 1. First check parent directory (or root) -// checkPath := "." -// if parentPath != "." { -// checkPath = parentPath + "/" -// } - -// _, err := f.conn.ListObjects(ctx, checkPath) -// if err != nil { -// return nil, err -// } - -// // 2. Handle name conflicts -// originalName := name -// index := 1 -// for { -// objects, err := f.conn.ListObjects(ctx, name) -// if err != nil { -// return nil, err -// } -// if len(objects) == 0 { -// break // file doesn't exist, safe to use -// } -// name = generateCopyName(originalName, index) -// index++ -// } - -// // 3. Create the file -// writer := f.conn.NewWriter(ctx, name) -// st = statusSuccess -// msg = "Write stream opened successfully" - -// return &GCSFile{ -// conn: f.conn, -// writer: writer, -// name: name, -// contentType: writer.ContentType, -// size: writer.Size, -// lastModified: writer.Updated, -// logger: f.logger, -// metrics: f.metrics, -// }, nil -// } func (f *FileSystem) Create(name string) (file.File, error) { var ( msg string diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go index 0f405afb7..0ead06056 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -189,8 +189,7 @@ func (f *FileSystem) ChDir(_ string) error { return errors.New("changing directory is not supported in GCS") } func (f *FileSystem) Getwd() (string, error) { - // Optional: If you track working directory, return it - // For now return root + const op = "GETWD" st := statusSuccess start := time.Now() @@ -228,9 +227,7 @@ func (f *FileSystem) Stat(name string) (file.FileInfo, error) { msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) return &GCSFile{ - // conn: f.conn, - name: name, - // body: reader, + name: name, logger: f.logger, metrics: f.metrics, size: attr.Size, From 5a893ba993ff989f7d309402c9acc05fa40527dd Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sat, 2 Aug 2025 20:23:07 +0530 Subject: [PATCH 03/12] sync with gofr/development --- examples/using-add-filestore/go.mod | 24 ++++----- examples/using-add-filestore/go.sum | 54 +++++-------------- go.mod | 6 +-- go.sum | 9 ++-- go.work.sum | 8 +-- pkg/gofr/datasource/arangodb/go.mod | 8 +-- pkg/gofr/datasource/arangodb/go.sum | 12 ++--- pkg/gofr/datasource/clickhouse/go.mod | 2 +- pkg/gofr/datasource/clickhouse/go.sum | 3 +- pkg/gofr/datasource/couchbase/go.mod | 18 ++++--- pkg/gofr/datasource/couchbase/go.sum | 27 ++++------ pkg/gofr/datasource/dgraph/go.mod | 13 ++--- pkg/gofr/datasource/dgraph/go.sum | 24 +++------ pkg/gofr/datasource/elasticsearch/go.mod | 4 +- pkg/gofr/datasource/elasticsearch/go.sum | 10 ++-- pkg/gofr/datasource/file/ftp/go.mod | 1 + pkg/gofr/datasource/file/ftp/go.sum | 6 +-- pkg/gofr/datasource/file/gcs/go.mod | 34 ++++++------ pkg/gofr/datasource/file/gcs/go.sum | 61 +++++++--------------- pkg/gofr/datasource/file/s3/go.mod | 1 + pkg/gofr/datasource/file/s3/go.sum | 6 +-- pkg/gofr/datasource/file/sftp/go.mod | 6 +-- pkg/gofr/datasource/file/sftp/go.sum | 12 ++--- pkg/gofr/datasource/kv-store/badger/go.mod | 8 +-- pkg/gofr/datasource/kv-store/badger/go.sum | 12 ++--- pkg/gofr/datasource/kv-store/nats/go.mod | 10 ++-- pkg/gofr/datasource/kv-store/nats/go.sum | 15 ++---- pkg/gofr/datasource/mongo/go.mod | 8 +-- pkg/gofr/datasource/mongo/go.sum | 12 ++--- pkg/gofr/datasource/opentsdb/go.mod | 2 +- pkg/gofr/datasource/opentsdb/go.sum | 3 +- pkg/gofr/datasource/oracle/go.mod | 8 ++- pkg/gofr/datasource/oracle/go.sum | 17 +++--- pkg/gofr/datasource/pubsub/eventhub/go.mod | 7 +-- pkg/gofr/datasource/pubsub/eventhub/go.sum | 21 +++----- pkg/gofr/datasource/pubsub/nats/go.mod | 8 +-- pkg/gofr/datasource/pubsub/nats/go.sum | 12 ++--- pkg/gofr/datasource/solr/go.mod | 1 + pkg/gofr/datasource/solr/go.sum | 3 +- pkg/gofr/datasource/surrealdb/go.mod | 2 +- pkg/gofr/datasource/surrealdb/go.sum | 3 +- 41 files changed, 200 insertions(+), 301 deletions(-) diff --git a/examples/using-add-filestore/go.mod b/examples/using-add-filestore/go.mod index c3a13b794..ebfb7edb7 100644 --- a/examples/using-add-filestore/go.mod +++ b/examples/using-add-filestore/go.mod @@ -3,14 +3,14 @@ module gofr.dev/examples/using-add-filestore go 1.25 require ( - github.com/stretchr/testify v1.11.0 + github.com/stretchr/testify v1.11.1 go.uber.org/mock v0.6.0 gofr.dev v1.43.0 gofr.dev/pkg/gofr/datasource/file/ftp v0.2.1 ) require ( - cloud.google.com/go v0.120.0 // indirect + cloud.google.com/go v0.121.1 // indirect cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect @@ -60,11 +60,11 @@ require ( github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f // indirect github.com/prometheus/procfs v0.17.0 // indirect - github.com/redis/go-redis/extra/rediscmd/v9 v9.11.0 // indirect - github.com/redis/go-redis/extra/redisotel/v9 v9.11.0 // indirect - github.com/redis/go-redis/v9 v9.11.0 // indirect + github.com/redis/go-redis/extra/rediscmd/v9 v9.12.1 // indirect + github.com/redis/go-redis/extra/redisotel/v9 v9.12.1 // indirect + github.com/redis/go-redis/v9 v9.12.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/segmentio/kafka-go v0.4.48 // indirect + github.com/segmentio/kafka-go v0.4.49 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -83,21 +83,21 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect - golang.org/x/crypto v0.40.0 // indirect + golang.org/x/crypto v0.41.0 // indirect golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect - golang.org/x/net v0.42.0 // indirect + golang.org/x/net v0.43.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/term v0.33.0 // indirect - golang.org/x/text v0.27.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/api v0.244.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect google.golang.org/grpc v1.74.2 // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.66.3 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/examples/using-add-filestore/go.sum b/examples/using-add-filestore/go.sum index 91a1a1b16..af0b5dc86 100644 --- a/examples/using-add-filestore/go.sum +++ b/examples/using-add-filestore/go.sum @@ -1,6 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA= -cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q= +cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= @@ -127,7 +126,6 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -151,7 +149,6 @@ github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJm github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -170,18 +167,14 @@ github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f h1:QQB6S github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= -github.com/redis/go-redis/extra/rediscmd/v9 v9.11.0 h1:vP5CH2rJ3L4yk3o8FdXqiPL1lGl5APjHcxk5/OT6H0Q= -github.com/redis/go-redis/extra/rediscmd/v9 v9.11.0/go.mod h1:/2yj0RD4xjZQ7wOg9u7gVoBM0IgMGrHunAql1hr1NDg= -github.com/redis/go-redis/extra/redisotel/v9 v9.11.0 h1:dMNmusapfQefntfUqAYAvaVJMrJCdKUaQoPSZtd99WU= -github.com/redis/go-redis/extra/redisotel/v9 v9.11.0/go.mod h1:Yy5oaeVwWj7KMu6Mga/i4imlXFvgitQWN5HFiT5JqoE= -github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= -github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/redis/go-redis/extra/rediscmd/v9 v9.12.1 h1:DR14pbiA9cjS5btoGU7oKuBcaYGzpxMsAyswO6mHqSk= +github.com/redis/go-redis/extra/redisotel/v9 v9.12.1 h1:2MioZj2s8Ovom2Yrpb/bBCJ88fR9L0MfMq2wAH44R8M= +github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg= 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.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/segmentio/kafka-go v0.4.48 h1:9jyu9CWK4W5W+SroCe8EffbrRZVqAOkuaLd/ApID4Vs= -github.com/segmentio/kafka-go v0.4.48/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg= +github.com/segmentio/kafka-go v0.4.49 h1:GJiNX1d/g+kG6ljyJEoi9++PUMdXGAxb7JGPiDCuNmk= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -196,8 +189,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -257,9 +249,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= @@ -270,7 +260,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -284,11 +273,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= @@ -298,7 +283,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -311,28 +295,16 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -345,7 +317,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -383,8 +354,7 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/go.mod b/go.mod index 5b5ed56a9..a88876658 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( ) require ( - cloud.google.com/go v0.120.0 // indirect + cloud.google.com/go v0.121.1 // indirect cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect @@ -93,9 +93,9 @@ require ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect - golang.org/x/crypto v0.40.0 // indirect + golang.org/x/crypto v0.41.0 // indirect golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect - golang.org/x/net v0.42.0 // indirect + golang.org/x/net v0.43.0 // indirect golang.org/x/sys v0.35.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect diff --git a/go.sum b/go.sum index 121f53752..7d680cb72 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA= -cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q= +cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= @@ -254,8 +253,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= @@ -279,8 +277,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= diff --git a/go.work.sum b/go.work.sum index d5437c19a..898d5e314 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1215,9 +1215,9 @@ go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxt go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= @@ -1450,8 +1450,7 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= @@ -1486,6 +1485,7 @@ google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2 google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/pkg/gofr/datasource/arangodb/go.mod b/pkg/gofr/datasource/arangodb/go.mod index e12e42d3a..4836d8aa0 100644 --- a/pkg/gofr/datasource/arangodb/go.mod +++ b/pkg/gofr/datasource/arangodb/go.mod @@ -4,7 +4,7 @@ go 1.25 require ( github.com/arangodb/go-driver/v2 v2.1.3 - github.com/stretchr/testify v1.11.0 + github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 go.uber.org/mock v0.6.0 @@ -25,8 +25,8 @@ require ( github.com/rs/zerolog v1.33.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/arangodb/go.sum b/pkg/gofr/datasource/arangodb/go.sum index 89205dc27..087d0aa0a 100644 --- a/pkg/gofr/datasource/arangodb/go.sum +++ b/pkg/gofr/datasource/arangodb/go.sum @@ -42,8 +42,7 @@ github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= @@ -54,15 +53,12 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/clickhouse/go.mod b/pkg/gofr/datasource/clickhouse/go.mod index 0498f1d8d..73a9ccbb4 100644 --- a/pkg/gofr/datasource/clickhouse/go.mod +++ b/pkg/gofr/datasource/clickhouse/go.mod @@ -25,7 +25,7 @@ require ( github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect - golang.org/x/sys v0.34.0 // indirect + golang.org/x/sys v0.35.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/clickhouse/go.sum b/pkg/gofr/datasource/clickhouse/go.sum index 4e2afd54b..2b791a250 100644 --- a/pkg/gofr/datasource/clickhouse/go.sum +++ b/pkg/gofr/datasource/clickhouse/go.sum @@ -92,8 +92,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/pkg/gofr/datasource/couchbase/go.mod b/pkg/gofr/datasource/couchbase/go.mod index e957a6b8d..ffd9df031 100644 --- a/pkg/gofr/datasource/couchbase/go.mod +++ b/pkg/gofr/datasource/couchbase/go.mod @@ -4,7 +4,7 @@ go 1.25 require ( github.com/couchbase/gocb/v2 v2.10.0 - github.com/stretchr/testify v1.11.0 + github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 go.uber.org/mock v0.6.0 @@ -24,15 +24,17 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect + google.golang.org/grpc v1.74.2 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/couchbase/go.sum b/pkg/gofr/datasource/couchbase/go.sum index eebc37626..c2b4c603f 100644 --- a/pkg/gofr/datasource/couchbase/go.sum +++ b/pkg/gofr/datasource/couchbase/go.sum @@ -37,6 +37,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -74,18 +75,18 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -118,8 +119,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -132,12 +132,10 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -156,17 +154,14 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/pkg/gofr/datasource/dgraph/go.mod b/pkg/gofr/datasource/dgraph/go.mod index 5127263de..9cdd56eab 100644 --- a/pkg/gofr/datasource/dgraph/go.mod +++ b/pkg/gofr/datasource/dgraph/go.mod @@ -24,13 +24,14 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/procfs v0.17.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect - google.golang.org/protobuf v1.36.6 // indirect + go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/dgraph/go.sum b/pkg/gofr/datasource/dgraph/go.sum index 6e2229469..e8fc4b92a 100644 --- a/pkg/gofr/datasource/dgraph/go.sum +++ b/pkg/gofr/datasource/dgraph/go.sum @@ -37,8 +37,7 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -51,10 +50,8 @@ go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= -go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -70,20 +67,17 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -92,12 +86,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM= google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/elasticsearch/go.mod b/pkg/gofr/datasource/elasticsearch/go.mod index cfc80db79..b859826bd 100644 --- a/pkg/gofr/datasource/elasticsearch/go.mod +++ b/pkg/gofr/datasource/elasticsearch/go.mod @@ -4,7 +4,7 @@ go 1.25 require ( github.com/elastic/go-elasticsearch/v8 v8.18.1 - github.com/stretchr/testify v1.11.0 + github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 go.uber.org/mock v0.6.0 @@ -18,5 +18,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + golang.org/x/sys v0.35.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/elasticsearch/go.sum b/pkg/gofr/datasource/elasticsearch/go.sum index 253ab9280..bdc1a9cf7 100644 --- a/pkg/gofr/datasource/elasticsearch/go.sum +++ b/pkg/gofr/datasource/elasticsearch/go.sum @@ -11,6 +11,7 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 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= @@ -19,22 +20,19 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/file/ftp/go.mod b/pkg/gofr/datasource/file/ftp/go.mod index e377338dc..54396bf9d 100644 --- a/pkg/gofr/datasource/file/ftp/go.mod +++ b/pkg/gofr/datasource/file/ftp/go.mod @@ -18,6 +18,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect + golang.org/x/term v0.34.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/file/ftp/go.sum b/pkg/gofr/datasource/file/ftp/go.sum index 2092f77f0..5018f35dd 100644 --- a/pkg/gofr/datasource/file/ftp/go.sum +++ b/pkg/gofr/datasource/file/ftp/go.sum @@ -35,10 +35,8 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= gofr.dev v1.43.0 h1:opQ5rq5+odYi8/VTY8tdVrtZaAjyYA01AS860EK55Ro= gofr.dev v1.43.0/go.mod h1:BNgk8HKwwuReAZT5btqkwL3ugpEaYyC7TmTxBA81X90= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/file/gcs/go.mod b/pkg/gofr/datasource/file/gcs/go.mod index c4b2457e7..722c1ce18 100644 --- a/pkg/gofr/datasource/file/gcs/go.mod +++ b/pkg/gofr/datasource/file/gcs/go.mod @@ -4,16 +4,16 @@ go 1.24.0 require ( cloud.google.com/go/storage v1.55.0 - github.com/golang/mock v1.6.0 - github.com/stretchr/testify v1.10.0 + github.com/golang/mock v1.7.0-rc.1 + github.com/stretchr/testify v1.11.1 gofr.dev v1.42.2 - google.golang.org/api v0.238.0 + google.golang.org/api v0.244.0 ) require ( - cel.dev/expr v0.23.0 // indirect + cel.dev/expr v0.24.0 // indirect cloud.google.com/go v0.121.1 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect @@ -22,7 +22,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect + github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -33,7 +33,7 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect @@ -49,18 +49,18 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - go.uber.org/mock v0.5.2 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect + go.uber.org/mock v0.6.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/net v0.43.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect - google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect + google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect + google.golang.org/grpc v1.74.2 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/file/gcs/go.sum b/pkg/gofr/datasource/file/gcs/go.sum index 705df407e..b8a8ea520 100644 --- a/pkg/gofr/datasource/file/gcs/go.sum +++ b/pkg/gofr/datasource/file/gcs/go.sum @@ -1,9 +1,7 @@ -cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss= -cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= @@ -30,8 +28,7 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= @@ -51,8 +48,7 @@ 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= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -65,8 +61,7 @@ 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/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -83,9 +78,7 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= @@ -108,60 +101,42 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= gofr.dev v1.42.2 h1:cqWFwnYzaDyNZgMDxdwgb4Wk3/1kam0E+mpXOyeiU4Q= gofr.dev v1.42.2/go.mod h1:viVap8+T4Uk6FbeK2brW3U8dau4R8xiGoo+/NyY7zrE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs= -google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= -google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= -google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= +google.golang.org/api v0.244.0 h1:lpkP8wVibSKr++NCD36XzTk/IzeKJ3klj7vbj+XU5pE= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/file/s3/go.mod b/pkg/gofr/datasource/file/s3/go.mod index a066854bf..f01fb17e3 100644 --- a/pkg/gofr/datasource/file/s3/go.mod +++ b/pkg/gofr/datasource/file/s3/go.mod @@ -33,6 +33,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect + golang.org/x/term v0.34.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/file/s3/go.sum b/pkg/gofr/datasource/file/s3/go.sum index 4ce69c9ea..2566c37ef 100644 --- a/pkg/gofr/datasource/file/s3/go.sum +++ b/pkg/gofr/datasource/file/s3/go.sum @@ -64,10 +64,8 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= gofr.dev v1.43.0 h1:opQ5rq5+odYi8/VTY8tdVrtZaAjyYA01AS860EK55Ro= gofr.dev v1.43.0/go.mod h1:BNgk8HKwwuReAZT5btqkwL3ugpEaYyC7TmTxBA81X90= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/file/sftp/go.mod b/pkg/gofr/datasource/file/sftp/go.mod index 1d6f9b24d..3e3c4aa55 100644 --- a/pkg/gofr/datasource/file/sftp/go.mod +++ b/pkg/gofr/datasource/file/sftp/go.mod @@ -5,9 +5,9 @@ go 1.25 require ( github.com/pkg/sftp v1.13.6 github.com/stretchr/testify v1.11.1 - go.uber.org/mock v0.5.2 + go.uber.org/mock v0.6.0 gofr.dev v1.43.0 - golang.org/x/crypto v0.40.0 + golang.org/x/crypto v0.41.0 ) require ( @@ -18,7 +18,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect - golang.org/x/sys v0.34.0 // indirect + golang.org/x/sys v0.35.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/file/sftp/go.sum b/pkg/gofr/datasource/file/sftp/go.sum index 7ffa76ba8..222c8f0dd 100644 --- a/pkg/gofr/datasource/file/sftp/go.sum +++ b/pkg/gofr/datasource/file/sftp/go.sum @@ -34,15 +34,13 @@ go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= gofr.dev v1.43.0 h1:opQ5rq5+odYi8/VTY8tdVrtZaAjyYA01AS860EK55Ro= gofr.dev v1.43.0/go.mod h1:BNgk8HKwwuReAZT5btqkwL3ugpEaYyC7TmTxBA81X90= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -56,13 +54,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/pkg/gofr/datasource/kv-store/badger/go.mod b/pkg/gofr/datasource/kv-store/badger/go.mod index e7333af95..8490b7f34 100644 --- a/pkg/gofr/datasource/kv-store/badger/go.mod +++ b/pkg/gofr/datasource/kv-store/badger/go.mod @@ -17,15 +17,15 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/flatbuffers v24.12.23+incompatible // indirect - github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sys v0.31.0 // indirect - google.golang.org/protobuf v1.36.3 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/kv-store/badger/go.sum b/pkg/gofr/datasource/kv-store/badger/go.sum index 276a7e4c3..2dc0297bc 100644 --- a/pkg/gofr/datasource/kv-store/badger/go.sum +++ b/pkg/gofr/datasource/kv-store/badger/go.sum @@ -46,8 +46,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -92,8 +91,7 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -102,8 +100,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -131,8 +128,7 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/kv-store/nats/go.mod b/pkg/gofr/datasource/kv-store/nats/go.mod index b71e4e63a..0d0fe872b 100644 --- a/pkg/gofr/datasource/kv-store/nats/go.mod +++ b/pkg/gofr/datasource/kv-store/nats/go.mod @@ -3,7 +3,7 @@ module gofr.dev/pkg/gofr/datasource/kv-store/nats go 1.25 require ( - github.com/nats-io/nats.go v1.38.0 + github.com/nats-io/nats.go v1.39.1 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 @@ -12,14 +12,14 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/nats-io/nkeys v0.4.9 // indirect + github.com/nats-io/nkeys v0.4.10 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/sys v0.35.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/kv-store/nats/go.sum b/pkg/gofr/datasource/kv-store/nats/go.sum index c2ef6b0cb..8caf14c52 100644 --- a/pkg/gofr/datasource/kv-store/nats/go.sum +++ b/pkg/gofr/datasource/kv-store/nats/go.sum @@ -3,8 +3,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -12,10 +11,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA= -github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw= -github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0= -github.com/nats-io/nkeys v0.4.9/go.mod h1:jcMqs+FLG+W5YO36OX6wFIFcmpdAns+w1Wm6D3I/evE= +github.com/nats-io/nats.go v1.39.1 h1:oTkfKBmz7W047vRxV762M67ZdXeOtUgvbBaNoQ+3PPk= +github.com/nats-io/nkeys v0.4.10 h1:glmRrpCmYLHByYcePvnTBEAwawwapjCPMjy2huw20wc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -32,10 +29,8 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/mongo/go.mod b/pkg/gofr/datasource/mongo/go.mod index 432894793..e93f05516 100644 --- a/pkg/gofr/datasource/mongo/go.mod +++ b/pkg/gofr/datasource/mongo/go.mod @@ -3,7 +3,7 @@ module gofr.dev/pkg/gofr/datasource/mongo go 1.25 require ( - github.com/stretchr/testify v1.11.0 + github.com/stretchr/testify v1.11.1 go.mongodb.org/mongo-driver v1.17.4 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 @@ -15,7 +15,7 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect @@ -24,8 +24,8 @@ require ( github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect - golang.org/x/crypto v0.35.0 // indirect + golang.org/x/crypto v0.41.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/text v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/mongo/go.sum b/pkg/gofr/datasource/mongo/go.sum index 6d51278f6..d600c6a06 100644 --- a/pkg/gofr/datasource/mongo/go.sum +++ b/pkg/gofr/datasource/mongo/go.sum @@ -9,8 +9,7 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/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/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 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= @@ -21,8 +20,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -46,8 +44,7 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -67,8 +64,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/pkg/gofr/datasource/opentsdb/go.mod b/pkg/gofr/datasource/opentsdb/go.mod index 63d7a6565..45da12443 100644 --- a/pkg/gofr/datasource/opentsdb/go.mod +++ b/pkg/gofr/datasource/opentsdb/go.mod @@ -3,7 +3,7 @@ module gofr.dev/pkg/gofr/datasource/opentsdb go 1.25 require ( - github.com/stretchr/testify v1.11.0 + github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 go.uber.org/mock v0.6.0 diff --git a/pkg/gofr/datasource/opentsdb/go.sum b/pkg/gofr/datasource/opentsdb/go.sum index d37f1bd59..7ba8d46bc 100644 --- a/pkg/gofr/datasource/opentsdb/go.sum +++ b/pkg/gofr/datasource/opentsdb/go.sum @@ -15,8 +15,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= diff --git a/pkg/gofr/datasource/oracle/go.mod b/pkg/gofr/datasource/oracle/go.mod index 25fbef622..a6dce5b97 100644 --- a/pkg/gofr/datasource/oracle/go.mod +++ b/pkg/gofr/datasource/oracle/go.mod @@ -16,8 +16,12 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/godror/knownpb v0.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - google.golang.org/protobuf v1.36.6 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/term v0.34.0 // indirect + google.golang.org/protobuf v1.36.7 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/oracle/go.sum b/pkg/gofr/datasource/oracle/go.sum index 808244610..7f2eca836 100644 --- a/pkg/gofr/datasource/oracle/go.sum +++ b/pkg/gofr/datasource/oracle/go.sum @@ -17,10 +17,13 @@ github.com/godror/knownpb v0.3.0/go.mod h1:PpTyfJwiOEAzQl7NtVCM8kdPCnp3uhxsZYIzZ 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/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc= github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= @@ -29,17 +32,13 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 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/pkg/gofr/datasource/pubsub/eventhub/go.mod b/pkg/gofr/datasource/pubsub/eventhub/go.mod index 9e08ac4ce..66696c84c 100644 --- a/pkg/gofr/datasource/pubsub/eventhub/go.mod +++ b/pkg/gofr/datasource/pubsub/eventhub/go.mod @@ -8,7 +8,7 @@ require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 - go.uber.org/mock v0.5.2 + go.uber.org/mock v0.6.0 gofr.dev v1.43.0 nhooyr.io/websocket v1.8.11 ) @@ -20,12 +20,13 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/mock v1.7.0-rc.1 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/text v0.27.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/text v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/pubsub/eventhub/go.sum b/pkg/gofr/datasource/pubsub/eventhub/go.sum index 6de5f4fea..fb3c18a86 100644 --- a/pkg/gofr/datasource/pubsub/eventhub/go.sum +++ b/pkg/gofr/datasource/pubsub/eventhub/go.sum @@ -27,8 +27,7 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= 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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -59,20 +58,14 @@ go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/Wgbsd go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= gofr.dev v1.43.0 h1:opQ5rq5+odYi8/VTY8tdVrtZaAjyYA01AS860EK55Ro= gofr.dev v1.43.0/go.mod h1:BNgk8HKwwuReAZT5btqkwL3ugpEaYyC7TmTxBA81X90= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/pubsub/nats/go.mod b/pkg/gofr/datasource/pubsub/nats/go.mod index bbdb7dd59..9729f0375 100644 --- a/pkg/gofr/datasource/pubsub/nats/go.mod +++ b/pkg/gofr/datasource/pubsub/nats/go.mod @@ -24,10 +24,10 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect go.opentelemetry.io/otel v1.37.0 // indirect - golang.org/x/crypto v0.40.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/term v0.33.0 // indirect - golang.org/x/text v0.27.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/gofr/datasource/pubsub/nats/go.sum b/pkg/gofr/datasource/pubsub/nats/go.sum index 83262398e..f8e251bc0 100644 --- a/pkg/gofr/datasource/pubsub/nats/go.sum +++ b/pkg/gofr/datasource/pubsub/nats/go.sum @@ -44,15 +44,11 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= gofr.dev v1.43.0 h1:opQ5rq5+odYi8/VTY8tdVrtZaAjyYA01AS860EK55Ro= gofr.dev v1.43.0/go.mod h1:BNgk8HKwwuReAZT5btqkwL3ugpEaYyC7TmTxBA81X90= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/gofr/datasource/solr/go.mod b/pkg/gofr/datasource/solr/go.mod index 709b14252..fc4002e6b 100644 --- a/pkg/gofr/datasource/solr/go.mod +++ b/pkg/gofr/datasource/solr/go.mod @@ -17,5 +17,6 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect + golang.org/x/sys v0.35.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/solr/go.sum b/pkg/gofr/datasource/solr/go.sum index 8d9f05840..e6e90cb3d 100644 --- a/pkg/gofr/datasource/solr/go.sum +++ b/pkg/gofr/datasource/solr/go.sum @@ -39,8 +39,7 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gofr/datasource/surrealdb/go.mod b/pkg/gofr/datasource/surrealdb/go.mod index 4a8701036..c23878fc3 100644 --- a/pkg/gofr/datasource/surrealdb/go.mod +++ b/pkg/gofr/datasource/surrealdb/go.mod @@ -7,7 +7,7 @@ require ( github.com/surrealdb/surrealdb.go v0.3.3 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/trace v1.37.0 - go.uber.org/mock v0.5.2 + go.uber.org/mock v0.6.0 ) require ( diff --git a/pkg/gofr/datasource/surrealdb/go.sum b/pkg/gofr/datasource/surrealdb/go.sum index 1df13da86..c19ebf683 100644 --- a/pkg/gofr/datasource/surrealdb/go.sum +++ b/pkg/gofr/datasource/surrealdb/go.sum @@ -35,8 +35,7 @@ go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/Wgbsd go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 0ee9c843d3c4b1ea6033bb8be89954494c16c529 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sat, 2 Aug 2025 23:18:19 +0530 Subject: [PATCH 04/12] added testcase for Stat --- pkg/gofr/datasource/file/gcs/file_parse.go | 43 +++- pkg/gofr/datasource/file/gcs/fs_dir.go | 67 ++++-- pkg/gofr/datasource/file/gcs/fs_test.go | 238 ++++++++++++-------- pkg/gofr/datasource/file/gcs/logger_test.go | 48 ++++ 4 files changed, 274 insertions(+), 122 deletions(-) create mode 100644 pkg/gofr/datasource/file/gcs/logger_test.go diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go index 8b7738f96..4cbb68ba2 100644 --- a/pkg/gofr/datasource/file/gcs/file_parse.go +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -127,6 +127,7 @@ func (f *textReader) Next() bool { // Scan scans the next line from the text file into the provided pointer to string. func (f *textReader) Scan(i any) error { + if val, ok := i.(*string); ok { *val = f.scanner.Text() return nil @@ -136,28 +137,62 @@ func (f *textReader) Scan(i any) error { } func (g *GCSFile) Name() string { + + g.sendOperationStats(&FileLog{ + Operation: "GET NAME", + Location: g.name, + }, time.Now()) + return g.name } func (g *GCSFile) Size() int64 { + + g.sendOperationStats(&FileLog{ + Operation: "FILE/DIR SIZE", + Location: g.name, + }, time.Now()) + return g.size } func (g *GCSFile) ModTime() time.Time { + + g.sendOperationStats(&FileLog{ + Operation: "LAST MODIFIED", + Location: g.name, + }, time.Now()) + return g.lastModified } -func (f *GCSFile) Mode() fs.FileMode { - if f.isDir { +func (g *GCSFile) Mode() fs.FileMode { + g.sendOperationStats(&FileLog{ + Operation: "MODE", + Location: g.name, + }, time.Now()) + + if g.isDir { return fs.ModeDir } return 0 } func (g *GCSFile) IsDir() bool { - return g.isDir + + g.sendOperationStats(&FileLog{ + Operation: "IS DIR", + Location: g.name, + }, time.Now()) + + return g.isDir || g.contentType == "application/x-directory" } -func (f *GCSFile) Sys() interface{} { +func (g *GCSFile) Sys() interface{} { + + g.sendOperationStats(&FileLog{ + Operation: "SYS", + Location: g.name, + }, time.Now()) return nil } diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go index 0ead06056..76e7c7827 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "cloud.google.com/go/storage" file "gofr.dev/pkg/gofr/datasource/file" "google.golang.org/api/googleapi" ) @@ -50,7 +51,7 @@ func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { writer := f.conn.NewWriter(ctx, objName) defer writer.Close() - _, err := writer.Write([]byte("dir")) // minimal content + _, err := writer.Write([]byte("dir")) if err != nil { if err != nil { msg = fmt.Sprintf("failed to create directory %q on GCS: %v", objName, err) @@ -67,7 +68,7 @@ func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { func (f *FileSystem) MkdirAll(path string, perm os.FileMode) error { cleaned := strings.Trim(path, "/") if cleaned == "" { - return nil // root directory + return nil } dirs := strings.Split(cleaned, "/") @@ -89,7 +90,7 @@ func pathJoin(parts ...string) string { func isAlreadyExistsError(err error) bool { // If using Google Cloud Storage SDK if gErr, ok := err.(*googleapi.Error); ok { - return gErr.Code == 409 || gErr.Code == 412 // Conflict or Precondition Failed + return gErr.Code == 409 || gErr.Code == 412 } // Fallback check return strings.Contains(err.Error(), "already exists") @@ -205,7 +206,6 @@ func (f *FileSystem) Getwd() (string, error) { } func (f *FileSystem) Stat(name string) (file.FileInfo, error) { var msg string - st := statusErr defer f.sendOperationStats(&FileLog{ @@ -217,23 +217,54 @@ func (f *FileSystem) Stat(name string) (file.FileInfo, error) { ctx := context.TODO() + // Try to stat the object (file) attr, err := f.conn.StatObject(ctx, name) - if err != nil { - f.logger.Errorf("Error returning file info: %v", err) - return nil, err + if err == nil { + st = statusSuccess + msg = fmt.Sprintf("File with path %q info retrieved successfully", name) + + return &GCSFile{ + name: name, + logger: f.logger, + metrics: f.metrics, + size: attr.Size, + contentType: attr.ContentType, + lastModified: attr.Updated, + }, nil } - st = statusSuccess - msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) - - return &GCSFile{ - name: name, - logger: f.logger, - metrics: f.metrics, - size: attr.Size, - contentType: attr.ContentType, - lastModified: attr.Updated, - }, nil + // If not found, check if it's a "directory" by listing with prefix + if errors.Is(err, storage.ErrObjectNotExist) { + // Ensure the name ends with slash for directories + prefix := name + if !strings.HasSuffix(prefix, "/") { + prefix += "/" + } + + objs, _, listErr := f.conn.ListDir(ctx, prefix) + + if listErr != nil { + f.logger.Errorf("Error checking directory prefix: %v", listErr) + return nil, listErr + } + + if len(objs) > 0 { + st = statusSuccess + msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) + return &GCSFile{ + name: name, + logger: f.logger, + metrics: f.metrics, + size: 0, + contentType: "application/x-directory", + lastModified: objs[0].Updated, + }, nil + } + + } + + f.logger.Errorf("Error returning file or directory info: %v", err) + return nil, err } func (f *FileSystem) sendOperationStats(fl *FileLog, startTime time.Time) { diff --git a/pkg/gofr/datasource/file/gcs/fs_test.go b/pkg/gofr/datasource/file/gcs/fs_test.go index 8e442494a..5ba1fd984 100644 --- a/pkg/gofr/datasource/file/gcs/fs_test.go +++ b/pkg/gofr/datasource/file/gcs/fs_test.go @@ -2,11 +2,14 @@ package gcs import ( "errors" + "fmt" "testing" + "time" "cloud.google.com/go/storage" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" ) func Test_CreateFile(t *testing.T) { @@ -212,103 +215,138 @@ func TestRenameFile(t *testing.T) { } } -// func Test_OpenFile_GCS(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// mockGCS := NewMockgcsClient(ctrl) -// mockLogger := NewMockLogger(ctrl) -// mockMetrics := NewMockMetrics(ctrl) - -// config := &Config{ -// BucketName: "test-bucket", -// CredentialsJSON: "fake-creds", -// ProjectID: "test-project", -// } - -// fs := &FileSystem{ -// conn: mockGCS, -// logger: mockLogger, -// config: config, -// metrics: mockMetrics, -// } - -// expectedContent := "Hello, GCS!" - -// // 👇 Create a mocked reader that returns your expected content -// mockReader := &storage.Reader{ -// reader: io.NopCloser(strings.NewReader("dummy data")), // or fakeReader -// } - -// // Set up expectations -// mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() -// mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() -// mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() - -// mockGCS.EXPECT(). -// NewReader(gomock.Any(), "abc/a1.txt"). -// Return(mockReader, nil) - -// mockGCS.EXPECT(). -// StatObject(gomock.Any(), "abc/a1.txt"). -// Return(&storage.ObjectAttrs{}, nil) - -// // Act -// file, err := fs.OpenFile("abc/a1.txt", 0, os.ModePerm) -// require.NoError(t, err, "Failed to open file") - -// content := make([]byte, 200) -// n, err := file.Read(content) -// require.NoError(t, err, "Failed to read file content") - -// require.Equal(t, expectedContent, string(content[:n]), "File content does not match") -// } - -// func Test_OpenFile_GCS(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// mockGCS := NewMockgcsClient(ctrl) -// mockLogger := NewMockLogger(ctrl) -// mockMetrics := NewMockMetrics(ctrl) - -// config := &Config{ -// BucketName: "test-bucket", -// CredentialsJSON: "fake-creds", -// ProjectID: "test-project", -// } - -// fs := &FileSystem{ -// conn: mockGCS, -// logger: mockLogger, -// config: config, -// metrics: mockMetrics, -// } - -// expectedContent := "Hello, GCS!" -// mockReader := ioutil.NopCloser(strings.NewReader(expectedContent)) - -// // Expect logger calls (optional but commonly included) -// mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() -// mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() -// mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() - -// // Set up mock for GCS client -// mockGCS.EXPECT(). -// NewReader(gomock.Any(), "abc/a1.txt"). -// Return(mockReader, nil) - -// mockGCS.EXPECT(). -// StatObject(gomock.Any(), "abc/a1.txt"). -// Return(&storage.ObjectAttrs{}, nil) - -// // Act -// file, err := fs.OpenFile("abc/a1.txt", 0, os.ModePerm) -// require.NoError(t, err, "Failed to open file") - -// content := make([]byte, 200) -// n, err := file.Read(content) -// require.NoError(t, err, "Failed to read file content") - -// require.Equal(t, expectedContent, string(content[:n]), "File content does not match") -// } +func Test_StatFile_GCS(t *testing.T) { + tm := time.Now() + + type result struct { + name string + size int64 + isDir bool + } + + tests := []struct { + name string + filePath string + mockAttr *storage.ObjectAttrs + mockError error + expected result + expectError bool + }{ + { + name: "Valid file stat", + filePath: "abc/efg/file.txt", + mockAttr: &storage.ObjectAttrs{ + Name: "abc/efg/file.txt", + Size: 123, + Updated: tm, + ContentType: "text/plain", + }, + expected: result{ + name: "abc/efg/file.txt", + size: 123, + isDir: false, + }, + }, + { + name: "File not found", + filePath: "notfound.txt", + mockAttr: nil, + mockError: fmt.Errorf("object not found"), + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{BucketName: "test-bucket"} + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + + mockGCS.EXPECT().StatObject(gomock.Any(), tt.filePath).Return(tt.mockAttr, tt.mockError) + + res, err := fs.Stat(tt.filePath) + if tt.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + actual := result{ + name: res.Name(), + size: res.Size(), + isDir: res.IsDir(), + } + + assert.Equal(t, tt.expected, actual) + }) + } +} +func Test_Stat_FileAndDir(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + fs := &FileSystem{ + conn: mockGCS, + logger: mockLogger, + metrics: mockMetrics, + config: &Config{ + BucketName: "test-bucket", + }, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + + fileName := "documents/testfile.txt" + fileAttrs := &storage.ObjectAttrs{ + Name: fileName, + Size: 1024, + ContentType: "text/plain", + Updated: time.Now(), + } + mockGCS.EXPECT().StatObject(gomock.Any(), fileName).Return(fileAttrs, nil) + + info, err := fs.Stat(fileName) + assert.NilError(t, err) + assert.Equal(t, fileName, info.Name()) + assert.Equal(t, int64(1024), info.Size()) + assert.Check(t, !info.IsDir()) + + dirName := "documents/folder/" + dirAttrs := &storage.ObjectAttrs{ + Name: dirName, + Size: 0, + ContentType: "application/x-directory", + Updated: time.Now(), + } + + mockGCS.EXPECT().StatObject(gomock.Any(), dirName).Return(dirAttrs, nil) + + info, err = fs.Stat(dirName) + + assert.NilError(t, err) + assert.Equal(t, dirName, info.Name()) + assert.Equal(t, int64(0), info.Size()) + assert.Check(t, info.IsDir()) +} diff --git a/pkg/gofr/datasource/file/gcs/logger_test.go b/pkg/gofr/datasource/file/gcs/logger_test.go new file mode 100644 index 000000000..a6e156d6d --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/logger_test.go @@ -0,0 +1,48 @@ +package gcs + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFileLogPrettyPrint(t *testing.T) { + msg := "File Created successfully" + + fileLog := FileLog{ + Operation: "Create file", + Duration: 1234, + Location: "/ftp/one", + Message: &msg, + } + + expected := "Create file" + + expectedMsg := "File Created successfully" + + var buf bytes.Buffer + + fileLog.PrettyPrint(&buf) + + assert.Contains(t, buf.String(), expected) + assert.Contains(t, buf.String(), expectedMsg) +} + +func TestFileLogPrettyPrintWhitespaceHandling(t *testing.T) { + msg := " File creation complete " + fileLog := FileLog{ + Operation: " Create file ", + Duration: 5678, + Message: &msg, + } + expected := "Create file" + expectedMsg := "File creation complete" + + var buf bytes.Buffer + + fileLog.PrettyPrint(&buf) + + assert.Contains(t, buf.String(), expected) + assert.Contains(t, buf.String(), expectedMsg) +} From 03e691cbac9b8ef865749dbe029d4b9ca39db22b Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sat, 2 Aug 2025 23:31:35 +0530 Subject: [PATCH 05/12] Fix some typo error --- pkg/gofr/datasource/file/gcs/file_parse.go | 20 ++++++++++++++------ pkg/gofr/datasource/file/gcs/fs.go | 2 +- pkg/gofr/datasource/file/gcs/logger.go | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go index 4cbb68ba2..b470027ce 100644 --- a/pkg/gofr/datasource/file/gcs/file_parse.go +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -137,39 +137,44 @@ func (f *textReader) Scan(i any) error { } func (g *GCSFile) Name() string { + bucketName := getBucketName(g.name) g.sendOperationStats(&FileLog{ Operation: "GET NAME", - Location: g.name, + Location: getLocation(bucketName), }, time.Now()) return g.name } func (g *GCSFile) Size() int64 { + bucketName := getBucketName(g.name) g.sendOperationStats(&FileLog{ Operation: "FILE/DIR SIZE", - Location: g.name, + Location: getLocation(bucketName), }, time.Now()) return g.size } func (g *GCSFile) ModTime() time.Time { + bucketName := getBucketName(g.name) g.sendOperationStats(&FileLog{ Operation: "LAST MODIFIED", - Location: g.name, + Location: getLocation(bucketName), }, time.Now()) return g.lastModified } func (g *GCSFile) Mode() fs.FileMode { + bucketName := getBucketName(g.name) + g.sendOperationStats(&FileLog{ Operation: "MODE", - Location: g.name, + Location: getLocation(bucketName), }, time.Now()) if g.isDir { @@ -179,20 +184,23 @@ func (g *GCSFile) Mode() fs.FileMode { } func (g *GCSFile) IsDir() bool { + bucketName := getBucketName(g.name) g.sendOperationStats(&FileLog{ Operation: "IS DIR", - Location: g.name, + Location: getLocation(bucketName), }, time.Now()) return g.isDir || g.contentType == "application/x-directory" } func (g *GCSFile) Sys() interface{} { + bucketName := getBucketName(g.name) g.sendOperationStats(&FileLog{ Operation: "SYS", - Location: g.name, + Location: getLocation(bucketName), }, time.Now()) + return nil } diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go index ae70727cd..12f5bf991 100644 --- a/pkg/gofr/datasource/file/gcs/fs.go +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -34,7 +34,7 @@ type FileSystem struct { metrics Metrics } -// Config represents the s3 configuration. +// Config represents the gcs configuration. type Config struct { BucketName string CredentialsJSON string diff --git a/pkg/gofr/datasource/file/gcs/logger.go b/pkg/gofr/datasource/file/gcs/logger.go index 2a6e8e8dc..992b79b29 100644 --- a/pkg/gofr/datasource/file/gcs/logger.go +++ b/pkg/gofr/datasource/file/gcs/logger.go @@ -30,5 +30,5 @@ func clean(query *string) string { func (fl *FileLog) PrettyPrint(writer io.Writer) { fmt.Fprintf(writer, "\u001B[38;5;8m%-32s \u001B[38;5;148m%-6s\u001B[0m %8d\u001B[38;5;8mµs\u001B[0m %-10s \u001B[0m %-48s \n", - clean(&fl.Operation), "AWS_S3", fl.Duration, clean(fl.Status), clean(fl.Message)) + clean(&fl.Operation), "GCS", fl.Duration, clean(fl.Status), clean(fl.Message)) } From 1acaf156988516db7e43a8304272957cfc285ba1 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sun, 3 Aug 2025 00:01:28 +0530 Subject: [PATCH 06/12] feat: add Google Cloud Storage (GCS) file provider (#2013) --- pkg/gofr/datasource/file/gcs/fs_dir.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go index 76e7c7827..038912c1d 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -153,8 +153,10 @@ func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { trimmedName := strings.TrimSuffix(p, "/") dirName := path.Base(trimmedName) fileinfo = append(fileinfo, &GCSFile{ - name: dirName, - isDir: true, + name: dirName, + isDir: true, + logger: f.logger, + metrics: f.metrics, }) } @@ -164,6 +166,8 @@ func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { size: o.Size, lastModified: o.Updated, isDir: false, + logger: f.logger, + metrics: f.metrics, }) } From 70f0a290343304e276a50fbc79e83b7a693e6ba8 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sun, 3 Aug 2025 23:30:08 +0530 Subject: [PATCH 07/12] format code using goimports and fix lint issues via golangci-lint --- pkg/gofr/datasource/file/gcs/file.go | 92 ++++++++++++------ pkg/gofr/datasource/file/gcs/file_parse.go | 50 +++++----- pkg/gofr/datasource/file/gcs/fs.go | 41 +++++--- pkg/gofr/datasource/file/gcs/fs_dir.go | 50 +++++++--- pkg/gofr/datasource/file/gcs/fs_dir_test.go | 101 ++++++++++---------- pkg/gofr/datasource/file/gcs/fs_test.go | 22 ++++- pkg/gofr/datasource/file/gcs/interface.go | 18 +++- 7 files changed, 237 insertions(+), 137 deletions(-) diff --git a/pkg/gofr/datasource/file/gcs/file.go b/pkg/gofr/datasource/file/gcs/file.go index 392f542ce..4321195f9 100644 --- a/pkg/gofr/datasource/file/gcs/file.go +++ b/pkg/gofr/datasource/file/gcs/file.go @@ -8,11 +8,13 @@ import ( "cloud.google.com/go/storage" ) +// GCSFile represents a file in an GCS bucket. +// +//nolint:revive // gcs.GCSFile is repetitive. A better name could have been chosen, but it's too late as it's already exported. type GCSFile struct { conn gcsClient writer *storage.Writer name string - offset int64 logger Logger metrics Metrics size int64 @@ -22,95 +24,127 @@ type GCSFile struct { isDir bool } +var ( + ErrNilGCSFileBody = errors.New("GCS file body is nil") + ErrSeekNotSupported = errors.New("seek not supported on GCSFile") + ErrReadAtNotSupported = errors.New("readAt not supported on GCSFile") + ErrWriteAtNotSupported = errors.New("writeAt not supported on GCSFile (read-only)") +) + +const ( + msgWriterClosed = "Writer closed successfully" + msgReaderClosed = "Reader closed successfully" +) + // ====== File interface methods ====== -func (g *GCSFile) Read(p []byte) (int, error) { - if g.body == nil { - return 0, errors.New("GCS file body is nil") +func (f *GCSFile) Read(p []byte) (int, error) { + if f.body == nil { + return 0, ErrNilGCSFileBody } - return g.body.Read(p) + + return f.body.Read(p) } -func (g *GCSFile) Write(p []byte) (int, error) { - bucketName := getBucketName(g.name) +func (f *GCSFile) Write(p []byte) (int, error) { + bucketName := getBucketName(f.name) var msg string st := statusErr - defer g.sendOperationStats(&FileLog{ + defer f.sendOperationStats(&FileLog{ Operation: "WRITE", Location: getLocation(bucketName), Status: &st, Message: &msg, }, time.Now()) - n, err := g.writer.Write(p) + n, err := f.writer.Write(p) + if err != nil { - g.logger.Errorf("failed to write: %v", err) + f.logger.Errorf("failed to write: %v", err) msg = err.Error() + return n, err } + st = statusSuccess msg = "Write successful" - return n, nil + f.logger.Logf(msg) + return n, nil } -func (g *GCSFile) Close() error { - bucketName := getBucketName(g.name) +func (f *GCSFile) Close() error { + bucketName := getBucketName(f.name) + var msg string + st := statusErr - defer g.sendOperationStats(&FileLog{ + defer f.sendOperationStats(&FileLog{ Operation: "CLOSE", Location: getLocation(bucketName), Status: &st, Message: &msg, }, time.Now()) - if g.writer != nil { - err := g.writer.Close() + if f.writer != nil { + err := f.writer.Close() if err != nil { msg = err.Error() return err } + st = statusSuccess - msg = "Writer closed successfully" + + msg = msgWriterClosed + + f.logger.Logf(msg) + return nil } - if g.body != nil { - err := g.body.Close() + if f.body != nil { + err := f.body.Close() if err != nil { msg = err.Error() return err } + st = statusSuccess - msg = "Reader closed successfully" + + msg = msgReaderClosed + + f.logger.Logf(msgReaderClosed) + return nil } + st = statusSuccess - msg = "Writer closed successfully" + + msg = msgWriterClosed + return nil } -func (g *GCSFile) Seek(offset int64, whence int) (int64, error) { +func (*GCSFile) Seek(_ int64, _ int) (int64, error) { // Not supported: Seek requires reopening with range. - return 0, errors.New("Seek not supported on GCSFile") + return 0, ErrSeekNotSupported } -func (g *GCSFile) ReadAt(_ []byte, _ int64) (int, error) { - return 0, errors.New("ReadAt not supported on GCSFile") +func (*GCSFile) ReadAt(_ []byte, _ int64) (int, error) { + return 0, ErrReadAtNotSupported } -func (g *GCSFile) WriteAt(_ []byte, _ int64) (int, error) { - return 0, errors.New("WriteAt not supported on GCSFile (read-only)") +func (*GCSFile) WriteAt(_ []byte, _ int64) (int, error) { + return 0, ErrWriteAtNotSupported } -func (g *GCSFile) sendOperationStats(fl *FileLog, startTime time.Time) { +func (f *GCSFile) sendOperationStats(fl *FileLog, startTime time.Time) { duration := time.Since(startTime).Microseconds() fl.Duration = duration - g.logger.Debug(fl) + f.logger.Debug(fl) } diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go index b470027ce..7fe0794fb 100644 --- a/pkg/gofr/datasource/file/gcs/file_parse.go +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -125,9 +125,8 @@ func (f *textReader) Next() bool { return f.scanner.Scan() } -// Scan scans the next line from the text file into the provided pointer to string. +// Scan scans the next line from the text file into the provided pointer to strinf. func (f *textReader) Scan(i any) error { - if val, ok := i.(*string); ok { *val = f.scanner.Text() return nil @@ -136,68 +135,69 @@ func (f *textReader) Scan(i any) error { return errStringNotPointer } -func (g *GCSFile) Name() string { - bucketName := getBucketName(g.name) +func (f *GCSFile) Name() string { + bucketName := getBucketName(f.name) - g.sendOperationStats(&FileLog{ + f.sendOperationStats(&FileLog{ Operation: "GET NAME", Location: getLocation(bucketName), }, time.Now()) - return g.name + return f.name } -func (g *GCSFile) Size() int64 { - bucketName := getBucketName(g.name) +func (f *GCSFile) Size() int64 { + bucketName := getBucketName(f.name) - g.sendOperationStats(&FileLog{ + f.sendOperationStats(&FileLog{ Operation: "FILE/DIR SIZE", Location: getLocation(bucketName), }, time.Now()) - return g.size + return f.size } -func (g *GCSFile) ModTime() time.Time { - bucketName := getBucketName(g.name) +func (f *GCSFile) ModTime() time.Time { + bucketName := getBucketName(f.name) - g.sendOperationStats(&FileLog{ + f.sendOperationStats(&FileLog{ Operation: "LAST MODIFIED", Location: getLocation(bucketName), }, time.Now()) - return g.lastModified + return f.lastModified } -func (g *GCSFile) Mode() fs.FileMode { - bucketName := getBucketName(g.name) +func (f *GCSFile) Mode() fs.FileMode { + bucketName := getBucketName(f.name) - g.sendOperationStats(&FileLog{ + f.sendOperationStats(&FileLog{ Operation: "MODE", Location: getLocation(bucketName), }, time.Now()) - if g.isDir { + if f.isDir { return fs.ModeDir } + return 0 } -func (g *GCSFile) IsDir() bool { - bucketName := getBucketName(g.name) +func (f *GCSFile) IsDir() bool { + bucketName := getBucketName(f.name) - g.sendOperationStats(&FileLog{ + f.sendOperationStats(&FileLog{ Operation: "IS DIR", Location: getLocation(bucketName), }, time.Now()) - return g.isDir || g.contentType == "application/x-directory" + return f.isDir || f.contentType == "application/x-directory" } -func (g *GCSFile) Sys() interface{} { - bucketName := getBucketName(g.name) +func (f *GCSFile) Sys() any { + bucketName := getBucketName(f.name) - g.sendOperationStats(&FileLog{ + f.sendOperationStats(&FileLog{ Operation: "SYS", Location: getLocation(bucketName), }, time.Now()) diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go index 12f5bf991..222d0615d 100644 --- a/pkg/gofr/datasource/file/gcs/fs.go +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -14,18 +14,10 @@ import ( "google.golang.org/api/option" ) -const ( - typeFile = "file" - typeDirectory = "directory" -) - var ( - errIncorrectFileType = errors.New("incorrect file type") + ErrWriterTypeAssertion = errors.New("writer is not of type *storage.Writer") ) -type client struct { - *storage.Client -} type FileSystem struct { GCSFile GCSFile conn gcsClient @@ -48,6 +40,7 @@ func New(config *Config) file.FileSystemProvider { func (f *FileSystem) Connect() { var msg string + st := statusErr defer f.sendOperationStats(&FileLog{ @@ -58,19 +51,24 @@ func (f *FileSystem) Connect() { }, time.Now()) f.logger.Debugf("connecting to GCS bucket: %s", f.config.BucketName) + ctx := context.TODO() + client, err := storage.NewClient(ctx, option.WithCredentialsJSON([]byte(f.config.CredentialsJSON))) if err != nil { f.logger.Errorf("Failed to connect to GCS: %v", err) return } + f.conn = &gcsClientImpl{ client: client, bucket: client.Bucket(f.config.BucketName), } + st = statusSuccess msg = "GCS Client connected." + f.logger.Logf("connected to GCS bucket %s", f.config.BucketName) } @@ -93,26 +91,37 @@ func (f *FileSystem) Create(name string) (file.File, error) { // 1. Check if parent directory exists parentPath := path.Dir(name) checkPath := "." + if parentPath != "." { checkPath = parentPath + "/" } if _, err := f.conn.ListObjects(ctx, checkPath); err != nil { msg = "Parent directory does not exist" + + f.logger.Errorf("Failed to list parent directory %q: %v", checkPath, err) + return nil, err } // 2. Resolve file name conflict originalName := name + for index := 1; ; index++ { objs, err := f.conn.ListObjects(ctx, name) + if err != nil { msg = "Error checking existing objects" + + f.logger.Errorf("Failed to list objects for name %q: %v", name, err) + return nil, err } + if len(objs) == 0 { break // Safe to use } + name = generateCopyName(originalName, index) } @@ -122,12 +131,17 @@ func (f *FileSystem) Create(name string) (file.File, error) { sw, ok := writer.(*storage.Writer) if !ok { msg = "Failed to assert writer to *storage.Writer" - return nil, errors.New(msg) + + f.logger.Errorf("Type assertion failed for writer to *storage.Writer") + + return nil, fmt.Errorf("type assertion failed: %w", ErrWriterTypeAssertion) } st = statusSuccess msg = "Write stream opened successfully" + f.logger.Logf("Write stream successfully opened for file %q", name) + return &GCSFile{ conn: f.conn, writer: sw, @@ -138,7 +152,6 @@ func (f *FileSystem) Create(name string) (file.File, error) { logger: f.logger, metrics: f.metrics, }, nil - } func (f *FileSystem) Remove(name string) error { @@ -155,6 +168,7 @@ func (f *FileSystem) Remove(name string) error { ctx := context.TODO() err := f.conn.DeleteObject(ctx, name) + if err != nil { f.logger.Errorf("Error while deleting file: %v", err) return err @@ -169,7 +183,6 @@ func (f *FileSystem) Remove(name string) error { } func (f *FileSystem) Open(name string) (file.File, error) { - var msg string st := statusErr @@ -200,7 +213,9 @@ func (f *FileSystem) Open(name string) (file.File, error) { reader.Close() return nil, err } + st = statusSuccess + msg = fmt.Sprintf("File with path %q retrieved successfully", name) return &GCSFile{ @@ -216,7 +231,6 @@ func (f *FileSystem) Open(name string) (file.File, error) { } func (f *FileSystem) Rename(oldname, newname string) error { - var msg string st := statusErr @@ -279,5 +293,6 @@ func (f *FileSystem) UseMetrics(metrics any) { func generateCopyName(original string, count int) string { ext := path.Ext(original) base := strings.TrimSuffix(original, ext) + return fmt.Sprintf("%s copy %d%s", base, count, ext) } diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go index 038912c1d..6ea20146e 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -17,6 +17,8 @@ import ( var ( ErrOperationNotPermitted = errors.New("operation not permitted") + ErrEmptyDirectoryName = errors.New("directory name cannot be empty") + ErrCHNDIRNotSupported = errors.New("changing directory is not supported in GCS") ) func getBucketName(filePath string) string { @@ -28,7 +30,6 @@ func getLocation(bucket string) string { } func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { - var msg string st := statusErr @@ -41,8 +42,10 @@ func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { }, time.Now()) if name == "" { - msg = fmt.Sprintf("directory name cannot be empty") - return errors.New("directory name cannot be empty") + msg = "directory name cannot be empty" + f.logger.Errorf(msg) + + return ErrEmptyDirectoryName } ctx := context.TODO() @@ -55,13 +58,18 @@ func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { if err != nil { if err != nil { msg = fmt.Sprintf("failed to create directory %q on GCS: %v", objName, err) + f.logger.Errorf(msg) + return err } } + st = statusSuccess + msg = fmt.Sprintf("Directories on path %q created successfully", name) f.logger.Logf("Created directories on path %q", name) + return err } @@ -72,15 +80,18 @@ func (f *FileSystem) MkdirAll(path string, perm os.FileMode) error { } dirs := strings.Split(cleaned, "/") + var currentPath string for _, dir := range dirs { currentPath = pathJoin(currentPath, dir) err := f.Mkdir(currentPath, perm) + if err != nil && !isAlreadyExistsError(err) { return err } } + return nil } func pathJoin(parts ...string) string { @@ -88,15 +99,16 @@ func pathJoin(parts ...string) string { } func isAlreadyExistsError(err error) bool { - // If using Google Cloud Storage SDK - if gErr, ok := err.(*googleapi.Error); ok { + var gErr *googleapi.Error + if errors.As(err, &gErr) { return gErr.Code == 409 || gErr.Code == 412 } + // Fallback check return strings.Contains(err.Error(), "already exists") } -func (f *FileSystem) RemoveAll(path string) error { +func (f *FileSystem) RemoveAll(path string) error { var msg string st := statusErr @@ -110,6 +122,7 @@ func (f *FileSystem) RemoveAll(path string) error { ctx := context.TODO() objects, err := f.conn.ListObjects(ctx, path) + if err != nil { msg = fmt.Sprintf("Error retrieving objects: %v", err) return err @@ -121,14 +134,17 @@ func (f *FileSystem) RemoveAll(path string) error { return err } } + st = statusSuccess + msg = fmt.Sprintf("Directory with path %q, deleted successfully", path) f.logger.Logf("Directory %s deleted.", path) + return nil } -func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { +func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { var msg string st := statusErr @@ -145,10 +161,13 @@ func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { objects, prefixes, err := f.conn.ListDir(ctx, dir) if err != nil { msg = fmt.Sprintf("Error retrieving objects: %v", err) + f.logger.Logf(msg) + return nil, err } - var fileinfo []file.FileInfo + fileinfo := make([]file.FileInfo, 0, len(prefixes)+len(objects)) + for _, p := range prefixes { trimmedName := strings.TrimSuffix(p, "/") dirName := path.Base(trimmedName) @@ -175,12 +194,15 @@ func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { msg = fmt.Sprintf("Directory/Files in directory with path %q retrieved successfully", dir) f.logger.Logf("Reading directory/files from GCS at path %q successful.", dir) + return fileinfo, nil } func (f *FileSystem) ChDir(_ string) error { const op = "CHDIR" + st := statusErr + var msg = "Changing directory not supported" defer f.sendOperationStats(&FileLog{ @@ -189,15 +211,18 @@ func (f *FileSystem) ChDir(_ string) error { Status: &st, Message: &msg, }, time.Now()) + f.logger.Errorf("%s: not supported in GCS", op) - return errors.New("changing directory is not supported in GCS") + return ErrCHNDIRNotSupported } func (f *FileSystem) Getwd() (string, error) { - const op = "GETWD" + st := statusSuccess + start := time.Now() + var msg = "Returning simulated root directory" defer f.sendOperationStats(&FileLog{ @@ -206,10 +231,12 @@ func (f *FileSystem) Getwd() (string, error) { Status: &st, Message: &msg, }, start) + return getLocation(f.config.BucketName), nil } func (f *FileSystem) Stat(name string) (file.FileInfo, error) { var msg string + st := statusErr defer f.sendOperationStats(&FileLog{ @@ -255,6 +282,7 @@ func (f *FileSystem) Stat(name string) (file.FileInfo, error) { if len(objs) > 0 { st = statusSuccess msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) + return &GCSFile{ name: name, logger: f.logger, @@ -264,10 +292,10 @@ func (f *FileSystem) Stat(name string) (file.FileInfo, error) { lastModified: objs[0].Updated, }, nil } - } f.logger.Errorf("Error returning file or directory info: %v", err) + return nil, err } diff --git a/pkg/gofr/datasource/file/gcs/fs_dir_test.go b/pkg/gofr/datasource/file/gcs/fs_dir_test.go index 558f41ee4..cceed25b3 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir_test.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir_test.go @@ -2,7 +2,7 @@ package gcs import ( "bytes" - "fmt" + "errors" "testing" "cloud.google.com/go/storage" @@ -14,18 +14,24 @@ type fakeWriteCloser struct { *bytes.Buffer } -func (fwc *fakeWriteCloser) Close() error { +func (*fakeWriteCloser) Close() error { return nil } type errorWriterCloser struct{} -func (e *errorWriterCloser) Write(p []byte) (int, error) { - return 0, fmt.Errorf("write error") +var ( + ErrWrite = errors.New("write error") + ErrClose = errors.New("close error") + ErrDirNotFound = errors.New("directory not found") +) + +func (*errorWriterCloser) Write(_ []byte) (int, error) { + return 0, ErrWrite } -func (e *errorWriterCloser) Close() error { - return fmt.Errorf("close error") +func (*errorWriterCloser) Close() error { + return ErrClose } type result struct { @@ -61,6 +67,7 @@ func Test_Mkdir_GCS(t *testing.T) { logger: mockLogger, metrics: mockMetrics, } + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debugf(gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() @@ -80,7 +87,7 @@ func Test_Mkdir_GCS(t *testing.T) { { name: "fail when directory name is empty", dirName: "", - setupMocks: func(m *MockgcsClient) { + setupMocks: func(_ *MockgcsClient) { // No mock needed for empty dir }, expectError: true, @@ -119,13 +126,9 @@ func Test_ReadDir_GCS(t *testing.T) { mockLogger := NewMockLogger(ctrl) mockMetrics := NewMockMetrics(ctrl) - config := &Config{ - BucketName: "test-bucket", - } - fs := &FileSystem{ conn: mockGCS, - config: config, + config: &Config{BucketName: "test-bucket"}, logger: mockLogger, metrics: mockMetrics, } @@ -134,13 +137,37 @@ func Test_ReadDir_GCS(t *testing.T) { mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() - tests := []struct { - name string - dirPath string - expectedResults []result - setupMock func() - expectError bool - }{ + for _, tt := range getReadDirTestCases(mockGCS) { + t.Run(tt.name, func(t *testing.T) { + tt.setupMock() + entries, err := fs.ReadDir(tt.dirPath) + + if tt.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Len(t, entries, len(tt.expectedResults)) + + for i, entry := range entries { + require.Equal(t, tt.expectedResults[i].Name, entry.Name()) + require.Equal(t, tt.expectedResults[i].IsDir, entry.IsDir()) + } + }) + } +} + +type readDirTestCase struct { + name string + dirPath string + expectedResults []result + setupMock func() + expectError bool +} + +func getReadDirTestCases(mockGCS *MockgcsClient) []readDirTestCase { + return []readDirTestCase{ { name: "Valid directory path with files and subdirectory", dirPath: "abc/efg", @@ -148,17 +175,12 @@ func Test_ReadDir_GCS(t *testing.T) { {"hij", 0, true}, {"file.txt", 1, false}, }, - setupMock: func() { mockGCS.EXPECT().ListDir(gomock.Any(), "abc/efg").Return( - []*storage.ObjectAttrs{ - {Name: "abc/efg/file.txt", Size: 1}, - }, - []string{ - "abc/efg/hij/", - }, - nil) - + []*storage.ObjectAttrs{{Name: "abc/efg/file.txt", Size: 1}}, + []string{"abc/efg/hij/"}, + nil, + ) }, }, { @@ -180,7 +202,7 @@ func Test_ReadDir_GCS(t *testing.T) { dirPath: "does-not-exist", expectedResults: nil, setupMock: func() { - mockGCS.EXPECT().ListDir(gomock.Any(), "does-not-exist").Return(nil, nil, fmt.Errorf("directory not found")) + mockGCS.EXPECT().ListDir(gomock.Any(), "does-not-exist").Return(nil, nil, ErrDirNotFound) }, expectError: true, }, @@ -207,25 +229,4 @@ func Test_ReadDir_GCS(t *testing.T) { }, }, } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.setupMock() - - entries, err := fs.ReadDir(tt.dirPath) - if tt.expectError { - require.Error(t, err) - return - } - - require.NoError(t, err) - require.Equal(t, len(tt.expectedResults), len(entries)) - - for i, entry := range entries { - // fmt.Printf("DEBUG [%d] => Name: %s, IsDir: %v\n", i, entry.Name(), entry.IsDir()) - require.Equal(t, tt.expectedResults[i].Name, entry.Name(), "entry name mismatch") - require.Equal(t, tt.expectedResults[i].IsDir, entry.IsDir(), "entry type mismatch (file/dir)") - } - }) - } } diff --git a/pkg/gofr/datasource/file/gcs/fs_test.go b/pkg/gofr/datasource/file/gcs/fs_test.go index 5ba1fd984..00ea6ef14 100644 --- a/pkg/gofr/datasource/file/gcs/fs_test.go +++ b/pkg/gofr/datasource/file/gcs/fs_test.go @@ -12,6 +12,11 @@ import ( "gotest.tools/v3/assert" ) +var ( + ErrObjectNotFound = errors.New("object not found") + ErrMock = fmt.Errorf("errMock") +) + func Test_CreateFile(t *testing.T) { type testCase struct { name string @@ -42,6 +47,7 @@ func Test_CreateFile(t *testing.T) { } mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() tests := []testCase{ @@ -52,8 +58,8 @@ func Test_CreateFile(t *testing.T) { m.EXPECT().ListObjects(gomock.Any(), ".").Return([]string{}, nil) m.EXPECT().ListObjects(gomock.Any(), "abc.txt").Return([]string{}, nil) m.EXPECT().NewWriter(gomock.Any(), "abc.txt").Return(&storage.Writer{}) - }, + expectError: false, isRoot: true, }, @@ -61,7 +67,7 @@ func Test_CreateFile(t *testing.T) { name: "fail when parent directory does not exist", createPath: "abc/abc.txt", setupMocks: func(m *MockgcsClient) { - m.EXPECT().ListObjects(gomock.Any(), "abc/").Return(nil, errors.New("errMock")) + m.EXPECT().ListObjects(gomock.Any(), "abc/").Return(nil, ErrMock) }, expectError: true, isRoot: false, @@ -126,6 +132,11 @@ func Test_Remove_GCS(t *testing.T) { require.NoError(t, err) } +var ( + errDeleteFailed = errors.New("delete failed") + errCopyFailed = errors.New("copy failed") +) + func TestRenameFile(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -165,7 +176,7 @@ func TestRenameFile(t *testing.T) { initialName: "dir/file.txt", newName: "dir/file-renamed.txt", setupMocks: func() { - mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(errors.New("copy failed")) + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(errCopyFailed) }, expectedError: true, }, @@ -175,7 +186,7 @@ func TestRenameFile(t *testing.T) { newName: "dir/file-renamed.txt", setupMocks: func() { mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(nil) - mockConn.EXPECT().DeleteObject(gomock.Any(), "dir/file.txt").Return(errors.New("delete failed")) + mockConn.EXPECT().DeleteObject(gomock.Any(), "dir/file.txt").Return(errDeleteFailed) }, expectedError: true, }, @@ -251,7 +262,7 @@ func Test_StatFile_GCS(t *testing.T) { name: "File not found", filePath: "notfound.txt", mockAttr: nil, - mockError: fmt.Errorf("object not found"), + mockError: ErrObjectNotFound, expectError: true, }, } @@ -287,6 +298,7 @@ func Test_StatFile_GCS(t *testing.T) { } require.NoError(t, err) + actual := result{ name: res.Name(), size: res.Size(), diff --git a/pkg/gofr/datasource/file/gcs/interface.go b/pkg/gofr/datasource/file/gcs/interface.go index af61a8659..fd4428d8a 100644 --- a/pkg/gofr/datasource/file/gcs/interface.go +++ b/pkg/gofr/datasource/file/gcs/interface.go @@ -4,6 +4,7 @@ package gcs import ( "context" + "errors" "fmt" "io" @@ -65,27 +66,34 @@ func (g *gcsClientImpl) CopyObject(ctx context.Context, src, dst string) error { srcObj := g.bucket.Object(src) dstObj := g.bucket.Object(dst) _, err := dstObj.CopierFrom(srcObj).Run(ctx) + return err } func (g *gcsClientImpl) ListObjects(ctx context.Context, prefix string) ([]string, error) { var objects []string + it := g.bucket.Objects(ctx, &storage.Query{Prefix: prefix}) + for { obj, err := it.Next() - if err == iterator.Done { + if errors.Is(err, iterator.Done) { break } + if err != nil { return nil, err } + objects = append(objects, obj.Name) } + return objects, nil } func (g *gcsClientImpl) ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) { var attrs []*storage.ObjectAttrs + var prefixes []string it := g.bucket.Objects(ctx, &storage.Query{ @@ -95,18 +103,20 @@ func (g *gcsClientImpl) ListDir(ctx context.Context, prefix string) ([]*storage. for { obj, err := it.Next() - if err == iterator.Done { + + if errors.Is(err, iterator.Done) { break - } - if err != nil { + } else if err != nil { return nil, nil, err } + if obj.Prefix != "" { prefixes = append(prefixes, obj.Prefix) } else { attrs = append(attrs, obj) } } + return attrs, prefixes, nil } From b192c182dee6926f91327f6f9472366c893709c8 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sat, 16 Aug 2025 23:31:41 +0530 Subject: [PATCH 08/12] fix lint issue --- CONTRIBUTING.md | 113 ++++++++++++------------- go.work.sum | 18 ++-- pkg/gofr/datasource/file/gcs/fs.go | 26 +++++- pkg/gofr/datasource/file/gcs/fs_dir.go | 12 +-- 4 files changed, 94 insertions(+), 75 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4df5abc09..bd5f619ad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,21 +1,23 @@ ## Contribution Guidelines -* Minor changes can be done directly by editing code on GitHub. GitHub automatically creates a temporary branch and + +- Minor changes can be done directly by editing code on GitHub. GitHub automatically creates a temporary branch and files a PR. This is only suitable for really small changes like: spelling fixes, variable name changes or error string change etc. For larger commits, following steps are recommended. -* (Optional) If you want to discuss your implementation with the users of GoFr, use the GitHub discussions of this repo. -* Configure your editor to use goimport and golangci-lint on file changes. Any code which is not formatted using these +- (Optional) If you want to discuss your implementation with the users of GoFr, use the GitHub discussions of this repo. +- Configure your editor to use goimport and golangci-lint on file changes. Any code which is not formatted using these tools, will fail on the pipeline. -* Contributors should begin working on an issue only after it has been assigned to them. To get an issue assigned, please comment on the GitHub thread +- Contributors should begin working on an issue only after it has been assigned to them. To get an issue assigned, please comment on the GitHub thread and request assignment from a maintainer. This helps avoid duplicate or conflicting pull requests from multiple contributors. -* Issues labeled triage are not open for direct contributions. If you're interested in working on a triage issue, please reach out to the maintainers - to discuss it before proceeding in the Github thread. +- Issues labeled triage are not open for direct contributions. If you're interested in working on a triage issue, please reach out to the maintainers +to discuss it before proceeding in the Github thread. -* We follow **American English** conventions in this project (e.g., *"favor"* instead of *"favour"*). Please keep this consistent across all code comments, documentation, etc. +- We follow **American English** conventions in this project (e.g., _"favor"_ instead of _"favour"_). Please keep this consistent across all code comments, documentation, etc. -* All code contributions should have associated tests and all new line additions should be covered in those testcases. +- All code contributions should have associated tests and all new line additions should be covered in those testcases. No PR should ever decrease the overall code coverage. -* Once your code changes are done along with the testcases, submit a PR to development branch. Please note that all PRs +- Once your code changes are done along with the testcases, submit a PR to development branch. Please note that all PRs are merged from feature branches to development first. + * PR should be raised only when development is complete and the code is ready for review. This approach helps reduce the number of open pull requests and facilitates a more efficient review process for the team. * All PRs need to be reviewed by at least 2 GoFr developers. They might reach out to you for any clarification. * Thank you for your contribution. :) @@ -28,32 +30,28 @@ Testing is a crucial aspect of software development, and adherence to these guid 1. **Test Types:** - - Write unit tests for every new function or method. - - Include integration tests for any major feature added. - - -2. **Test Coverage:** - -- No new code should decrease the existing code coverage for the packages and files. -> The `code-climate` coverage check will not pass if there is any decrease in the test-coverage before and after any new PR is submitted. + - Write unit tests for every new function or method. + - Include integration tests for any major feature added. +2. **Test Coverage:** +- No new code should decrease the existing code coverage for the packages and files. + > The `code-climate` coverage check will not pass if there is any decrease in the test-coverage before and after any new PR is submitted. 3. **Naming Conventions:** -- Prefix unit test functions with `Test`. -- Use clear and descriptive names. +- Prefix unit test functions with `Test`. +- Use clear and descriptive names. + ```go func TestFunctionName(t *testing.T) { // Test logic } ``` - - 4. **Table-Driven Tests:** -- Consider using table-driven tests for testing multiple scenarios. +- Consider using table-driven tests for testing multiple scenarios. > [!NOTE] > Some services will be required to pass the entire test suite. We recommend using docker for running those services. @@ -96,53 +94,52 @@ docker run -d --name arangodb \ -e ARANGO_ROOT_PASSWORD=rootpassword \ --pull always \ arangodb:latest -<<<<<<< HEAD docker run -d --name db -p 8091-8096:8091-8096 -p 11210-11211:11210-11211 couchbase -======= docker login container-registry.oracle.com docker pull container-registry.oracle.com/database/free:latest docker run -d --name oracle-free -p 1521:1521 -e ORACLE_PWD=YourPasswordHere container-registry.oracle.com/database/free:latest ->>>>>>> origin +docker run -it --rm -p 4443:4443 -e STORAGE_EMULATOR_HOST=0.0.0.0:4443 fsouza/fake-gcs-server:latest ``` > [!NOTE] > Please note that the recommended local port for the services are different from the actual ports. This is done to avoid conflict with the local installation on developer machines. This method also allows a developer to work on multiple projects which uses the same services but bound on different ports. One can choose to change the port for these services. Just remember to add the same in configs/.local.env, if you decide to do that. - ### Coding Guidelines -* Use only what is given to you as part of function parameter or receiver. No globals. Inject all dependencies including + +- Use only what is given to you as part of function parameter or receiver. No globals. Inject all dependencies including DB, Logger etc. -* No magic. So, no init. In a large project, it becomes difficult to track which package is doing what at the +- No magic. So, no init. In a large project, it becomes difficult to track which package is doing what at the initialization step. -* Exported functions must have an associated godoc. -* Sensitive data(username, password, keys) should not be pushed. Always use environment variables. -* Take interfaces and return concrete types. - - Lean interfaces - take 'exactly' what you need, not more. Onus of interface definition is on the package who is - using it. so, it should be as lean as possible. This makes it easier to test. - - Be careful of type assertions in this context. If you take an interface and type assert to a type - then it's - similar to taking concrete type. -* Uses of context: - - We should use context as a first parameter. - - Can not use string as a key for the context. Define your own type and provide context accessor method to avoid - conflict. -* External Library uses: - - A little copying is better than a little dependency. - - All external dependencies should go through the same careful consideration, we would have done to our own written - code. We need to test the functionality we are going to use from an external library, as sometimes library - implementation may change. - - All dependencies must be abstracted as an interface. This will make it easier to switch libraries at later point - of time. -* Version tagging as per Semantic versioning (https://semver.org/) +- Exported functions must have an associated godoc. +- Sensitive data(username, password, keys) should not be pushed. Always use environment variables. +- Take interfaces and return concrete types. + - Lean interfaces - take 'exactly' what you need, not more. Onus of interface definition is on the package who is + using it. so, it should be as lean as possible. This makes it easier to test. + - Be careful of type assertions in this context. If you take an interface and type assert to a type - then it's + similar to taking concrete type. +- Uses of context: + - We should use context as a first parameter. + - Can not use string as a key for the context. Define your own type and provide context accessor method to avoid + conflict. +- External Library uses: + - A little copying is better than a little dependency. + - All external dependencies should go through the same careful consideration, we would have done to our own written + code. We need to test the functionality we are going to use from an external library, as sometimes library + implementation may change. + - All dependencies must be abstracted as an interface. This will make it easier to switch libraries at later point + of time. +- Version tagging as per Semantic versioning (https://semver.org/) ### Documentation -* After adding or modifying existing code, update the documentation too - [development/docs](https://github.com/gofr-dev/gofr/tree/development/docs). -* When you consider a new documentation page is needed, start by adding a new file and writing your new documentation. Then - add a reference to it in [navigation.js](https://gofr.dev/docs/navigation.js). -* If needed, update or add proper code examples for your changes. -* In case images are needed, add it to [docs/public](./docs/public) folder. -* Make sure you don't break existing links and references. -* Maintain Markdown standards, you can read more [here](https://www.markdownguide.org/basic-syntax/), this includes: - - Headings (`#`, `##`, etc.) should be placed in order. - - Use trailing white space or the
HTML tag at the end of the line. - - Use "`" sign to add single line code and "```" to add multi-line code block. - - Use relative references to images (in `public` folder as mentioned above.) -* The [gofr.dev documentation](https://gofr.dev/docs) site is updated upon push to `/docs` path in the repo. Verify your changes are live after next GoFr version. + +- After adding or modifying existing code, update the documentation too - [development/docs](https://github.com/gofr-dev/gofr/tree/development/docs). +- When you consider a new documentation page is needed, start by adding a new file and writing your new documentation. Then - add a reference to it in [navigation.js](https://gofr.dev/docs/navigation.js). +- If needed, update or add proper code examples for your changes. +- In case images are needed, add it to [docs/public](./docs/public) folder. +- Make sure you don't break existing links and references. +- Maintain Markdown standards, you can read more [here](https://www.markdownguide.org/basic-syntax/), this includes: + - Headings (`#`, `##`, etc.) should be placed in order. + - Use trailing white space or the
HTML tag at the end of the line. + - Use "`" sign to add single line code and "```" to add multi-line code block. + - Use relative references to images (in `public` folder as mentioned above.) +- The [gofr.dev documentation](https://gofr.dev/docs) site is updated upon push to `/docs` path in the repo. Verify your changes are live after next GoFr version. diff --git a/go.work.sum b/go.work.sum index 898d5e314..9e43df1f8 100644 --- a/go.work.sum +++ b/go.work.sum @@ -9,7 +9,6 @@ cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4= cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI= cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -828,8 +827,6 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1Ig github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk= github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= @@ -1180,8 +1177,6 @@ go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//sn go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo= go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA= go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= @@ -1189,6 +1184,7 @@ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0. go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= @@ -1242,6 +1238,7 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= @@ -1316,9 +1313,7 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1344,8 +1339,6 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1393,6 +1386,7 @@ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fq golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= @@ -1544,6 +1538,9 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2/go. google.golang.org/genproto/googleapis/api v0.0.0-20250227231956-55c901821b1e/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= +google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A= +google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U= google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250106144421-5f5ef82da422 h1:w6g+P/ZscmNlGxVVXGaPVQOLu1q19ubsTOZKwaDqm4k= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250106144421-5f5ef82da422/go.mod h1:s4mHJ3FfG8P6A3O+gZ8TVqB3ufjOl9UG3ANCMMwCHmo= @@ -1604,6 +1601,7 @@ google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe0 google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go index 222d0615d..dbd7565cf 100644 --- a/pkg/gofr/datasource/file/gcs/fs.go +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -28,6 +28,7 @@ type FileSystem struct { // Config represents the gcs configuration. type Config struct { + EndPoint string BucketName string CredentialsJSON string ProjectID string @@ -54,7 +55,30 @@ func (f *FileSystem) Connect() { ctx := context.TODO() - client, err := storage.NewClient(ctx, option.WithCredentialsJSON([]byte(f.config.CredentialsJSON))) + var client *storage.Client + + var err error + + switch { + case f.config.EndPoint != "": + // Local emulator mode + client, err = storage.NewClient( + ctx, + option.WithEndpoint(f.config.EndPoint), + option.WithoutAuthentication(), + ) + + case f.config.CredentialsJSON != "": + // Direct JSON mode + client, err = storage.NewClient( + ctx, + option.WithCredentialsJSON([]byte(f.config.CredentialsJSON)), + ) + + default: + // Env var mode (GOOGLE_APPLICATION_CREDENTIALS) + client, err = storage.NewClient(ctx) + } if err != nil { f.logger.Errorf("Failed to connect to GCS: %v", err) diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go index 6ea20146e..3507dc7f6 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -73,8 +73,8 @@ func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { return err } -func (f *FileSystem) MkdirAll(path string, perm os.FileMode) error { - cleaned := strings.Trim(path, "/") +func (f *FileSystem) MkdirAll(dirPath string, perm os.FileMode) error { + cleaned := strings.Trim(dirPath, "/") if cleaned == "" { return nil } @@ -108,7 +108,7 @@ func isAlreadyExistsError(err error) bool { return strings.Contains(err.Error(), "already exists") } -func (f *FileSystem) RemoveAll(path string) error { +func (f *FileSystem) RemoveAll(dirPath string) error { var msg string st := statusErr @@ -121,7 +121,7 @@ func (f *FileSystem) RemoveAll(path string) error { }, time.Now()) ctx := context.TODO() - objects, err := f.conn.ListObjects(ctx, path) + objects, err := f.conn.ListObjects(ctx, dirPath) if err != nil { msg = fmt.Sprintf("Error retrieving objects: %v", err) @@ -137,9 +137,9 @@ func (f *FileSystem) RemoveAll(path string) error { st = statusSuccess - msg = fmt.Sprintf("Directory with path %q, deleted successfully", path) + msg = fmt.Sprintf("Directory with path %q, deleted successfully", dirPath) - f.logger.Logf("Directory %s deleted.", path) + f.logger.Logf("Directory %s deleted.", dirPath) return nil } From 350ececba80a76d309b4c10e9edc75a997c8be2b Mon Sep 17 00:00:00 2001 From: Suryakant Date: Sun, 17 Aug 2025 12:55:51 +0530 Subject: [PATCH 09/12] Updated unified handling-files documentation for GCS setup guide --- docs/advanced-guide/handling-file/page.md | 104 ++++++++++++++++++---- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/docs/advanced-guide/handling-file/page.md b/docs/advanced-guide/handling-file/page.md index fb9649e22..185df5201 100644 --- a/docs/advanced-guide/handling-file/page.md +++ b/docs/advanced-guide/handling-file/page.md @@ -6,9 +6,10 @@ GoFr simplifies the complexity of working with different file stores by offering By default, local file-store is initialized and user can access it from the context. -GoFr also supports FTP/SFTP file-store. Developers can also connect and use their AWS S3 bucket as a file-store. The file-store can be initialized as follows: +GoFr also supports FTP/SFTP file-store. Developers can also connect and use their AWS S3 bucket or Google Cloud Storage (GCS) bucket as a file-store. The file-store can be initialized as follows: ### FTP file-store + ```go package main @@ -34,6 +35,7 @@ func main() { ``` ### SFTP file-store + ```go package main @@ -60,8 +62,7 @@ func main() { ### AWS S3 Bucket as File-Store To run S3 File-Store locally we can use localstack, -``docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack`` - +`docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack` ```go package main @@ -90,17 +91,68 @@ func main() { app.Run() } ``` -> Note: The current implementation supports handling only one bucket at a time, -> as shown in the example with `gofr-bucket-2`. Bucket switching mid-operation is not supported. + +> Note: The current implementation supports handling only one bucket at a time, +> as shown in the example with `gofr-bucket-2`. Bucket switching mid-operation is not supported. + +### Google Cloud Storage (GCS) Bucket as File-Store + +To run GCS File-Store locally we can use fake-gcs-server: +`docker run -it --rm -p 4443:4443 -e STORAGE_EMULATOR_HOST=0.0.0.0:4443 fsouza/fake-gcs-server:latest` + +```go +package main + +import ( + "gofr.dev/pkg/gofr" + + "gofr.dev/pkg/gofr/datasource/file/gcs" +) + +func main() { + app := gofr.New() + + // Option 1: Using JSON credentials string + app.AddFileStore(gcs.New(&gcs.Config{ + BucketName: "my-bucket", + CredentialsJSON: readFile("gcs-credentials.json"), + ProjectID: "my-project-id", + })) + + // Option 2: Using default credentials from env + // app.AddFileStore(gcs.New(&gcs.Config{ + // BucketName: "my-bucket", + // ProjectID: "my-project-id", + // })) + + app.Run() +} + +// Helper function to read credentials file +func readFile(filename string) []byte { + data, err := os.ReadFile(filename) + if err != nil { + log.Fatalf("Failed to read credentials file: %v", err) + } + return data +} + +``` + +> **Note:** When connecting to the actual GCS service, authentication can be provided via CredentialsJSON or the GOOGLE_APPLICATION_CREDENTIALS environment variable. +> When using fake-gcs-server, authentication is not required. +> Currently supports one bucket per file-store instance. ### Creating Directory To create a single directory + ```go err := ctx.File.Mkdir("my_dir",os.ModePerm) ``` To create subdirectories as well + ```go err := ctx.File.MkdirAll("my_dir/sub_dir", os.ModePerm) ``` @@ -114,27 +166,32 @@ currentDir, err := ctx.File.Getwd() ### Change current Directory To switch to parent directory + ```go currentDir, err := ctx.File.Chdir("..") ``` To switch to another directory in same parent directory + ```go currentDir, err := ctx.File.Chdir("../my_dir2") ``` To switch to a subfolder of the current directory + ```go currentDir, err := ctx.File.Chdir("sub_dir") ``` + > Note: This method attempts to change the directory, but S3's flat structure and fixed bucket -> make this operation inapplicable. +> make this operation inapplicable. Similarly, GCS uses a flat structure where directories are simulated through object prefixes. ### Read a Directory -The ReadDir function reads the specified directory and returns a sorted list of its entries as FileInfo objects. Each FileInfo object provides access to its associated methods, eliminating the need for additional stat calls. +The ReadDir function reads the specified directory and returns a sorted list of its entries as FileInfo objects. Each FileInfo object provides access to its associated methods, eliminating the need for additional stat calls. If an error occurs during the read operation, ReadDir returns the successfully read entries up to the point of the error along with the error itself. Passing "." as the directory argument returns the entries for the current directory. + ```go entries, err := ctx.File.ReadDir("../testdir") @@ -143,12 +200,13 @@ for _, entry := range entries { if entry.IsDir() { entryType = "Dir" - } + } fmt.Printf("%v: %v Size: %v Last Modified Time : %v\n", entryType, entry.Name(), entry.Size(), entry.ModTime()) } ``` -> Note: In S3, directories are represented as prefixes of file keys. This method retrieves file + +> Note: In S3 and GCS, directories are represented as prefixes of file keys/object names. This method retrieves file > entries only from the immediate level within the specified directory. ### Creating and Save a File with Content @@ -163,6 +221,7 @@ _, _ = file.Write([]byte("Hello World!")) ``` ### Reading file as CSV/JSON/TEXT + GoFr support reading CSV/JSON/TEXT files line by line. ```go @@ -170,7 +229,7 @@ reader, err := file.ReadAll() for reader.Next() { var b string - + // For reading CSV/TEXT files user need to pass pointer to string to SCAN. // In case of JSON user should pass structs with JSON tags as defined in encoding/json. err = reader.Scan(&b) @@ -179,10 +238,12 @@ for reader.Next() { } ``` - ### Opening and Reading Content from a File + To open a file with default settings, use the `Open` command, which provides read and seek permissions only. For write permissions, use `OpenFile` with the appropriate file modes. + > Note: In FTP, file permissions are not differentiated; both `Open` and `OpenFile` allow all file operations regardless of specified permissions. + ```go csvFile, _ := ctx.File.Open("my_file.csv") @@ -205,6 +266,7 @@ if err != nil { ### Getting Information of the file/directory Stat retrieves details of a file or directory, including its name, size, last modified time, and type (such as whether it is a file or folder) + ```go file, _ := ctx.File.Stat("my_file.text") entryType := "File" @@ -215,10 +277,12 @@ if entry.IsDir() { fmt.Printf("%v: %v Size: %v Last Modified Time : %v\n", entryType, entry.Name(), entry.Size(), entry.ModTime()) ``` ->Note: In S3: + +> Note: In S3 and GCS: +> > - Names without a file extension are treated as directories by default. -> - Names starting with "0" are interpreted as binary files, with the "0" prefix removed. -> +> - Names starting with "0" are interpreted as binary files, with the "0" prefix removed (S3 specific behavior). +> > For directories, the method calculates the total size of all contained objects and returns the most recent modification time. For files, it directly returns the file's size and last modified time. ### Rename/Move a File @@ -234,18 +298,22 @@ err := ctx.File.Rename("old_name.text", "new_name.text") ### Deleting Files `Remove` deletes a single file -> Note: Currently, the S3 package supports the deletion of unversioned files from general-purpose buckets only. Directory buckets and versioned files are not supported for deletion by this method. + +> Note: Currently, the S3 package supports the deletion of unversioned files from general-purpose buckets only. Directory buckets and versioned files are not supported for deletion by this method. GCS supports deletion of both files and empty directories. + ```go err := ctx.File.Remove("my_dir") ``` The `RemoveAll` command deletes all subdirectories as well. If you delete the current working directory, such as "../currentDir", the working directory will be reset to its parent directory. -> Note: In S3, RemoveAll only supports deleting directories and will return an error if a file path (as indicated by a file extension) is provided. + +> Note: In S3 and GCS, RemoveAll only supports deleting directories and will return an error if a file path (as indicated by a file extension) is provided for S3. GCS handles both files and directories. + ```go err := ctx.File.RemoveAll("my_dir/my_text") ``` -> GoFr supports relative paths, allowing locations to be referenced relative to the current working directory. However, since S3 uses -> a flat file structure, all methods require a full path relative to the S3 bucket. +> GoFr supports relative paths, allowing locations to be referenced relative to the current working directory. However, since S3 and GCS use +> a flat file structure, all methods require a full path relative to the bucket. > Errors have been skipped in the example to focus on the core logic, it is recommended to handle all the errors. From ff93d5391de1c22a67d3116bb797117df8275f27 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Tue, 19 Aug 2025 23:02:44 +0530 Subject: [PATCH 10/12] added traces and metrics --- pkg/gofr/datasource/file/gcs/file.go | 3 +++ pkg/gofr/datasource/file/gcs/file_parse.go | 1 + pkg/gofr/datasource/file/gcs/fs_dir_test.go | 4 ++++ pkg/gofr/datasource/file/gcs/fs_test.go | 10 ++++++++++ pkg/gofr/datasource/file/gcs/interface.go | 2 -- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/pkg/gofr/datasource/file/gcs/file.go b/pkg/gofr/datasource/file/gcs/file.go index 4321195f9..f899ccfc0 100644 --- a/pkg/gofr/datasource/file/gcs/file.go +++ b/pkg/gofr/datasource/file/gcs/file.go @@ -1,6 +1,7 @@ package gcs import ( + "context" "errors" "io" "time" @@ -147,4 +148,6 @@ func (f *GCSFile) sendOperationStats(fl *FileLog, startTime time.Time) { fl.Duration = duration f.logger.Debug(fl) + f.metrics.RecordHistogram(context.Background(), appFTPStats, float64(duration), + "type", fl.Operation, "status", clean(fl.Status)) } diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go index 7fe0794fb..c72f563bf 100644 --- a/pkg/gofr/datasource/file/gcs/file_parse.go +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -21,6 +21,7 @@ var ( ) const ( + appFTPStats = "app_ftp_stats" statusErr = "ERROR" statusSuccess = "SUCCESS" ) diff --git a/pkg/gofr/datasource/file/gcs/fs_dir_test.go b/pkg/gofr/datasource/file/gcs/fs_dir_test.go index cceed25b3..cd4d64d10 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir_test.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir_test.go @@ -72,6 +72,8 @@ func Test_Mkdir_GCS(t *testing.T) { mockLogger.EXPECT().Debugf(gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() tests := []testCase{ { @@ -136,6 +138,8 @@ func Test_ReadDir_GCS(t *testing.T) { mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() for _, tt := range getReadDirTestCases(mockGCS) { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/gofr/datasource/file/gcs/fs_test.go b/pkg/gofr/datasource/file/gcs/fs_test.go index 00ea6ef14..e8d19a840 100644 --- a/pkg/gofr/datasource/file/gcs/fs_test.go +++ b/pkg/gofr/datasource/file/gcs/fs_test.go @@ -49,6 +49,8 @@ func Test_CreateFile(t *testing.T) { mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() tests := []testCase{ { @@ -122,6 +124,8 @@ func Test_Remove_GCS(t *testing.T) { mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() mockGCS.EXPECT(). DeleteObject(gomock.Any(), "abc/a1.txt"). @@ -211,6 +215,8 @@ func TestRenameFile(t *testing.T) { mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -290,6 +296,8 @@ func Test_StatFile_GCS(t *testing.T) { mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() mockGCS.EXPECT().StatObject(gomock.Any(), tt.filePath).Return(tt.mockAttr, tt.mockError) + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() res, err := fs.Stat(tt.filePath) if tt.expectError { @@ -329,6 +337,8 @@ func Test_Stat_FileAndDir(t *testing.T) { mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() fileName := "documents/testfile.txt" fileAttrs := &storage.ObjectAttrs{ diff --git a/pkg/gofr/datasource/file/gcs/interface.go b/pkg/gofr/datasource/file/gcs/interface.go index fd4428d8a..2d2297eb7 100644 --- a/pkg/gofr/datasource/file/gcs/interface.go +++ b/pkg/gofr/datasource/file/gcs/interface.go @@ -24,7 +24,6 @@ type gcsClientImpl struct { } type gcsClient interface { - // NewWriter(ctx context.Context, name string) *storage.Writer NewWriter(ctx context.Context, name string) io.WriteCloser NewReader(ctx context.Context, name string) (*storage.Reader, error) DeleteObject(ctx context.Context, name string) error @@ -32,7 +31,6 @@ type gcsClient interface { ListObjects(ctx context.Context, prefix string) ([]string, error) ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) - // GetSignedURL(ctx context.Context, object string, expiry time.Duration) (string, error) } type Metrics interface { From 22e4f09ab46e1a2430d63d03331027f8bccd67db Mon Sep 17 00:00:00 2001 From: Suryakant Date: Thu, 21 Aug 2025 22:43:29 +0530 Subject: [PATCH 11/12] refactor: update docs, logging, and contribution guidelines based on feedback --- CONTRIBUTING.md | 109 +++++++++++---------- docs/advanced-guide/handling-file/page.md | 10 +- pkg/gofr/datasource/file/gcs/file.go | 28 +++--- pkg/gofr/datasource/file/gcs/file_parse.go | 18 ++-- pkg/gofr/datasource/file/gcs/fs.go | 6 +- pkg/gofr/datasource/file/gcs/fs_dir.go | 8 +- 6 files changed, 91 insertions(+), 88 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd5f619ad..2b4fef022 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,23 +1,21 @@ ## Contribution Guidelines - -- Minor changes can be done directly by editing code on GitHub. GitHub automatically creates a temporary branch and +* Minor changes can be done directly by editing code on GitHub. GitHub automatically creates a temporary branch and files a PR. This is only suitable for really small changes like: spelling fixes, variable name changes or error string change etc. For larger commits, following steps are recommended. -- (Optional) If you want to discuss your implementation with the users of GoFr, use the GitHub discussions of this repo. -- Configure your editor to use goimport and golangci-lint on file changes. Any code which is not formatted using these +* (Optional) If you want to discuss your implementation with the users of GoFr, use the GitHub discussions of this repo. +* Configure your editor to use goimport and golangci-lint on file changes. Any code which is not formatted using these tools, will fail on the pipeline. -- Contributors should begin working on an issue only after it has been assigned to them. To get an issue assigned, please comment on the GitHub thread +* Contributors should begin working on an issue only after it has been assigned to them. To get an issue assigned, please comment on the GitHub thread and request assignment from a maintainer. This helps avoid duplicate or conflicting pull requests from multiple contributors. -- Issues labeled triage are not open for direct contributions. If you're interested in working on a triage issue, please reach out to the maintainers -to discuss it before proceeding in the Github thread. +* Issues labeled triage are not open for direct contributions. If you're interested in working on a triage issue, please reach out to the maintainers + to discuss it before proceeding in the Github thread. -- We follow **American English** conventions in this project (e.g., _"favor"_ instead of _"favour"_). Please keep this consistent across all code comments, documentation, etc. +* We follow **American English** conventions in this project (e.g., *"favor"* instead of *"favour"*). Please keep this consistent across all code comments, documentation, etc. -- All code contributions should have associated tests and all new line additions should be covered in those testcases. +* All code contributions should have associated tests and all new line additions should be covered in those testcases. No PR should ever decrease the overall code coverage. -- Once your code changes are done along with the testcases, submit a PR to development branch. Please note that all PRs +* Once your code changes are done along with the testcases, submit a PR to development branch. Please note that all PRs are merged from feature branches to development first. - * PR should be raised only when development is complete and the code is ready for review. This approach helps reduce the number of open pull requests and facilitates a more efficient review process for the team. * All PRs need to be reviewed by at least 2 GoFr developers. They might reach out to you for any clarification. * Thank you for your contribution. :) @@ -30,28 +28,32 @@ Testing is a crucial aspect of software development, and adherence to these guid 1. **Test Types:** - - Write unit tests for every new function or method. - - Include integration tests for any major feature added. + - Write unit tests for every new function or method. + - Include integration tests for any major feature added. -2. **Test Coverage:** -- No new code should decrease the existing code coverage for the packages and files. - > The `code-climate` coverage check will not pass if there is any decrease in the test-coverage before and after any new PR is submitted. +2. **Test Coverage:** -3. **Naming Conventions:** +- No new code should decrease the existing code coverage for the packages and files. +> The `code-climate` coverage check will not pass if there is any decrease in the test-coverage before and after any new PR is submitted. -- Prefix unit test functions with `Test`. -- Use clear and descriptive names. + +3. **Naming Conventions:** + +- Prefix unit test functions with `Test`. +- Use clear and descriptive names. ```go func TestFunctionName(t *testing.T) { // Test logic } ``` + + 4. **Table-Driven Tests:** -- Consider using table-driven tests for testing multiple scenarios. +- Consider using table-driven tests for testing multiple scenarios. > [!NOTE] > Some services will be required to pass the entire test suite. We recommend using docker for running those services. @@ -104,42 +106,41 @@ docker run -it --rm -p 4443:4443 -e STORAGE_EMULATOR_HOST=0.0.0.0:4443 fsouza/fa > [!NOTE] > Please note that the recommended local port for the services are different from the actual ports. This is done to avoid conflict with the local installation on developer machines. This method also allows a developer to work on multiple projects which uses the same services but bound on different ports. One can choose to change the port for these services. Just remember to add the same in configs/.local.env, if you decide to do that. -### Coding Guidelines -- Use only what is given to you as part of function parameter or receiver. No globals. Inject all dependencies including +### Coding Guidelines +* Use only what is given to you as part of function parameter or receiver. No globals. Inject all dependencies including DB, Logger etc. -- No magic. So, no init. In a large project, it becomes difficult to track which package is doing what at the +* No magic. So, no init. In a large project, it becomes difficult to track which package is doing what at the initialization step. -- Exported functions must have an associated godoc. -- Sensitive data(username, password, keys) should not be pushed. Always use environment variables. -- Take interfaces and return concrete types. - - Lean interfaces - take 'exactly' what you need, not more. Onus of interface definition is on the package who is - using it. so, it should be as lean as possible. This makes it easier to test. - - Be careful of type assertions in this context. If you take an interface and type assert to a type - then it's - similar to taking concrete type. -- Uses of context: - - We should use context as a first parameter. - - Can not use string as a key for the context. Define your own type and provide context accessor method to avoid - conflict. -- External Library uses: - - A little copying is better than a little dependency. - - All external dependencies should go through the same careful consideration, we would have done to our own written - code. We need to test the functionality we are going to use from an external library, as sometimes library - implementation may change. - - All dependencies must be abstracted as an interface. This will make it easier to switch libraries at later point - of time. -- Version tagging as per Semantic versioning (https://semver.org/) +* Exported functions must have an associated godoc. +* Sensitive data(username, password, keys) should not be pushed. Always use environment variables. +* Take interfaces and return concrete types. + - Lean interfaces - take 'exactly' what you need, not more. Onus of interface definition is on the package who is + using it. so, it should be as lean as possible. This makes it easier to test. + - Be careful of type assertions in this context. If you take an interface and type assert to a type - then it's + similar to taking concrete type. +* Uses of context: + - We should use context as a first parameter. + - Can not use string as a key for the context. Define your own type and provide context accessor method to avoid + conflict. +* External Library uses: + - A little copying is better than a little dependency. + - All external dependencies should go through the same careful consideration, we would have done to our own written + code. We need to test the functionality we are going to use from an external library, as sometimes library + implementation may change. + - All dependencies must be abstracted as an interface. This will make it easier to switch libraries at later point + of time. +* Version tagging as per Semantic versioning (https://semver.org/) ### Documentation - -- After adding or modifying existing code, update the documentation too - [development/docs](https://github.com/gofr-dev/gofr/tree/development/docs). -- When you consider a new documentation page is needed, start by adding a new file and writing your new documentation. Then - add a reference to it in [navigation.js](https://gofr.dev/docs/navigation.js). -- If needed, update or add proper code examples for your changes. -- In case images are needed, add it to [docs/public](./docs/public) folder. -- Make sure you don't break existing links and references. -- Maintain Markdown standards, you can read more [here](https://www.markdownguide.org/basic-syntax/), this includes: - - Headings (`#`, `##`, etc.) should be placed in order. - - Use trailing white space or the
HTML tag at the end of the line. - - Use "`" sign to add single line code and "```" to add multi-line code block. - - Use relative references to images (in `public` folder as mentioned above.) -- The [gofr.dev documentation](https://gofr.dev/docs) site is updated upon push to `/docs` path in the repo. Verify your changes are live after next GoFr version. +* After adding or modifying existing code, update the documentation too - [development/docs](https://github.com/gofr-dev/gofr/tree/development/docs). +* When you consider a new documentation page is needed, start by adding a new file and writing your new documentation. Then - add a reference to it in [navigation.js](https://gofr.dev/docs/navigation.js). +* If needed, update or add proper code examples for your changes. +* In case images are needed, add it to [docs/public](./docs/public) folder. +* Make sure you don't break existing links and references. +* Maintain Markdown standards, you can read more [here](https://www.markdownguide.org/basic-syntax/), this includes: + - Headings (`#`, `##`, etc.) should be placed in order. + - Use trailing white space or the
HTML tag at the end of the line. + - Use "`" sign to add single line code and "```" to add multi-line code block. + - Use relative references to images (in `public` folder as mentioned above.) +* The [gofr.dev documentation](https://gofr.dev/docs) site is updated upon push to `/docs` path in the repo. Verify your changes are live after next GoFr version. \ No newline at end of file diff --git a/docs/advanced-guide/handling-file/page.md b/docs/advanced-guide/handling-file/page.md index 185df5201..e4edf74ff 100644 --- a/docs/advanced-guide/handling-file/page.md +++ b/docs/advanced-guide/handling-file/page.md @@ -6,7 +6,12 @@ GoFr simplifies the complexity of working with different file stores by offering By default, local file-store is initialized and user can access it from the context. -GoFr also supports FTP/SFTP file-store. Developers can also connect and use their AWS S3 bucket or Google Cloud Storage (GCS) bucket as a file-store. The file-store can be initialized as follows: +GoFr also supports FTP/SFTP file-store. Developers can also connect and use their cloud storage bucket as a file-store. Following cloud storage options are currently supported: + +- **AWS S3** +- **Google Cloud Storage (GCS)** + +The file-store can be initialized as follows: ### FTP file-store @@ -307,7 +312,8 @@ err := ctx.File.Remove("my_dir") The `RemoveAll` command deletes all subdirectories as well. If you delete the current working directory, such as "../currentDir", the working directory will be reset to its parent directory. -> Note: In S3 and GCS, RemoveAll only supports deleting directories and will return an error if a file path (as indicated by a file extension) is provided for S3. GCS handles both files and directories. +> Note: In S3, RemoveAll only supports deleting directories and will return an error if a file path (as indicated by a file extension) is provided for S3. +> GCS handles both files and directories. ```go err := ctx.File.RemoveAll("my_dir/my_text") diff --git a/pkg/gofr/datasource/file/gcs/file.go b/pkg/gofr/datasource/file/gcs/file.go index f899ccfc0..dc7e8d369 100644 --- a/pkg/gofr/datasource/file/gcs/file.go +++ b/pkg/gofr/datasource/file/gcs/file.go @@ -9,10 +9,7 @@ import ( "cloud.google.com/go/storage" ) -// GCSFile represents a file in an GCS bucket. -// -//nolint:revive // gcs.GCSFile is repetitive. A better name could have been chosen, but it's too late as it's already exported. -type GCSFile struct { +type File struct { conn gcsClient writer *storage.Writer name string @@ -39,14 +36,14 @@ const ( // ====== File interface methods ====== -func (f *GCSFile) Read(p []byte) (int, error) { +func (f *File) Read(p []byte) (int, error) { if f.body == nil { return 0, ErrNilGCSFileBody } return f.body.Read(p) } -func (f *GCSFile) Write(p []byte) (int, error) { +func (f *File) Write(p []byte) (int, error) { bucketName := getBucketName(f.name) var msg string @@ -69,14 +66,13 @@ func (f *GCSFile) Write(p []byte) (int, error) { return n, err } - st = statusSuccess - msg = "Write successful" - f.logger.Logf(msg) + st, msg = statusSuccess, "Write successful" + f.logger.Debug(msg) return n, nil } -func (f *GCSFile) Close() error { +func (f *File) Close() error { bucketName := getBucketName(f.name) var msg string @@ -101,7 +97,7 @@ func (f *GCSFile) Close() error { msg = msgWriterClosed - f.logger.Logf(msg) + f.logger.Debug(msg) return nil } @@ -117,7 +113,7 @@ func (f *GCSFile) Close() error { msg = msgReaderClosed - f.logger.Logf(msgReaderClosed) + f.logger.Debug(msgReaderClosed) return nil } @@ -129,20 +125,20 @@ func (f *GCSFile) Close() error { return nil } -func (*GCSFile) Seek(_ int64, _ int) (int64, error) { +func (*File) Seek(_ int64, _ int) (int64, error) { // Not supported: Seek requires reopening with range. return 0, ErrSeekNotSupported } -func (*GCSFile) ReadAt(_ []byte, _ int64) (int, error) { +func (*File) ReadAt(_ []byte, _ int64) (int, error) { return 0, ErrReadAtNotSupported } -func (*GCSFile) WriteAt(_ []byte, _ int64) (int, error) { +func (*File) WriteAt(_ []byte, _ int64) (int, error) { return 0, ErrWriteAtNotSupported } -func (f *GCSFile) sendOperationStats(fl *FileLog, startTime time.Time) { +func (f *File) sendOperationStats(fl *FileLog, startTime time.Time) { duration := time.Since(startTime).Microseconds() fl.Duration = duration diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go index c72f563bf..5adfbc8f1 100644 --- a/pkg/gofr/datasource/file/gcs/file_parse.go +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -38,7 +38,7 @@ type jsonReader struct { token json.Token } -func (f *GCSFile) ReadAll() (file.RowReader, error) { +func (f *File) ReadAll() (file.RowReader, error) { bucketName := getBucketName(f.name) location := path.Join(bucketName, f.name) @@ -55,7 +55,7 @@ func (f *GCSFile) ReadAll() (file.RowReader, error) { } // createJSONReader creates a JSON reader for JSON files. -func (f *GCSFile) createJSONReader(location string) (file.RowReader, error) { +func (f *File) createJSONReader(location string) (file.RowReader, error) { status := statusErr defer f.sendOperationStats(&FileLog{Operation: "JSON READER", Location: location, Status: &status}, time.Now()) @@ -92,7 +92,7 @@ func (f *GCSFile) createJSONReader(location string) (file.RowReader, error) { } // createTextCSVReader creates a text reader for reading text files. -func (f *GCSFile) createTextCSVReader(location string) (file.RowReader, error) { +func (f *File) createTextCSVReader(location string) (file.RowReader, error) { status := statusErr defer f.sendOperationStats(&FileLog{Operation: "TEXT/CSV READER", Location: location, Status: &status}, time.Now()) @@ -136,7 +136,7 @@ func (f *textReader) Scan(i any) error { return errStringNotPointer } -func (f *GCSFile) Name() string { +func (f *File) Name() string { bucketName := getBucketName(f.name) f.sendOperationStats(&FileLog{ @@ -147,7 +147,7 @@ func (f *GCSFile) Name() string { return f.name } -func (f *GCSFile) Size() int64 { +func (f *File) Size() int64 { bucketName := getBucketName(f.name) f.sendOperationStats(&FileLog{ @@ -158,7 +158,7 @@ func (f *GCSFile) Size() int64 { return f.size } -func (f *GCSFile) ModTime() time.Time { +func (f *File) ModTime() time.Time { bucketName := getBucketName(f.name) f.sendOperationStats(&FileLog{ @@ -169,7 +169,7 @@ func (f *GCSFile) ModTime() time.Time { return f.lastModified } -func (f *GCSFile) Mode() fs.FileMode { +func (f *File) Mode() fs.FileMode { bucketName := getBucketName(f.name) f.sendOperationStats(&FileLog{ @@ -184,7 +184,7 @@ func (f *GCSFile) Mode() fs.FileMode { return 0 } -func (f *GCSFile) IsDir() bool { +func (f *File) IsDir() bool { bucketName := getBucketName(f.name) f.sendOperationStats(&FileLog{ @@ -195,7 +195,7 @@ func (f *GCSFile) IsDir() bool { return f.isDir || f.contentType == "application/x-directory" } -func (f *GCSFile) Sys() any { +func (f *File) Sys() any { bucketName := getBucketName(f.name) f.sendOperationStats(&FileLog{ diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go index dbd7565cf..62f8ddce7 100644 --- a/pkg/gofr/datasource/file/gcs/fs.go +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -19,7 +19,7 @@ var ( ) type FileSystem struct { - GCSFile GCSFile + GCSFile File conn gcsClient config *Config logger Logger @@ -166,7 +166,7 @@ func (f *FileSystem) Create(name string) (file.File, error) { f.logger.Logf("Write stream successfully opened for file %q", name) - return &GCSFile{ + return &File{ conn: f.conn, writer: sw, name: name, @@ -242,7 +242,7 @@ func (f *FileSystem) Open(name string) (file.File, error) { msg = fmt.Sprintf("File with path %q retrieved successfully", name) - return &GCSFile{ + return &File{ conn: f.conn, name: name, body: reader, diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go index 3507dc7f6..83d0638d0 100644 --- a/pkg/gofr/datasource/file/gcs/fs_dir.go +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -171,7 +171,7 @@ func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { for _, p := range prefixes { trimmedName := strings.TrimSuffix(p, "/") dirName := path.Base(trimmedName) - fileinfo = append(fileinfo, &GCSFile{ + fileinfo = append(fileinfo, &File{ name: dirName, isDir: true, logger: f.logger, @@ -180,7 +180,7 @@ func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { } for _, o := range objects { - fileinfo = append(fileinfo, &GCSFile{ + fileinfo = append(fileinfo, &File{ name: path.Base(o.Name), size: o.Size, lastModified: o.Updated, @@ -254,7 +254,7 @@ func (f *FileSystem) Stat(name string) (file.FileInfo, error) { st = statusSuccess msg = fmt.Sprintf("File with path %q info retrieved successfully", name) - return &GCSFile{ + return &File{ name: name, logger: f.logger, metrics: f.metrics, @@ -283,7 +283,7 @@ func (f *FileSystem) Stat(name string) (file.FileInfo, error) { st = statusSuccess msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) - return &GCSFile{ + return &File{ name: name, logger: f.logger, metrics: f.metrics, From 690b993b2ad61d1f11b5c91e68d91075aeb68d40 Mon Sep 17 00:00:00 2001 From: Suryakant Date: Wed, 3 Sep 2025 19:28:00 +0530 Subject: [PATCH 12/12] feat(file/gcs): add GCS support with Go 1.25 and fix requested changes --- CONTRIBUTING.md | 4 +- docs/advanced-guide/handling-file/page.md | 110 +++++- go.work | 1 + go.work.sum | 65 ++- pkg/gofr/datasource/file/gcs/file.go | 149 +++++++ pkg/gofr/datasource/file/gcs/file_parse.go | 206 ++++++++++ pkg/gofr/datasource/file/gcs/fs.go | 323 +++++++++++++++ pkg/gofr/datasource/file/gcs/fs_dir.go | 307 ++++++++++++++ pkg/gofr/datasource/file/gcs/fs_dir_test.go | 236 +++++++++++ pkg/gofr/datasource/file/gcs/fs_test.go | 374 ++++++++++++++++++ pkg/gofr/datasource/file/gcs/go.mod | 68 ++++ pkg/gofr/datasource/file/gcs/go.sum | 171 ++++++++ pkg/gofr/datasource/file/gcs/interface.go | 123 ++++++ pkg/gofr/datasource/file/gcs/logger.go | 34 ++ pkg/gofr/datasource/file/gcs/logger_test.go | 48 +++ .../datasource/file/gcs/mock_interface.go | 287 ++++++++++++++ 16 files changed, 2451 insertions(+), 55 deletions(-) create mode 100644 pkg/gofr/datasource/file/gcs/file.go create mode 100644 pkg/gofr/datasource/file/gcs/file_parse.go create mode 100644 pkg/gofr/datasource/file/gcs/fs.go create mode 100644 pkg/gofr/datasource/file/gcs/fs_dir.go create mode 100644 pkg/gofr/datasource/file/gcs/fs_dir_test.go create mode 100644 pkg/gofr/datasource/file/gcs/fs_test.go create mode 100644 pkg/gofr/datasource/file/gcs/go.mod create mode 100644 pkg/gofr/datasource/file/gcs/go.sum create mode 100644 pkg/gofr/datasource/file/gcs/interface.go create mode 100644 pkg/gofr/datasource/file/gcs/logger.go create mode 100644 pkg/gofr/datasource/file/gcs/logger_test.go create mode 100644 pkg/gofr/datasource/file/gcs/mock_interface.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4df5abc09..677c50546 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,13 +96,11 @@ docker run -d --name arangodb \ -e ARANGO_ROOT_PASSWORD=rootpassword \ --pull always \ arangodb:latest -<<<<<<< HEAD docker run -d --name db -p 8091-8096:8091-8096 -p 11210-11211:11210-11211 couchbase -======= docker login container-registry.oracle.com docker pull container-registry.oracle.com/database/free:latest docker run -d --name oracle-free -p 1521:1521 -e ORACLE_PWD=YourPasswordHere container-registry.oracle.com/database/free:latest ->>>>>>> origin +docker run -it --rm -p 4443:4443 -e STORAGE_EMULATOR_HOST=0.0.0.0:4443 fsouza/fake-gcs-server:latest ``` > [!NOTE] diff --git a/docs/advanced-guide/handling-file/page.md b/docs/advanced-guide/handling-file/page.md index fb9649e22..e4edf74ff 100644 --- a/docs/advanced-guide/handling-file/page.md +++ b/docs/advanced-guide/handling-file/page.md @@ -6,9 +6,15 @@ GoFr simplifies the complexity of working with different file stores by offering By default, local file-store is initialized and user can access it from the context. -GoFr also supports FTP/SFTP file-store. Developers can also connect and use their AWS S3 bucket as a file-store. The file-store can be initialized as follows: +GoFr also supports FTP/SFTP file-store. Developers can also connect and use their cloud storage bucket as a file-store. Following cloud storage options are currently supported: + +- **AWS S3** +- **Google Cloud Storage (GCS)** + +The file-store can be initialized as follows: ### FTP file-store + ```go package main @@ -34,6 +40,7 @@ func main() { ``` ### SFTP file-store + ```go package main @@ -60,8 +67,7 @@ func main() { ### AWS S3 Bucket as File-Store To run S3 File-Store locally we can use localstack, -``docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack`` - +`docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack` ```go package main @@ -90,17 +96,68 @@ func main() { app.Run() } ``` -> Note: The current implementation supports handling only one bucket at a time, -> as shown in the example with `gofr-bucket-2`. Bucket switching mid-operation is not supported. + +> Note: The current implementation supports handling only one bucket at a time, +> as shown in the example with `gofr-bucket-2`. Bucket switching mid-operation is not supported. + +### Google Cloud Storage (GCS) Bucket as File-Store + +To run GCS File-Store locally we can use fake-gcs-server: +`docker run -it --rm -p 4443:4443 -e STORAGE_EMULATOR_HOST=0.0.0.0:4443 fsouza/fake-gcs-server:latest` + +```go +package main + +import ( + "gofr.dev/pkg/gofr" + + "gofr.dev/pkg/gofr/datasource/file/gcs" +) + +func main() { + app := gofr.New() + + // Option 1: Using JSON credentials string + app.AddFileStore(gcs.New(&gcs.Config{ + BucketName: "my-bucket", + CredentialsJSON: readFile("gcs-credentials.json"), + ProjectID: "my-project-id", + })) + + // Option 2: Using default credentials from env + // app.AddFileStore(gcs.New(&gcs.Config{ + // BucketName: "my-bucket", + // ProjectID: "my-project-id", + // })) + + app.Run() +} + +// Helper function to read credentials file +func readFile(filename string) []byte { + data, err := os.ReadFile(filename) + if err != nil { + log.Fatalf("Failed to read credentials file: %v", err) + } + return data +} + +``` + +> **Note:** When connecting to the actual GCS service, authentication can be provided via CredentialsJSON or the GOOGLE_APPLICATION_CREDENTIALS environment variable. +> When using fake-gcs-server, authentication is not required. +> Currently supports one bucket per file-store instance. ### Creating Directory To create a single directory + ```go err := ctx.File.Mkdir("my_dir",os.ModePerm) ``` To create subdirectories as well + ```go err := ctx.File.MkdirAll("my_dir/sub_dir", os.ModePerm) ``` @@ -114,27 +171,32 @@ currentDir, err := ctx.File.Getwd() ### Change current Directory To switch to parent directory + ```go currentDir, err := ctx.File.Chdir("..") ``` To switch to another directory in same parent directory + ```go currentDir, err := ctx.File.Chdir("../my_dir2") ``` To switch to a subfolder of the current directory + ```go currentDir, err := ctx.File.Chdir("sub_dir") ``` + > Note: This method attempts to change the directory, but S3's flat structure and fixed bucket -> make this operation inapplicable. +> make this operation inapplicable. Similarly, GCS uses a flat structure where directories are simulated through object prefixes. ### Read a Directory -The ReadDir function reads the specified directory and returns a sorted list of its entries as FileInfo objects. Each FileInfo object provides access to its associated methods, eliminating the need for additional stat calls. +The ReadDir function reads the specified directory and returns a sorted list of its entries as FileInfo objects. Each FileInfo object provides access to its associated methods, eliminating the need for additional stat calls. If an error occurs during the read operation, ReadDir returns the successfully read entries up to the point of the error along with the error itself. Passing "." as the directory argument returns the entries for the current directory. + ```go entries, err := ctx.File.ReadDir("../testdir") @@ -143,12 +205,13 @@ for _, entry := range entries { if entry.IsDir() { entryType = "Dir" - } + } fmt.Printf("%v: %v Size: %v Last Modified Time : %v\n", entryType, entry.Name(), entry.Size(), entry.ModTime()) } ``` -> Note: In S3, directories are represented as prefixes of file keys. This method retrieves file + +> Note: In S3 and GCS, directories are represented as prefixes of file keys/object names. This method retrieves file > entries only from the immediate level within the specified directory. ### Creating and Save a File with Content @@ -163,6 +226,7 @@ _, _ = file.Write([]byte("Hello World!")) ``` ### Reading file as CSV/JSON/TEXT + GoFr support reading CSV/JSON/TEXT files line by line. ```go @@ -170,7 +234,7 @@ reader, err := file.ReadAll() for reader.Next() { var b string - + // For reading CSV/TEXT files user need to pass pointer to string to SCAN. // In case of JSON user should pass structs with JSON tags as defined in encoding/json. err = reader.Scan(&b) @@ -179,10 +243,12 @@ for reader.Next() { } ``` - ### Opening and Reading Content from a File + To open a file with default settings, use the `Open` command, which provides read and seek permissions only. For write permissions, use `OpenFile` with the appropriate file modes. + > Note: In FTP, file permissions are not differentiated; both `Open` and `OpenFile` allow all file operations regardless of specified permissions. + ```go csvFile, _ := ctx.File.Open("my_file.csv") @@ -205,6 +271,7 @@ if err != nil { ### Getting Information of the file/directory Stat retrieves details of a file or directory, including its name, size, last modified time, and type (such as whether it is a file or folder) + ```go file, _ := ctx.File.Stat("my_file.text") entryType := "File" @@ -215,10 +282,12 @@ if entry.IsDir() { fmt.Printf("%v: %v Size: %v Last Modified Time : %v\n", entryType, entry.Name(), entry.Size(), entry.ModTime()) ``` ->Note: In S3: + +> Note: In S3 and GCS: +> > - Names without a file extension are treated as directories by default. -> - Names starting with "0" are interpreted as binary files, with the "0" prefix removed. -> +> - Names starting with "0" are interpreted as binary files, with the "0" prefix removed (S3 specific behavior). +> > For directories, the method calculates the total size of all contained objects and returns the most recent modification time. For files, it directly returns the file's size and last modified time. ### Rename/Move a File @@ -234,18 +303,23 @@ err := ctx.File.Rename("old_name.text", "new_name.text") ### Deleting Files `Remove` deletes a single file -> Note: Currently, the S3 package supports the deletion of unversioned files from general-purpose buckets only. Directory buckets and versioned files are not supported for deletion by this method. + +> Note: Currently, the S3 package supports the deletion of unversioned files from general-purpose buckets only. Directory buckets and versioned files are not supported for deletion by this method. GCS supports deletion of both files and empty directories. + ```go err := ctx.File.Remove("my_dir") ``` The `RemoveAll` command deletes all subdirectories as well. If you delete the current working directory, such as "../currentDir", the working directory will be reset to its parent directory. -> Note: In S3, RemoveAll only supports deleting directories and will return an error if a file path (as indicated by a file extension) is provided. + +> Note: In S3, RemoveAll only supports deleting directories and will return an error if a file path (as indicated by a file extension) is provided for S3. +> GCS handles both files and directories. + ```go err := ctx.File.RemoveAll("my_dir/my_text") ``` -> GoFr supports relative paths, allowing locations to be referenced relative to the current working directory. However, since S3 uses -> a flat file structure, all methods require a full path relative to the S3 bucket. +> GoFr supports relative paths, allowing locations to be referenced relative to the current working directory. However, since S3 and GCS use +> a flat file structure, all methods require a full path relative to the bucket. > Errors have been skipped in the example to focus on the core logic, it is recommended to handle all the errors. diff --git a/go.work b/go.work index e2667a918..0c75a4422 100644 --- a/go.work +++ b/go.work @@ -11,6 +11,7 @@ use ( ./pkg/gofr/datasource/elasticsearch ./pkg/gofr/datasource/file/ftp ./pkg/gofr/datasource/file/s3 + ./pkg/gofr/datasource/file/gcs ./pkg/gofr/datasource/file/sftp ./pkg/gofr/datasource/kv-store/badger ./pkg/gofr/datasource/kv-store/nats diff --git a/go.work.sum b/go.work.sum index da01c42da..2a6236ce4 100644 --- a/go.work.sum +++ b/go.work.sum @@ -9,7 +9,6 @@ cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4= cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI= cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -108,6 +107,8 @@ cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9m cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= +cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.14.2/go.mod h1:mIat+Mf77W30eWQ/vrhjXsXaRh8Qfu4WiymR0hR6Uxk= cloud.google.com/go/automl v1.14.4 h1:vkD+hQ75SMINMgJBT/KDpFYvfQLzJbtIQZdw0AWq8Rs= @@ -388,6 +389,7 @@ cloud.google.com/go/gkemulticloud v1.5.3 h1:334aZmOzIt3LVBpguCof8IHaLaftcZlx+L0T cloud.google.com/go/gkemulticloud v1.5.3/go.mod h1:KPFf+/RcfvmuScqwS9/2MF5exZAmXSuoSLPuaQ98Xlk= cloud.google.com/go/grafeas v0.3.11 h1:CobnwnyeY1j1Defi5vbEircI+jfrk3ci5m004ZjiFP4= cloud.google.com/go/grafeas v0.3.11/go.mod h1:dcQyG2+T4tBgG0MvJAh7g2wl/xHV2w+RZIqivwuLjNg= +cloud.google.com/go/grafeas v0.3.15/go.mod h1:irwcwIQOBlLBotGdMwme8PipnloOPqILfIvMwlmu8Pk= cloud.google.com/go/gsuiteaddons v1.7.2/go.mod h1:GD32J2rN/4APilqZw4JKmwV84+jowYYMkEVwQEYuAWc= cloud.google.com/go/gsuiteaddons v1.7.3 h1:QafYhVhyFGpidBUUlVhy6lUHFogFOycVYm9DV7MinhA= cloud.google.com/go/gsuiteaddons v1.7.3/go.mod h1:0rR+LC21v1Sx1Yb6uohHI/F8DF3h2arSJSHvfi3GmyQ= @@ -426,9 +428,8 @@ cloud.google.com/go/lifesciences v0.10.3/go.mod h1:hnUUFht+KcZcliixAg+iOh88FUwAz cloud.google.com/go/lifesciences v0.10.6 h1:Vu7XF4s5KJ8+mSLIL4eaQM6JTyWXvSB54oqC+CUZH20= cloud.google.com/go/lifesciences v0.10.6/go.mod h1:1nnZwaZcBThDujs9wXzECnd1S5d+UiDkPuJWAmhRi7Q= cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM= -cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= -cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= cloud.google.com/go/managedidentities v1.7.2/go.mod h1:t0WKYzagOoD3FNtJWSWcU8zpWZz2i9cw2sKa9RiPx5I= cloud.google.com/go/managedidentities v1.7.3 h1:b9xGs24BIjfyvLgCtJoClOZpPi8d8owPgWe5JEINgaY= cloud.google.com/go/managedidentities v1.7.3/go.mod h1:H9hO2aMkjlpY+CNnKWRh+WoQiUIDO8457wWzUGsdtLA= @@ -467,8 +468,6 @@ cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6sr cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= cloud.google.com/go/monitoring v1.24.0 h1:csSKiCJ+WVRgNkRzzz3BPoGjFhjPY23ZTcaenToJxMM= cloud.google.com/go/monitoring v1.24.0/go.mod h1:Bd1PRK5bmQBQNnuGwHBfUamAV1ys9049oEPHnn4pcsc= -cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= -cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= cloud.google.com/go/networkconnectivity v1.15.2/go.mod h1:N1O01bEk5z9bkkWwXLKcN2T53QN49m/pSpjfUvlHDQY= cloud.google.com/go/networkconnectivity v1.16.1 h1:YsVhG71ZC4FkqCP2oCI55x/JeGFyd7738Lt8iNTrzJw= cloud.google.com/go/networkconnectivity v1.16.1/go.mod h1:GBC1iOLkblcnhcnfRV92j4KzqGBrEI6tT7LP52nZCTk= @@ -651,6 +650,7 @@ cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyX cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA= cloud.google.com/go/storagetransfer v1.11.2/go.mod h1:FcM29aY4EyZ3yVPmW5SxhqUdhjgPBUOFyy4rqiQbias= cloud.google.com/go/storagetransfer v1.12.1 h1:W3v9A7MGBN7H9sAFstyciwP/1XEQhUhZfrjclmDnpMs= cloud.google.com/go/storagetransfer v1.12.1/go.mod h1:hQqbfs8/LTmObJyCC0KrlBw8yBJ2bSFlaGila0qBMk4= @@ -684,8 +684,6 @@ cloud.google.com/go/tpu v1.8.3/go.mod h1:Do6Gq+/Jx6Xs3LcY2WhHyGwKDKVw++9jIJp+X+0 cloud.google.com/go/trace v1.11.2/go.mod h1:bn7OwXd4pd5rFuAnTrzBuoZ4ax2XQeG3qNgYmfCy0Io= cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= -cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= -cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= cloud.google.com/go/translate v1.12.2/go.mod h1:jjLVf2SVH2uD+BNM40DYvRRKSsuyKxVvs3YjTW/XSWY= cloud.google.com/go/translate v1.12.3 h1:XJ7LipYJi80BCgVk2lx1fwc7DIYM6oV2qx1G4IAGQ5w= @@ -766,8 +764,6 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 h1:f2Qw/Ehhimh5uO1fayV0QIW7DShEQqhtUfhYc+cBPlw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0/go.mod h1:2bIszWvQRlJVmJLiuLhukLImRjKPcYdzzsx6darK02A= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 h1:5IT7xOdq17MtcdtL/vtl6mGfzhaq4m4vpollPRmlsBQ= @@ -831,8 +827,6 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1Ig github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk= github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= @@ -889,19 +883,11 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= -github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= -github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= -github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= -github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= -github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= -github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -909,8 +895,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= @@ -976,8 +960,6 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= -github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -1001,6 +983,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= @@ -1120,8 +1103,6 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= @@ -1153,11 +1134,8 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= -github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/testcontainers/testcontainers-go v0.28.0 h1:1HLm9qm+J5VikzFDYhOd+Zw12NtOl+8drH2E8nTY1r8= github.com/testcontainers/testcontainers-go v0.28.0/go.mod h1:COlDpUXbwW3owtpMkEB1zo9gwb1CoKVKlyrVPejF4AU= github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= @@ -1175,13 +1153,12 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8 github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= -github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1199,14 +1176,14 @@ go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//sn go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo= go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA= go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0/go.mod h1:3qi2EEwMgB4xnKgPLqsDP3j9qxnHDZeHsnAxfjQqTko= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= @@ -1233,7 +1210,9 @@ go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxt go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= @@ -1255,8 +1234,10 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= @@ -1291,6 +1272,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -1319,6 +1301,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= @@ -1329,7 +1312,7 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1358,7 +1341,6 @@ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1387,6 +1369,7 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1405,6 +1388,7 @@ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fq golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= @@ -1415,6 +1399,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1456,6 +1441,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= @@ -1493,6 +1479,10 @@ google.golang.org/api v0.219.0/go.mod h1:K6OmjGm+NtLrIkHxv1U3a0qIf/0JOvAHd5O/6Ao google.golang.org/api v0.222.0/go.mod h1:efZia3nXpWELrwMlN5vyQrD4GmJN1Vw0x68Et3r+a9c= google.golang.org/api v0.224.0/go.mod h1:3V39my2xAGkodXy0vEqcEtkqgw2GtrFL5WuBZlCTCOQ= google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ= +google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= +google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= +google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -1535,6 +1525,7 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= @@ -1550,6 +1541,9 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2/go. google.golang.org/genproto/googleapis/api v0.0.0-20250227231956-55c901821b1e/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= +google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A= +google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U= google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250106144421-5f5ef82da422 h1:w6g+P/ZscmNlGxVVXGaPVQOLu1q19ubsTOZKwaDqm4k= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250106144421-5f5ef82da422/go.mod h1:s4mHJ3FfG8P6A3O+gZ8TVqB3ufjOl9UG3ANCMMwCHmo= @@ -1587,6 +1581,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1607,6 +1603,7 @@ google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe0 google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= diff --git a/pkg/gofr/datasource/file/gcs/file.go b/pkg/gofr/datasource/file/gcs/file.go new file mode 100644 index 000000000..0edf7317f --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/file.go @@ -0,0 +1,149 @@ +package gcs + +import ( + "context" + "errors" + "io" + "time" + + "cloud.google.com/go/storage" +) + +type File struct { + conn gcsClient + writer *storage.Writer + name string + logger Logger + metrics Metrics + size int64 + contentType string + body io.ReadCloser + lastModified time.Time + isDir bool +} + +var ( + errNilGCSFileBody = errors.New("GCS file body is nil") + errSeekNotSupported = errors.New("seek not supported on GCSFile") + errReadAtNotSupported = errors.New("readAt not supported on GCSFile") + errWriteAtNotSupported = errors.New("writeAt not supported on GCSFile (read-only)") +) + +const ( + msgWriterClosed = "Writer closed successfully" + msgReaderClosed = "Reader closed successfully" +) + +// ====== File interface methods ====== + +func (f *File) Read(p []byte) (int, error) { + if f.body == nil { + return 0, errNilGCSFileBody + } + + return f.body.Read(p) +} +func (f *File) Write(p []byte) (int, error) { + bucketName := getBucketName(f.name) + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "WRITE", + Location: getLocation(bucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + n, err := f.writer.Write(p) + + if err != nil { + f.logger.Errorf("failed to write: %v", err) + msg = err.Error() + + return n, err + } + + st, msg = statusSuccess, "Write successful" + f.logger.Debug(msg) + + return n, nil +} + +func (f *File) Close() error { + bucketName := getBucketName(f.name) + + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "CLOSE", + Location: getLocation(bucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + if f.writer != nil { + err := f.writer.Close() + if err != nil { + msg = err.Error() + return err + } + + st = statusSuccess + + msg = msgWriterClosed + + f.logger.Debug(msg) + + return nil + } + + if f.body != nil { + err := f.body.Close() + if err != nil { + msg = err.Error() + return err + } + + st = statusSuccess + + msg = msgReaderClosed + + f.logger.Debug(msgReaderClosed) + + return nil + } + + st = statusSuccess + + msg = msgWriterClosed + + return nil +} + +func (*File) Seek(_ int64, _ int) (int64, error) { + // Not supported: Seek requires reopening with range. + return 0, errSeekNotSupported +} + +func (*File) ReadAt(_ []byte, _ int64) (int, error) { + return 0, errReadAtNotSupported +} + +func (*File) WriteAt(_ []byte, _ int64) (int, error) { + return 0, errWriteAtNotSupported +} + +func (f *File) sendOperationStats(fl *FileLog, startTime time.Time) { + duration := time.Since(startTime).Microseconds() + + fl.Duration = duration + + f.logger.Debug(fl) + f.metrics.RecordHistogram(context.Background(), appFTPStats, float64(duration), + "type", fl.Operation, "status", clean(fl.Status)) +} diff --git a/pkg/gofr/datasource/file/gcs/file_parse.go b/pkg/gofr/datasource/file/gcs/file_parse.go new file mode 100644 index 000000000..e700e8fba --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/file_parse.go @@ -0,0 +1,206 @@ +package gcs + +import ( + "bufio" + "bytes" + "encoding/json" + "errors" + "io" + "io/fs" + "path" + "strings" + "time" + + "gofr.dev/pkg/gofr/datasource/file" +) + +var ( + // errNotPointer is returned when Read method is called with a non-pointer argument. + errStringNotPointer = errors.New("input should be a pointer to a string") +) + +const ( + appFTPStats = "app_ftp_stats" + statusErr = "ERROR" + statusSuccess = "SUCCESS" +) + +// textReader implements RowReader for reading text files. +type textReader struct { + scanner *bufio.Scanner + logger Logger +} + +// jsonReader implements RowReader for reading JSON files. +type jsonReader struct { + decoder *json.Decoder + token json.Token +} + +func (f *File) ReadAll() (file.RowReader, error) { + bucketName := getBucketName(f.name) + location := path.Join(bucketName, f.name) + + defer f.sendOperationStats(&FileLog{ + Operation: "READALL", + Location: location, + }, time.Now()) + + if strings.HasSuffix(f.Name(), ".json") { + return f.createJSONReader(location) + } + + return f.createTextCSVReader(location) +} + +// createJSONReader creates a JSON reader for JSON files. +func (f *File) createJSONReader(location string) (file.RowReader, error) { + status := statusErr + + defer f.sendOperationStats(&FileLog{Operation: "JSON READER", Location: location, Status: &status}, time.Now()) + + buffer, err := io.ReadAll(f.body) + if err != nil { + f.logger.Errorf("ReadAll Failed: Unable to read json file: %v", err) + return nil, err + } + + reader := bytes.NewReader(buffer) + + decoder := json.NewDecoder(reader) + + // Peek the first JSON token to determine the type + // Note: This results in offset to move ahead, making it necessary to + // decode again if we are decoding a json object instead of array + token, err := decoder.Token() + if err != nil { + f.logger.Errorf("Error decoding token: %v", err) + return nil, err + } + + if d, ok := token.(json.Delim); ok && d == '[' { + status = statusSuccess + return &jsonReader{decoder: decoder, token: token}, err + } + + // Reading JSON object + decoder = json.NewDecoder(reader) + status = statusSuccess + + return &jsonReader{decoder: decoder}, nil +} + +// createTextCSVReader creates a text reader for reading text files. +func (f *File) createTextCSVReader(location string) (file.RowReader, error) { + status := statusErr + + defer f.sendOperationStats(&FileLog{Operation: "TEXT/CSV READER", Location: location, Status: &status}, time.Now()) + + buffer, err := io.ReadAll(f.body) + if err != nil { + f.logger.Errorf("ReadAll failed: Unable to read text file: %v", err) + return nil, err + } + + reader := bytes.NewReader(buffer) + status = statusSuccess + + return &textReader{ + scanner: bufio.NewScanner(reader), + logger: f.logger, + }, err +} + +func (j *jsonReader) Next() bool { + return j.decoder.More() +} + +// Scan decodes the next JSON object into the provided structure. +func (j *jsonReader) Scan(i any) error { + return j.decoder.Decode(&i) +} + +// Next checks if there is another line available in the text file. +func (f *textReader) Next() bool { + return f.scanner.Scan() +} + +// Scan scans the next line from the text file into the provided pointer to strinf. +func (f *textReader) Scan(i any) error { + if val, ok := i.(*string); ok { + *val = f.scanner.Text() + return nil + } + + return errStringNotPointer +} + +func (f *File) Name() string { + bucketName := getBucketName(f.name) + + f.sendOperationStats(&FileLog{ + Operation: "GET NAME", + Location: getLocation(bucketName), + }, time.Now()) + + return f.name +} + +func (f *File) Size() int64 { + bucketName := getBucketName(f.name) + + f.sendOperationStats(&FileLog{ + Operation: "FILE/DIR SIZE", + Location: getLocation(bucketName), + }, time.Now()) + + return f.size +} + +func (f *File) ModTime() time.Time { + bucketName := getBucketName(f.name) + + f.sendOperationStats(&FileLog{ + Operation: "LAST MODIFIED", + Location: getLocation(bucketName), + }, time.Now()) + + return f.lastModified +} + +func (f *File) Mode() fs.FileMode { + bucketName := getBucketName(f.name) + + f.sendOperationStats(&FileLog{ + Operation: "MODE", + Location: getLocation(bucketName), + }, time.Now()) + + if f.isDir { + return fs.ModeDir + } + + return 0 +} + +func (f *File) IsDir() bool { + bucketName := getBucketName(f.name) + + f.sendOperationStats(&FileLog{ + Operation: "IS DIR", + Location: getLocation(bucketName), + }, time.Now()) + + return f.isDir || f.contentType == "application/x-directory" +} + +func (f *File) Sys() any { + bucketName := getBucketName(f.name) + + f.sendOperationStats(&FileLog{ + Operation: "SYS", + Location: getLocation(bucketName), + }, time.Now()) + + return nil +} diff --git a/pkg/gofr/datasource/file/gcs/fs.go b/pkg/gofr/datasource/file/gcs/fs.go new file mode 100644 index 000000000..7c5c85f48 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs.go @@ -0,0 +1,323 @@ +package gcs + +import ( + "context" + "errors" + "fmt" + "os" + "path" + "strings" + "time" + + "cloud.google.com/go/storage" + file "gofr.dev/pkg/gofr/datasource/file" + "google.golang.org/api/option" +) + +var ( + errOperationNotPermitted = errors.New("operation not permitted") + errWriterTypeAssertion = errors.New("writer is not of type *storage.Writer") +) + +type FileSystem struct { + GCSFile File + conn gcsClient + config *Config + logger Logger + metrics Metrics +} + +// Config represents the gcs configuration. +type Config struct { + EndPoint string + BucketName string + CredentialsJSON string + ProjectID string +} + +// New initializes a new instance of FTP fileSystem with provided configuration. +func New(config *Config) file.FileSystemProvider { + return &FileSystem{config: config} +} + +func (f *FileSystem) Connect() { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "CONNECT", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + f.logger.Debugf("connecting to GCS bucket: %s", f.config.BucketName) + + ctx := context.TODO() + + var client *storage.Client + + var err error + + switch { + case f.config.EndPoint != "": + // Local emulator mode + client, err = storage.NewClient( + ctx, + option.WithEndpoint(f.config.EndPoint), + option.WithoutAuthentication(), + ) + + case f.config.CredentialsJSON != "": + // Direct JSON mode + client, err = storage.NewClient( + ctx, + option.WithCredentialsJSON([]byte(f.config.CredentialsJSON)), + ) + + default: + // Env var mode (GOOGLE_APPLICATION_CREDENTIALS) + client, err = storage.NewClient(ctx) + } + + if err != nil { + f.logger.Errorf("Failed to connect to GCS: %v", err) + return + } + + f.conn = &gcsClientImpl{ + client: client, + bucket: client.Bucket(f.config.BucketName), + } + + st = statusSuccess + msg = "GCS Client connected." + + f.logger.Logf("connected to GCS bucket %s", f.config.BucketName) +} + +func (f *FileSystem) Create(name string) (file.File, error) { + var ( + msg string + st = statusErr + ) + + startTime := time.Now() + defer f.sendOperationStats(&FileLog{ + Operation: "CREATE FILE", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, startTime) + + ctx := context.Background() + + // 1. Check if parent directory exists + parentPath := path.Dir(name) + checkPath := "." + + if parentPath != "." { + checkPath = parentPath + "/" + } + + if _, err := f.conn.ListObjects(ctx, checkPath); err != nil { + msg = "Parent directory does not exist" + + f.logger.Errorf("Failed to list parent directory %q: %v", checkPath, err) + + return nil, err + } + + // 2. Resolve file name conflict + originalName := name + + for index := 1; ; index++ { + objs, err := f.conn.ListObjects(ctx, name) + + if err != nil { + msg = "Error checking existing objects" + + f.logger.Errorf("Failed to list objects for name %q: %v", name, err) + + return nil, err + } + + if len(objs) == 0 { + break // Safe to use + } + + name = generateCopyName(originalName, index) + } + + // 3. Open writer to create file + writer := f.conn.NewWriter(ctx, name) + + sw, ok := writer.(*storage.Writer) + if !ok { + msg = "Failed to assert writer to *storage.Writer" + + f.logger.Errorf("Type assertion failed for writer to *storage.Writer") + + return nil, fmt.Errorf("type assertion failed: %w", errWriterTypeAssertion) + } + + st = statusSuccess + msg = "Write stream opened successfully" + + f.logger.Logf("Write stream successfully opened for file %q", name) + + return &File{ + conn: f.conn, + writer: sw, + name: name, + contentType: sw.ContentType, + size: sw.Size, + lastModified: sw.Updated, + logger: f.logger, + metrics: f.metrics, + }, nil +} + +func (f *FileSystem) Remove(name string) error { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "REMOVE FILE", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + err := f.conn.DeleteObject(ctx, name) + + if err != nil { + f.logger.Errorf("Error while deleting file: %v", err) + return err + } + + st = statusSuccess + msg = "File deletion on GCS successful" + + f.logger.Logf("File with path %q deleted", name) + + return nil +} + +func (f *FileSystem) Open(name string) (file.File, error) { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "OPEN FILE", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + reader, err := f.conn.NewReader(ctx, name) + + if err != nil { + if errors.Is(err, storage.ErrObjectNotExist) { + return nil, file.ErrFileNotFound + } + + f.logger.Errorf("failed to retrieve %q: %v", name, err) + + return nil, err + } + + attr, err := f.conn.StatObject(ctx, name) + if err != nil { + reader.Close() + return nil, err + } + + st = statusSuccess + + msg = fmt.Sprintf("File with path %q retrieved successfully", name) + + return &File{ + conn: f.conn, + name: name, + body: reader, + logger: f.logger, + metrics: f.metrics, + size: attr.Size, + contentType: attr.ContentType, + lastModified: attr.Updated, + }, nil +} + +func (f *FileSystem) Rename(oldname, newname string) error { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "RENAME", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + if oldname == newname { + f.logger.Logf("%q & %q are same", oldname, newname) + return nil + } + + if path.Dir(oldname) != path.Dir(newname) { + f.logger.Errorf("%q & %q are not in same location", oldname, newname) + return fmt.Errorf("%w: renaming as well as moving file to different location is not allowed", errOperationNotPermitted) + } + // Copy old object to new + if err := f.conn.CopyObject(ctx, oldname, newname); err != nil { + msg = fmt.Sprintf("Error while copying file: %v", err) + return err + } + + // Delete old + err := f.conn.DeleteObject(ctx, oldname) + if err != nil { + msg = fmt.Sprintf("failed to remove old file %s", oldname) + return err + } + + st = statusSuccess + msg = "File renamed successfully" + + f.logger.Logf("File with path %q renamed to %q", oldname, newname) + + return nil +} +func (f *FileSystem) OpenFile(name string, _ int, _ os.FileMode) (file.File, error) { + return f.Open(name) +} + +// UseLogger sets the Logger interface for the FTP file system. +func (f *FileSystem) UseLogger(logger any) { + if l, ok := logger.(Logger); ok { + f.logger = l + } +} + +// UseMetrics sets the Metrics interface. +func (f *FileSystem) UseMetrics(metrics any) { + if m, ok := metrics.(Metrics); ok { + f.metrics = m + } +} +func generateCopyName(original string, count int) string { + ext := path.Ext(original) + base := strings.TrimSuffix(original, ext) + + return fmt.Sprintf("%s copy %d%s", base, count, ext) +} diff --git a/pkg/gofr/datasource/file/gcs/fs_dir.go b/pkg/gofr/datasource/file/gcs/fs_dir.go new file mode 100644 index 000000000..ce9f77ec7 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs_dir.go @@ -0,0 +1,307 @@ +package gcs + +import ( + "context" + "errors" + "fmt" + "os" + "path" + "path/filepath" + "strings" + "time" + + "cloud.google.com/go/storage" + file "gofr.dev/pkg/gofr/datasource/file" + "google.golang.org/api/googleapi" +) + +var ( + errEmptyDirectoryName = errors.New("directory name cannot be empty") + errCHNDIRNotSupported = errors.New("changing directory is not supported in GCS") +) + +func getBucketName(filePath string) string { + return strings.Split(filePath, string(filepath.Separator))[0] +} + +func getLocation(bucket string) string { + return path.Join(string(filepath.Separator), bucket) +} + +func (f *FileSystem) Mkdir(name string, _ os.FileMode) error { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "MKDIR", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + if name == "" { + msg = "directory name cannot be empty" + f.logger.Errorf(msg) + + return errEmptyDirectoryName + } + + ctx := context.TODO() + objName := name + "/" + + writer := f.conn.NewWriter(ctx, objName) + defer writer.Close() + + _, err := writer.Write([]byte("dir")) + if err != nil { + if err != nil { + msg = fmt.Sprintf("failed to create directory %q on GCS: %v", objName, err) + f.logger.Errorf(msg) + + return err + } + } + + st = statusSuccess + + msg = fmt.Sprintf("Directories on path %q created successfully", name) + + f.logger.Logf("Created directories on path %q", name) + + return err +} + +func (f *FileSystem) MkdirAll(dirPath string, perm os.FileMode) error { + cleaned := strings.Trim(dirPath, "/") + if cleaned == "" { + return nil + } + + dirs := strings.Split(cleaned, "/") + + var currentPath string + + for _, dir := range dirs { + currentPath = pathJoin(currentPath, dir) + err := f.Mkdir(currentPath, perm) + + if err != nil && !isAlreadyExistsError(err) { + return err + } + } + + return nil +} +func pathJoin(parts ...string) string { + return path.Join(parts...) +} + +func isAlreadyExistsError(err error) bool { + var gErr *googleapi.Error + if errors.As(err, &gErr) { + return gErr.Code == 409 || gErr.Code == 412 + } + + // Fallback check + return strings.Contains(err.Error(), "already exists") +} + +func (f *FileSystem) RemoveAll(dirPath string) error { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "REMOVEALL", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + objects, err := f.conn.ListObjects(ctx, dirPath) + + if err != nil { + msg = fmt.Sprintf("Error retrieving objects: %v", err) + return err + } + + for _, obj := range objects { + if err := f.conn.DeleteObject(ctx, obj); err != nil { + f.logger.Errorf("Error while deleting directory: %v", err) + return err + } + } + + st = statusSuccess + + msg = fmt.Sprintf("Directory with path %q, deleted successfully", dirPath) + + f.logger.Logf("Directory %s deleted.", dirPath) + + return nil +} + +func (f *FileSystem) ReadDir(dir string) ([]file.FileInfo, error) { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "READDIR", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + objects, prefixes, err := f.conn.ListDir(ctx, dir) + if err != nil { + msg = fmt.Sprintf("Error retrieving objects: %v", err) + f.logger.Logf(msg) + + return nil, err + } + + fileinfo := make([]file.FileInfo, 0, len(prefixes)+len(objects)) + + for _, p := range prefixes { + trimmedName := strings.TrimSuffix(p, "/") + dirName := path.Base(trimmedName) + fileinfo = append(fileinfo, &File{ + name: dirName, + isDir: true, + logger: f.logger, + metrics: f.metrics, + }) + } + + for _, o := range objects { + fileinfo = append(fileinfo, &File{ + name: path.Base(o.Name), + size: o.Size, + lastModified: o.Updated, + isDir: false, + logger: f.logger, + metrics: f.metrics, + }) + } + + st = statusSuccess + msg = fmt.Sprintf("Directory/Files in directory with path %q retrieved successfully", dir) + + f.logger.Logf("Reading directory/files from GCS at path %q successful.", dir) + + return fileinfo, nil +} + +func (f *FileSystem) ChDir(_ string) error { + const op = "CHDIR" + + st := statusErr + + var msg = "Changing directory not supported" + + defer f.sendOperationStats(&FileLog{ + Operation: op, + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + f.logger.Errorf("%s: not supported in GCS", op) + + return errCHNDIRNotSupported +} +func (f *FileSystem) Getwd() (string, error) { + const op = "GETWD" + + st := statusSuccess + + start := time.Now() + + var msg = "Returning simulated root directory" + + defer f.sendOperationStats(&FileLog{ + Operation: op, + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, start) + + return getLocation(f.config.BucketName), nil +} +func (f *FileSystem) Stat(name string) (file.FileInfo, error) { + var msg string + + st := statusErr + + defer f.sendOperationStats(&FileLog{ + Operation: "STAT", + Location: getLocation(f.config.BucketName), + Status: &st, + Message: &msg, + }, time.Now()) + + ctx := context.TODO() + + // Try to stat the object (file) + attr, err := f.conn.StatObject(ctx, name) + if err == nil { + st = statusSuccess + msg = fmt.Sprintf("File with path %q info retrieved successfully", name) + + return &File{ + name: name, + logger: f.logger, + metrics: f.metrics, + size: attr.Size, + contentType: attr.ContentType, + lastModified: attr.Updated, + }, nil + } + + // If not found, check if it's a "directory" by listing with prefix + if errors.Is(err, storage.ErrObjectNotExist) { + // Ensure the name ends with slash for directories + prefix := name + if !strings.HasSuffix(prefix, "/") { + prefix += "/" + } + + objs, _, listErr := f.conn.ListDir(ctx, prefix) + + if listErr != nil { + f.logger.Errorf("Error checking directory prefix: %v", listErr) + return nil, listErr + } + + if len(objs) > 0 { + st = statusSuccess + msg = fmt.Sprintf("Directory with path %q info retrieved successfully", name) + + return &File{ + name: name, + logger: f.logger, + metrics: f.metrics, + size: 0, + contentType: "application/x-directory", + lastModified: objs[0].Updated, + }, nil + } + } + + f.logger.Errorf("Error returning file or directory info: %v", err) + + return nil, err +} + +func (f *FileSystem) sendOperationStats(fl *FileLog, startTime time.Time) { + duration := time.Since(startTime).Microseconds() + + fl.Duration = duration + + f.logger.Debug(fl) +} diff --git a/pkg/gofr/datasource/file/gcs/fs_dir_test.go b/pkg/gofr/datasource/file/gcs/fs_dir_test.go new file mode 100644 index 000000000..cd4d64d10 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs_dir_test.go @@ -0,0 +1,236 @@ +package gcs + +import ( + "bytes" + "errors" + "testing" + + "cloud.google.com/go/storage" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" +) + +type fakeWriteCloser struct { + *bytes.Buffer +} + +func (*fakeWriteCloser) Close() error { + return nil +} + +type errorWriterCloser struct{} + +var ( + ErrWrite = errors.New("write error") + ErrClose = errors.New("close error") + ErrDirNotFound = errors.New("directory not found") +) + +func (*errorWriterCloser) Write(_ []byte) (int, error) { + return 0, ErrWrite +} + +func (*errorWriterCloser) Close() error { + return ErrClose +} + +type result struct { + Name string + Size int64 + IsDir bool +} + +func Test_Mkdir_GCS(t *testing.T) { + type testCase struct { + name string + dirName string + setupMocks func(mockGCS *MockgcsClient) + expectError bool + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{ + BucketName: "test-bucket", + CredentialsJSON: "fake-creds", + ProjectID: "test-project", + } + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debugf(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + tests := []testCase{ + { + name: "successfully create directory", + dirName: "testDir", + setupMocks: func(m *MockgcsClient) { + buf := &bytes.Buffer{} + fakeWriter := &fakeWriteCloser{Buffer: buf} + m.EXPECT().NewWriter(gomock.Any(), "testDir/").Return(fakeWriter) + }, + expectError: false, + }, + { + name: "fail when directory name is empty", + dirName: "", + setupMocks: func(_ *MockgcsClient) { + // No mock needed for empty dir + }, + expectError: true, + }, + { + name: "fail when GCS write fails", + dirName: "brokenDir", + setupMocks: func(m *MockgcsClient) { + errorWriter := &errorWriterCloser{} + m.EXPECT().NewWriter(gomock.Any(), "brokenDir/").Return(errorWriter) + }, + expectError: true, + }, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks(mockGCS) + + err := fs.Mkdir(tt.dirName, 0777) + + if tt.expectError { + require.Error(t, err, "Test %d (%s): expected an error", i, tt.name) + } else { + require.NoError(t, err, "Test %d (%s): expected no error", i, tt.name) + } + }) + } +} + +func Test_ReadDir_GCS(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + fs := &FileSystem{ + conn: mockGCS, + config: &Config{BucketName: "test-bucket"}, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + for _, tt := range getReadDirTestCases(mockGCS) { + t.Run(tt.name, func(t *testing.T) { + tt.setupMock() + entries, err := fs.ReadDir(tt.dirPath) + + if tt.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Len(t, entries, len(tt.expectedResults)) + + for i, entry := range entries { + require.Equal(t, tt.expectedResults[i].Name, entry.Name()) + require.Equal(t, tt.expectedResults[i].IsDir, entry.IsDir()) + } + }) + } +} + +type readDirTestCase struct { + name string + dirPath string + expectedResults []result + setupMock func() + expectError bool +} + +func getReadDirTestCases(mockGCS *MockgcsClient) []readDirTestCase { + return []readDirTestCase{ + { + name: "Valid directory path with files and subdirectory", + dirPath: "abc/efg", + expectedResults: []result{ + {"hij", 0, true}, + {"file.txt", 1, false}, + }, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "abc/efg").Return( + []*storage.ObjectAttrs{{Name: "abc/efg/file.txt", Size: 1}}, + []string{"abc/efg/hij/"}, + nil, + ) + }, + }, + { + name: "Valid directory path with only subdirectory", + dirPath: "abc", + expectedResults: []result{ + {"efg", 0, true}, + }, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "abc").Return( + []*storage.ObjectAttrs{}, + []string{"abc/efg/"}, + nil, + ) + }, + }, + { + name: "Directory not found", + dirPath: "does-not-exist", + expectedResults: nil, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "does-not-exist").Return(nil, nil, ErrDirNotFound) + }, + expectError: true, + }, + { + name: "Empty directory", + dirPath: "empty", + expectedResults: []result{}, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "empty").Return([]*storage.ObjectAttrs{}, nil, nil) + }, + }, + { + name: "Directory with multiple files", + dirPath: "many/files", + expectedResults: []result{ + {"file1.txt", 1, false}, + {"file2.txt", 2, false}, + }, + setupMock: func() { + mockGCS.EXPECT().ListDir(gomock.Any(), "many/files").Return([]*storage.ObjectAttrs{ + {Name: "many/files/file1.txt", Size: 1}, + {Name: "many/files/file2.txt", Size: 2}, + }, nil, nil) + }, + }, + } +} diff --git a/pkg/gofr/datasource/file/gcs/fs_test.go b/pkg/gofr/datasource/file/gcs/fs_test.go new file mode 100644 index 000000000..e8d19a840 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/fs_test.go @@ -0,0 +1,374 @@ +package gcs + +import ( + "errors" + "fmt" + "testing" + "time" + + "cloud.google.com/go/storage" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" +) + +var ( + ErrObjectNotFound = errors.New("object not found") + ErrMock = fmt.Errorf("errMock") +) + +func Test_CreateFile(t *testing.T) { + type testCase struct { + name string + createPath string + setupMocks func(mockGCS *MockgcsClient) + expectError bool + isRoot bool + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{ + BucketName: "test-bucket", + CredentialsJSON: "fake-creds", + ProjectID: "test-project", + } + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + tests := []testCase{ + { + name: "create file at root level", + createPath: "abc.txt", + setupMocks: func(m *MockgcsClient) { + m.EXPECT().ListObjects(gomock.Any(), ".").Return([]string{}, nil) + m.EXPECT().ListObjects(gomock.Any(), "abc.txt").Return([]string{}, nil) + m.EXPECT().NewWriter(gomock.Any(), "abc.txt").Return(&storage.Writer{}) + }, + + expectError: false, + isRoot: true, + }, + { + name: "fail when parent directory does not exist", + createPath: "abc/abc.txt", + setupMocks: func(m *MockgcsClient) { + m.EXPECT().ListObjects(gomock.Any(), "abc/").Return(nil, ErrMock) + }, + expectError: true, + isRoot: false, + }, + { + name: "create file inside existing directory", + createPath: "abc/efg.txt", + setupMocks: func(m *MockgcsClient) { + // parent path "abc/" exists + m.EXPECT().ListObjects(gomock.Any(), "abc/").Return([]string{"abc/.keep"}, nil) + // filename does not exist + m.EXPECT().ListObjects(gomock.Any(), "abc/efg.txt").Return([]string{}, nil) + m.EXPECT().NewWriter(gomock.Any(), "abc/efg.txt").Return(&storage.Writer{}) + }, + expectError: false, + isRoot: false, + }, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks(mockGCS) + + file, err := fs.Create(tt.createPath) + + if tt.expectError { + require.Error(t, err, "Test %d (%s): expected an error", i, tt.name) + return + } + + require.NoError(t, err, "Test %d (%s): expected no error", i, tt.name) + require.NotNil(t, file) + }) + } +} +func Test_Remove_GCS(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + fs := &FileSystem{ + conn: mockGCS, + logger: mockLogger, + config: &Config{BucketName: "test-bucket"}, + metrics: mockMetrics, + } + + // Expectations + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + mockGCS.EXPECT(). + DeleteObject(gomock.Any(), "abc/a1.txt"). + Return(nil). + Times(1) + + err := fs.Remove("abc/a1.txt") + require.NoError(t, err) +} + +var ( + errDeleteFailed = errors.New("delete failed") + errCopyFailed = errors.New("copy failed") +) + +func TestRenameFile(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockConn := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{BucketName: "test-bucket"} + + fs := &FileSystem{ + conn: mockConn, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + tests := []struct { + name string + initialName string + newName string + setupMocks func() + expectedError bool + }{ + { + name: "Rename file to new name", + initialName: "dir/file.txt", + newName: "dir/file-renamed.txt", + setupMocks: func() { + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(nil) + mockConn.EXPECT().DeleteObject(gomock.Any(), "dir/file.txt").Return(nil) + }, + expectedError: false, + }, + { + name: "Rename file with copy failure", + initialName: "dir/file.txt", + newName: "dir/file-renamed.txt", + setupMocks: func() { + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(errCopyFailed) + }, + expectedError: true, + }, + { + name: "Rename file with delete failure", + initialName: "dir/file.txt", + newName: "dir/file-renamed.txt", + setupMocks: func() { + mockConn.EXPECT().CopyObject(gomock.Any(), "dir/file.txt", "dir/file-renamed.txt").Return(nil) + mockConn.EXPECT().DeleteObject(gomock.Any(), "dir/file.txt").Return(errDeleteFailed) + }, + expectedError: true, + }, + { + name: "Rename file to same name", + initialName: "dir/file.txt", + newName: "dir/file.txt", + setupMocks: func() {}, // No calls expected + expectedError: false, + }, + { + name: "Rename file to different directory (not allowed)", + initialName: "dir1/file.txt", + newName: "dir2/file.txt", + setupMocks: func() {}, // No calls expected + expectedError: true, + }, + } + + // Set up logger mocks globally + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks() + err := fs.Rename(tt.initialName, tt.newName) + + if tt.expectedError { + require.Error(t, err, "Expected error but got none") + } else { + require.NoError(t, err, "Unexpected error: %v", err) + } + }) + } +} + +func Test_StatFile_GCS(t *testing.T) { + tm := time.Now() + + type result struct { + name string + size int64 + isDir bool + } + + tests := []struct { + name string + filePath string + mockAttr *storage.ObjectAttrs + mockError error + expected result + expectError bool + }{ + { + name: "Valid file stat", + filePath: "abc/efg/file.txt", + mockAttr: &storage.ObjectAttrs{ + Name: "abc/efg/file.txt", + Size: 123, + Updated: tm, + ContentType: "text/plain", + }, + expected: result{ + name: "abc/efg/file.txt", + size: 123, + isDir: false, + }, + }, + { + name: "File not found", + filePath: "notfound.txt", + mockAttr: nil, + mockError: ErrObjectNotFound, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + config := &Config{BucketName: "test-bucket"} + + fs := &FileSystem{ + conn: mockGCS, + config: config, + logger: mockLogger, + metrics: mockMetrics, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + + mockGCS.EXPECT().StatObject(gomock.Any(), tt.filePath).Return(tt.mockAttr, tt.mockError) + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + res, err := fs.Stat(tt.filePath) + if tt.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + + actual := result{ + name: res.Name(), + size: res.Size(), + isDir: res.IsDir(), + } + + assert.Equal(t, tt.expected, actual) + }) + } +} +func Test_Stat_FileAndDir(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGCS := NewMockgcsClient(ctrl) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + fs := &FileSystem{ + conn: mockGCS, + logger: mockLogger, + metrics: mockMetrics, + config: &Config{ + BucketName: "test-bucket", + }, + } + + mockLogger.EXPECT().Logf(gomock.Any(), gomock.Any()).AnyTimes() + mockLogger.EXPECT().Debug(gomock.Any()).AnyTimes() + mockLogger.EXPECT().Errorf(gomock.Any(), gomock.Any()).AnyTimes() + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), appFTPStats, gomock.Any(), + "type", gomock.Any(), "status", gomock.Any()).AnyTimes() + + fileName := "documents/testfile.txt" + fileAttrs := &storage.ObjectAttrs{ + Name: fileName, + Size: 1024, + ContentType: "text/plain", + Updated: time.Now(), + } + mockGCS.EXPECT().StatObject(gomock.Any(), fileName).Return(fileAttrs, nil) + + info, err := fs.Stat(fileName) + assert.NilError(t, err) + assert.Equal(t, fileName, info.Name()) + assert.Equal(t, int64(1024), info.Size()) + assert.Check(t, !info.IsDir()) + + dirName := "documents/folder/" + dirAttrs := &storage.ObjectAttrs{ + Name: dirName, + Size: 0, + ContentType: "application/x-directory", + Updated: time.Now(), + } + + mockGCS.EXPECT().StatObject(gomock.Any(), dirName).Return(dirAttrs, nil) + + info, err = fs.Stat(dirName) + + assert.NilError(t, err) + assert.Equal(t, dirName, info.Name()) + assert.Equal(t, int64(0), info.Size()) + assert.Check(t, info.IsDir()) +} diff --git a/pkg/gofr/datasource/file/gcs/go.mod b/pkg/gofr/datasource/file/gcs/go.mod new file mode 100644 index 000000000..705879dd3 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/go.mod @@ -0,0 +1,68 @@ +module gofr.dev/pkg/gofr/datasource/file/gcs + +go 1.25.0 + +require ( + cloud.google.com/go/storage v1.55.0 + github.com/golang/mock v1.6.0 + github.com/stretchr/testify v1.10.0 + gofr.dev v1.42.2 + google.golang.org/api v0.238.0 + gotest.tools/v3 v3.5.2 +) + +require ( + cel.dev/expr v0.23.0 // indirect + cloud.google.com/go v0.121.1 // indirect + cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/iam v1.5.2 // indirect + cloud.google.com/go/monitoring v1.24.2 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect + github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/zeebo/errs v1.4.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.uber.org/mock v0.5.2 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/grpc v1.73.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/pkg/gofr/datasource/file/gcs/go.sum b/pkg/gofr/datasource/file/gcs/go.sum new file mode 100644 index 000000000..9ecffed09 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/go.sum @@ -0,0 +1,171 @@ +cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss= +cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= +cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= +cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= +cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= +cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= +cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2znf0= +cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY= +cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= +cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +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/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= +github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +gofr.dev v1.42.2 h1:cqWFwnYzaDyNZgMDxdwgb4Wk3/1kam0E+mpXOyeiU4Q= +gofr.dev v1.42.2/go.mod h1:viVap8+T4Uk6FbeK2brW3U8dau4R8xiGoo+/NyY7zrE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs= +google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= diff --git a/pkg/gofr/datasource/file/gcs/interface.go b/pkg/gofr/datasource/file/gcs/interface.go new file mode 100644 index 000000000..2d2297eb7 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/interface.go @@ -0,0 +1,123 @@ +//go:generate mockgen -source=interface.go -destination=mock_interface.go -package=gcs + +package gcs + +import ( + "context" + "errors" + "fmt" + "io" + + "cloud.google.com/go/storage" + "google.golang.org/api/iterator" +) + +type Logger interface { + Debug(args ...any) + Debugf(pattern string, args ...any) + Logf(pattern string, args ...any) + Errorf(pattern string, args ...any) +} +type gcsClientImpl struct { + client *storage.Client + bucket *storage.BucketHandle +} + +type gcsClient interface { + NewWriter(ctx context.Context, name string) io.WriteCloser + NewReader(ctx context.Context, name string) (*storage.Reader, error) + DeleteObject(ctx context.Context, name string) error + CopyObject(ctx context.Context, src, dst string) error + ListObjects(ctx context.Context, prefix string) ([]string, error) + ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) + StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) +} + +type Metrics interface { + NewHistogram(name, desc string, buckets ...float64) + RecordHistogram(ctx context.Context, name string, value float64, labels ...string) +} + +func (g *gcsClientImpl) NewWriter(ctx context.Context, name string) io.WriteCloser { + return g.bucket.Object(name).NewWriter(ctx) +} + +func (g *gcsClientImpl) NewReader(ctx context.Context, name string) (*storage.Reader, error) { + return g.bucket.Object(name).NewReader(ctx) +} + +func (g *gcsClientImpl) DeleteObject(ctx context.Context, name string) error { + attrs, err := g.bucket.Object(name).Attrs(ctx) + if err != nil { + return fmt.Errorf("failed to get object attributes: %w", err) + } + + err = g.bucket.Object(name).If(storage.Conditions{GenerationMatch: attrs.Generation}).Delete(ctx) + if err != nil { + return fmt.Errorf("failed to delete object: %w", err) + } + + return nil +} + +func (g *gcsClientImpl) CopyObject(ctx context.Context, src, dst string) error { + srcObj := g.bucket.Object(src) + dstObj := g.bucket.Object(dst) + _, err := dstObj.CopierFrom(srcObj).Run(ctx) + + return err +} + +func (g *gcsClientImpl) ListObjects(ctx context.Context, prefix string) ([]string, error) { + var objects []string + + it := g.bucket.Objects(ctx, &storage.Query{Prefix: prefix}) + + for { + obj, err := it.Next() + if errors.Is(err, iterator.Done) { + break + } + + if err != nil { + return nil, err + } + + objects = append(objects, obj.Name) + } + + return objects, nil +} + +func (g *gcsClientImpl) ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) { + var attrs []*storage.ObjectAttrs + + var prefixes []string + + it := g.bucket.Objects(ctx, &storage.Query{ + Prefix: prefix, + Delimiter: "/", + }) + + for { + obj, err := it.Next() + + if errors.Is(err, iterator.Done) { + break + } else if err != nil { + return nil, nil, err + } + + if obj.Prefix != "" { + prefixes = append(prefixes, obj.Prefix) + } else { + attrs = append(attrs, obj) + } + } + + return attrs, prefixes, nil +} + +func (g *gcsClientImpl) StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) { + return g.bucket.Object(name).Attrs(ctx) +} diff --git a/pkg/gofr/datasource/file/gcs/logger.go b/pkg/gofr/datasource/file/gcs/logger.go new file mode 100644 index 000000000..992b79b29 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/logger.go @@ -0,0 +1,34 @@ +package gcs + +import ( + "fmt" + "io" + "regexp" + "strings" +) + +// FileLog handles logging with different levels. +// In DEBUG MODE, this FileLog can be exported into a file while +// running the application or can be logged in the terminal. +type FileLog struct { + Operation string `json:"operation"` + Duration int64 `json:"duration"` + Status *string `json:"status"` + Location string `json:"location,omitempty"` + Message *string `json:"message,omitempty"` +} + +var regexpSpaces = regexp.MustCompile(`\s+`) + +func clean(query *string) string { + if query == nil { + return "" + } + + return strings.TrimSpace(regexpSpaces.ReplaceAllString(*query, " ")) +} + +func (fl *FileLog) PrettyPrint(writer io.Writer) { + fmt.Fprintf(writer, "\u001B[38;5;8m%-32s \u001B[38;5;148m%-6s\u001B[0m %8d\u001B[38;5;8mµs\u001B[0m %-10s \u001B[0m %-48s \n", + clean(&fl.Operation), "GCS", fl.Duration, clean(fl.Status), clean(fl.Message)) +} diff --git a/pkg/gofr/datasource/file/gcs/logger_test.go b/pkg/gofr/datasource/file/gcs/logger_test.go new file mode 100644 index 000000000..a6e156d6d --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/logger_test.go @@ -0,0 +1,48 @@ +package gcs + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFileLogPrettyPrint(t *testing.T) { + msg := "File Created successfully" + + fileLog := FileLog{ + Operation: "Create file", + Duration: 1234, + Location: "/ftp/one", + Message: &msg, + } + + expected := "Create file" + + expectedMsg := "File Created successfully" + + var buf bytes.Buffer + + fileLog.PrettyPrint(&buf) + + assert.Contains(t, buf.String(), expected) + assert.Contains(t, buf.String(), expectedMsg) +} + +func TestFileLogPrettyPrintWhitespaceHandling(t *testing.T) { + msg := " File creation complete " + fileLog := FileLog{ + Operation: " Create file ", + Duration: 5678, + Message: &msg, + } + expected := "Create file" + expectedMsg := "File creation complete" + + var buf bytes.Buffer + + fileLog.PrettyPrint(&buf) + + assert.Contains(t, buf.String(), expected) + assert.Contains(t, buf.String(), expectedMsg) +} diff --git a/pkg/gofr/datasource/file/gcs/mock_interface.go b/pkg/gofr/datasource/file/gcs/mock_interface.go new file mode 100644 index 000000000..31d3ba436 --- /dev/null +++ b/pkg/gofr/datasource/file/gcs/mock_interface.go @@ -0,0 +1,287 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: interface.go + +// Package gcs is a generated GoMock package. +package gcs + +import ( + context "context" + io "io" + reflect "reflect" + + storage "cloud.google.com/go/storage" + gomock "github.com/golang/mock/gomock" +) + +// MockLogger is a mock of Logger interface. +type MockLogger struct { + ctrl *gomock.Controller + recorder *MockLoggerMockRecorder +} + +// MockLoggerMockRecorder is the mock recorder for MockLogger. +type MockLoggerMockRecorder struct { + mock *MockLogger +} + +// NewMockLogger creates a new mock instance. +func NewMockLogger(ctrl *gomock.Controller) *MockLogger { + mock := &MockLogger{ctrl: ctrl} + mock.recorder = &MockLoggerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { + return m.recorder +} + +// Debug mocks base method. +func (m *MockLogger) Debug(args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debug", varargs...) +} + +// Debug indicates an expected call of Debug. +func (mr *MockLoggerMockRecorder) Debug(args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), args...) +} + +// Debugf mocks base method. +func (m *MockLogger) Debugf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debugf", varargs...) +} + +// Debugf indicates an expected call of Debugf. +func (mr *MockLoggerMockRecorder) Debugf(pattern interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...) +} + +// Errorf mocks base method. +func (m *MockLogger) Errorf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Errorf", varargs...) +} + +// Errorf indicates an expected call of Errorf. +func (mr *MockLoggerMockRecorder) Errorf(pattern interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) +} + +// Logf mocks base method. +func (m *MockLogger) Logf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []interface{}{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Logf", varargs...) +} + +// Logf indicates an expected call of Logf. +func (mr *MockLoggerMockRecorder) Logf(pattern interface{}, args ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Logf", reflect.TypeOf((*MockLogger)(nil).Logf), varargs...) +} + +// MockgcsClient is a mock of gcsClient interface. +type MockgcsClient struct { + ctrl *gomock.Controller + recorder *MockgcsClientMockRecorder +} + +// MockgcsClientMockRecorder is the mock recorder for MockgcsClient. +type MockgcsClientMockRecorder struct { + mock *MockgcsClient +} + +// NewMockgcsClient creates a new mock instance. +func NewMockgcsClient(ctrl *gomock.Controller) *MockgcsClient { + mock := &MockgcsClient{ctrl: ctrl} + mock.recorder = &MockgcsClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockgcsClient) EXPECT() *MockgcsClientMockRecorder { + return m.recorder +} + +// CopyObject mocks base method. +func (m *MockgcsClient) CopyObject(ctx context.Context, src, dst string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyObject", ctx, src, dst) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyObject indicates an expected call of CopyObject. +func (mr *MockgcsClientMockRecorder) CopyObject(ctx, src, dst interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyObject", reflect.TypeOf((*MockgcsClient)(nil).CopyObject), ctx, src, dst) +} + +// DeleteObject mocks base method. +func (m *MockgcsClient) DeleteObject(ctx context.Context, name string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteObject", ctx, name) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteObject indicates an expected call of DeleteObject. +func (mr *MockgcsClientMockRecorder) DeleteObject(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObject", reflect.TypeOf((*MockgcsClient)(nil).DeleteObject), ctx, name) +} + +// ListDir mocks base method. +func (m *MockgcsClient) ListDir(ctx context.Context, prefix string) ([]*storage.ObjectAttrs, []string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListDir", ctx, prefix) + ret0, _ := ret[0].([]*storage.ObjectAttrs) + ret1, _ := ret[1].([]string) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// ListDir indicates an expected call of ListDir. +func (mr *MockgcsClientMockRecorder) ListDir(ctx, prefix interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDir", reflect.TypeOf((*MockgcsClient)(nil).ListDir), ctx, prefix) +} + +// ListObjects mocks base method. +func (m *MockgcsClient) ListObjects(ctx context.Context, prefix string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListObjects", ctx, prefix) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListObjects indicates an expected call of ListObjects. +func (mr *MockgcsClientMockRecorder) ListObjects(ctx, prefix interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjects", reflect.TypeOf((*MockgcsClient)(nil).ListObjects), ctx, prefix) +} + +// NewReader mocks base method. +func (m *MockgcsClient) NewReader(ctx context.Context, name string) (*storage.Reader, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewReader", ctx, name) + ret0, _ := ret[0].(*storage.Reader) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewReader indicates an expected call of NewReader. +func (mr *MockgcsClientMockRecorder) NewReader(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewReader", reflect.TypeOf((*MockgcsClient)(nil).NewReader), ctx, name) +} + +// NewWriter mocks base method. +func (m *MockgcsClient) NewWriter(ctx context.Context, name string) io.WriteCloser { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewWriter", ctx, name) + ret0, _ := ret[0].(io.WriteCloser) + return ret0 +} + +// NewWriter indicates an expected call of NewWriter. +func (mr *MockgcsClientMockRecorder) NewWriter(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewWriter", reflect.TypeOf((*MockgcsClient)(nil).NewWriter), ctx, name) +} + +// StatObject mocks base method. +func (m *MockgcsClient) StatObject(ctx context.Context, name string) (*storage.ObjectAttrs, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StatObject", ctx, name) + ret0, _ := ret[0].(*storage.ObjectAttrs) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StatObject indicates an expected call of StatObject. +func (mr *MockgcsClientMockRecorder) StatObject(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatObject", reflect.TypeOf((*MockgcsClient)(nil).StatObject), ctx, name) +} + +// MockMetrics is a mock of Metrics interface. +type MockMetrics struct { + ctrl *gomock.Controller + recorder *MockMetricsMockRecorder +} + +// MockMetricsMockRecorder is the mock recorder for MockMetrics. +type MockMetricsMockRecorder struct { + mock *MockMetrics +} + +// NewMockMetrics creates a new mock instance. +func NewMockMetrics(ctrl *gomock.Controller) *MockMetrics { + mock := &MockMetrics{ctrl: ctrl} + mock.recorder = &MockMetricsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMetrics) EXPECT() *MockMetricsMockRecorder { + return m.recorder +} + +// NewHistogram mocks base method. +func (m *MockMetrics) NewHistogram(name, desc string, buckets ...float64) { + m.ctrl.T.Helper() + varargs := []interface{}{name, desc} + for _, a := range buckets { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "NewHistogram", varargs...) +} + +// NewHistogram indicates an expected call of NewHistogram. +func (mr *MockMetricsMockRecorder) NewHistogram(name, desc interface{}, buckets ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{name, desc}, buckets...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewHistogram", reflect.TypeOf((*MockMetrics)(nil).NewHistogram), varargs...) +} + +// RecordHistogram mocks base method. +func (m *MockMetrics) RecordHistogram(ctx context.Context, name string, value float64, labels ...string) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, name, value} + for _, a := range labels { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "RecordHistogram", varargs...) +} + +// RecordHistogram indicates an expected call of RecordHistogram. +func (mr *MockMetricsMockRecorder) RecordHistogram(ctx, name, value interface{}, labels ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, name, value}, labels...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHistogram", reflect.TypeOf((*MockMetrics)(nil).RecordHistogram), varargs...) +}