soft-serve

Fork https://github.com/charmbracelet/soft-serve

git clone git://git.lin.moe/go/soft-serve.git

  1package cmd
  2
  3import (
  4	"fmt"
  5	"strconv"
  6	"strings"
  7
  8	"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)
 14
 15// 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 err
 38			}
 39
 40			r, err := rr.Open()
 41			if err != nil {
 42				return err
 43			}
 44
 45			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 err
 52				}
 53
 54				ref = head.ID
 55			}
 56
 57			tree, err := r.LsTree(ref)
 58			if err != nil {
 59				return err
 60			}
 61
 62			ents := git.Entries{}
 63			if path != "" && path != "/" {
 64				te, err := tree.TreeEntry(path)
 65				if err == git.ErrRevisionNotExist {
 66					return proto.ErrFileNotFound
 67				}
 68				if err != nil {
 69					return err
 70				}
 71				if te.Type() == "tree" {
 72					tree, err = tree.SubTree(path)
 73					if err != nil {
 74						return err
 75					}
 76					ents, err = tree.Entries()
 77					if err != nil {
 78						return err
 79					}
 80				} else {
 81					ents = append(ents, te)
 82				}
 83			} else {
 84				ents, err = tree.Entries()
 85				if err != nil {
 86					return err
 87				}
 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:gosec
 97				}
 98				cmd.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, unquoteFilename(ent.Name()))
 99			}
100			return nil
101		},
102	}
103	return cmd
104}
105
106func unquoteFilename(s string) string {
107	name := s
108	if n, err := strconv.Unquote(`"` + s + `"`); err == nil {
109		name = n
110	}
111
112	name = strconv.Quote(name)
113	return strings.Trim(name, `"`)
114}