1package workspace 2 3import ( 4 "os" 5 "path/filepath" 6) 7 8// PathType is either a path to a dir or file, or the name of an exercise. 9type PathType int 10 11const ( 12 // TypeExerciseID is the name of an exercise. 13 TypeExerciseID PathType = iota 14 // TypeDir is a relative or absolute path to a directory. 15 TypeDir 16 // TypeFile is a relative or absolute path to a file. 17 TypeFile 18) 19 20// DetectPathType determines whether the given path is a directory, a file, or the name of an exercise. 21func DetectPathType(path string) (PathType, error) { 22 // If it's not an absolute path, make it one. 23 if !filepath.IsAbs(path) { 24 var err error 25 path, err = filepath.Abs(path) 26 if err != nil { 27 return -1, err 28 } 29 } 30 31 // If it doesn't exist, then it's an exercise name. 32 // We'll have to walk the workspace to find it. 33 if _, err := os.Stat(path); err != nil { 34 return TypeExerciseID, nil 35 } 36 37 // We found it. It's an actual path of some sort. 38 info, err := os.Lstat(path) 39 if err != nil { 40 return -1, err 41 } 42 43 // If it's a symlink, resolve it. 44 if info.Mode()&os.ModeSymlink == os.ModeSymlink { 45 src, err := filepath.EvalSymlinks(path) 46 if err != nil { 47 return -1, err 48 } 49 path = src 50 // Overwrite the symlinked info with the source info. 51 info, err = os.Lstat(path) 52 if err != nil { 53 return -1, err 54 } 55 } 56 57 if info.IsDir() { 58 return TypeDir, nil 59 } 60 return TypeFile, nil 61} 62