Skip to content

Commit

Permalink
feat(server): add tree & blob server commands
Browse files Browse the repository at this point in the history
Replace show & list
  • Loading branch information
aymanbagabas committed May 2, 2023
1 parent 1f673f3 commit 4277403
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 116 deletions.
23 changes: 14 additions & 9 deletions git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ func (r *Repository) References() ([]*Reference, error) {
return rrefs, nil
}

// LsTree returns the tree for the given reference.
func (r *Repository) LsTree(ref string) (*Tree, error) {
tree, err := r.Repository.LsTree(ref)
if err != nil {
return nil, err
}
return &Tree{
Tree: tree,
Path: "",
Repository: r,
}, nil
}

// Tree returns the tree for the given reference.
func (r *Repository) Tree(ref *Reference) (*Tree, error) {
if ref == nil {
Expand All @@ -123,15 +136,7 @@ func (r *Repository) Tree(ref *Reference) (*Tree, error) {
}
ref = rref
}
tree, err := r.LsTree(ref.Hash.String())
if err != nil {
return nil, err
}
return &Tree{
Tree: tree,
Path: "",
Repository: r,
}, nil
return r.LsTree(ref.Hash.String())
}

// TreePath returns the tree for the given path.
Expand Down
107 changes: 73 additions & 34 deletions server/cmd/show.go → server/cmd/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/alecthomas/chroma/lexers"
gansi "github.com/charmbracelet/glamour/ansi"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/soft-serve/server/backend"
"github.com/charmbracelet/soft-serve/git"
"github.com/charmbracelet/soft-serve/ui/common"
"github.com/muesli/termenv"
"github.com/spf13/cobra"
Expand All @@ -21,60 +21,99 @@ var (
filemodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#777777"))
)

