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