From ad502c67493ed882d58a9cd4fdc8234238e1d0ba Mon Sep 17 00:00:00 2001 From: Radhi Fadlillah Date: Fri, 9 Aug 2019 10:19:43 +0700 Subject: [PATCH] Add portable mode --- internal/cmd/add.go | 8 ++--- internal/cmd/delete.go | 10 +++--- internal/cmd/export.go | 2 +- internal/cmd/import.go | 6 ++-- internal/cmd/open.go | 4 +-- internal/cmd/pocket.go | 6 ++-- internal/cmd/print.go | 4 +-- internal/cmd/root-dev.go | 7 ++++ internal/cmd/root.go | 76 ++++++++++++++++++++++++++++++++++++---- internal/cmd/serve.go | 2 +- internal/cmd/update.go | 10 +++--- main.go | 22 +++--------- path-generator.go | 35 ------------------ 13 files changed, 106 insertions(+), 86 deletions(-) create mode 100644 internal/cmd/root-dev.go delete mode 100644 path-generator.go diff --git a/internal/cmd/add.go b/internal/cmd/add.go index d6907f6..8f592c9 100644 --- a/internal/cmd/add.go +++ b/internal/cmd/add.go @@ -63,7 +63,7 @@ func addHandler(cmd *cobra.Command, args []string) { } // Create bookmark ID - book.ID, err = DB.CreateNewID("bookmark") + book.ID, err = db.CreateNewID("bookmark") if err != nil { cError.Printf("Failed to create ID: %v\n", err) return @@ -150,7 +150,7 @@ func addHandler(cmd *cobra.Command, args []string) { // If needed, create offline archive as well if !noArchival { - archivePath := fp.Join(DataDir, "archive", fmt.Sprintf("%d", book.ID)) + archivePath := fp.Join(dataDir, "archive", fmt.Sprintf("%d", book.ID)) archivalRequest := warc.ArchivalRequest{ URL: url, Reader: archivalInput, @@ -173,14 +173,14 @@ func addHandler(cmd *cobra.Command, args []string) { } // Save bookmark to database - _, err = DB.SaveBookmarks(book) + _, err = db.SaveBookmarks(book) if err != nil { cError.Printf("Failed to save bookmark: %v\n", err) return } // Save article image to local disk - imgPath := fp.Join(DataDir, "thumb", fmt.Sprintf("%d", book.ID)) + imgPath := fp.Join(dataDir, "thumb", fmt.Sprintf("%d", book.ID)) for _, imageURL := range imageURLs { err = downloadBookImage(imageURL, imgPath, time.Minute) if err == nil { diff --git a/internal/cmd/delete.go b/internal/cmd/delete.go index 838ff7d..0826691 100644 --- a/internal/cmd/delete.go +++ b/internal/cmd/delete.go @@ -52,7 +52,7 @@ func deleteHandler(cmd *cobra.Command, args []string) { } // Delete bookmarks from database - err = DB.DeleteBookmarks(ids...) + err = db.DeleteBookmarks(ids...) if err != nil { cError.Printf("Failed to delete bookmarks: %v\n", err) return @@ -60,15 +60,15 @@ func deleteHandler(cmd *cobra.Command, args []string) { // Delete thumbnail image and archives from local disk if len(ids) == 0 { - thumbDir := fp.Join(DataDir, "thumb") - archiveDir := fp.Join(DataDir, "archive") + thumbDir := fp.Join(dataDir, "thumb") + archiveDir := fp.Join(dataDir, "archive") os.RemoveAll(thumbDir) os.RemoveAll(archiveDir) } else { for _, id := range ids { strID := strconv.Itoa(id) - imgPath := fp.Join(DataDir, "thumb", strID) - archivePath := fp.Join(DataDir, "archive", strID) + imgPath := fp.Join(dataDir, "thumb", strID) + archivePath := fp.Join(dataDir, "archive", strID) os.Remove(imgPath) os.Remove(archivePath) diff --git a/internal/cmd/export.go b/internal/cmd/export.go index 03fe4b1..de671b8 100644 --- a/internal/cmd/export.go +++ b/internal/cmd/export.go @@ -25,7 +25,7 @@ func exportCmd() *cobra.Command { func exportHandler(cmd *cobra.Command, args []string) { // Fetch bookmarks from database - bookmarks, err := DB.GetBookmarks(database.GetBookmarksOptions{}) + bookmarks, err := db.GetBookmarks(database.GetBookmarksOptions{}) if err != nil { cError.Printf("Failed to get bookmarks: %v\n", err) return diff --git a/internal/cmd/import.go b/internal/cmd/import.go index 11d9675..96043e7 100644 --- a/internal/cmd/import.go +++ b/internal/cmd/import.go @@ -40,7 +40,7 @@ func importHandler(cmd *cobra.Command, args []string) { } // Prepare bookmark's ID - bookID, err := DB.CreateNewID("bookmark") + bookID, err := db.CreateNewID("bookmark") if err != nil { cError.Printf("Failed to create ID: %v\n", err) return @@ -96,7 +96,7 @@ func importHandler(cmd *cobra.Command, args []string) { return } - if _, exist := DB.GetBookmark(0, url); exist { + if _, exist := db.GetBookmark(0, url); exist { cError.Printf("Skip %s: URL already exists\n", url) mapURL[url] = struct{}{} return @@ -133,7 +133,7 @@ func importHandler(cmd *cobra.Command, args []string) { }) // Save bookmark to database - bookmarks, err = DB.SaveBookmarks(bookmarks...) + bookmarks, err = db.SaveBookmarks(bookmarks...) if err != nil { cError.Printf("Failed to save bookmarks: %v\n", err) return diff --git a/internal/cmd/open.go b/internal/cmd/open.go index 986d862..ebbac29 100644 --- a/internal/cmd/open.go +++ b/internal/cmd/open.go @@ -72,7 +72,7 @@ func openHandler(cmd *cobra.Command, args []string) { WithContent: true, } - bookmarks, err := DB.GetBookmarks(getOptions) + bookmarks, err := db.GetBookmarks(getOptions) if err != nil { cError.Printf("Failed to get bookmarks: %v\n", err) return @@ -123,7 +123,7 @@ func openHandler(cmd *cobra.Command, args []string) { // Open archive id := strconv.Itoa(bookmarks[0].ID) - archivePath := fp.Join(DataDir, "archive", id) + archivePath := fp.Join(dataDir, "archive", id) archive, err := warc.Open(archivePath) if err != nil { diff --git a/internal/cmd/pocket.go b/internal/cmd/pocket.go index bc34ce7..61bbf4f 100644 --- a/internal/cmd/pocket.go +++ b/internal/cmd/pocket.go @@ -26,7 +26,7 @@ func pocketCmd() *cobra.Command { func pocketHandler(cmd *cobra.Command, args []string) { // Prepare bookmark's ID - bookID, err := DB.CreateNewID("bookmark") + bookID, err := db.CreateNewID("bookmark") if err != nil { cError.Printf("Failed to create ID: %v\n", err) return @@ -77,7 +77,7 @@ func pocketHandler(cmd *cobra.Command, args []string) { return } - if _, exist := DB.GetBookmark(0, url); exist { + if _, exist := db.GetBookmark(0, url); exist { cError.Printf("Skip %s: URL already exists\n", url) mapURL[url] = struct{}{} return @@ -106,7 +106,7 @@ func pocketHandler(cmd *cobra.Command, args []string) { }) // Save bookmark to database - bookmarks, err = DB.SaveBookmarks(bookmarks...) + bookmarks, err = db.SaveBookmarks(bookmarks...) if err != nil { cError.Printf("Failed to save bookmarks: %v\n", err) return diff --git a/internal/cmd/print.go b/internal/cmd/print.go index 23c7ea3..e90cd5b 100644 --- a/internal/cmd/print.go +++ b/internal/cmd/print.go @@ -12,7 +12,7 @@ func printCmd() *cobra.Command { cmd := &cobra.Command{ Use: "print [indices]", Short: "Print the saved bookmarks", - Long: "Show the saved bookmarks by its DB index. " + + Long: "Show the saved bookmarks by its database index. " + "Accepts space-separated list of indices (e.g. 5 6 23 4 110 45), " + "hyphenated range (e.g. 100-200) or both (e.g. 1-3 7 9). " + "If no arguments, all records with actual index from database are shown.", @@ -57,7 +57,7 @@ func printHandler(cmd *cobra.Command, args []string) { OrderMethod: orderMethod, } - bookmarks, err := DB.GetBookmarks(searchOptions) + bookmarks, err := db.GetBookmarks(searchOptions) if err != nil { cError.Printf("Failed to get bookmarks: %v\n", err) return diff --git a/internal/cmd/root-dev.go b/internal/cmd/root-dev.go new file mode 100644 index 0000000..7d4d626 --- /dev/null +++ b/internal/cmd/root-dev.go @@ -0,0 +1,7 @@ +// +build dev + +package cmd + +func init() { + developmentMode = true +} diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 97ea13b..4864975 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -4,20 +4,20 @@ import ( "crypto/tls" "net/http" "net/http/cookiejar" + "os" + fp "path/filepath" "time" "github.com/go-shiori/shiori/internal/database" + apppaths "github.com/muesli/go-app-paths" "github.com/spf13/cobra" ) var ( - // DB is database that used by cmd - DB database.DB - - // DataDir is directory for downloaded data - DataDir string - - httpClient *http.Client + db database.DB + dataDir string + httpClient *http.Client + developmentMode bool ) func init() { @@ -40,6 +40,8 @@ func ShioriCmd() *cobra.Command { Short: "Simple command-line bookmark manager built with Go", } + rootCmd.PersistentPreRun = preRunRootHandler + rootCmd.PersistentFlags().Bool("portable", false, "run shiori in portable mode") rootCmd.AddCommand( addCmd(), printCmd(), @@ -54,3 +56,63 @@ func ShioriCmd() *cobra.Command { return rootCmd } + +func preRunRootHandler(cmd *cobra.Command, args []string) { + // Read flag + var err error + portableMode, _ := cmd.Flags().GetBool("portable") + + // Get and create data dir + dataDir, err = getDataDir(portableMode) + if err != nil { + cError.Printf("Failed to get data dir: %v\n", err) + os.Exit(1) + } + + err = os.MkdirAll(dataDir, os.ModePerm) + if err != nil { + cError.Printf("Failed to create data dir: %v\n", err) + os.Exit(1) + } + + // Open database + dbPath := fp.Join(dataDir, "shiori.db") + db, err = database.OpenSQLiteDatabase(dbPath) + if err != nil { + cError.Printf("Failed to open database: %v\n", err) + os.Exit(1) + } +} + +func getDataDir(portableMode bool) (string, error) { + // If in portable mode, uses directory of executable + if portableMode { + exePath, err := os.Executable() + if err != nil { + return "", err + } + + exeDir := fp.Dir(exePath) + return fp.Join(exeDir, "shiori-data"), nil + } + + if developmentMode { + return "dev-data", nil + } + + // Try to look at environment variables + dataDir, found := os.LookupEnv("SHIORI_DIR") + if found { + return dataDir, nil + } + + // Try to use platform specific app path + userScope := apppaths.NewScope(apppaths.User, "shiori", "shiori") + dataDir, err := userScope.DataDir() + if err == nil { + return dataDir, nil + } + + // When all fail, use current working directory + return ".", nil +} diff --git a/internal/cmd/serve.go b/internal/cmd/serve.go index cd2957e..f3815a1 100644 --- a/internal/cmd/serve.go +++ b/internal/cmd/serve.go @@ -24,7 +24,7 @@ func serveCmd() *cobra.Command { func serveHandler(cmd *cobra.Command, args []string) { port, _ := cmd.Flags().GetInt("port") - err := webserver.ServeApp(DB, DataDir, port) + err := webserver.ServeApp(db, dataDir, port) if err != nil { logrus.Fatalf("Server error: %v\n", err) } diff --git a/internal/cmd/update.go b/internal/cmd/update.go index bf8ad4a..cd4af67 100644 --- a/internal/cmd/update.go +++ b/internal/cmd/update.go @@ -28,7 +28,7 @@ func updateCmd() *cobra.Command { "Accepts space-separated list of indices (e.g. 5 6 23 4 110 45), " + "hyphenated range (e.g. 100-200) or both (e.g. 1-3 7 9). " + "If no arguments, ALL bookmarks will be updated. Update works differently depending on the flags:\n" + - "- If indices are passed without any flags (--url, --title, --tag and --excerpt), read the URLs from DB and update titles from web.\n" + + "- If indices are passed without any flags (--url, --title, --tag and --excerpt), read the URLs from database and update titles from web.\n" + "- If --url is passed (and --title is omitted), update the title from web using the URL. While using this flag, update only accept EXACTLY one index.\n" + "While updating bookmark's tags, you can use - to remove tag (e.g. -nature to remove nature tag from this bookmark).", Run: updateHandler, @@ -106,7 +106,7 @@ func updateHandler(cmd *cobra.Command, args []string) { IDs: ids, } - bookmarks, err := DB.GetBookmarks(filterOptions) + bookmarks, err := db.GetBookmarks(filterOptions) if err != nil { cError.Printf("Failed to get bookmarks: %v\n", err) return @@ -230,7 +230,7 @@ func updateHandler(cmd *cobra.Command, args []string) { imageURLs = append(imageURLs, article.Favicon) } - imgPath := fp.Join(DataDir, "thumb", fmt.Sprintf("%d", book.ID)) + imgPath := fp.Join(dataDir, "thumb", fmt.Sprintf("%d", book.ID)) for _, imageURL := range imageURLs { err = downloadBookImage(imageURL, imgPath, time.Minute) if err == nil { @@ -242,7 +242,7 @@ func updateHandler(cmd *cobra.Command, args []string) { // If needed, update offline archive as well. // Make sure to delete the old one first. if !noArchival { - archivePath := fp.Join(DataDir, "archive", fmt.Sprintf("%d", book.ID)) + archivePath := fp.Join(dataDir, "archive", fmt.Sprintf("%d", book.ID)) os.Remove(archivePath) archivalRequest := warc.ArchivalRequest{ @@ -360,7 +360,7 @@ func updateHandler(cmd *cobra.Command, args []string) { } // Save bookmarks to database - bookmarks, err = DB.SaveBookmarks(bookmarks...) + bookmarks, err = db.SaveBookmarks(bookmarks...) if err != nil { cError.Printf("Failed to save bookmark: %v\n", err) return diff --git a/main.go b/main.go index 7ad3e2c..e0571bd 100644 --- a/main.go +++ b/main.go @@ -3,14 +3,12 @@ package main import ( - "os" - fp "path/filepath" - "github.com/go-shiori/shiori/internal/cmd" - "github.com/go-shiori/shiori/internal/database" - _ "github.com/mattn/go-sqlite3" "github.com/sirupsen/logrus" + // Database driver + _ "github.com/mattn/go-sqlite3" + // Add this to prevent it removed by go mod tidy _ "github.com/shurcooL/vfsgen" ) @@ -18,20 +16,8 @@ import ( var dataDir = "dev-data" func main() { - // Make sure data dir exists - os.MkdirAll(dataDir, os.ModePerm) - - // Open database - dbPath := fp.Join(dataDir, "shiori.db") - sqliteDB, err := database.OpenSQLiteDatabase(dbPath) + err := cmd.ShioriCmd().Execute() if err != nil { logrus.Fatalln(err) } - - // Execute cmd - cmd.DB = sqliteDB - cmd.DataDir = dataDir - if err := cmd.ShioriCmd().Execute(); err != nil { - logrus.Fatalln(err) - } } diff --git a/path-generator.go b/path-generator.go deleted file mode 100644 index 310c585..0000000 --- a/path-generator.go +++ /dev/null @@ -1,35 +0,0 @@ -// +build !dev - -package main - -import ( - "os" - - apppaths "github.com/muesli/go-app-paths" -) - -func init() { - // Get data directory - dataDir = getDataDirectory() - - // Make sure directory exist - os.MkdirAll(dataDir, os.ModePerm) -} - -func getDataDirectory() string { - // Try to look at environment variables - dataDir, found := os.LookupEnv("SHIORI_DIR") - if found { - return dataDir - } - - // Try to use platform specific app path - userScope := apppaths.NewScope(apppaths.User, "shiori", "shiori") - dataDir, err := userScope.DataDir() - if err == nil { - return dataDir - } - - // When all fail, use current working directory - return "." -}