diff options
| author | Přemysl Eric Janouch <p@janouch.name> | 2024-12-29 16:05:53 +0100 | 
|---|---|---|
| committer | Přemysl Eric Janouch <p@janouch.name> | 2024-12-29 16:22:50 +0100 | 
| commit | fd192310c722f9169dab06282a908ddef509fb58 (patch) | |
| tree | d6a8a7d43b69f41754a1ae1c678ede9d5ad4c806 | |
| parent | b73e0b46225f447b08bb5b21cd7c1f199f9ff701 (diff) | |
| download | gallery-fd192310c722f9169dab06282a908ddef509fb58.tar.gz gallery-fd192310c722f9169dab06282a908ddef509fb58.tar.xz gallery-fd192310c722f9169dab06282a908ddef509fb58.zip | |
Add a forget function to dispose of orphans
Previously, there was no way of removing images from the database.
| -rw-r--r-- | main.go | 83 | 
1 files changed, 83 insertions, 0 deletions
| @@ -2030,6 +2030,88 @@ func cmdRemove(fs *flag.FlagSet, args []string) error {  	return tx.Commit()  } +// --- Forgetting -------------------------------------------------------------- + +// cmdForget is for purging orphaned images from the database. +func cmdForget(fs *flag.FlagSet, args []string) error { +	if err := fs.Parse(args); err != nil { +		return err +	} +	if fs.NArg() < 2 { +		return errWrongUsage +	} +	if err := openDB(fs.Arg(0)); err != nil { +		return err +	} + +	tx, err := db.Begin() +	if err != nil { +		return err +	} +	defer tx.Rollback() + +	// Creating a temporary database seems justifiable in this case. +	_, err = tx.Exec( +		`CREATE TEMPORARY TABLE forgotten (sha1 TEXT PRIMARY KEY)`) +	if err != nil { +		return err +	} +	stmt, err := tx.Prepare(`INSERT INTO forgotten (sha1) VALUES (?)`) +	if err != nil { +		return err +	} +	defer stmt.Close() +	for _, sha1 := range fs.Args()[1:] { +		if _, err := stmt.Exec(sha1); err != nil { +			return err +		} +	} + +	rows, err := tx.Query(`DELETE FROM forgotten +		WHERE sha1 IN (SELECT sha1 FROM node) +		OR sha1 NOT IN (SELECT sha1 FROM image) +		RETURNING sha1`) +	if err != nil { +		return err +	} +	defer rows.Close() +	for rows.Next() { +		var sha1 string +		if err := rows.Scan(&sha1); err != nil { +			return err +		} +		log.Printf("not an orphan or not known at all: %s", sha1) +	} +	if _, err = tx.Exec(` +		DELETE FROM tag_assignment WHERE sha1 IN (SELECT sha1 FROM forgotten); +		DELETE FROM orphan WHERE sha1 IN (SELECT sha1 FROM forgotten); +		DELETE FROM image WHERE sha1 IN (SELECT sha1 FROM forgotten); +	 `); err != nil { +		return err +	} + +	rows, err = tx.Query(`SELECT sha1 FROM forgotten`) +	if err != nil { +		return err +	} +	defer rows.Close() +	for rows.Next() { +		var sha1 string +		if err := rows.Scan(&sha1); err != nil { +			return err +		} +		if err := os.Remove(imagePath(sha1)); err != nil && +			!os.IsNotExist(err) { +			log.Printf("%s", err) +		} +		if err := os.Remove(thumbPath(sha1)); err != nil && +			!os.IsNotExist(err) { +			log.Printf("%s", err) +		} +	} +	return tx.Commit() +} +  // --- Tagging -----------------------------------------------------------------  // cmdTag mass imports tags from data passed on stdin as a TSV @@ -2641,6 +2723,7 @@ var commands = map[string]struct {  	"tag":       {cmdTag, "GD SPACE [DESCRIPTION]", "Import tags."},  	"sync":      {cmdSync, "GD ROOT...", "Synchronise with the filesystem."},  	"remove":    {cmdRemove, "GD PATH...", "Remove database subtrees."}, +	"forget":    {cmdForget, "GD SHA1...", "Dispose of orphans."},  	"check":     {cmdCheck, "GD", "Run consistency checks."},  	"thumbnail": {cmdThumbnail, "GD [SHA1...]", "Generate thumbnails."},  	"dhash":     {cmdDhash, "GD [SHA1...]", "Compute perceptual hashes."}, | 