// showCommand returns a command that prints the contents of a file.
func showCommand() *cobra.Command {
// blobCommand returns a command that prints the contents of a file.
func blobCommand() *cobra.Command {
var linenumber bool
var color bool
var raw bool

showCmd := &cobra.Command{
Use: "show PATH",
Aliases: []string{"cat"},
Short: "Read the contents of file at path.",
Args: cobra.ExactArgs(1),
cmd := &cobra.Command{
Use: "blob REPOSITORY [REFERENCE] [PATH]",
Aliases: []string{"cat", "show"},
Short: "Print out the contents of file at path.",
Args: cobra.RangeArgs(1, 3),
PersistentPreRunE: checkIfReadable,
RunE: func(cmd *cobra.Command, args []string) error {
cfg, _ := fromContext(cmd)
// FIXME: nested repos are not supported.
ps := strings.Split(args[0], "/")
rn := strings.TrimSuffix(ps[0], ".git")
fp := strings.Join(ps[1:], "/")
var repo backend.Repository
repoExists := false
repos, err := cfg.Backend.Repositories()
rn := args[0]
ref := ""
fp := ""
switch len(args) {
case 2:
fp = args[1]
case 3:
ref = args[1]
fp = args[2]
}

repo, err := cfg.Backend.Repository(rn)
if err != nil {
return err
}
for _, rp := range repos {
if rp.Name() == rn {
repoExists = true
repo = rp
break
}
}
if !repoExists {
return ErrRepoNotFound
}
c, _, err := backend.LatestFile(repo, fp)

r, err := repo.Open()
if err != nil {
return err
}
if color {
c, err = withFormatting(fp, c)

if ref == "" {
head, err := r.HEAD()
if err != nil {
return err
}
ref = head.Hash.String()
}

tree, err := r.LsTree(ref)
if err != nil {
return err
}

te, err := tree.TreeEntry(fp)
if err != nil {
return err
}

if te.Type() != "blob" {
return git.ErrFileNotFound
}

bts, err := te.Contents()
if err != nil {
return err
}
if linenumber {
c = withLineNumber(c, color)

c := string(bts)
isBin, _ := te.File().IsBinary()
if isBin {
if raw {
cmd.Println(c)
} else {
return fmt.Errorf("binary file: use --raw to print")
}
} else {
if color {
c, err = withFormatting(fp, c)
if err != nil {
return err
}
}

if linenumber {
c = withLineNumber(c, color)
}

cmd.Println(c)
}
cmd.Println(c)
return nil
},
}
showCmd.Flags().BoolVarP(&linenumber, "linenumber", "l", false, "Print line numbers")
showCmd.Flags().BoolVarP(&color, "color", "c", false, "Colorize output")

return showCmd
cmd.Flags().BoolVarP(&raw, "raw", "r", false, "Print raw contents")
cmd.Flags().BoolVarP(&linenumber, "linenumber", "l", false, "Print line numbers")
cmd.Flags().BoolVarP(&color, "color", "c", false, "Colorize output")

return cmd
}

func withLineNumber(s string, color bool) string {
Expand Down
3 changes: 2 additions & 1 deletion server/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ func rootCommand() *cobra.Command {
listCommand(),
privateCommand(),
renameCommand(),
showCommand(),
blobCommand(),
tagCommand(),
treeCommand(),
)

return rootCmd
Expand Down
79 changes: 7 additions & 72 deletions server/cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,92 +1,27 @@
package cmd

import (
"fmt"
"path/filepath"
"strings"

"github.com/charmbracelet/soft-serve/git"
"github.com/charmbracelet/soft-serve/server/backend"
"github.com/spf13/cobra"
)

// listCommand returns a command that list file or directory at path.
func listCommand() *cobra.Command {
listCmd := &cobra.Command{
Use: "list PATH",
Use: "list",
Aliases: []string{"ls"},
Short: "List files at repository.",
Args: cobra.RangeArgs(0, 1),
Short: "List repositories.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cfg, s := fromContext(cmd)
rn := ""
path := ""
ps := []string{}
if len(args) > 0 {
// FIXME: nested repos are not supported.
path = filepath.Clean(args[0])
ps = strings.Split(path, "/")
rn = strings.TrimSuffix(ps[0], ".git")
auth := cfg.Backend.AccessLevel(rn, s.PublicKey())
if auth < backend.ReadOnlyAccess {
return ErrUnauthorized
}
}
if path == "" || path == "." || path == "/" {
repos, err := cfg.Backend.Repositories()
if err != nil {
return err
}
for _, r := range repos {
if cfg.Backend.AccessLevel(r.Name(), s.PublicKey()) >= backend.ReadOnlyAccess {
cmd.Println(r.Name())
}
}
return nil
}
rr, err := cfg.Backend.Repository(rn)
if err != nil {
return err
}
r, err := rr.Open()
if err != nil {
return err
}
head, err := r.HEAD()
if err != nil {
if bs, err := r.Branches(); err != nil && len(bs) == 0 {
return fmt.Errorf("repository is empty")
}
return err
}
tree, err := r.TreePath(head, "")
repos, err := cfg.Backend.Repositories()
if err != nil {
return err
}
subpath := strings.Join(ps[1:], "/")
ents := git.Entries{}
te, err := tree.TreeEntry(subpath)
if err == git.ErrRevisionNotExist {
return ErrFileNotFound
}
if err != nil {
return err
}
if te.Type() == "tree" {
tree, err = tree.SubTree(subpath)
if err != nil {
return err
for _, r := range repos {
if cfg.Backend.AccessLevel(r.Name(), s.PublicKey()) >= backend.ReadOnlyAccess {
cmd.Println(r.Name())
}
ents, err = tree.Entries()
if err != nil {
return err
}
} else {
ents = append(ents, te)
}
ents.Sort()
for _, ent := range ents {
cmd.Printf("%s\t%d\t %s\n", ent.Mode(), ent.Size(), ent.Name())
}
return nil
},
Expand Down
99 changes: 99 additions & 0 deletions server/cmd/tree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package cmd

import (
"fmt"

"github.com/charmbracelet/soft-serve/git"
"github.com/dustin/go-humanize"
"github.com/spf13/cobra"
)

// treeCommand returns a command that list file or directory at path.
func treeCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "tree REPOSITORY [REFERENCE] [PATH]",
Short: "Print repository tree at path.",
Args: cobra.RangeArgs(1, 3),
PersistentPreRunE: checkIfReadable,
RunE: func(cmd *cobra.Command, args []string) error {
cfg, _ := fromContext(cmd)
rn := args[0]
path := ""
ref := ""
switch len(args) {
case 2:
path = args[1]
case 3:
ref = args[1]
path = args[2]
}
rr, err := cfg.Backend.Repository(rn)
if err != nil {
return err
}

r, err := rr.Open()
if err != nil {
return err
}

if ref == "" {
head, err := r.HEAD()
if err != nil {
if bs, err := r.Branches(); err != nil && len(bs) == 0 {
return fmt.Errorf("repository is empty")
}
return err
}

ref = head.Hash.String()
}

tree, err := r.LsTree(ref)
if err != nil {
return err
}

ents := git.Entries{}
if path != "" && path != "/" {
te, err := tree.TreeEntry(path)
if err == git.ErrRevisionNotExist {
return ErrFileNotFound
}
if err != nil {
return err
}
if te.Type() == "tree" {
tree, err = tree.SubTree(path)
if err != nil {
return err
}
ents, err = tree.Entries()
if err != nil {
return err
}
} else {
ents = append(ents, te)
}
} else {
ents, err = tree.Entries()
if err != nil {
return err
}
}
ents.Sort()
for _, ent := range ents {
size := ent.Size()
ssize := ""
if size == 0 {
ssize = "-"
} else {
ssize = humanize.Bytes(uint64(size))
}
cmd.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, ent.Name())
}
return nil
},
}
return cmd
}

0 comments on commit 4277403

Please sign in to comment.