-
Notifications
You must be signed in to change notification settings - Fork 538
/
root.go
141 lines (119 loc) · 3.34 KB
/
root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package cmd
import (
"fmt"
"os"
fp "path/filepath"
"github.com/go-shiori/shiori/internal/database"
apppaths "github.com/muesli/go-app-paths"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)
var (
db database.DB
dataDir string
developmentMode bool
)
// ShioriCmd returns the root command for shiori
func ShioriCmd() *cobra.Command {
rootCmd := &cobra.Command{
Use: "shiori",
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(),
updateCmd(),
deleteCmd(),
openCmd(),
importCmd(),
exportCmd(),
pocketCmd(),
serveCmd(),
checkCmd(),
migrateCmd(),
)
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
db, err = openDatabase(cmd.Context())
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")
dataDir, err := userScope.DataPath("")
if err == nil {
return dataDir, nil
}
// When all fail, use current working directory
return ".", nil
}
func openDatabase(ctx context.Context) (database.DB, error) {
switch dbms, _ := os.LookupEnv("SHIORI_DBMS"); dbms {
case "mysql":
return openMySQLDatabase(ctx)
case "postgresql":
return openPostgreSQLDatabase(ctx)
default:
return openSQLiteDatabase(ctx)
}
}
func openSQLiteDatabase(ctx context.Context) (database.DB, error) {
dbPath := fp.Join(dataDir, "shiori.db")
return database.OpenSQLiteDatabase(ctx, dbPath)
}
func openMySQLDatabase(ctx context.Context) (database.DB, error) {
user, _ := os.LookupEnv("SHIORI_MYSQL_USER")
password, _ := os.LookupEnv("SHIORI_MYSQL_PASS")
dbName, _ := os.LookupEnv("SHIORI_MYSQL_NAME")
dbAddress, _ := os.LookupEnv("SHIORI_MYSQL_ADDRESS")
connString := fmt.Sprintf("%s:%s@%s/%s?charset=utf8mb4", user, password, dbAddress, dbName)
return database.OpenMySQLDatabase(ctx, connString)
}
func openPostgreSQLDatabase(ctx context.Context) (database.DB, error) {
host, _ := os.LookupEnv("SHIORI_PG_HOST")
port, _ := os.LookupEnv("SHIORI_PG_PORT")
user, _ := os.LookupEnv("SHIORI_PG_USER")
password, _ := os.LookupEnv("SHIORI_PG_PASS")
dbName, _ := os.LookupEnv("SHIORI_PG_NAME")
connString := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbName)
return database.OpenPGDatabase(ctx, connString)
}