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/server/backend"
10 "github.com/spf13/cobra"
11)
12
13// listCommand returns a command that list file or directory at path.
14func listCommand() *cobra.Command {
15 listCmd := &cobra.Command{
16 Use: "list PATH",
17 Aliases: []string{"ls"},
18 Short: "List files at repository.",
19 Args: cobra.RangeArgs(0, 1),
20 PersistentPreRunE: checkIfReadable,
21 RunE: func(cmd *cobra.Command, args []string) error {
22 cfg, s := fromContext(cmd)
23 rn := ""
24 path := ""
25 ps := []string{}
26 if len(args) > 0 {
27 path = filepath.Clean(args[0])
28 ps = strings.Split(path, "/")
29 rn = strings.TrimSuffix(ps[0], ".git")
30 auth := cfg.Access.AccessLevel(rn, s.PublicKey())
31 if auth < backend.ReadOnlyAccess {
32 return ErrUnauthorized
33 }
34 }
35 if path == "" || path == "." || path == "/" {
36 repos, err := cfg.Backend.Repositories()
37 if err != nil {
38 return err
39 }
40 for _, r := range repos {
41 if cfg.Access.AccessLevel(r.Name(), s.PublicKey()) >= backend.ReadOnlyAccess {
42 cmd.Println(r.Name())
43 }
44 }
45 return nil
46 }
47 rr, err := cfg.Backend.Repository(rn)
48 if err != nil {
49 return err
50 }
51 r, err := rr.Open()
52 if err != nil {
53 return err
54 }
55 head, err := r.HEAD()
56 if err != nil {
57 if bs, err := r.Branches(); err != nil && len(bs) == 0 {
58 return fmt.Errorf("repository is empty")
59 }
60 return err
61 }
62 tree, err := r.TreePath(head, "")
63 if err != nil {
64 return err
65 }
66 subpath := strings.Join(ps[1:], "/")
67 ents := git.Entries{}
68 te, err := tree.TreeEntry(subpath)
69 if err == git.ErrRevisionNotExist {
70 return ErrFileNotFound
71 }
72 if err != nil {
73 return err
74 }
75 if te.Type() == "tree" {
76 tree, err = tree.SubTree(subpath)
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 ents.Sort()
88 for _, ent := range ents {
89 cmd.Printf("%s\t%d\t %s\n", ent.Mode(), ent.Size(), ent.Name())
90 }
91 return nil
92 },
93 }
94 return listCmd
95}