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/charmbracelet/soft-serve/pkg/ui/common"
12 "github.com/charmbracelet/soft-serve/pkg/ui/styles"
13 "github.com/spf13/cobra"
14)
15
16// blobCommand returns a command that prints the contents of a file.
17func blobCommand() *cobra.Command {
18 var linenumber bool
19 var color bool
20 var raw bool
21
22 styles := styles.DefaultStyles()
23 cmd := &cobra.Command{
24 Use: "blob REPOSITORY [REFERENCE] [PATH]",
25 Aliases: []string{"cat", "show"},
26 Short: "Print out the contents of file at path",
27 Args: cobra.RangeArgs(1, 3),
28 RunE: func(co *cobra.Command, args []string) error {
29 ctx := co.Context()
30 be := backend.FromContext(ctx)
31 rn := args[0]
32 ref := ""
33 fp := ""
34 switch len(args) {
35 case 2:
36 fp = args[1]
37 case 3:
38 ref = args[1]
39 fp = args[2]
40 }
41
42 repo, err := be.Repository(ctx, rn)
43 if err != nil {
44 return err
45 }
46
47 if !cmd.CheckUserHasAccess(co, repo.Name(), access.ReadOnlyAccess) {
48 return proto.ErrUnauthorized
49 }
50
51 r, err := repo.Open()
52 if err != nil {
53 return err
54 }
55
56 if ref == "" {
57 head, err := r.HEAD()
58 if err != nil {
59 return err
60 }
61 ref = head.ID
62 }
63
64 tree, err := r.LsTree(ref)
65 if err != nil {
66 return err
67 }
68
69 te, err := tree.TreeEntry(fp)
70 if err != nil {
71 return err
72 }
73
74 if te.Type() != "blob" {
75 return git.ErrFileNotFound
76 }
77
78 bts, err := te.Contents()
79 if err != nil {
80 return err
81 }
82
83 c := string(bts)
84 isBin, _ := te.File().IsBinary()
85 if isBin {
86 if raw {
87 co.Println(c)
88 } else {
89 return fmt.Errorf("binary file: use --raw to print")
90 }
91 } else {
92 if color {
93 c, err = common.FormatHighlight(fp, c)
94 if err != nil {
95 return err
96 }
97 }
98
99 if linenumber {
100 c, _ = common.FormatLineNumber(styles, c, color)
101 }
102
103 co.Println(c)
104 }
105 return nil
106 },
107 }
108
109 cmd.Flags().BoolVarP(&raw, "raw", "r", false, "Print raw contents")
110 cmd.Flags().BoolVarP(&linenumber, "linenumber", "l", false, "Print line numbers")
111 cmd.Flags().BoolVarP(&color, "color", "c", false, "Colorize output")
112
113 return cmd
114}