1package cmd
 2
 3import (
 4	"fmt"
 5	"path/filepath"
 6	"strings"
 7
 8	"github.com/charmbracelet/soft-serve/git"
 9	"github.com/charmbracelet/soft-serve/proto"
10	"github.com/spf13/cobra"
11)
12
13// ListCommand returns a command that list file or directory at path.
14func ListCommand() *cobra.Command {
15	lsCmd := &cobra.Command{
16		Use:     "ls PATH",
17		Aliases: []string{"list"},
18		Short:   "List file or directory at path.",
19		Args:    cobra.RangeArgs(0, 1),
20		RunE: func(cmd *cobra.Command, args []string) error {
21			cfg, s := fromContext(cmd)
22			rn := ""
23			path := ""
24			ps := []string{}
25			if len(args) > 0 {
26				path = filepath.Clean(args[0])
27				ps = strings.Split(path, "/")
28				rn = strings.TrimSuffix(ps[0], ".git")
29				auth := cfg.AuthRepo(rn, s.PublicKey())
30				if auth < proto.ReadOnlyAccess {
31					return ErrUnauthorized
32				}
33			}
34			if path == "" || path == "." || path == "/" {
35				repos, err := cfg.ListRepos()
36				if err != nil {
37					return err
38				}
39				for _, r := range repos {
40					if cfg.AuthRepo(r.Name(), s.PublicKey()) >= proto.ReadOnlyAccess {
41						fmt.Fprintln(s, r.Name())
42					}
43				}
44				return nil
45			}
46			r, err := cfg.Open(rn)
47			if err != nil {
48				return err
49			}
50			head, err := r.Repository().HEAD()
51			if err != nil {
52				return err
53			}
54			tree, err := r.Repository().TreePath(head, "")
55			if err != nil {
56				return err
57			}
58			subpath := strings.Join(ps[1:], "/")
59			ents := git.Entries{}
60			te, err := tree.TreeEntry(subpath)
61			if err == git.ErrRevisionNotExist {
62				return ErrFileNotFound
63			}
64			if err != nil {
65				return err
66			}
67			if te.Type() == "tree" {
68				tree, err = tree.SubTree(subpath)
69				if err != nil {
70					return err
71				}
72				ents, err = tree.Entries()
73				if err != nil {
74					return err
75				}
76			} else {
77				ents = append(ents, te)
78			}
79			ents.Sort()
80			for _, ent := range ents {
81				fmt.Fprintf(s, "%s\t%d\t %s\n", ent.Mode(), ent.Size(), ent.Name())
82			}
83			return nil
84		},
85	}
86	return lsCmd
87}