repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

commit
1f65f3f
parent
e94d326
author
Eric Bower
date
2024-02-28 03:31:39 +0000 UTC
refactor(pgs): new cli api
3 files changed,  +120, -51
M pgs/access.go
+1, -1
1@@ -32,7 +32,7 @@ func HasProjectAccess(project *db.Project, owner *db.User, requester *db.User, p
2 		return slices.Contains(data, requester.Name)
3 	}
4 
5-	if aclType == "public_keys" {
6+	if aclType == "pubkeys" {
7 		key := ssh.FingerprintSHA256(pubkey)
8 		if len(data) == 0 {
9 			return true
M pgs/cli.go
+6, -5
 1@@ -69,10 +69,11 @@ func projectTable(projects []*db.Project) *table.Table {
 2 	return t
 3 }
 4 
 5-func getHelpText(userName, projectName string) string {
 6+func getHelpText(userName string) string {
 7 	helpStr := "Commands: [help, stats, ls, rm, link, unlink, prune, retain, depends, acl]\n\n"
 8 	helpStr += "NOTICE: *must* append with `--write` for the changes to persist.\n\n"
 9 
10+	projectName := "projA"
11 	headers := []string{"Cmd", "Description"}
12 	data := [][]string{
13 		{
14@@ -92,8 +93,8 @@ func getHelpText(userName, projectName string) string {
15 			fmt.Sprintf("delete %s", projectName),
16 		},
17 		{
18-			fmt.Sprintf("link %s project-b", projectName),
19-			fmt.Sprintf("symbolic link `%s` to `project-b`", projectName),
20+			fmt.Sprintf("link %s --to projB", projectName),
21+			fmt.Sprintf("symbolic link `%s` to `projB`", projectName),
22 		},
23 		{
24 			fmt.Sprintf("unlink %s", projectName),
25@@ -105,7 +106,7 @@ func getHelpText(userName, projectName string) string {
26 		},
27 		{
28 			fmt.Sprintf("retain %s", projectName),
29-			"alias `prune` but keeps last (3) projects",
30+			"alias to `prune` but keeps last N projects",
31 		},
32 		{
33 			fmt.Sprintf("depends %s", projectName),
34@@ -235,7 +236,7 @@ func (c *Cmd) RmProjectAssets(projectName string) error {
35 }
36 
37 func (c *Cmd) help() {
38-	c.output(getHelpText(c.User.Name, "project-a"))
39+	c.output(getHelpText(c.User.Name))
40 }
41 
42 func (c *Cmd) stats(cfgMaxSize uint64) error {
M pgs/wish.go
+113, -45
  1@@ -1,6 +1,7 @@
  2 package pgs
  3 
  4 import (
  5+	"flag"
  6 	"fmt"
  7 	"slices"
  8 	"strings"
  9@@ -32,6 +33,35 @@ func getUser(s ssh.Session, dbpool db.DB) (*db.User, error) {
 10 	return user, nil
 11 }
 12 
 13+type arrayFlags []string
 14+
 15+func (i *arrayFlags) String() string {
 16+    return "array flags"
 17+}
 18+
 19+func (i *arrayFlags) Set(value string) error {
 20+    *i = append(*i, value)
 21+    return nil
 22+}
 23+
 24+func flagSet(cmdName string, sesh ssh.Session) (*flag.FlagSet, bool) {
 25+	cmd := flag.NewFlagSet(cmdName, flag.ContinueOnError)
 26+	cmd.SetOutput(sesh)
 27+    write := cmd.Bool("write", false, "apply changes")
 28+    return cmd, *write
 29+}
 30+
 31+func flagCheck(cmd *flag.FlagSet, posArg string, cmdArgs []string) bool {
 32+    cmd.Parse(cmdArgs)
 33+
 34+	if posArg == "-h" || posArg == "--help" || posArg == "-help" {
 35+		cmd.Usage()
 36+		return false
 37+	}
 38+	return true
 39+}
 40+
 41+
 42 func WishMiddleware(handler *uploadassets.UploadAssetHandler) wish.Middleware {
 43 	dbpool := handler.DBPool
 44 	log := handler.Cfg.Logger
 45@@ -82,37 +112,51 @@ func WishMiddleware(handler *uploadassets.UploadAssetHandler) wish.Middleware {
 46 				}
 47 			}
 48 
 49-			log.Info("pgs middleware detected command", "args", args)
 50 			projectName := strings.TrimSpace(args[1])
 51-
 52-			if projectName == "--write" {
 53-				utils.ErrorHandler(sesh, fmt.Errorf("`--write` should be placed at end of command"))
 54-				return
 55-			}
 56+			cmdArgs := args[2:]
 57+			log.Info(
 58+				"pgs middleware detected command",
 59+				"args", args,
 60+				"cmd", cmd,
 61+				"projectName", projectName,
 62+				"cmdArgs", cmdArgs,
 63+			)
 64 
 65 			if cmd == "link" {
 66-				if len(args) < 3 {
 67-					utils.ErrorHandler(sesh, fmt.Errorf("must supply link command like: `projectA link projectB`"))
 68-					return
 69-				}
 70-				linkTo := strings.TrimSpace(args[2])
 71-				if len(args) >= 4 && strings.TrimSpace(args[3]) == "--write" {
 72+				linkCmd, write := flagSet("link", sesh)
 73+    			linkTo := linkCmd.String("to", "", "symbolic link to this project")
 74+    			if !flagCheck(linkCmd, projectName, cmdArgs) {
 75+    				return
 76+    			}
 77+
 78+				if write == true {
 79 					opts.Write = true
 80 				}
 81 
 82-				err := opts.link(projectName, linkTo)
 83+				if *linkTo == "" {
 84+					err := fmt.Errorf(
 85+						"must provide `--to` flag",
 86+					)
 87+					opts.bail(err)
 88+					return
 89+				}
 90+
 91+				err := opts.link(projectName, *linkTo)
 92 				opts.notice()
 93 				if err != nil {
 94 					opts.bail(err)
 95 				}
 96 				return
 97-			}
 98+			} else if cmd == "unlink" {
 99+				unlinkCmd, write := flagSet("unlink", sesh)
100+				if !flagCheck(unlinkCmd, projectName, cmdArgs) {
101+					return
102+				}
103 
104-			if len(args) >= 3 && strings.TrimSpace(args[2]) == "--write" {
105-				opts.Write = true
106-			}
107+				if write == true {
108+					opts.Write = true
109+				}
110 
111-			if cmd == "unlink" {
112 				err := opts.unlink(projectName)
113 				opts.notice()
114 				opts.bail(err)
115@@ -122,51 +166,75 @@ func WishMiddleware(handler *uploadassets.UploadAssetHandler) wish.Middleware {
116 				opts.bail(err)
117 				return
118 			} else if cmd == "retain" {
119-				err := opts.prune(projectName, 3)
120+				retainCmd, write := flagSet("retain", sesh)
121+    			retainNum := retainCmd.Int("n", 3, "latest number of projects to keep")
122+    			if !flagCheck(retainCmd, projectName, cmdArgs) {
123+    				return
124+    			}
125+
126+				if write == true {
127+					opts.Write = true
128+				}
129+
130+				err := opts.prune(projectName, *retainNum)
131 				opts.notice()
132 				opts.bail(err)
133 				return
134 			} else if cmd == "prune" {
135+				pruneCmd, write := flagSet("prune", sesh)
136+				if !flagCheck(pruneCmd, projectName, cmdArgs) {
137+					return
138+				}
139+
140+				if write == true {
141+					opts.Write = true
142+				}
143+
144 				err := opts.prune(projectName, 0)
145 				opts.notice()
146 				opts.bail(err)
147 				return
148 			} else if cmd == "rm" {
149+				rmCmd, write := flagSet("rm", sesh)
150+				if !flagCheck(rmCmd, projectName, cmdArgs) {
151+					return
152+				}
153+
154+				if write == true {
155+					opts.Write = true
156+				}
157+
158 				err := opts.rm(projectName)
159 				opts.notice()
160 				opts.bail(err)
161 				return
162 			} else if cmd == "acl" {
163-				aclType := strings.TrimSpace(args[2])
164-				if !slices.Contains([]string{"public", "public_keys", "pico"}, aclType) {
165-					err := fmt.Errorf("acl type must be one of the following: [public, public_keys, pico], found %s", aclType)
166+				aclCmd, write := flagSet("acl", sesh)
167+    			aclType := aclCmd.String("type", "", "access type: public, pico, pubkeys")
168+    			var acls arrayFlags
169+    			aclCmd.Var(
170+    				&acls,
171+    				"acl",
172+    				"list of pico usernames or sha256 public keys, delimited by commas",
173+    			)
174+    			if !flagCheck(aclCmd, projectName, cmdArgs) {
175+    				return
176+    			}
177+
178+				if write == true {
179+					opts.Write = true
180+				}
181+
182+				if !slices.Contains([]string{"public", "pubkeys", "pico"}, *aclType) {
183+					err := fmt.Errorf(
184+						"acl type must be one of the following: [public, pubkeys, pico], found %s",
185+						*aclType,
186+					)
187 					opts.bail(err)
188 					return
189 				}
190 
191-				aclsRaw := ""
192-				if len(args) == 4 {
193-					if strings.TrimSpace(args[3]) == "--write" {
194-						opts.Write = true
195-					} else {
196-						aclsRaw = strings.TrimSpace(args[3])
197-					}
198-				}
199-				if len(args) == 5 {
200-					aclsRaw = strings.TrimSpace(args[3])
201-					if strings.TrimSpace(args[4]) == "--write" {
202-						opts.Write = true
203-					}
204-				}
205-				acls := []string{}
206-				for _, key := range strings.Split(aclsRaw, ",") {
207-					st := strings.TrimSpace(key)
208-					if st == "" {
209-						continue
210-					}
211-					acls = append(acls, st)
212-				}
213-				err := opts.acl(projectName, aclType, acls)
214+				err := opts.acl(projectName, *aclType, acls)
215 				opts.notice()
216 				opts.bail(err)
217 			} else {