github.com/shved/got@v0.0.0-20230322140632-a4bfa1e99685/got/got.go (about) 1 // Package got holds all the global repo vars and functions. 2 package got 3 4 import ( 5 "errors" 6 "io/ioutil" 7 "log" 8 "os" 9 "path" 10 "path/filepath" 11 "sort" 12 "strings" 13 ) 14 15 var ( 16 ErrRepoAlreadyInited = errors.New("repo already initialized") 17 ErrInvalidObjType = errors.New("invalid object type") 18 ErrNotGotRepo = errors.New("not a got repo") 19 ErrWrongRootType = errors.New("only commit could be an object graph root") 20 ErrWrongLogEntryType = errors.New("only commit could be saved in repo logs") 21 ErrObjDoesNotExist = errors.New("object does not exist") 22 ) 23 24 var DefaultIgnoreEntries = []string{ 25 ".gitignore", 26 ".gitkeep", 27 ".git", 28 ".got", 29 ".DS_Store", 30 } 31 32 var AbsRepoRoot string 33 34 var EmptyCommitRef = []byte("0000000000000000000000000000000000000000") 35 36 var ( 37 gotPath string = ".got" 38 objectsPath string = path.Join(gotPath, "objects") 39 headPath string = path.Join(gotPath, "HEAD") 40 logPath string = path.Join(gotPath, "LOG") 41 42 CommitPath string = path.Join(objectsPath, "commit") 43 TreePath string = path.Join(objectsPath, "tree") 44 BlobPath string = path.Join(objectsPath, "blob") 45 46 logsHeader string = "Time\t\t\tCommit hash\t\t\t\t\tParent hash\t\t\t\t\tCommit message\n" 47 ) 48 49 // InitRepo initializes a repo in a current working directory by creating a .got dir with all the needing content. 50 func InitRepo() { 51 if _, err := os.Stat(gotPath); !os.IsNotExist(err) { 52 log.Fatal(ErrRepoAlreadyInited) 53 } 54 55 err := os.Mkdir(gotPath, 0755) 56 err = os.Mkdir(objectsPath, 0755) 57 err = os.Mkdir(CommitPath, 0755) 58 err = os.Mkdir(TreePath, 0755) 59 err = os.Mkdir(BlobPath, 0755) 60 err = ioutil.WriteFile(headPath, EmptyCommitRef, 0644) 61 _, err = os.Create(logPath) 62 63 if err != nil { 64 log.Fatal(err) 65 } 66 } 67 68 // SetRepoRoot finds closer .got dir in parent paths and sets its absolute path into an exported variable. 69 func SetRepoRoot() { 70 AbsRepoRoot = getRepoRoot() 71 } 72 73 // CommitDirAbsPath returns absolute path holding commit objects. 74 func CommitDirAbsPath() string { 75 return path.Join(AbsRepoRoot, CommitPath) 76 } 77 78 // TreeDirAbsPath returns absolute path holding tree objects. 79 func TreeDirAbsPath() string { 80 return path.Join(AbsRepoRoot, TreePath) 81 } 82 83 // BlobDirAbsPath returns absolute path holding blob objects. 84 func BlobDirAbsPath() string { 85 return path.Join(AbsRepoRoot, BlobPath) 86 } 87 88 // HeadsAbsPath returns absolute HEAD file path. 89 func HeadAbsPath() string { 90 return path.Join(AbsRepoRoot, headPath) 91 } 92 93 // HeadsAbsPath returns absolute LOG file path. 94 func LogAbsPath() string { 95 return path.Join(AbsRepoRoot, logPath) 96 } 97 98 // ReadLog reads all LOG file contents, reverses it for the right historical order, ads headers 99 // and returns the result as a string. 100 func ReadLog() string { 101 contents, err := ioutil.ReadFile(LogAbsPath()) 102 if err != nil { 103 log.Fatal(err) 104 } 105 withHeaders := string(contents) + logsHeader 106 entries := strings.Split(withHeaders, "\n") 107 sort.Sort(sort.Reverse(sort.StringSlice(entries))) 108 logs := strings.Join(entries, "\n") 109 return logs 110 } 111 112 // UpdateLog adds a log entry into a LOG file. 113 func UpdateLog(entry string) { 114 f, err := os.OpenFile(LogAbsPath(), os.O_APPEND|os.O_WRONLY, 0644) 115 defer f.Close() 116 _, err = f.WriteString(entry) 117 118 if err != nil { 119 log.Fatal(err) 120 } 121 } 122 123 // UpdateHead refresh last commit hash string in a HEAD file. 124 func UpdateHead(sha string) { 125 if err := ioutil.WriteFile(HeadAbsPath(), []byte(sha), 0644); err != nil { 126 log.Fatal(err) 127 } 128 } 129 130 // ReadHead reads commit hash string from a HEAD file. 131 func ReadHead() string { 132 commitSha, err := ioutil.ReadFile(HeadAbsPath()) 133 if err != nil { 134 log.Fatal(err) 135 } 136 return string(commitSha) 137 } 138 139 func getRepoRoot() string { 140 relPath := getRootRelPath() 141 absPath, err := filepath.Abs(relPath) 142 if err != nil { 143 log.Fatal(err) 144 } 145 return absPath 146 } 147 148 func getRootRelPath() string { 149 path := "." 150 if isRepoRoot(path) { 151 return path 152 } 153 154 path = ".." 155 156 for { 157 if abs, _ := filepath.Abs(path); abs == string(filepath.Separator) { 158 log.Fatal(ErrNotGotRepo) 159 } 160 if isRepoRoot(path) { 161 return path 162 } 163 path = path + string(filepath.Separator) + ".." 164 } 165 166 log.Fatal(ErrNotGotRepo) 167 panic("never reach") 168 } 169 170 func isRepoRoot(path string) bool { 171 files, err := ioutil.ReadDir(path) 172 if err != nil { 173 log.Fatal(err) 174 } 175 176 for _, file := range files { 177 if file.Name() == gotPath { 178 return true 179 } 180 } 181 182 return false 183 }