From c0f3dbb929971eb584c493fb83b9c27f4fcf6518 Mon Sep 17 00:00:00 2001 From: Vyshnav Vinod Date: Fri, 24 May 2024 20:45:57 +0530 Subject: [PATCH 1/3] Add pathInfo struct --- main.go | 75 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/main.go b/main.go index 9b1f33f..456d01c 100644 --- a/main.go +++ b/main.go @@ -32,6 +32,21 @@ var ( timeStart time.Time ) +type pathInfo struct { + // Stores the user input + userInput string + // Restrict is used to denote whether user has specified + // the parent directory of the directory to search as well. + // Eg: User has specified "parent/searchfolder" + // We must only find "searchfolder" which is a child of the + // directory named "parent". Any other folders named + // "searchfolder" will be rejected if their parent directory + // is not "parent" + restrict bool + // Full path (if found) + path string +} + func main() { // Ignore, This is a build flag for testing purposes @@ -77,7 +92,7 @@ func main() { } if previousDir { path, _ := filepath.Abs(c.GetPreviousDir()) - os.Exit(success(os.Stdout, path, c)) + os.Exit(success(os.Stdout, pathInfo{path: path, restrict: false, userInput: filepath.Base(path)}, c)) } if path == "" { flaggy.ShowHelpAndExit("Please provide arguments") @@ -91,9 +106,9 @@ func main() { } } -func pathfinder(w io.Writer, c *Cache, ignoreDir bool, path string) int { +func pathfinder(w io.Writer, c *Cache, ignoreDir bool, searchPath string) int { - absPath, err := filepath.Abs(path) + absPath, err := filepath.Abs(searchPath) if err != nil { HandleError(err) } @@ -105,40 +120,44 @@ func pathfinder(w io.Writer, c *Cache, ignoreDir bool, path string) int { if _, err := os.Stat(absPath); !os.IsNotExist(err) { // To support ~, .. , etc if !ignoreDir { - return success(w, absPath, c) + return success(w, pathInfo{path: absPath, restrict: false, userInput: filepath.Base(absPath)}, c) } else { if !strings.Contains(absPath, cwd) { // Check if it is in current directory - return success(w, absPath, c) + return success(w, pathInfo{path: absPath, restrict: false, userInput: filepath.Base(absPath)}, c) } } } + pathInfo := pathInfo{userInput: searchPath} + pathInfo.restrict = !(len(strings.Split(searchPath, "/")) == 1) + // Assume that the path is not an actual path but a search query by the user and it might exist - if cacheEntry, ok := c.GetCacheEntry(filepath.Base(path)); ok { + if cacheEntry, ok := c.GetCacheEntry(pathInfo); ok { if !ignoreDir { - return success(w, cacheEntry.Path, c) + pathInfo.path = cacheEntry.Path + return success(w, pathInfo, c) } else { if !strings.Contains(cacheEntry.Path, cwd) { // Check if it is in current directory - return success(w, cacheEntry.Path, c) + pathInfo.path = cacheEntry.Path + return success(w, pathInfo, c) } } } - var pathReturned string dirsAlreadyWalked := make(map[string]struct{}) // to ignore walking through already walked directories // TODO: Goroutines or a new algorithm if !ignoreDir { - if traverseAndMatchDir(w, cwd, path, &pathReturned, dirsAlreadyWalked, c) { + if traverseAndMatchDir(w, cwd, pathInfo, &pathInfo.path, dirsAlreadyWalked, c) { // Walk inside working directory - return success(w, pathReturned, c) + return success(w, pathInfo, c) } } dirsAlreadyWalked[cwd] = struct{}{} - if traverseAndMatchDir(w, filepath.Dir(cwd), path, &pathReturned, dirsAlreadyWalked, c) { + if traverseAndMatchDir(w, filepath.Dir(cwd), pathInfo, &pathInfo.path, dirsAlreadyWalked, c) { // Walk from one directory above - return success(w, pathReturned, c) + return success(w, pathInfo, c) } usrHome, err := os.UserHomeDir() @@ -146,19 +165,19 @@ func pathfinder(w io.Writer, c *Cache, ignoreDir bool, path string) int { HandleError(err) } dirsAlreadyWalked[filepath.Dir(cwd)] = struct{}{} - if traverseAndMatchDir(w, usrHome, path, &pathReturned, dirsAlreadyWalked, c) { + if traverseAndMatchDir(w, usrHome, pathInfo, &pathInfo.path, dirsAlreadyWalked, c) { // Walk from $HOME - return success(w, pathReturned, c) + return success(w, pathInfo, c) } // pathfinder failed to find the directory and prints // the path (user input) to stdout for the bash script // to capture and return as an error msg - fmt.Fprint(w, path) + fmt.Fprint(w, searchPath) return EXIT_FOLDERNOTFOUND } -func traverseAndMatchDir(w io.Writer, dirName string, searchDir string, pathReturned *string, dirsAlreadyWalked map[string]struct{}, c *Cache) bool { +func traverseAndMatchDir(w io.Writer, dirName string, searchDir pathInfo, pathReturned *string, dirsAlreadyWalked map[string]struct{}, c *Cache) bool { if strings.HasPrefix(filepath.Base(dirName), ".") { return false } @@ -184,9 +203,20 @@ func traverseAndMatchDir(w io.Writer, dirName string, searchDir string, pathRetu continue } if f.IsDir() { - if f.Name() == searchDir { - *pathReturned = path - return true + if f.Name() == filepath.Base(searchDir.userInput) { + if !searchDir.restrict { + *pathReturned = path + return true + } else { + if strings.Contains(path, searchDir.userInput) { + *pathReturned = path + return true + } else { + if traverseAndMatchDir(w, path, searchDir, pathReturned, dirsAlreadyWalked, c) { + return true + } + } + } } else { if traverseAndMatchDir(w, path, searchDir, pathReturned, dirsAlreadyWalked, c) { return true @@ -198,10 +228,11 @@ func traverseAndMatchDir(w io.Writer, dirName string, searchDir string, pathRetu return false } -func success(w io.Writer, path string, c *Cache) int { +func success(w io.Writer, path pathInfo, c *Cache) int { // Prints to stdout for bash script to capture - fmt.Fprint(w, path) + fmt.Fprint(w, path.path) c.SetPreviousDir() + fmt.Println("\nentry : ", path) c.SetCacheEntry(path) return EXIT_SUCCESS } From fd9d0f7f2cc9e7033ce5efdb55ea4962ae8ee55f Mon Sep 17 00:00:00 2001 From: Vyshnav Vinod Date: Fri, 24 May 2024 21:26:12 +0530 Subject: [PATCH 2/3] Redo cache to work with pathInfo.restrict --- cache.go | 30 ++++++++++++++++++++---------- main.go | 1 - 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/cache.go b/cache.go index b9c9c84..5a600bb 100644 --- a/cache.go +++ b/cache.go @@ -19,6 +19,7 @@ import ( "encoding/json" "os" "path/filepath" + "strings" "time" ) @@ -119,33 +120,42 @@ func (c *Cache) SetPreviousDir() { } } -func (c *Cache) GetCacheEntry(entry string) (cacheEntry CacheEntry, ok bool) { - if cache, found := c.contents[entry]; found { - return cache, true +func (c *Cache) GetCacheEntry(entry pathInfo) (cacheEntry CacheEntry, ok bool) { + baseInput := filepath.Base(entry.userInput) + if cache, found := c.contents[baseInput]; found { + if !entry.restrict { + return cache, true + } else { + if strings.Contains(cache.Path, entry.userInput) { + return cache, true + } + } } return CacheEntry{}, false } -func (c *Cache) SetCacheEntry(entry string) { +func (c *Cache) SetCacheEntry(entry pathInfo) { // Shoudl check if entry is in cache ,if yes just update // else pop from cache and add new entry home, _ := os.UserHomeDir() - if !(entry == home) { // Do not add home directory to cache - if cacheEntry, ok := c.GetCacheEntry(filepath.Base(entry)); ok { - if cacheEntry.Path == entry { - c.contents[filepath.Base(entry)] = CacheEntry{ + if !((entry.path) == home) { + if cacheEntry, ok := c.GetCacheEntry(entry); ok { + if cacheEntry.Path == entry.path { + c.contents[filepath.Base(entry.path)] = CacheEntry{ Path: cacheEntry.Path, Frequency: cacheEntry.Frequency + 1, LastHit: time.Now(), } } + // TODO: Else condition } else { - c.contents[filepath.Base(entry)] = CacheEntry{ - Path: entry, + c.contents[filepath.Base(entry.path)] = CacheEntry{ + Path: entry.path, Frequency: 0, LastHit: time.Now(), } } + if len(c.contents) > (c.maxCap + 1) { // +1 to denote the previous dir store c.popCache() } diff --git a/main.go b/main.go index 456d01c..e5caa1e 100644 --- a/main.go +++ b/main.go @@ -232,7 +232,6 @@ func success(w io.Writer, path pathInfo, c *Cache) int { // Prints to stdout for bash script to capture fmt.Fprint(w, path.path) c.SetPreviousDir() - fmt.Println("\nentry : ", path) c.SetCacheEntry(path) return EXIT_SUCCESS } From 61c9e9f2aff36f89297c8536271b4877ab6a63af Mon Sep 17 00:00:00 2001 From: Vyshnav Vinod Date: Fri, 24 May 2024 22:56:58 +0530 Subject: [PATCH 3/3] Redo tests to support pathInfo.restrict --- cache.go | 2 ++ cache_test.go | 62 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/cache.go b/cache.go index 5a600bb..9f7f6da 100644 --- a/cache.go +++ b/cache.go @@ -200,3 +200,5 @@ func (c *Cache) cleanCache() { HandleError(err) } } + +// TODO: Add logging while in DEV \ No newline at end of file diff --git a/cache_test.go b/cache_test.go index c2eabad..1ab3e12 100644 --- a/cache_test.go +++ b/cache_test.go @@ -15,7 +15,7 @@ var c Cache var ( toPopEntryLRU = "entry/to/pop/LRU" // will be popped according to LRU - toPopEntryLFU = "entry/to/popLFU" // Will be popped according to LFU + toPopEntryLFU = "entry/to/pop/LFU" // Will be popped according to LFU ) @@ -65,30 +65,64 @@ func Test_validateCache(t *testing.T) { } } +// TODO: Make this cleaner func Test_SetCacheEntry(t *testing.T) { - entry := "random/entry" - for i := 0; i < 2; i++ { + entries := []pathInfo{ + { + userInput: "entry", + restrict: false, + path: "file/path/entry", + }, + { + userInput: "path/entry", + restrict: true, + path: "file/path/entry", + }, + } + for _, entry := range entries { c.SetCacheEntry(entry) - ce, got := c.GetCacheEntry(filepath.Base(entry)) + _, got := c.GetCacheEntry(entry) if !got { - t.Errorf("SetCacheEntry() failed to add %s to cache", entry) - } - if ce.Frequency != i { - t.Errorf("SetCacheEntry() got frequency = %d, want = %d", ce.Frequency, i) + t.Errorf("SetCacheEntry() failed to add %v to cache", entry) } } - c.SetCacheEntry(toPopEntryLRU) - c.SetCacheEntry(toPopEntryLFU) + test_entries_popCache := []pathInfo{ + { + userInput: filepath.Base(toPopEntryLRU), + restrict: false, + path: toPopEntryLRU, + }, + { + userInput: filepath.Base(toPopEntryLFU), + restrict: false, + path: toPopEntryLFU, + }, + } + for _, entry := range test_entries_popCache { + c.SetCacheEntry(entry) + } } // Test for popCache is depended on test for SetCacheEntry func Test_popCache(t *testing.T) { c.LoadCache() - var popEntries = []string{toPopEntryLRU, toPopEntryLFU} - for _, j := range popEntries { + // fmt.Println(c.contents) + var popEntries = []pathInfo{ + { + userInput: filepath.Base(toPopEntryLRU), + restrict: false, + path: toPopEntryLRU, + }, + { + userInput: filepath.Base(toPopEntryLFU), + restrict: false, + path: toPopEntryLFU, + }, + } + for _, e := range popEntries { c.popCache() - if entry, ok := c.GetCacheEntry(filepath.Base(j)); ok { - t.Errorf("popCache() failed to pop %v", entry) + if ce, got := c.GetCacheEntry(e); got { + t.Errorf("popEntry() failed to pop %v ", ce) } } }