- commit
- 327b26e
- parent
- 1fc495d
- author
- Eric Bower
- date
- 2023-08-17 19:41:36 +0000 UTC
refactor(pgs): cli outputs and asset upload optimizations
4 files changed,
+125,
-63
M
db/db.go
+1,
-0
1@@ -207,6 +207,7 @@ type DB interface {
2 FindFeedItemsByPostID(postID string) ([]*FeedItem, error)
3
4 InsertProject(userID, name, projectDir string) (string, error)
5+ UpdateProject(userID, name string) error
6 LinkToProject(userID, projectID, projectDir string, commit bool) error
7 RemoveProject(projectID string) error
8 FindProjectByName(userID, name string) (*Project, error)
+6,
-0
1@@ -245,6 +245,7 @@ const (
2 sqlRemoveUsers = `DELETE FROM app_users WHERE id = ANY($1::uuid[])`
3
4 sqlInsertProject = `INSERT INTO projects (user_id, name, project_dir) VALUES ($1, $2, $3) RETURNING id;`
5+ sqlUpdateProject = `UPDATE projects SET updated_at = $3 WHERE user_id = $1 AND name = $2;`
6 sqlFindProjectByName = `SELECT id, user_id, name, project_dir FROM projects WHERE user_id = $1 AND name = $2;`
7 sqlFindProjectsByUser = `SELECT id, user_id, name, project_dir FROM projects WHERE user_id = $1 ORDER BY name ASC;`
8 sqlFindProjectsByPrefix = `SELECT id, user_id, name, project_dir FROM projects WHERE user_id = $1 AND name = project_dir AND name ILIKE $2 ORDER BY updated_at ASC, name ASC;`
9@@ -1196,6 +1197,11 @@ func (me *PsqlDB) InsertProject(userID, name, projectDir string) (string, error)
10 return id, nil
11 }
12
13+func (me *PsqlDB) UpdateProject(userID, name string) error {
14+ _, err := me.Db.Exec(sqlUpdateProject, userID, name, time.Now())
15+ return err
16+}
17+
18 func (me *PsqlDB) LinkToProject(userID, projectID, projectDir string, commit bool) error {
19 linkToProject, err := me.FindProjectByName(userID, projectDir)
20 if err != nil {
+46,
-13
1@@ -18,6 +18,8 @@ import (
2 )
3
4 type ctxUserKey struct{}
5+type ctxBucketKey struct{}
6+type ctxProjectKey struct{}
7
8 func getAssetURL(c *shared.ConfigSite, username, projectName, fpath string) string {
9 return fmt.Sprintf(
10@@ -30,6 +32,23 @@ func getAssetURL(c *shared.ConfigSite, username, projectName, fpath string) stri
11 )
12 }
13
14+func getProject(s ssh.Session) *db.Project {
15+ v := s.Context().Value(ctxProjectKey{})
16+ if v == nil {
17+ return nil
18+ }
19+ project := s.Context().Value(ctxProjectKey{}).(*db.Project)
20+ return project
21+}
22+
23+func getBucket(s ssh.Session) (storage.Bucket, error) {
24+ bucket := s.Context().Value(ctxBucketKey{}).(storage.Bucket)
25+ if bucket.Name == "" {
26+ return bucket, fmt.Errorf("bucket not set on `ssh.Context()` for connection")
27+ }
28+ return bucket, nil
29+}
30+
31 func getUser(s ssh.Session) (*db.User, error) {
32 user := s.Context().Value(ctxUserKey{}).(*db.User)
33 if user == nil {
34@@ -145,6 +164,8 @@ func (h *UploadAssetHandler) Validate(s ssh.Session) error {
35 if err != nil {
36 return err
37 }
38+ s.Context().SetValue(ctxBucketKey{}, bucket)
39+
40 totalFileSize, err := h.Storage.GetBucketQuota(bucket)
41 if err != nil {
42 return err
43@@ -176,12 +197,35 @@ func (h *UploadAssetHandler) Write(s ssh.Session, entry *utils.FileEntry) (strin
44 // filesize from sftp,scp,rsync
45 entry.Size = int64(fileSize)
46
47- assetBucket := shared.GetAssetBucketName(user.ID)
48- bucket, err := h.Storage.UpsertBucket(assetBucket)
49+ bucket, err := getBucket(s)
50 if err != nil {
51 return "", err
52 }
53
54+ hasProject := getProject(s)
55+ projectName := shared.GetProjectName(entry)
56+
57+ // find, create, or update project if we haven't already done it
58+ if hasProject == nil {
59+ project, err := h.DBPool.FindProjectByName(user.ID, projectName)
60+ if err == nil {
61+ err = h.DBPool.UpdateProject(user.ID, projectName)
62+ if err != nil {
63+ return "", err
64+ }
65+ } else {
66+ _, err = h.DBPool.InsertProject(user.ID, projectName, projectName)
67+ if err != nil {
68+ return "", err
69+ }
70+ project, err = h.DBPool.FindProjectByName(user.ID, projectName)
71+ if err != nil {
72+ return "", err
73+ }
74+ }
75+ s.Context().SetValue(ctxProjectKey{}, project)
76+ }
77+
78 data := &FileData{
79 FileEntry: entry,
80 User: user,
81@@ -193,17 +237,6 @@ func (h *UploadAssetHandler) Write(s ssh.Session, entry *utils.FileEntry) (strin
82 return "", err
83 }
84
85- projectName := shared.GetProjectName(entry)
86-
87- // find and create project
88- _, err = h.DBPool.FindProjectByName(user.ID, projectName)
89- if err != nil {
90- _, err = h.DBPool.InsertProject(user.ID, projectName, projectName)
91- if err != nil {
92- return "", err
93- }
94- }
95-
96 url := getAssetURL(
97 h.Cfg,
98 user.Name,
+72,
-50
1@@ -14,6 +14,8 @@ import (
2
3 func getHelpText(userName, projectName string) string {
4 helpStr := "commands: [help, stats, ls, rm, link, unlink, prune, retain, depends]\n\n"
5+ helpStr += "NOTICE: any cmd that results in a mutation *must* be appended with `--write` for the changes to persist, otherwise it will simply output a dry-run.\n\n"
6+
7 sshCmdStr := fmt.Sprintf("ssh %s@pgs.sh", userName)
8 helpStr += fmt.Sprintf("`%s help`: prints this screen\n", sshCmdStr)
9 helpStr += fmt.Sprintf("`%s stats`: prints stats for user\n", sshCmdStr)
10@@ -39,36 +41,61 @@ type Cmd struct {
11 write bool
12 }
13
14+func (c *Cmd) output(out string) {
15+ _, _ = c.session.Write([]byte(out + "\n"))
16+}
17+
18+func (c *Cmd) bail(err error) {
19+ if err == nil {
20+ return
21+ }
22+ c.log.Error(err)
23+ utils.ErrorHandler(c.session, err)
24+}
25+
26+func (c *Cmd) notice() {
27+ if !c.write {
28+ c.output("\nNOTICE: changes not commited, use `--write` to save operation")
29+ }
30+}
31+
32 func (c *Cmd) rmProjectAssets(projectName string) error {
33 bucketName := shared.GetAssetBucketName(c.user.ID)
34 bucket, err := c.store.GetBucket(bucketName)
35 if err != nil {
36 return err
37 }
38+ c.output(fmt.Sprintf("removing project assets (%s)", projectName))
39
40 fileList, err := c.store.ListFiles(bucket, projectName+"/", true)
41 if err != nil {
42 return err
43 }
44
45+ if len(fileList) == 0 {
46+ c.output(fmt.Sprintf("no assets found for project (%s)", projectName))
47+ return nil
48+ }
49+ c.output(fmt.Sprintf("found (%d) assets for project (%s), removing", len(fileList), projectName))
50+
51 for _, file := range fileList {
52- intent := []byte(fmt.Sprintf("deleted (%s)\n", file.Name()))
53+ intent := fmt.Sprintf("deleted (%s)", file.Name())
54 if c.write {
55 err = c.store.DeleteFile(bucket, file.Name())
56 if err == nil {
57- _, _ = c.session.Write(intent)
58+ c.output(intent)
59 } else {
60 return err
61 }
62 } else {
63- _, _ = c.session.Write(intent)
64+ c.output(intent)
65 }
66 }
67 return nil
68 }
69
70 func (c *Cmd) help() {
71- _, _ = c.session.Write([]byte(getHelpText(c.user.Name, "project-a")))
72+ c.output(getHelpText(c.user.Name, "project-a"))
73 }
74
75 func (c *Cmd) stats(maxSize int) error {
76@@ -96,8 +123,8 @@ func (c *Cmd) stats(maxSize int) error {
77 shared.BytesToGB(maxSize),
78 (float32(totalFileSize)/float32(maxSize))*100,
79 )
80- str += fmt.Sprintf("projects:\t%d\n", len(projects))
81- _, _ = c.session.Write([]byte(str))
82+ str += fmt.Sprintf("projects:\t%d", len(projects))
83+ c.output(str)
84
85 return nil
86 }
87@@ -109,16 +136,15 @@ func (c *Cmd) ls() error {
88 }
89
90 if len(projects) == 0 {
91- out := "no linked projects found\n"
92- _, _ = c.session.Write([]byte(out))
93+ c.output("no projects found")
94 }
95
96 for _, project := range projects {
97- out := fmt.Sprintf("%s (links to: %s)\n", project.Name, project.ProjectDir)
98+ out := fmt.Sprintf("%s (links to: %s)", project.Name, project.ProjectDir)
99 if project.Name == project.ProjectDir {
100- out = fmt.Sprintf("%s\n", project.Name)
101+ out = project.Name
102 }
103- _, _ = c.session.Write([]byte(out))
104+ c.output(out)
105 }
106
107 return nil
108@@ -135,6 +161,7 @@ func (c *Cmd) unlink(projectName string) error {
109 if err != nil {
110 return err
111 }
112+ c.output(fmt.Sprintf("(%s) unlinked", project.Name))
113
114 return nil
115 }
116@@ -153,16 +180,16 @@ func (c *Cmd) link(projectName, linkTo string) error {
117 projectID := ""
118 if err == nil {
119 projectID = project.ID
120- c.log.Infof("user (%s) already has project (%s), updating ...", c.user.Name, projectName)
121+ c.log.Infof("user (%s) already has project (%s), updating", c.user.Name, projectName)
122 err = c.dbpool.LinkToProject(c.user.ID, project.ID, projectDir, c.write)
123 if err != nil {
124 return err
125 }
126 } else {
127- c.log.Infof("user (%s) has no project record (%s), creating ...", c.user.Name, projectName)
128+ c.log.Infof("user (%s) has no project record (%s), creating", c.user.Name, projectName)
129 if !c.write {
130- out := fmt.Sprintf("(%s) cannot create a new project without `--write` permission, aborting ...\n", projectName)
131- _, _ = c.session.Write([]byte(out))
132+ out := fmt.Sprintf("(%s) cannot create a new project without `--write` permission, aborting", projectName)
133+ c.output(out)
134 return nil
135 }
136 id, err := c.dbpool.InsertProject(c.user.ID, projectName, projectName)
137@@ -172,22 +199,22 @@ func (c *Cmd) link(projectName, linkTo string) error {
138 projectID = id
139 }
140
141- c.log.Infof("user (%s) linking (%s) to (%s) ...", c.user.Name, projectName, projectDir)
142+ c.log.Infof("user (%s) linking (%s) to (%s)", c.user.Name, projectName, projectDir)
143 err = c.dbpool.LinkToProject(c.user.ID, projectID, projectDir, c.write)
144 if err != nil {
145 return err
146 }
147
148- out := fmt.Sprintf("(%s) might have orphaned assets, removing ...\n", projectName)
149- _, _ = c.session.Write([]byte(out))
150+ out := fmt.Sprintf("(%s) might have orphaned assets, removing", projectName)
151+ c.output(out)
152
153 err = c.rmProjectAssets(projectName)
154 if err != nil {
155 return err
156 }
157
158- out = fmt.Sprintf("(%s) now points to (%s)\n", projectName, linkTo)
159- _, _ = c.session.Write([]byte(out))
160+ out = fmt.Sprintf("(%s) now points to (%s)", projectName, linkTo)
161+ c.output(out)
162 return nil
163 }
164
165@@ -198,17 +225,17 @@ func (c *Cmd) depends(projectName string) error {
166 }
167
168 if len(projects) == 0 {
169- out := fmt.Sprintf("no projects linked to this project (%s) found\n", projectName)
170- _, _ = c.session.Write([]byte(out))
171+ out := fmt.Sprintf("no projects linked to this project (%s) found", projectName)
172+ c.output(out)
173 return nil
174 }
175
176 for _, project := range projects {
177- out := fmt.Sprintf("%s (links to: %s)\n", project.Name, project.ProjectDir)
178+ out := fmt.Sprintf("%s (links to: %s)", project.Name, project.ProjectDir)
179 if project.Name == project.ProjectDir {
180- out = fmt.Sprintf("%s\n", project.Name)
181+ out = project.Name
182 }
183- _, _ = c.session.Write([]byte(out))
184+ c.output(out)
185 }
186
187 return nil
188@@ -218,6 +245,8 @@ func (c *Cmd) depends(projectName string) error {
189 // but keep the latest N records.
190 func (c *Cmd) prune(prefix string, keepNumLatest int) error {
191 c.log.Infof("user (%s) running `clean` command for (%s)", c.user.Name, prefix)
192+ c.output(fmt.Sprintf("searching for projects that match prefix (%s) and are not linked to other projects", prefix))
193+
194 if prefix == "" || prefix == "*" {
195 e := fmt.Errorf("must provide valid prefix")
196 return e
197@@ -228,6 +257,11 @@ func (c *Cmd) prune(prefix string, keepNumLatest int) error {
198 return err
199 }
200
201+ if len(projects) == 0 {
202+ c.output(fmt.Sprintf("no projects found matching prefix (%s)", prefix))
203+ return nil
204+ }
205+
206 rmProjects := []*db.Project{}
207 for _, project := range projects {
208 links, err := c.dbpool.FindProjectLinks(c.user.ID, project.Name)
209@@ -236,9 +270,10 @@ func (c *Cmd) prune(prefix string, keepNumLatest int) error {
210 }
211
212 if len(links) == 0 {
213- out := fmt.Sprintf("project (%s) is available to delete\n", project.Name)
214- _, _ = c.session.Write([]byte(out))
215 rmProjects = append(rmProjects, project)
216+ } else {
217+ out := fmt.Sprintf("project (%s) has (%d) projects linked to it, cannot prune", project.Name, len(projects))
218+ c.output(out)
219 }
220 }
221
222@@ -248,16 +283,18 @@ func (c *Cmd) prune(prefix string, keepNumLatest int) error {
223 }
224
225 for _, project := range goodbye {
226+ out := fmt.Sprintf("project (%s) is available to be pruned", project.Name)
227+ c.output(out)
228 err = c.rmProjectAssets(project.Name)
229 if err != nil {
230 return err
231 }
232
233- out := fmt.Sprintf("(%s) removing ...\n", project.Name)
234- _, _ = c.session.Write([]byte(out))
235+ out = fmt.Sprintf("(%s) removing", project.Name)
236+ c.output(out)
237
238 if c.write {
239- c.log.Infof("(%s) removing ...", project.Name)
240+ c.log.Infof("(%s) removing", project.Name)
241 err = c.dbpool.RemoveProject(project.ID)
242 if err != nil {
243 return err
244@@ -272,7 +309,7 @@ func (c *Cmd) rm(projectName string) error {
245 c.log.Infof("user (%s) running `rm` command for (%s)", c.user.Name, projectName)
246 project, err := c.dbpool.FindProjectByName(c.user.ID, projectName)
247 if err == nil {
248- c.log.Infof("found project (%s) (%s), checking dependencies ...", projectName, project.ID)
249+ c.log.Infof("found project (%s) (%s), checking dependencies", projectName, project.ID)
250
251 links, err := c.dbpool.FindProjectLinks(c.user.ID, projectName)
252 if err != nil {
253@@ -280,14 +317,14 @@ func (c *Cmd) rm(projectName string) error {
254 }
255
256 if len(links) > 0 {
257- e := fmt.Errorf("project (%s) has (%d) other projects linking to it, cannot delete project until they have been unlinked or removed, aborting ...", projectName, len(links))
258+ e := fmt.Errorf("project (%s) has (%d) projects linking to it, cannot delete project until they have been unlinked or removed, aborting", projectName, len(links))
259 return e
260 }
261
262- out := fmt.Sprintf("(%s) removing ...\n", project.Name)
263- _, _ = c.session.Write([]byte(out))
264+ out := fmt.Sprintf("(%s) removing", project.Name)
265+ c.output(out)
266 if c.write {
267- c.log.Infof("(%s) removing ...", project.Name)
268+ c.log.Infof("(%s) removing", project.Name)
269 err = c.dbpool.RemoveProject(project.ID)
270 if err != nil {
271 return err
272@@ -301,18 +338,3 @@ func (c *Cmd) rm(projectName string) error {
273 err = c.rmProjectAssets(project.Name)
274 return err
275 }
276-
277-func (c *Cmd) bail(err error) {
278- if err == nil {
279- return
280- }
281- c.log.Error(err)
282- utils.ErrorHandler(c.session, err)
283-}
284-
285-func (c *Cmd) notice() {
286- if !c.write {
287- out := "\nNOTICE: changes not commited, use `--write` to save operation\n"
288- _, _ = c.session.Write([]byte(out))
289- }
290-}