tree.go

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