steffenfritz / FileTrove

FileTrove indexes files and creates metadata from them.
https://filetrove.fritz.wtf
GNU Affero General Public License v3.0
26 stars 5 forks source link

[CHANGE] Fully enable customization of install directory #50

Open ross-spencer opened 3 months ago

ross-spencer commented 3 months ago

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Install allows a user to specify an installation directory but filetrove uses hard-coded paths to determine locations, e.g. in the diff below I have tried to demonstrate each affected path on application startup with my own tmp path (the list isn't exhaustive):

diff --git a/cmd/ftrove/main.go b/cmd/ftrove/main.go
index ebbd0c5..f1c05f5 100644
--- a/cmd/ftrove/main.go
+++ b/cmd/ftrove/main.go
@@ -153,7 +153,7 @@ func main() {
    }

    // Change logger to MultiWriter for output to logfile and os.Stdout
-   logfd, err := os.OpenFile("logs/filetrove.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+   logfd, err := os.OpenFile("/tmp/filetrove/logs/filetrove.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        logger.Error("Could not open filetrove log file.", slog.String("error", err.Error()))
        os.Exit(1)
@@ -230,7 +230,7 @@ func main() {
    nsrlcount := 0

    // Prepare BoltDB for reading hashes
-   db, err := ft.ConnectNSRL("db/nsrl.db")
+   db, err := ft.ConnectNSRL("/tmp/filetrove/db/nsrl.db")
    if err != nil {
        logger.Error("Could not connect to NSRL database", slog.String("error", err.Error()))
        err = ftdb.Close()
@@ -343,7 +343,7 @@ func main() {
    }

    // Initialize siegfried database
-   s, err := siegfried.Load("db/siegfried.sig")
+   s, err := siegfried.Load("/tmp/filetrove/db/siegfried.sig")
    if err != nil {
        logger.Error("Could not read siegfried's database.", slog.String("error", err.Error()))
        err = ftdb.Close()
diff --git a/db.go b/db.go
index cb16074..c7da8d7 100644
--- a/db.go
+++ b/db.go
@@ -234,7 +234,7 @@ func ListSessions(db *sql.DB) error {
 // ExportSessionSessionTSV exports all session metadata from a session to a TSV file.
 // Filtering is done by session UUID.
 func ExportSessionSessionTSV(sessionuuid string) ([]string, error) {
-   db, err := sql.Open("sqlite3", "db/filetrove.db")
+   db, err := sql.Open("sqlite3", "/filetrove/tmp/db/filetrove.db")
    if err != nil {
        return nil, err
    }
@@ -312,7 +312,7 @@ func ExportSessionSessionTSV(sessionuuid string) ([]string, error) {
 // ExportSessionFilesTSV exports all file metadata from a session to a TSV file.
 // Filtering is done by session UUID.
 func ExportSessionFilesTSV(sessionuuid string) error {
-   db, err := sql.Open("sqlite3", "db/filetrove.db")
+   db, err := sql.Open("sqlite3", "/tmp/filetrove/db/filetrove.db")
    if err != nil {
        return err
    }
@@ -389,7 +389,7 @@ func ExportSessionFilesTSV(sessionuuid string) error {
 // ExportSessionDirectoriesTSV exports all directory metadata from a session to a TSV file.
 // Filtering is done by session UUID.
 func ExportSessionDirectoriesTSV(sessionuuid string) error {
-   db, err := sql.Open("sqlite3", "db/filetrove.db")
+   db, err := sql.Open("sqlite3", "/tmp/filetrove/db/filetrove.db")
    if err != nil {
        return err
    }
@@ -465,7 +465,7 @@ func ExportSessionDirectoriesTSV(sessionuuid string) error {

 // ExportSessionEXIFTSV exports all exif metadata from a session to a TSV file. Filtering is done by session UUID.
 func ExportSessionEXIFTSV(sessionuuid string) error {
-   db, err := sql.Open("sqlite3", "db/filetrove.db")
+   db, err := sql.Open("sqlite3", "/tmp/filetrove/db/filetrove.db")
    if err != nil {
        return err
    }
@@ -541,7 +541,7 @@ func ExportSessionEXIFTSV(sessionuuid string) error {

 // ExportSessionDCTSV exports all exif metadata from a session to a TSV file. Filtering is done by session UUID.
 func ExportSessionDCTSV(sessionuuid string) error {
-   db, err := sql.Open("sqlite3", "db/filetrove.db")
+   db, err := sql.Open("sqlite3", "/tmp/filetrove/db/filetrove.db")
    if err != nil {
        return err
    }

Describe the solution you'd like A clear and concise description of what you want to happen.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Leaving the code as-is will likely break use anywhere that isn't a standalone use of the tool, e.g. installed from /usr/bin where the user probably doesn't also want to install filetrove's static files there.

steffenfritz commented 3 months ago

For reference: Similar comment in closed issue #25, see https://github.com/steffenfritz/FileTrove/issues/25#issuecomment-1924822964

Use case: Installation of ftrove in /usr/bin and data somewhere else

General impacts: (i) Installation has to be rewritten and (ii) installation becomes more complex for the user

I see four possibilities, with different chances and problems:

  1. one flag for an application root, where db and logs are expected, nsrl.db, siegfried.sig and filetrove.db must be in db (+) Data and version(s) are coupled (+) Projects can have their own folders (-) less flexibility (-) nsrl.db has to be linked/copied manually

  2. two flags, one for db and one for logs (like mentioned in the referenced issue). Here is the idea to keep the binary and the NSRL coupled. (--) makes no sense with the above premise

  3. two flags, (i) one for root (like in 1.), coupling logs and db with filetrove.db and siegfried.sig, and (ii) one for the nsrl.db (+) Flexible (+) Reuse of NSRL (+) Installation paths clear for users (-) No coupling between nsrl data and version (at least the versions are stored in filetrove.db)

  4. four flags: nsrl.db, _filetrove.log, filetrove.db, siegfried.sig (+) Flexible (-) Scattered installations

For 1), 3) : During installation a env/toml/... file could be created in a root directory and if ftrove is run again, e.g. for listing sessions, this could be read and all "flag" information is stored there.

For 4): A general configuration file, e.g. in ~/.config, has to be used as there is no project root.

Probably I missed some combinations but from the above I think 3) is the best one. We could also have the nsrl.db location defaulting to db directory, like it is today.

On the other hand: ftrove is a statically linked binary that lives alone in a directory with just a few MB. To keep the data and the binary coupled is also not too bad (and was the idea in the first place). While I see the necessity to reuse nsrl.db, maybe we can leave everything as it is while add an optional location flag for nsrl.db?

ross-spencer commented 3 months ago

For configuration a dotfile seems great, the potential for XDG compatible directories might be worth investigating? (nb. I haven't enough experience with them yet so I need to brush up on that)

As for the use-cases, then the potential to reuse the NSRL database seems like an exciting one.

Where filetrove and its databases sit is less of a problem once the user can customize the configuration, e.g. my golang apps all install to one location that is on the $PATH so I might not co-locate these files but if I'm reading from a config it doesn't prevent me from using a number of different layouts.