From fd0d07c01464c20a13d3b5c4c83436be5bb5ee28 Mon Sep 17 00:00:00 2001 From: jnbdz Date: Sat, 17 Aug 2024 11:23:40 -0400 Subject: [PATCH] Worked on tmp directory paths and command line for validation. --- collection/cmd/init.go | 26 ++----- entity/cmd/validate.go | 15 +++- storage/mock_Storage.go | 159 ++++++++++++++++++++++++++++++++++++++++ storage/storage.go | 107 +++++++++++++++++++++------ storage/tmp.go | 37 ---------- storage/tmp_test.go | 72 ------------------ 6 files changed, 263 insertions(+), 153 deletions(-) delete mode 100644 storage/tmp.go delete mode 100644 storage/tmp_test.go diff --git a/collection/cmd/init.go b/collection/cmd/init.go index 83bf654..095b1ab 100644 --- a/collection/cmd/init.go +++ b/collection/cmd/init.go @@ -1,12 +1,10 @@ package cmd import ( - "fmt" "github.com/AmadlaOrg/hery/collection/validation" "github.com/AmadlaOrg/hery/storage" "github.com/spf13/cobra" "log" - "os" ) var InitCmd = &cobra.Command{ @@ -18,33 +16,25 @@ var InitCmd = &cobra.Command{ log.Fatal("Missing collection name.") } - arg := args[0] + collectionName := args[0] // Validate the collection name that is pass in `arg` - if validation.Name(arg) { + if validation.Name(collectionName) { log.Fatal("Collection name is required or is in the wrong format.") } // Retrieve storage path storageService := storage.NewStorageService() - storagePath, err := storageService.Main() + paths, err := storageService.Paths(collectionName) if err != nil { log.Fatal(err) } - // Full path to the target directory - targetDir := fmt.Sprintf("%s/%s", storagePath, arg) - - // Check if the directory exists - if _, err := os.Stat(targetDir); os.IsNotExist(err) { - // Create the directory - err = os.MkdirAll(fmt.Sprintf("%s/entity", targetDir), os.ModePerm) - if err != nil { - log.Fatal(err) - } - fmt.Printf("Directory '%s' with subdirectory 'entity' created.\n", targetDir) - } else { - fmt.Printf("Directory '%s' already exists.\n", targetDir) + err = storageService.MakePaths(*paths) + if err != nil { + return } + + log.Printf("Collection '%s' created within the storage: '%s'.", collectionName, paths.Storage) }, } diff --git a/entity/cmd/validate.go b/entity/cmd/validate.go index 105daa9..86df750 100644 --- a/entity/cmd/validate.go +++ b/entity/cmd/validate.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/AmadlaOrg/hery/entity" - "github.com/AmadlaOrg/hery/entity/get" entityValidation "github.com/AmadlaOrg/hery/entity/validation" "github.com/AmadlaOrg/hery/storage" "github.com/spf13/cobra" @@ -25,6 +24,12 @@ var ValidateCmd = &cobra.Command{ log.Fatal(err) } return + } else if isValidateAll && isRm { + err := cmd.Help() + if err != nil { + log.Fatal(err) + } + return } concoct(cmd, args, func(collectionName string, paths *storage.AbsPaths, args []string) { @@ -38,8 +43,10 @@ var ValidateCmd = &cobra.Command{ log.Fatal("too many entity URIs (the limit is 60)") } + storageService := storage.NewStorageService() + // Replace paths with temporary directory before . - newPaths, err := storage.ReplaceWithTempDir(paths, collectionName) + newPaths, err := storageService.TmpPaths(collectionName) if err != nil { println("error") log.Fatal(err) @@ -55,11 +62,11 @@ var ValidateCmd = &cobra.Command{ println(newPaths.Entities) println(newPaths.Cache) - getService := get.NewGetService() + /*getService := get.NewGetService() err = getService.Get(collectionName, paths, args) if err != nil { log.Fatalf("Error getting entity: %s", err) - } + }*/ } println(args) diff --git a/storage/mock_Storage.go b/storage/mock_Storage.go index 7ebe3e6..0b85b98 100644 --- a/storage/mock_Storage.go +++ b/storage/mock_Storage.go @@ -119,6 +119,52 @@ func (_c *MockStorage_Main_Call) RunAndReturn(run func() (string, error)) *MockS return _c } +// MakePaths provides a mock function with given fields: paths +func (_m *MockStorage) MakePaths(paths AbsPaths) error { + ret := _m.Called(paths) + + if len(ret) == 0 { + panic("no return value specified for MakePaths") + } + + var r0 error + if rf, ok := ret.Get(0).(func(AbsPaths) error); ok { + r0 = rf(paths) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStorage_MakePaths_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MakePaths' +type MockStorage_MakePaths_Call struct { + *mock.Call +} + +// MakePaths is a helper method to define mock.On call +// - paths AbsPaths +func (_e *MockStorage_Expecter) MakePaths(paths interface{}) *MockStorage_MakePaths_Call { + return &MockStorage_MakePaths_Call{Call: _e.mock.On("MakePaths", paths)} +} + +func (_c *MockStorage_MakePaths_Call) Run(run func(paths AbsPaths)) *MockStorage_MakePaths_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(AbsPaths)) + }) + return _c +} + +func (_c *MockStorage_MakePaths_Call) Return(_a0 error) *MockStorage_MakePaths_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStorage_MakePaths_Call) RunAndReturn(run func(AbsPaths) error) *MockStorage_MakePaths_Call { + _c.Call.Return(run) + return _c +} + // Paths provides a mock function with given fields: collectionName func (_m *MockStorage) Paths(collectionName string) (*AbsPaths, error) { ret := _m.Called(collectionName) @@ -177,6 +223,119 @@ func (_c *MockStorage_Paths_Call) RunAndReturn(run func(string) (*AbsPaths, erro return _c } +// TmpMain provides a mock function with given fields: +func (_m *MockStorage) TmpMain() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for TmpMain") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStorage_TmpMain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TmpMain' +type MockStorage_TmpMain_Call struct { + *mock.Call +} + +// TmpMain is a helper method to define mock.On call +func (_e *MockStorage_Expecter) TmpMain() *MockStorage_TmpMain_Call { + return &MockStorage_TmpMain_Call{Call: _e.mock.On("TmpMain")} +} + +func (_c *MockStorage_TmpMain_Call) Run(run func()) *MockStorage_TmpMain_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockStorage_TmpMain_Call) Return(_a0 string, _a1 error) *MockStorage_TmpMain_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStorage_TmpMain_Call) RunAndReturn(run func() (string, error)) *MockStorage_TmpMain_Call { + _c.Call.Return(run) + return _c +} + +// TmpPaths provides a mock function with given fields: collectionName +func (_m *MockStorage) TmpPaths(collectionName string) (*AbsPaths, error) { + ret := _m.Called(collectionName) + + if len(ret) == 0 { + panic("no return value specified for TmpPaths") + } + + var r0 *AbsPaths + var r1 error + if rf, ok := ret.Get(0).(func(string) (*AbsPaths, error)); ok { + return rf(collectionName) + } + if rf, ok := ret.Get(0).(func(string) *AbsPaths); ok { + r0 = rf(collectionName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*AbsPaths) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(collectionName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStorage_TmpPaths_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TmpPaths' +type MockStorage_TmpPaths_Call struct { + *mock.Call +} + +// TmpPaths is a helper method to define mock.On call +// - collectionName string +func (_e *MockStorage_Expecter) TmpPaths(collectionName interface{}) *MockStorage_TmpPaths_Call { + return &MockStorage_TmpPaths_Call{Call: _e.mock.On("TmpPaths", collectionName)} +} + +func (_c *MockStorage_TmpPaths_Call) Run(run func(collectionName string)) *MockStorage_TmpPaths_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockStorage_TmpPaths_Call) Return(_a0 *AbsPaths, _a1 error) *MockStorage_TmpPaths_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStorage_TmpPaths_Call) RunAndReturn(run func(string) (*AbsPaths, error)) *MockStorage_TmpPaths_Call { + _c.Call.Return(run) + return _c +} + // NewMockStorage creates a new instance of MockStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewMockStorage(t interface { diff --git a/storage/storage.go b/storage/storage.go index 0f74181..1451a13 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -12,6 +12,9 @@ type Storage interface { Paths(collectionName string) (*AbsPaths, error) Main() (string, error) EntityPath(collectionPath, entityRelativePath string) string + TmpPaths(collectionName string) (*AbsPaths, error) + TmpMain() (string, error) + MakePaths(paths AbsPaths) error } type AbsPaths struct { @@ -22,42 +25,34 @@ type AbsPaths struct { Cache string } +const perm os.FileMode = os.ModePerm + var ( - osGetenv = os.Getenv osGetwd = os.Getwd filepathAbs = filepath.Abs filepathJoin = filepath.Join fileExists = file.Exists + osMkdirAll = os.MkdirAll + osMkdirTemp = os.MkdirTemp ) -// Paths returns the absolute path to where the entities are stored +// Paths returns the absolute paths for the different parts of storage func (d *AbsPaths) Paths(collectionName string) (*AbsPaths, error) { mainPath, err := d.Main() if err != nil { return &AbsPaths{}, err } - catalogPath := d.catalogPath(mainPath) - collectionPath := d.collectionPath(catalogPath, collectionName) - entityPath := d.entitiesPath(collectionPath) - cachePath := d.cachePath(collectionName, collectionPath) - - return &AbsPaths{ - Storage: mainPath, - Catalog: catalogPath, - Collection: collectionPath, - Entities: entityPath, - Cache: cachePath, - }, nil + return d.paths(mainPath, collectionName) } -// Main returns the main path for .hery storage path +// Main returns the main path for `.hery` storage path func (d *AbsPaths) Main() (string, error) { // // Using env var // - envStoragePathValue := osGetenv(HeryStoragePath) + envStoragePathValue := os.Getenv(HeryStoragePath) if envStoragePathValue != "" { envStoragePath, err := filepathAbs(envStoragePathValue) @@ -89,7 +84,7 @@ func (d *AbsPaths) Main() (string, error) { var mainDir string switch runtime.GOOS { case "windows": - appDataDir := osGetenv("APPDATA") + appDataDir := os.Getenv("APPDATA") mainDir = filepathJoin(appDataDir, "Hery") default: // "linux" and "darwin" (macOS) homeDir, err := os.UserHomeDir() @@ -102,6 +97,79 @@ func (d *AbsPaths) Main() (string, error) { return mainDir, nil } +// EntityPath returns the absolute path to a specific entity +func (d *AbsPaths) EntityPath(entitiesPath, entityRelativePath string) string { + return filepathJoin(entitiesPath, entityRelativePath) +} + +// TmpPaths returns the tmp absolute paths for the different parts of storage +func (d *AbsPaths) TmpPaths(collectionName string) (*AbsPaths, error) { + mainTmpPath, err := d.TmpMain() + if err != nil { + return &AbsPaths{}, err + } + + return d.paths(mainTmpPath, collectionName) +} + +// TmpMain returns the tmp main path for `.hery` storage path +func (d *AbsPaths) TmpMain() (string, error) { + tempDir, err := osMkdirTemp("", "hery_*") + if err != nil { + return "", err + } + + storageTmpPath := filepath.Join(tempDir, ".hery") + err = osMkdirAll(storageTmpPath, perm) + if err != nil { + return "", err + } + + return storageTmpPath, nil +} + +// MakePaths makes all the storage subdirectories +func (d *AbsPaths) MakePaths(paths AbsPaths) error { + err := osMkdirAll(paths.Storage, perm) + if err != nil { + return err + } + + err = osMkdirAll(paths.Catalog, perm) + if err != nil { + return err + } + + err = osMkdirAll(paths.Collection, perm) + if err != nil { + return err + } + + err = osMkdirAll(paths.Entities, perm) + if err != nil { + return err + } + + return nil +} + +// paths internal function to generate the paths for different part of storage based on main path and collection name +func (d *AbsPaths) paths(mainPath, collectionName string) (*AbsPaths, error) { + catalogPath := d.catalogPath(mainPath) + collectionPath := d.collectionPath(catalogPath, collectionName) + entityPath := d.entitiesPath(collectionPath) + cachePath := d.cachePath(collectionName, collectionPath) + + return &AbsPaths{ + Storage: mainPath, + Catalog: catalogPath, + Collection: collectionPath, + Entities: entityPath, + Cache: cachePath, + }, nil +} + +// catalogPath returns the catalog absolute path func (d *AbsPaths) catalogPath(mainPath string) string { return filepathJoin(mainPath, "collection") } @@ -120,8 +188,3 @@ func (d *AbsPaths) entitiesPath(collectionPath string) string { func (d *AbsPaths) cachePath(collectionName, collectionPath string) string { return filepathJoin(collectionPath, fmt.Sprintf("%s.cache", collectionName)) } - -// EntityPath returns the absolute path to a specific entity -func (d *AbsPaths) EntityPath(entitiesPath, entityRelativePath string) string { - return filepathJoin(entitiesPath, entityRelativePath) -} diff --git a/storage/tmp.go b/storage/tmp.go deleted file mode 100644 index 010c6ce..0000000 --- a/storage/tmp.go +++ /dev/null @@ -1,37 +0,0 @@ -package storage - -import ( - "fmt" - "log" - "os" - "path/filepath" - "strings" -) - -// ReplaceWithTempDir -func ReplaceWithTempDir(paths *AbsPaths, collectionName string) (*AbsPaths, error) { - // Create a temporary directory - tempDir, err := os.MkdirTemp("", "tempdir_*") - if err != nil { - return nil, fmt.Errorf("failed to create temp directory: %w", err) - } - - // Replace the prefix before . with the tempDir path - replacePath := func(originalPath string) string { - // Find the part of the path that starts with . - collectionIndex := strings.Index(originalPath, fmt.Sprintf(".%s", collectionName)) - if collectionIndex == -1 { - log.Fatalf("collectionName '%s' not found in path: %s", collectionName, originalPath) - } - // Join the tempDir with the part after . - return filepath.Join(tempDir, originalPath[collectionIndex:]) - } - - // Return new paths with replacements - return &AbsPaths{ - Storage: replacePath(paths.Storage), - Collection: replacePath(paths.Collection), - Entities: replacePath(paths.Entities), - Cache: replacePath(paths.Cache), - }, nil -} diff --git a/storage/tmp_test.go b/storage/tmp_test.go deleted file mode 100644 index daa9695..0000000 --- a/storage/tmp_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package storage - -import ( - "os" - "path/filepath" - "strings" - "testing" -) - -func TestReplaceWithTempDir(t *testing.T) { - // Test input - paths := &AbsPaths{ - Storage: "/some/path/to/.hery/", - Catalog: "/some/path/to/.hery/collection", - Collection: "/some/path/to/.hery/collection/collectionName", - Entities: "/some/path/to/.hery/collection/collectionName/entity", - Cache: "/some/path/to/.hery/collection/collectionName/collectionName.cache", - } - - collectionName := "collectionName" - - // Call the function - newPaths, err := ReplaceWithTempDir(paths, collectionName) - if err != nil { - t.Fatalf("ReplaceWithTempDir returned an error: %v", err) - } - - // Check if the temp directory was correctly created - tempDir := filepath.Dir(newPaths.Storage) - if !strings.HasPrefix(tempDir, os.TempDir()) { - t.Errorf("Expected new paths to start with temp directory, got %s", tempDir) - } - - // Validate that each path is correctly replaced - expectedSuffix := filepath.Join(".collectionName", "storage") - if !strings.HasSuffix(newPaths.Storage, expectedSuffix) { - t.Errorf("Expected storage path to end with %s, got %s", expectedSuffix, newPaths.Storage) - } - - expectedSuffix = filepath.Join(".collectionName", "collection") - if !strings.HasSuffix(newPaths.Collection, expectedSuffix) { - t.Errorf("Expected collection path to end with %s, got %s", expectedSuffix, newPaths.Collection) - } - - expectedSuffix = filepath.Join(".collectionName", "entities") - if !strings.HasSuffix(newPaths.Entities, expectedSuffix) { - t.Errorf("Expected entities path to end with %s, got %s", expectedSuffix, newPaths.Entities) - } - - expectedSuffix = filepath.Join(".collectionName", "cache") - if !strings.HasSuffix(newPaths.Cache, expectedSuffix) { - t.Errorf("Expected cache path to end with %s, got %s", expectedSuffix, newPaths.Cache) - } - - // Check for invalid collectionName case - invalidPaths := &AbsPaths{ - Storage: "/some/path/to/.hery/", - Catalog: "/some/path/to/.hery/collection", - Collection: "/some/path/to/.hery/collection/collectionName", - Entities: "/some/path/to/.hery/collection/collectionName/entities", - Cache: "/some/path/to/.hery/collection/collectionName/cache", - } - - defer func() { - if r := recover(); r == nil { - t.Errorf("Expected panic when collectionName is not found in paths, but got none") - } - }() - - // This should cause a panic due to invalid paths - _, _ = ReplaceWithTempDir(invalidPaths, collectionName) -}