github.com/tilt-dev/wat@v0.0.2-0.20180626175338-9349b638e250/data/pathutil/pathutil.go (about) 1 // Common utilities for DB paths and OS paths 2 3 package pathutil 4 5 import ( 6 "strings" 7 ) 8 9 type PathUtil interface { 10 Base(path string) string 11 Dir(path string) string 12 Join(dir, base string) string 13 Match(pattern, name string) (matched bool, err error) 14 Separator() rune 15 } 16 17 // Split the path into (firstDir, rest). Note that this is 18 // different from normal Split(), which splits things into (dir, base). 19 // SplitFirst is better for matching algorithms. 20 // 21 // If the path cannot be split, returns (p, ""). 22 func SplitFirst(util PathUtil, p string) (string, string) { 23 firstSlash := strings.IndexRune(p, util.Separator()) 24 if firstSlash == -1 { 25 return p, "" 26 } 27 28 return p[0:firstSlash], p[firstSlash+1:] 29 } 30 31 // Given absolute paths `dir` and `file`, returns 32 // the relative path of `file` relative to `dir`. 33 // 34 // Returns true if successful. If `file` is not under `dir`, returns false. 35 func Child(util PathUtil, dir, file string) (string, bool) { 36 current := file 37 child := "" 38 for true { 39 if dir == current { 40 return child, true 41 } 42 43 if len(current) <= len(dir) || current == "." { 44 return "", false 45 } 46 47 cDir := util.Dir(current) 48 cBase := util.Base(current) 49 child = util.Join(cBase, child) 50 current = cDir 51 } 52 53 return "", false 54 } 55 56 // Like Child(), but file is a pattern instead of a path. 57 func childPattern(util PathUtil, dir, filePattern string) (string, bool) { 58 current := filePattern 59 child := "" 60 for true { 61 matched := (&patternMatcher{util: util, pattern: current}).Match(dir) 62 if matched { 63 // The recursive glob (**) can match multiple directories. 64 // So if current terminates in a recursive glob, then the child pattern 65 // must also begin with a recursive glob. 66 currentBase := util.Base(current) 67 if currentBase == "**" { 68 return util.Join("**", child), true 69 } 70 71 return child, true 72 } 73 74 if current == "." || current == "" { 75 return "", false 76 } 77 78 cDir := util.Dir(current) 79 cBase := util.Base(current) 80 child = util.Join(cBase, child) 81 current = cDir 82 } 83 84 return "", false 85 }