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