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