types: rework NiceTree to use go-git filemodes #790

merged
opened by oppi.li targeting master from push-lqyxyyrozyxs

we can now differentiate between regular directories and submodules in filetree walkers. this fixes things like broken commit info and language detection in submodules.

Signed-off-by: oppiliappan me@oppi.li

Changed files
+47 -37
appview
knotserver
types
+4 -5
appview/repo/index.go
··· 351 if treeResp != nil && treeResp.Files != nil { 352 for _, file := range treeResp.Files { 353 niceFile := types.NiceTree{ 354 - IsFile: file.Is_file, 355 - IsSubtree: file.Is_subtree, 356 - Name: file.Name, 357 - Mode: file.Mode, 358 - Size: file.Size, 359 } 360 if file.Last_commit != nil { 361 when, _ := time.Parse(time.RFC3339, file.Last_commit.When) 362 niceFile.LastCommit = &types.LastCommitInfo{
··· 351 if treeResp != nil && treeResp.Files != nil { 352 for _, file := range treeResp.Files { 353 niceFile := types.NiceTree{ 354 + Name: file.Name, 355 + Mode: file.Mode, 356 + Size: file.Size, 357 } 358 + 359 if file.Last_commit != nil { 360 when, _ := time.Parse(time.RFC3339, file.Last_commit.When) 361 niceFile.LastCommit = &types.LastCommitInfo{
+2 -2
appview/repo/repo_util.go
··· 17 18 func sortFiles(files []types.NiceTree) { 19 sort.Slice(files, func(i, j int) bool { 20 - iIsFile := files[i].IsFile 21 - jIsFile := files[j].IsFile 22 if iIsFile != jIsFile { 23 return !iIsFile 24 }
··· 17 18 func sortFiles(files []types.NiceTree) { 19 sort.Slice(files, func(i, j int) bool { 20 + iIsFile := files[i].IsFile() 21 + jIsFile := files[j].IsFile() 22 if iIsFile != jIsFile { 23 return !iIsFile 24 }
+4 -5
appview/repo/tree.go
··· 50 files := make([]types.NiceTree, len(xrpcResp.Files)) 51 for i, xrpcFile := range xrpcResp.Files { 52 file := types.NiceTree{ 53 - Name: xrpcFile.Name, 54 - Mode: xrpcFile.Mode, 55 - Size: int64(xrpcFile.Size), 56 - IsFile: xrpcFile.Is_file, 57 - IsSubtree: xrpcFile.Is_subtree, 58 } 59 // Convert last commit info if present 60 if xrpcFile.Last_commit != nil { ··· 97 } 98 } 99 sortFiles(result.Files) 100 rp.pages.RepoTree(w, pages.RepoTreeParams{ 101 LoggedInUser: user, 102 BreadCrumbs: breadcrumbs,
··· 50 files := make([]types.NiceTree, len(xrpcResp.Files)) 51 for i, xrpcFile := range xrpcResp.Files { 52 file := types.NiceTree{ 53 + Name: xrpcFile.Name, 54 + Mode: xrpcFile.Mode, 55 + Size: int64(xrpcFile.Size), 56 } 57 // Convert last commit info if present 58 if xrpcFile.Last_commit != nil { ··· 95 } 96 } 97 sortFiles(result.Files) 98 + 99 rp.pages.RepoTree(w, pages.RepoTreeParams{ 100 LoggedInUser: user, 101 BreadCrumbs: breadcrumbs,
+4 -13
knotserver/git/tree.go
··· 7 "path" 8 "time" 9 10 "github.com/go-git/go-git/v5/plumbing/object" 11 "tangled.org/core/types" 12 ) ··· 53 } 54 55 for _, e := range subtree.Entries { 56 - mode, _ := e.Mode.ToOSFileMode() 57 sz, _ := subtree.Size(e.Name) 58 - 59 fpath := path.Join(parent, e.Name) 60 61 var lastCommit *types.LastCommitInfo ··· 69 70 nts = append(nts, types.NiceTree{ 71 Name: e.Name, 72 - Mode: mode.String(), 73 - IsFile: e.Mode.IsFile(), 74 Size: sz, 75 LastCommit: lastCommit, 76 }) ··· 126 default: 127 } 128 129 - mode, err := e.Mode.ToOSFileMode() 130 - if err != nil { 131 - // TODO: log this 132 - continue 133 - } 134 - 135 if e.Mode.IsFile() { 136 - err = cb(e, currentTree, root) 137 - if errors.Is(err, TerminateWalk) { 138 return err 139 } 140 } 141 142 // e is a directory 143 - if mode.IsDir() { 144 subtree, err := currentTree.Tree(e.Name) 145 if err != nil { 146 return fmt.Errorf("sub tree %s: %w", e.Name, err)
··· 7 "path" 8 "time" 9 10 + "github.com/go-git/go-git/v5/plumbing/filemode" 11 "github.com/go-git/go-git/v5/plumbing/object" 12 "tangled.org/core/types" 13 ) ··· 54 } 55 56 for _, e := range subtree.Entries { 57 sz, _ := subtree.Size(e.Name) 58 fpath := path.Join(parent, e.Name) 59 60 var lastCommit *types.LastCommitInfo ··· 68 69 nts = append(nts, types.NiceTree{ 70 Name: e.Name, 71 + Mode: e.Mode.String(), 72 Size: sz, 73 LastCommit: lastCommit, 74 }) ··· 124 default: 125 } 126 127 if e.Mode.IsFile() { 128 + if err := cb(e, currentTree, root); errors.Is(err, TerminateWalk) { 129 return err 130 } 131 } 132 133 // e is a directory 134 + if e.Mode == filemode.Dir { 135 subtree, err := currentTree.Tree(e.Name) 136 if err != nil { 137 return fmt.Errorf("sub tree %s: %w", e.Name, err)
+1 -1
knotserver/ingester.go
··· 161 162 var pipeline workflow.RawPipeline 163 for _, e := range workflowDir { 164 - if !e.IsFile { 165 continue 166 } 167
··· 161 162 var pipeline workflow.RawPipeline 163 for _, e := range workflowDir { 164 + if !e.IsFile() { 165 continue 166 } 167
+1 -1
knotserver/internal.go
··· 277 278 var pipeline workflow.RawPipeline 279 for _, e := range workflowDir { 280 - if !e.IsFile { 281 continue 282 } 283
··· 277 278 var pipeline workflow.RawPipeline 279 for _, e := range workflowDir { 280 + if !e.IsFile() { 281 continue 282 } 283
+3 -5
knotserver/xrpc/repo_tree.go
··· 67 treeEntries := make([]*tangled.RepoTree_TreeEntry, len(files)) 68 for i, file := range files { 69 entry := &tangled.RepoTree_TreeEntry{ 70 - Name: file.Name, 71 - Mode: file.Mode, 72 - Size: file.Size, 73 - Is_file: file.IsFile, 74 - Is_subtree: file.IsSubtree, 75 } 76 77 if file.LastCommit != nil {
··· 67 treeEntries := make([]*tangled.RepoTree_TreeEntry, len(files)) 68 for i, file := range files { 69 entry := &tangled.RepoTree_TreeEntry{ 70 + Name: file.Name, 71 + Mode: file.Mode, 72 + Size: file.Size, 73 } 74 75 if file.LastCommit != nil {
+28 -5
types/tree.go
··· 4 "time" 5 6 "github.com/go-git/go-git/v5/plumbing" 7 ) 8 9 // A nicer git tree representation. 10 type NiceTree struct { 11 // Relative path 12 - Name string `json:"name"` 13 - Mode string `json:"mode"` 14 - Size int64 `json:"size"` 15 - IsFile bool `json:"is_file"` 16 - IsSubtree bool `json:"is_subtree"` 17 18 LastCommit *LastCommitInfo `json:"last_commit,omitempty"` 19 } 20 21 type LastCommitInfo struct { 22 Hash plumbing.Hash 23 Message string
··· 4 "time" 5 6 "github.com/go-git/go-git/v5/plumbing" 7 + "github.com/go-git/go-git/v5/plumbing/filemode" 8 ) 9 10 // A nicer git tree representation. 11 type NiceTree struct { 12 // Relative path 13 + Name string `json:"name"` 14 + Mode string `json:"mode"` 15 + Size int64 `json:"size"` 16 17 LastCommit *LastCommitInfo `json:"last_commit,omitempty"` 18 } 19 20 + func (t *NiceTree) FileMode() (filemode.FileMode, error) { 21 + return filemode.New(t.Mode) 22 + } 23 + 24 + func (t *NiceTree) IsFile() bool { 25 + m, err := t.FileMode() 26 + 27 + if err != nil { 28 + return false 29 + } 30 + 31 + return m.IsFile() 32 + } 33 + 34 + func (t *NiceTree) IsSubmodule() bool { 35 + m, err := t.FileMode() 36 + 37 + if err != nil { 38 + return false 39 + } 40 + 41 + return m == filemode.Submodule 42 + } 43 + 44 type LastCommitInfo struct { 45 Hash plumbing.Hash 46 Message string