tree.go

  1package repo
  2
  3import (
  4	"fmt"
  5
  6	"github.com/charmbracelet/soft-serve/cmd"
  7	"github.com/charmbracelet/soft-serve/git"
  8	"github.com/charmbracelet/soft-serve/pkg/access"
  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		RunE: func(co *cobra.Command, args []string) error {
 22			ctx := co.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
 35			rr, err := be.Repository(ctx, rn)
 36			if err != nil {
 37				return err
 38			}
 39
 40			if !cmd.CheckUserHasAccess(co, rr.Name(), access.ReadOnlyAccess) {
 41				return proto.ErrUnauthorized
 42			}
 43
 44			r, err := rr.Open()
 45			if err != nil {
 46				return err
 47			}
 48
 49			if ref == "" {
 50				head, err := r.HEAD()
 51				if err != nil {
 52					if bs, err := r.Branches(); err != nil && len(bs) == 0 {
 53						return fmt.Errorf("repository is empty")
 54					}
 55					return err
 56				}
 57
 58				ref = head.ID
 59			}
 60
 61			tree, err := r.LsTree(ref)
 62			if err != nil {
 63				return err
 64			}
 65
 66			ents := git.Entries{}
 67			if path != "" && path != "/" {
 68				te, err := tree.TreeEntry(path)
 69				if err == git.ErrRevisionNotExist {
 70					return proto.ErrFileNotFound
 71				}
 72				if err != nil {
 73					return err
 74				}
 75				if te.Type() == "tree" {
 76					tree, err = tree.SubTree(path)
 77					if err != nil {
 78						return err
 79					}
 80					ents, err = tree.Entries()
 81					if err != nil {
 82						return err
 83					}
 84				} else {
 85					ents = append(ents, te)
 86				}
 87			} else {
 88				ents, err = tree.Entries()
 89				if err != nil {
 90					return err
 91				}
 92			}
 93			ents.Sort()
 94			for _, ent := range ents {
 95				size := ent.Size()
 96				ssize := ""
 97				if size == 0 {
 98					ssize = "-"
 99				} else {
100					ssize = humanize.Bytes(uint64(size))
101				}
102				co.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, ent.Name())
103			}
104			return nil
105		},
106	}
107	return cmd
108}