aboutsummaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2023-12-25 11:54:07 +0100
committerPřemysl Eric Janouch <p@janouch.name>2023-12-25 11:54:07 +0100
commitccf9aa8512e46261cca0df3e27f71904c22234d8 (patch)
treeeecf47eab17fb767679113fcb693c8b5a2e51639 /main.go
parentb1857cbe0437060faa1fc5aa64bc4676a34acd78 (diff)
downloadgallery-ccf9aa8512e46261cca0df3e27f71904c22234d8.tar.gz
gallery-ccf9aa8512e46261cca0df3e27f71904c22234d8.tar.xz
gallery-ccf9aa8512e46261cca0df3e27f71904c22234d8.zip
Add a remove command
Diffstat (limited to 'main.go')
-rw-r--r--main.go56
1 files changed, 51 insertions, 5 deletions
diff --git a/main.go b/main.go
index 8179446..811a2c6 100644
--- a/main.go
+++ b/main.go
@@ -344,7 +344,7 @@ func handleAPIBrowse(w http.ResponseWriter, r *http.Request) {
}
defer tx.Rollback()
- parent, err := idForPath(tx, decodeWebPath(params.Path), false)
+ parent, err := idForDirectoryPath(tx, decodeWebPath(params.Path), false)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
@@ -621,7 +621,7 @@ func getOrphanReplacement(webPath string) (*webOrphanImage, error) {
return nil, nil
}
- parent, err := idForPath(tx, path[:len(path)-1], false)
+ parent, err := idForDirectoryPath(tx, path[:len(path)-1], false)
if err != nil {
return nil, err
}
@@ -1070,7 +1070,7 @@ func cmdWeb(args []string) error {
// --- Import ------------------------------------------------------------------
-func idForPath(tx *sql.Tx, path []string, create bool) (int64, error) {
+func idForDirectoryPath(tx *sql.Tx, path []string, create bool) (int64, error) {
var parent sql.NullInt64
for _, name := range path {
if err := tx.QueryRow(`SELECT id FROM node
@@ -1130,7 +1130,7 @@ func (dm *directoryManager) IDForDirectoryPath(
return id, nil
}
- id, err := idForPath(tx, list, true)
+ id, err := idForDirectoryPath(tx, list, true)
if err != nil {
return 0, err
}
@@ -1688,7 +1688,7 @@ func syncRoot(c *syncContext, fsPath string) error {
//
// Synchronizing F → D or * → F are special cases not worth implementing.
crumbs := decodeWebPath(filepath.ToSlash(fsPath))
- dbParent, err := idForPath(c.tx, crumbs, true)
+ dbParent, err := idForDirectoryPath(c.tx, crumbs, true)
if err != nil {
return err
}
@@ -1881,6 +1881,51 @@ func cmdSync(args []string) error {
return tx.Commit()
}
+// --- Removal -----------------------------------------------------------------
+
+// cmdRemove is for manual removal of subtrees from the database.
+// Beware that inputs are database, not filesystem paths.
+func cmdRemove(args []string) error {
+ if len(args) < 2 {
+ return errors.New("usage: GD PATH...")
+ }
+ if err := openDB(args[0]); err != nil {
+ return err
+ }
+
+ tx, err := db.BeginTx(context.Background(), nil)
+ if err != nil {
+ return err
+ }
+ defer tx.Rollback()
+
+ for _, path := range args[1:] {
+ var id sql.NullInt64
+ for _, name := range decodeWebPath(path) {
+ if err := tx.QueryRow(`SELECT id FROM node
+ WHERE parent IS ? AND name = ?`,
+ id, name).Scan(&id); err != nil {
+ return err
+ }
+ }
+ if id.Int64 == 0 {
+ return errors.New("can't remove root")
+ }
+
+ if _, err = tx.Exec(disposeCTE+`
+ INSERT OR IGNORE INTO orphan(sha1, path)
+ SELECT sha1, path FROM orphaned`, id); err != nil {
+ return err
+ }
+ if _, err = tx.Exec(disposeCTE+`
+ DELETE FROM node WHERE id
+ IN (SELECT DISTINCT id FROM children)`, id); err != nil {
+ return err
+ }
+ }
+ return tx.Commit()
+}
+
// --- Tagging -----------------------------------------------------------------
// cmdTag mass imports tags from data passed on stdin as a TSV
@@ -2338,6 +2383,7 @@ var commands = map[string]struct {
"import": {cmdImport},
"tag": {cmdTag},
"sync": {cmdSync},
+ "remove": {cmdRemove},
"check": {cmdCheck},
"thumbnail": {cmdThumbnail},
"dhash": {cmdDhash},