1package cmd23import (4 "fmt"5 "strconv"6 "strings"78 "github.com/charmbracelet/soft-serve/git"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)1415// 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 PersistentPreRunE: checkIfReadable,22 RunE: func(cmd *cobra.Command, args []string) error {23 ctx := cmd.Context()24 be := backend.FromContext(ctx)25 rn := args[0]26 path := ""27 ref := ""28 switch len(args) {29 case 2:30 path = args[1]31 case 3:32 ref = args[1]33 path = args[2]34 }35 rr, err := be.Repository(ctx, rn)36 if err != nil {37 return err38 }3940 r, err := rr.Open()41 if err != nil {42 return err43 }4445 if ref == "" {46 head, err := r.HEAD()47 if err != nil {48 if bs, err := r.Branches(); err != nil && len(bs) == 0 {49 return fmt.Errorf("repository is empty")50 }51 return err52 }5354 ref = head.ID55 }5657 tree, err := r.LsTree(ref)58 if err != nil {59 return err60 }6162 ents := git.Entries{}63 if path != "" && path != "/" {64 te, err := tree.TreeEntry(path)65 if err == git.ErrRevisionNotExist {66 return proto.ErrFileNotFound67 }68 if err != nil {69 return err70 }71 if te.Type() == "tree" {72 tree, err = tree.SubTree(path)73 if err != nil {74 return err75 }76 ents, err = tree.Entries()77 if err != nil {78 return err79 }80 } else {81 ents = append(ents, te)82 }83 } else {84 ents, err = tree.Entries()85 if err != nil {86 return err87 }88 }89 ents.Sort()90 for _, ent := range ents {91 size := ent.Size()92 ssize := ""93 if size == 0 {94 ssize = "-"95 } else {96 ssize = humanize.Bytes(uint64(size)) //nolint:gosec97 }98 cmd.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, unquoteFilename(ent.Name()))99 }100 return nil101 },102 }103 return cmd104}105106func unquoteFilename(s string) string {107 name := s108 if n, err := strconv.Unquote(`"` + s + `"`); err == nil {109 name = n110 }111112 name = strconv.Quote(name)113 return strings.Trim(name, `"`)114}