42774038e3a8e5c0913c0f520c9cf7563a84e028
- Author
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Committer
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/git/repo.go b/git/repo.go
2index 9d1f49d776e763fa2fb30be2c36fcc3f6259305f..e91df362e4558b87ab00ae8a89c5e5c59d2ffd2a 100644
3--- a/git/repo.go
4+++ b/git/repo.go
5@@ -114,6 +114,19 @@ func (r *Repository) References() ([]*Reference, error) {
6 return rrefs, nil
7 }
8
9+// LsTree returns the tree for the given reference.
10+func (r *Repository) LsTree(ref string) (*Tree, error) {
11+ tree, err := r.Repository.LsTree(ref)
12+ if err != nil {
13+ return nil, err
14+ }
15+ return &Tree{
16+ Tree: tree,
17+ Path: "",
18+ Repository: r,
19+ }, nil
20+}
21+
22 // Tree returns the tree for the given reference.
23 func (r *Repository) Tree(ref *Reference) (*Tree, error) {
24 if ref == nil {
25@@ -123,15 +136,7 @@ func (r *Repository) Tree(ref *Reference) (*Tree, error) {
26 }
27 ref = rref
28 }
29- tree, err := r.LsTree(ref.Hash.String())
30- if err != nil {
31- return nil, err
32- }
33- return &Tree{
34- Tree: tree,
35- Path: "",
36- Repository: r,
37- }, nil
38+ return r.LsTree(ref.Hash.String())
39 }
40
41 // TreePath returns the tree for the given path.
42diff --git a/server/cmd/show.go b/server/cmd/blob.go
43rename from server/cmd/show.go
44rename to server/cmd/blob.go
45index 14981dc27d95c1ecaa97ec189c3b615e57dbf5b8..58e2361f9342c32d1c482b8b2f5ad2031104c00f 100644
46--- a/server/cmd/show.go
47+++ b/server/cmd/blob.go
48@@ -7,7 +7,7 @@ import (
49 "github.com/alecthomas/chroma/lexers"
50 gansi "github.com/charmbracelet/glamour/ansi"
51 "github.com/charmbracelet/lipgloss"
52- "github.com/charmbracelet/soft-serve/server/backend"
53+ "github.com/charmbracelet/soft-serve/git"
54 "github.com/charmbracelet/soft-serve/ui/common"
55 "github.com/muesli/termenv"
56 "github.com/spf13/cobra"
57@@ -21,60 +21,99 @@ var (
58 filemodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#777777"))
59 )
60
61-// showCommand returns a command that prints the contents of a file.
62-func showCommand() *cobra.Command {
63+// blobCommand returns a command that prints the contents of a file.
64+func blobCommand() *cobra.Command {
65 var linenumber bool
66 var color bool
67+ var raw bool
68
69- showCmd := &cobra.Command{
70- Use: "show PATH",
71- Aliases: []string{"cat"},
72- Short: "Read the contents of file at path.",
73- Args: cobra.ExactArgs(1),
74+ cmd := &cobra.Command{
75+ Use: "blob REPOSITORY [REFERENCE] [PATH]",
76+ Aliases: []string{"cat", "show"},
77+ Short: "Print out the contents of file at path.",
78+ Args: cobra.RangeArgs(1, 3),
79 PersistentPreRunE: checkIfReadable,
80 RunE: func(cmd *cobra.Command, args []string) error {
81 cfg, _ := fromContext(cmd)
82- // FIXME: nested repos are not supported.
83- ps := strings.Split(args[0], "/")
84- rn := strings.TrimSuffix(ps[0], ".git")
85- fp := strings.Join(ps[1:], "/")
86- var repo backend.Repository
87- repoExists := false
88- repos, err := cfg.Backend.Repositories()
89+ rn := args[0]
90+ ref := ""
91+ fp := ""
92+ switch len(args) {
93+ case 2:
94+ fp = args[1]
95+ case 3:
96+ ref = args[1]
97+ fp = args[2]
98+ }
99+
100+ repo, err := cfg.Backend.Repository(rn)
101 if err != nil {
102 return err
103 }
104- for _, rp := range repos {
105- if rp.Name() == rn {
106- repoExists = true
107- repo = rp
108- break
109- }
110- }
111- if !repoExists {
112- return ErrRepoNotFound
113- }
114- c, _, err := backend.LatestFile(repo, fp)
115+
116+ r, err := repo.Open()
117 if err != nil {
118 return err
119 }
120- if color {
121- c, err = withFormatting(fp, c)
122+
123+ if ref == "" {
124+ head, err := r.HEAD()
125 if err != nil {
126 return err
127 }
128+ ref = head.Hash.String()
129+ }
130+
131+ tree, err := r.LsTree(ref)
132+ if err != nil {
133+ return err
134+ }
135+
136+ te, err := tree.TreeEntry(fp)
137+ if err != nil {
138+ return err
139+ }
140+
141+ if te.Type() != "blob" {
142+ return git.ErrFileNotFound
143+ }
144+
145+ bts, err := te.Contents()
146+ if err != nil {
147+ return err
148diff --git a/server/cmd/cmd.go b/server/cmd/cmd.go
149index e32836abb31be39b40829fddcb9f8082aaa8b60e..a23ee8afdb5c752b710b576b579aeec1fdbb5b18 100644
150--- a/server/cmd/cmd.go
151+++ b/server/cmd/cmd.go
152@@ -55,8 +55,9 @@ func rootCommand() *cobra.Command {
153 listCommand(),
154 privateCommand(),
155 renameCommand(),
156- showCommand(),
157+ blobCommand(),
158 tagCommand(),
159+ treeCommand(),
160 )
161
162 return rootCmd
163diff --git a/server/cmd/list.go b/server/cmd/list.go
164index 86f95d7770087a404814c5c23313a5ec03ac61bc..8ed558a15cdfc55d8c9cd19889b03a258c8988d4 100644
165--- a/server/cmd/list.go
166+++ b/server/cmd/list.go
167@@ -1,11 +1,6 @@
168 package cmd
169
170 import (
171- "fmt"
172- "path/filepath"
173- "strings"
174-
175- "github.com/charmbracelet/soft-serve/git"
176 "github.com/charmbracelet/soft-serve/server/backend"
177 "github.com/spf13/cobra"
178 )
179@@ -13,80 +8,20 @@ import (
180 // listCommand returns a command that list file or directory at path.
181 func listCommand() *cobra.Command {
182 listCmd := &cobra.Command{
183- Use: "list PATH",
184+ Use: "list",
185 Aliases: []string{"ls"},
186- Short: "List files at repository.",
187- Args: cobra.RangeArgs(0, 1),
188+ Short: "List repositories.",
189+ Args: cobra.NoArgs,
190 RunE: func(cmd *cobra.Command, args []string) error {
191 cfg, s := fromContext(cmd)
192- rn := ""
193- path := ""
194- ps := []string{}
195- if len(args) > 0 {
196- // FIXME: nested repos are not supported.
197- path = filepath.Clean(args[0])
198- ps = strings.Split(path, "/")
199- rn = strings.TrimSuffix(ps[0], ".git")
200- auth := cfg.Backend.AccessLevel(rn, s.PublicKey())
201- if auth < backend.ReadOnlyAccess {
202- return ErrUnauthorized
203- }
204- }
205- if path == "" || path == "." || path == "/" {
206- repos, err := cfg.Backend.Repositories()
207- if err != nil {
208- return err
209- }
210- for _, r := range repos {
211- if cfg.Backend.AccessLevel(r.Name(), s.PublicKey()) >= backend.ReadOnlyAccess {
212- cmd.Println(r.Name())
213- }
214- }
215- return nil
216- }
217- rr, err := cfg.Backend.Repository(rn)
218- if err != nil {
219- return err
220- }
221- r, err := rr.Open()
222- if err != nil {
223- return err
224- }
225- head, err := r.HEAD()
226- if err != nil {
227- if bs, err := r.Branches(); err != nil && len(bs) == 0 {
228- return fmt.Errorf("repository is empty")
229- }
230- return err
231- }
232- tree, err := r.TreePath(head, "")
233+ repos, err := cfg.Backend.Repositories()
234 if err != nil {
235 return err
236 }
237- subpath := strings.Join(ps[1:], "/")
238- ents := git.Entries{}
239- te, err := tree.TreeEntry(subpath)
240- if err == git.ErrRevisionNotExist {
241- return ErrFileNotFound
242- }
243- if err != nil {
244- return err
245- }
246- if te.Type() == "tree" {
247- tree, err = tree.SubTree(subpath)
248- if err != nil {
249- return err
250+ for _, r := range repos {
251+ if cfg.Backend.AccessLevel(r.Name(), s.PublicKey()) >= backend.ReadOnlyAccess {
252+ cmd.Println(r.Name())
253 }
254- ents, err = tree.Entries()
255- if err != nil {
256- return err
257- }
258- } else {
259- ents = append(ents, te)
260- }
261- ents.Sort()
262- for _, ent := range ents {
263- cmd.Printf("%s\t%d\t %s\n", ent.Mode(), ent.Size(), ent.Name())
264 }
265 return nil
266 },
267diff --git a/server/cmd/tree.go b/server/cmd/tree.go
268new file mode 100644
269index 0000000000000000000000000000000000000000..43be304c6a1eb640ed7748d1408ad6b1fdb5b128
270--- /dev/null
271+++ b/server/cmd/tree.go
272@@ -0,0 +1,99 @@
273+package cmd
274+
275+import (
276+ "fmt"
277+
278+ "github.com/charmbracelet/soft-serve/git"
279+ "github.com/dustin/go-humanize"
280+ "github.com/spf13/cobra"
281+)
282+
283+// treeCommand returns a command that list file or directory at path.
284+func treeCommand() *cobra.Command {
285+ cmd := &cobra.Command{
286+ Use: "tree REPOSITORY [REFERENCE] [PATH]",
287+ Short: "Print repository tree at path.",
288+ Args: cobra.RangeArgs(1, 3),
289+ PersistentPreRunE: checkIfReadable,
290+ RunE: func(cmd *cobra.Command, args []string) error {
291+ cfg, _ := fromContext(cmd)
292+ rn := args[0]
293+ path := ""
294+ ref := ""
295+ switch len(args) {
296+ case 2:
297+ path = args[1]
298+ case 3:
299+ ref = args[1]
300+ path = args[2]
301+ }
302+ rr, err := cfg.Backend.Repository(rn)
303+ if err != nil {
304+ return err
305+ }
306+
307+ r, err := rr.Open()
308+ if err != nil {
309+ return err
310+ }
311+
312+ if ref == "" {
313+ head, err := r.HEAD()
314+ if err != nil {
315+ if bs, err := r.Branches(); err != nil && len(bs) == 0 {
316+ return fmt.Errorf("repository is empty")
317+ }
318+ return err
319+ }
320+
321+ ref = head.Hash.String()
322+ }
323+
324+ tree, err := r.LsTree(ref)
325+ if err != nil {
326+ return err
327+ }
328+
329+ ents := git.Entries{}
330+ if path != "" && path != "/" {
331+ te, err := tree.TreeEntry(path)
332+ if err == git.ErrRevisionNotExist {
333+ return ErrFileNotFound
334+ }
335+ if err != nil {
336+ return err
337+ }
338+ if te.Type() == "tree" {
339+ tree, err = tree.SubTree(path)
340+ if err != nil {
341+ return err
342+ }
343+ ents, err = tree.Entries()
344+ if err != nil {
345+ return err
346+ }
347+ } else {
348+ ents = append(ents, te)
349+ }
350+ } else {
351+ ents, err = tree.Entries()
352+ if err != nil {
353+ return err
354+ }
355+ }
356+ ents.Sort()
357+ for _, ent := range ents {
358+ size := ent.Size()
359+ ssize := ""
360+ if size == 0 {
361+ ssize = "-"
362+ } else {
363+ ssize = humanize.Bytes(uint64(size))
364+ }
365+ cmd.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, ent.Name())
366+ }
367+ return nil
368+ },
369+ }
370+ return cmd
371+}