0aec8c2ed4b8d1a9a416128cdae72995bd2ea006
- 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/go.mod b/go.mod
2index f81b8c1dac06beb4aa618bd5678591a70fb6a759..a1fae4825654acfc2d901bc0a852be14e7b07faa 100755
3--- a/go.mod
4+++ b/go.mod
5@@ -29,6 +29,7 @@ require (
6 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
7 github.com/muesli/mango v0.1.0
8 github.com/muesli/roff v0.1.0
9+ github.com/spf13/cobra v1.4.0
10 )
11
12 require (
13@@ -45,6 +46,7 @@ require (
14 github.com/go-git/gcfg v1.5.0 // indirect
15 github.com/gorilla/css v1.0.0 // indirect
16 github.com/imdario/mergo v0.3.12 // indirect
17+ github.com/inconshreveable/mousetrap v1.0.0 // indirect
18 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
19 github.com/kevinburke/ssh_config v1.1.0 // indirect
20 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
21@@ -57,6 +59,7 @@ require (
22 github.com/olekukonko/tablewriter v0.0.5 // indirect
23 github.com/rivo/uniseg v0.2.0 // indirect
24 github.com/sahilm/fuzzy v0.1.0 // indirect
25+ github.com/spf13/pflag v1.0.5 // indirect
26 github.com/xanzy/ssh-agent v0.3.1 // indirect
27 github.com/yuin/goldmark v1.4.4 // indirect
28 github.com/yuin/goldmark-emoji v1.0.1 // indirect
29diff --git a/go.sum b/go.sum
30index 8dc59b6d4986b7b5a014f448aa0204dc51a8661f..85a6b542c3b828213c3ec81be4688c62fb7fad0f 100644
31--- a/go.sum
32+++ b/go.sum
33@@ -40,6 +40,7 @@ github.com/charmbracelet/wish v0.3.1-0.20220405152319-bea68c3da3b1/go.mod h1:+Eg
34 github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
35 github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
36 github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
37+github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
38 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
39 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
40 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
41@@ -76,6 +77,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
42 github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
43 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
44 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
45+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
46+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
47 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
48 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
49 github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
50@@ -135,12 +138,17 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
51 github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
52 github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
53 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
54+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
55 github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
56 github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
57 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
58 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
59 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
60 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
61+github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
62+github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
63+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
64+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
65 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
66 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
67 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
68diff --git a/server/cmd/cat.go b/server/cmd/cat.go
69new file mode 100644
70index 0000000000000000000000000000000000000000..18ff5678c982d9e4b73cab235c331c9d57d78d3b
71--- /dev/null
72+++ b/server/cmd/cat.go
73@@ -0,0 +1,123 @@
74+package cmd
75+
76+import (
77+ "fmt"
78+ "strings"
79+
80+ "github.com/alecthomas/chroma/lexers"
81+ gansi "github.com/charmbracelet/glamour/ansi"
82+ "github.com/charmbracelet/lipgloss"
83+ "github.com/charmbracelet/soft-serve/internal/git"
84+ "github.com/charmbracelet/soft-serve/tui/common"
85+ gitwish "github.com/charmbracelet/wish/git"
86+ "github.com/muesli/termenv"
87+ "github.com/spf13/cobra"
88+)
89+
90+var (
91+ lineDigitStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("239"))
92+ lineBarStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("236"))
93+ dirnameStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00AAFF"))
94+ filenameStyle = lipgloss.NewStyle()
95+ filemodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#777777"))
96+)
97+
98+// CatCommand returns a command that prints the contents of a file.
99+func CatCommand() *cobra.Command {
100+ var linenumber bool
101+ var color bool
102+
103+ catCmd := &cobra.Command{
104+ Use: "cat PATH",
105+ Short: "Outputs the contents of the file at path.",
106+ Args: cobra.ExactArgs(1),
107+ RunE: func(cmd *cobra.Command, args []string) error {
108+ ac, s := fromContext(cmd)
109+ ps := strings.Split(args[0], "/")
110+ rn := ps[0]
111+ fp := strings.Join(ps[1:], "/")
112+ auth := ac.AuthRepo(rn, s.PublicKey())
113+ if auth < gitwish.ReadOnlyAccess {
114+ return ErrUnauthorized
115+ }
116+ var repo *git.Repo
117+ repoExists := false
118+ for _, rp := range ac.Source.AllRepos() {
119+ if rp.Name() == rn {
120+ repoExists = true
121+ repo = rp
122+ break
123+ }
124+ }
125+ if !repoExists {
126+ return ErrRepoNotFound
127+ }
128+ c, _, err := repo.LatestFile(fp)
129+ if err != nil {
130+ return err
131+ }
132+ if color {
133+ c, err = withFormatting(fp, c)
134+ if err != nil {
135+ return err
136+ }
137+ }
138+ if linenumber {
139+ c = withLineNumber(c, color)
140+ }
141+ fmt.Fprint(s, c)
142+ return nil
143+ },
144+ }
145+ catCmd.Flags().BoolVarP(&linenumber, "linenumber", "l", false, "Print line numbers")
146+ catCmd.Flags().BoolVarP(&color, "color", "c", false, "Colorize output")
147+
148+ return catCmd
149+}
150+
151+func withLineNumber(s string, color bool) string {
152+ lines := strings.Split(s, "\n")
153+ // NB: len() is not a particularly safe way to count string width (because
154+ // it's counting bytes instead of runes) but in this case it's okay
155+ // because we're only dealing with digits, which are one byte each.
156+ mll := len(fmt.Sprintf("%d", len(lines)))
157+ for i, l := range lines {
158+ digit := fmt.Sprintf("%*d", mll, i+1)
159+ bar := "│"
160+ if color {
161+ digit = lineDigitStyle.Render(digit)
162+ bar = lineBarStyle.Render(bar)
163+ }
164+ if i < len(lines)-1 || len(l) != 0 {
165+ // If the final line was a newline we'll get an empty string for
166+ // the final line, so drop the newline altogether.
167+ lines[i] = fmt.Sprintf(" %s %s %s", digit, bar, l)
168+ }
169+ }
170+ return strings.Join(lines, "\n")
171+}
172+
173diff --git a/server/cmd/cmd.go b/server/cmd/cmd.go
174new file mode 100644
175index 0000000000000000000000000000000000000000..e71ab65357ed0978b0a65bc9c6f77e3167da9941
176--- /dev/null
177+++ b/server/cmd/cmd.go
178@@ -0,0 +1,70 @@
179+package cmd
180+
181+import (
182+ "fmt"
183+
184+ appCfg "github.com/charmbracelet/soft-serve/internal/config"
185+ "github.com/gliderlabs/ssh"
186+ "github.com/spf13/cobra"
187+)
188+
189+var (
190+ // ErrUnauthorized is returned when the user is not authorized to perform action.
191+ ErrUnauthorized = fmt.Errorf("Unauthorized")
192+ // ErrRepoNotFound is returned when the repo is not found.
193+ ErrRepoNotFound = fmt.Errorf("Repository not found")
194+ // ErrFileNotFound is returned when the file is not found.
195+ ErrFileNotFound = fmt.Errorf("File not found")
196+
197+ usageTemplate = `Usage:{{if .Runnable}}
198+ {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
199+ {{.UseLine}} [command]{{end}}{{if gt (len .Aliases) 0}}
200+
201+Aliases:
202+ {{.NameAndAliases}}{{end}}{{if .HasExample}}
203+
204+Examples:
205+{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
206+
207+Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
208+ {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
209+
210+Flags:
211+{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
212+
213+Global Flags:
214+{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
215+
216+Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
217+ {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
218+
219+Use "{{.UseLine}} [command] --help" for more information about a command.{{end}}
220+`
221+)
222+
223+// RootCommand is the root command for the server.
224+func RootCommand() *cobra.Command {
225+ rootCmd := &cobra.Command{
226+ Use: "ssh [-p PORT] HOST",
227+ Long: "Soft Serve is a self-hostable Git server for the command line.",
228+ Args: cobra.MinimumNArgs(1),
229+ DisableFlagsInUseLine: true,
230+ }
231+ rootCmd.SetUsageTemplate(usageTemplate)
232+ rootCmd.CompletionOptions.DisableDefaultCmd = true
233+ rootCmd.AddCommand(
234+ ReloadCommand(),
235+ CatCommand(),
236+ ListCommand(),
237+ GitCommand(),
238+ )
239+
240+ return rootCmd
241+}
242+
243+func fromContext(cmd *cobra.Command) (*appCfg.Config, ssh.Session) {
244+ ctx := cmd.Context()
245+ ac := ctx.Value("config").(*appCfg.Config)
246+ s := ctx.Value("session").(ssh.Session)
247+ return ac, s
248+}
249diff --git a/server/cmd/git.go b/server/cmd/git.go
250new file mode 100644
251index 0000000000000000000000000000000000000000..fd2c3be87505141eb56f3c2dd625fcd43097c84f
252--- /dev/null
253+++ b/server/cmd/git.go
254@@ -0,0 +1,54 @@
255+package cmd
256+
257+import (
258+ "io"
259+ "os/exec"
260+
261+ "github.com/charmbracelet/soft-serve/internal/git"
262+ gitwish "github.com/charmbracelet/wish/git"
263+ "github.com/spf13/cobra"
264+)
265+
266+// GitCommand returns a command that handles Git operations.
267+func GitCommand() *cobra.Command {
268+ gitCmd := &cobra.Command{
269+ Use: "git REPO COMMAND",
270+ Short: "Perform Git operations on a repository.",
271+ RunE: func(cmd *cobra.Command, args []string) error {
272+ ac, s := fromContext(cmd)
273+ auth := ac.AuthRepo("config", s.PublicKey())
274+ if auth < gitwish.AdminAccess {
275+ return ErrUnauthorized
276+ }
277+ if len(args) < 1 {
278+ return runGit(nil, s, s, "")
279+ }
280+ var repo *git.Repo
281+ rn := args[0]
282+ repoExists := false
283+ for _, rp := range ac.Source.AllRepos() {
284+ if rp.Name() == rn {
285+ repoExists = true
286+ repo = rp
287+ break
288+ }
289+ }
290+ if !repoExists {
291+ return ErrRepoNotFound
292+ }
293+ return runGit(nil, s, s, repo.Path(), args[1:]...)
294+ },
295+ }
296+ gitCmd.Flags().SetInterspersed(false)
297+
298+ return gitCmd
299+}
300+
301+func runGit(in io.Reader, out, err io.Writer, dir string, args ...string) error {
302+ cmd := exec.Command("git", args...)
303+ cmd.Stdin = in
304+ cmd.Stdout = out
305+ cmd.Stderr = err
306+ cmd.Dir = dir
307+ return cmd.Run()
308+}
309diff --git a/server/cmd/list.go b/server/cmd/list.go
310new file mode 100644
311index 0000000000000000000000000000000000000000..f07a2a68f3600357e0020ea6269a954714740220
312--- /dev/null
313+++ b/server/cmd/list.go
314@@ -0,0 +1,81 @@
315+package cmd
316+
317+import (
318+ "fmt"
319+ "path/filepath"
320+ "strings"
321+
322+ "github.com/charmbracelet/soft-serve/git"
323+ gitwish "github.com/charmbracelet/wish/git"
324+ "github.com/spf13/cobra"
325+)
326+
327+// ListCommand returns a command that list file or directory at path.
328+func ListCommand() *cobra.Command {
329+ lsCmd := &cobra.Command{
330+ Use: "ls PATH",
331+ Aliases: []string{"list"},
332+ Short: "List file or directory at path.",
333+ Args: cobra.RangeArgs(0, 1),
334+ RunE: func(cmd *cobra.Command, args []string) error {
335+ ac, s := fromContext(cmd)
336+ rn := ""
337+ path := ""
338+ ps := []string{}
339+ if len(args) > 0 {
340+ path = filepath.Clean(args[0])
341+ ps = strings.Split(path, "/")
342+ rn = ps[0]
343+ auth := ac.AuthRepo(rn, s.PublicKey())
344+ if auth < gitwish.ReadOnlyAccess {
345+ return ErrUnauthorized
346+ }
347+ }
348+ if path == "" || path == "." || path == "/" {
349+ for _, r := range ac.Source.AllRepos() {
350+ fmt.Fprintln(s, r.Name())
351+ }
352+ return nil
353+ }
354+ r, err := ac.Source.GetRepo(rn)
355+ if err != nil {
356+ return err
357+ }
358+ head, err := r.HEAD()
359+ if err != nil {
360+ return err
361+ }
362+ tree, err := r.Tree(head, "")
363+ if err != nil {
364+ return err
365+ }
366+ subpath := strings.Join(ps[1:], "/")
367+ ents := git.Entries{}
368+ te, err := tree.TreeEntry(subpath)
369+ if err == git.ErrRevisionNotExist {
370+ return ErrFileNotFound
371+ }
372+ if err != nil {
373+ return err
374+ }
375+ if te.Type() == "tree" {
376+ tree, err = tree.SubTree(subpath)
377+ if err != nil {
378+ return err
379+ }
380+ ents, err = tree.Entries()
381+ if err != nil {
382+ return err
383+ }
384+ } else {
385+ ents = append(ents, te)
386+ }
387+ ents.Sort()
388+ for _, ent := range ents {
389+ fmt.Fprintf(s, "%s\t%d\t %s\n", ent.Mode(), ent.Size(), ent.Name())
390+ }
391+ return nil
392+ },
393+ }
394+ return lsCmd
395+}
396diff --git a/server/cmd/reload.go b/server/cmd/reload.go
397new file mode 100644
398index 0000000000000000000000000000000000000000..7f2312ab6e550109e9c52d0ee9c0ef80f3fa1253
399--- /dev/null
400+++ b/server/cmd/reload.go
401@@ -0,0 +1,23 @@
402+package cmd
403+
404+import (
405+ gitwish "github.com/charmbracelet/wish/git"
406+ "github.com/spf13/cobra"
407+)
408+
409+// ReloadCommand returns a command that reloads the server configuration.
410+func ReloadCommand() *cobra.Command {
411+ reloadCmd := &cobra.Command{
412+ Use: "reload",
413+ Short: "Reloads the configuration",
414+ RunE: func(cmd *cobra.Command, args []string) error {
415+ ac, s := fromContext(cmd)
416+ auth := ac.AuthRepo("config", s.PublicKey())
417+ if auth < gitwish.AdminAccess {
418+ return ErrUnauthorized
419+ }
420+ return ac.Reload()
421+ },
422+ }
423+ return reloadCmd
424+}
425diff --git a/server/middleware.go b/server/middleware.go
426index cfe89a3fd9a444ee19de17eb504fe4bfdf23de47..3dd61517925175e8478cd94d6ac607d85f643afb 100644
427--- a/server/middleware.go
428+++ b/server/middleware.go
429@@ -1,186 +1,48 @@
430 package server
431
432 import (
433+ "context"
434 "fmt"
435- "path/filepath"
436- "strings"
437
438- "github.com/alecthomas/chroma/lexers"
439- gansi "github.com/charmbracelet/glamour/ansi"
440- "github.com/charmbracelet/lipgloss"
441- "github.com/charmbracelet/soft-serve/git"
442 appCfg "github.com/charmbracelet/soft-serve/internal/config"
443- "github.com/charmbracelet/soft-serve/tui/common"
444+ "github.com/charmbracelet/soft-serve/server/cmd"
445 "github.com/charmbracelet/wish"
446- gitwish "github.com/charmbracelet/wish/git"
447 "github.com/gliderlabs/ssh"
448- ggit "github.com/gogs/git-module"
449- "github.com/muesli/termenv"
450 )
451
452-var (
453- lineDigitStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("239"))
454- lineBarStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("236"))
455- dirnameStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00AAFF"))
456- filenameStyle = lipgloss.NewStyle()
457- filemodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#777777"))
458-)
459-
460-// softServeMiddleware is a middleware that handles displaying files with the
461-// option of syntax highlighting and line numbers.
462-func softServeMiddleware(ac *appCfg.Config) wish.Middleware {
463+// softMiddleware is the Soft Serve middleware that handles SSH commands.
464+func softMiddleware(ac *appCfg.Config) wish.Middleware {
465 return func(sh ssh.Handler) ssh.Handler {
466 return func(s ssh.Session) {
467- _, _, active := s.Pty()
468- cmds := s.Command()
469- if !active && len(cmds) > 0 {
470- func() {
471- color := false
472- lineno := false
473- fp := filepath.Clean(cmds[0])
474- ps := strings.Split(fp, "/")
475- repo := ps[0]
476- if repo == "config" {
477- return
478- }
479- repoExists := false
480- for _, rp := range ac.Source.AllRepos() {
481- if rp.Name() == repo {
482- repoExists = true
483- break
484- }
485- }
486- if !repoExists {
487- s.Write([]byte("repository not found"))
488- s.Exit(1)
489- return
490- }
491- auth := ac.AuthRepo(repo, s.PublicKey())
492- if auth < gitwish.ReadOnlyAccess {
493- s.Write([]byte("unauthorized"))
494- s.Exit(1)
495- return
496- }
497- for _, op := range cmds[1:] {
498- if op == "-c" || op == "--color" {
499- color = true
500- } else if op == "-l" || op == "--lineno" || op == "--linenumber" {
501- lineno = true
502- }
503- }
504- rs, err := ac.Source.GetRepo(repo)
505- if err != nil {
506- _, _ = s.Write([]byte(err.Error()))
507- _ = s.Exit(1)
508- return
509- }
510- ref, err := rs.HEAD()
511- if err != nil {
512- _, _ = s.Write([]byte(err.Error()))
513- _ = s.Exit(1)
514- return
515- }
516- p := strings.Join(ps[1:], "/")
517- t, err := rs.Tree(ref, p)
518- if err != nil && err != ggit.ErrRevisionNotExist {
519- _, _ = s.Write([]byte(err.Error()))
520- _ = s.Exit(1)
521- return
522- }
523- if err == ggit.ErrRevisionNotExist {
524- _, _ = s.Write([]byte(git.ErrFileNotFound.Error()))
525- _ = s.Exit(1)
526- return
527- }
528- ents, err := t.Entries()
529diff --git a/server/middleware_test.go b/server/middleware_test.go
530index 9b8fe2661ad16c5c42995755c8415b122d655691..94ac3ebbfef8dd25bbdcf392ec31e48f4f6301f4 100644
531--- a/server/middleware_test.go
532+++ b/server/middleware_test.go
533@@ -1,8 +1,10 @@
534 package server
535
536 import (
537+ "os"
538 "testing"
539
540+ sconfig "github.com/charmbracelet/soft-serve/config"
541 "github.com/charmbracelet/soft-serve/internal/config"
542 "github.com/charmbracelet/wish/testsession"
543 "github.com/gliderlabs/ssh"
544@@ -12,13 +14,21 @@ import (
545 var ()
546
547 func TestMiddleware(t *testing.T) {
548+ t.Cleanup(func() {
549+ os.RemoveAll("testmiddleware")
550+ })
551 is := is.New(t)
552- appCfg, err := config.NewConfig(cfg)
553+ appCfg, err := config.NewConfig(&sconfig.Config{
554+ Host: "localhost",
555+ Port: 22223,
556+ RepoPath: "testmiddleware/repos",
557+ KeyPath: "testmiddleware/key",
558+ })
559 is.NoErr(err)
560 _ = testsession.New(t, &ssh.Server{
561- Handler: softServeMiddleware(appCfg)(func(s ssh.Session) {
562+ Handler: softMiddleware(appCfg)(func(s ssh.Session) {
563 t.Run("TestCatConfig", func(t *testing.T) {
564- _, err := s.Write([]byte("config/config.json"))
565+ _, err := s.Write([]byte("cat config/config.json"))
566 if err == nil {
567 t.Errorf("Expected error, got nil")
568 }
569diff --git a/server/server.go b/server/server.go
570index 87bc4755118f52ec809b9f9fa4084bb5ae24a2a5..aa4063728974d110a19fc60dee32fa595576162b 100644
571--- a/server/server.go
572+++ b/server/server.go
573@@ -36,7 +36,7 @@ func NewServer(cfg *config.Config) *Server {
574 mw := []wish.Middleware{
575 rm.MiddlewareWithLogger(
576 cfg.ErrorLog,
577- softServeMiddleware(ac),
578+ softMiddleware(ac),
579 bm.Middleware(tui.SessionHandler(ac)),
580 gm.Middleware(cfg.RepoPath, ac),
581 lm.Middleware(),