1package repo
2
3import (
4 "fmt"
5
6 "github.com/charmbracelet/soft-serve/cmd"
7 "github.com/charmbracelet/soft-serve/git"
8 "github.com/charmbracelet/soft-serve/pkg/access"
9 "github.com/charmbracelet/soft-serve/pkg/backend"
10 "github.com/charmbracelet/soft-serve/pkg/proto"
11 "github.com/dustin/go-humanize"
12 "github.com/spf13/cobra"
13)
14
15// treeCommand returns a command that list file or directory at path.
16func treeCommand() *cobra.Command {
17 cmd := &cobra.Command{
18 Use: "tree REPOSITORY [REFERENCE] [PATH]",
19 Short: "Print repository tree at path",
20 Args: cobra.RangeArgs(1, 3),
21 RunE: func(co *cobra.Command, args []string) error {
22 ctx := co.Context()
23 be := backend.FromContext(ctx)
24 rn := args[0]
25 path := ""
26 ref := ""
27 switch len(args) {
28 case 2:
29 path = args[1]
30 case 3:
31 ref = args[1]
32 path = args[2]
33 }
34
35 rr, err := be.Repository(ctx, rn)
36 if err != nil {
37 return err
38 }
39
40 if !cmd.CheckUserHasAccess(co, rr.Name(), access.ReadOnlyAccess) {
41 return proto.ErrUnauthorized
42 }
43
44 r, err := rr.Open()
45 if err != nil {
46 return err
47 }
48
49 if ref == "" {
50 head, err := r.HEAD()
51 if err != nil {
52 if bs, err := r.Branches(); err != nil && len(bs) == 0 {
53 return fmt.Errorf("repository is empty")
54 }
55 return err
56 }
57
58 ref = head.ID
59 }
60
61 tree, err := r.LsTree(ref)
62 if err != nil {
63 return err
64 }
65
66 ents := git.Entries{}
67 if path != "" && path != "/" {
68 te, err := tree.TreeEntry(path)
69 if err == git.ErrRevisionNotExist {
70 return proto.ErrFileNotFound
71 }
72 if err != nil {
73 return err
74 }
75 if te.Type() == "tree" {
76 tree, err = tree.SubTree(path)
77 if err != nil {
78 return err
79 }
80 ents, err = tree.Entries()
81 if err != nil {
82 return err
83 }
84 } else {
85 ents = append(ents, te)
86 }
87 } else {
88 ents, err = tree.Entries()
89 if err != nil {
90 return err
91 }
92 }
93 ents.Sort()
94 for _, ent := range ents {
95 size := ent.Size()
96 ssize := ""
97 if size == 0 {
98 ssize = "-"
99 } else {
100 ssize = humanize.Bytes(uint64(size))
101 }
102 co.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, ent.Name())
103 }
104 return nil
105 },
106 }
107 return cmd
108}