feat: cleanup cli

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
Henrique Dias 2019-01-06 13:21:31 +00:00
parent 2b8bd28158
commit 999c69de5c
15 changed files with 176 additions and 132 deletions

View File

@ -1,22 +1,20 @@
package cmd
import (
"strings"
"github.com/spf13/cobra"
)
func init() {
cmdsCmd.AddCommand(cmdsAddCmd)
cmdsAddCmd.Flags().StringP("command", "c", "", "command to add")
cmdsAddCmd.Flags().StringP("event", "e", "", "corresponding event")
cmdsAddCmd.MarkFlagRequired("command")
cmdsAddCmd.MarkFlagRequired("event")
}
var cmdsAddCmd = &cobra.Command{
Use: "add",
Use: "add <event> <command>",
Short: "Add a command to run on a specific event",
Long: `Add a command to run on a specific event.`,
Args: cobra.NoArgs,
Args: cobra.MinimumNArgs(2),
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
@ -24,10 +22,9 @@ var cmdsAddCmd = &cobra.Command{
s, err := st.Settings.Get()
checkErr(err)
evt := mustGetString(cmd, "event")
command := mustGetString(cmd, "command")
command := strings.Join(args[1:], " ")
s.Commands[evt] = append(s.Commands[evt], command)
s.Commands[args[0]] = append(s.Commands[args[0]], command)
err = st.Settings.Save(s)
checkErr(err)
printEvents(s.Commands)

View File

@ -1,34 +1,49 @@
package cmd
import (
"strconv"
"github.com/spf13/cobra"
)
func init() {
cmdsCmd.AddCommand(cmdsRmCmd)
cmdsRmCmd.Flags().StringP("event", "e", "", "corresponding event")
cmdsRmCmd.Flags().UintP("index", "i", 0, "command index")
cmdsRmCmd.MarkFlagRequired("event")
cmdsRmCmd.MarkFlagRequired("index")
}
var cmdsRmCmd = &cobra.Command{
Use: "rm",
Use: "rm <event> <index> [index_end]",
Short: "Removes a command from an event hooker",
Long: `Removes a command from an event hooker.`,
Args: cobra.NoArgs,
Args: func(cmd *cobra.Command, args []string) error {
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
return err
}
for _, arg := range args[1:] {
if _, err := strconv.Atoi(arg); err != nil {
return err
}
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
evt := args[0]
evt := mustGetString(cmd, "event")
i, err := cmd.Flags().GetUint("index")
i, err := strconv.Atoi(args[1])
checkErr(err)
f := i
if len(args) == 3 {
f, err = strconv.Atoi(args[2])
checkErr(err)
}
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][i+1:]...)
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...)
err = st.Settings.Save(s)
checkErr(err)
printEvents(s.Commands)

View File

@ -31,7 +31,6 @@ var configCmd = &cobra.Command{
func addConfigFlags(cmd *cobra.Command) {
addUserFlags(cmd)
cmd.Flags().StringP("baseURL", "b", "/", "base url of this installation")
cmd.Flags().BoolP("signup", "s", false, "allow users to signup")
cmd.Flags().String("shell", "", "shell command to which other commands should be appended")
@ -91,7 +90,6 @@ func getAuthentication(cmd *cobra.Command) (settings.AuthMethod, auth.Auther) {
func printSettings(s *settings.Settings, auther auth.Auther) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "\nBase URL:\t%s\n", s.BaseURL)
fmt.Fprintf(w, "Sign up:\t%t\n", s.Signup)
fmt.Fprintf(w, "Auth method:\t%s\n", s.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(s.Shell, " "))

View File

@ -43,7 +43,6 @@ override the options.`,
st := getStorage(db)
s := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit
BaseURL: mustGetString(cmd, "baseURL"),
Signup: mustGetBool(cmd, "signup"),
Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "),
AuthMethod: authMethod,

View File

@ -30,8 +30,6 @@ you want to change.`,
hasAuth := false
cmd.Flags().Visit(func(flag *pflag.Flag) {
switch flag.Name {
case "baseURL":
s.BaseURL = mustGetString(cmd, flag.Name)
case "signup":
s.Signup = mustGetBool(cmd, flag.Name)
case "auth.method":

View File

@ -2,6 +2,7 @@ package cmd
import (
"crypto/tls"
"errors"
"io/ioutil"
"log"
"net"
@ -27,10 +28,12 @@ var (
)
func init() {
cobra.OnInitialize(initConfig)
f := rootCmd.Flags()
pf := rootCmd.PersistentFlags()
f.StringVarP(&cfgFile, "config", "c", "", "config file (defaults are './.filebrowser[ext]', '$HOME/.filebrowser[ext]' or '/etc/filebrowser/.filebrowser[ext]')")
pf.StringVarP(&cfgFile, "config", "c", "", "config file path")
vaddP(pf, "database", "d", "./filebrowser.db", "path to the database")
vaddP(f, "address", "a", "127.0.0.1", "address to listen on")
vaddP(f, "log", "l", "stdout", "log output")
@ -38,6 +41,9 @@ func init() {
vaddP(f, "cert", "t", "", "tls certificate")
vaddP(f, "key", "k", "", "tls key")
vaddP(f, "scope", "s", ".", "scope to prepend to a user's scope when it is relative")
vaddP(f, "baseurl", "b", "", "base url")
vadd(f, "username", "admin", "username for the first user when using quick config")
vadd(f, "password", "admin", "password for the first user when using quick config")
if err := v.BindPFlags(f); err != nil {
panic(err)
@ -52,17 +58,43 @@ var rootCmd = &cobra.Command{
Use: "filebrowser",
Short: "A stylish web-based file browser",
Long: `File Browser CLI lets you create the database to use with File Browser,
manage your user and all the configurations without accessing the
manage your users and all the configurations without acessing the
web interface.
If you've never run File Browser, you will need to create the database.
See 'filebrowser help config init' for more information.`,
If you've never run File Browser, you'll need to have a database for
it. Don't worry: you don't need to setup a separate database server.
We're using Bolt DB which is a single file database and all managed
by ourselves.
For this specific command, all the flags you have available (except
"config" for the configuration file), can be given either through
environment variables or configuration files.
If you don't set "config", it will look for a configuration file called
.filebrowser.{json, toml, yaml, yml} in the following directories:
- ./
- $HOME/
- /etc/filebrowser/
The precedence of the configuration values are as follows:
- flag
- environment variable
- configuration file
- defaults
The environment variables are prefixed by "FB_" followed by the option
name in caps. So to set "database" via an env variable, you should
set FB_DATABASE equals to the path.
Also, if the database path doesn't exist, File Browser will enter into
the quick setup mode and a new database will be bootstraped and a new
user created with the credentials from options "username" and "password".`,
Run: serveAndListen,
}
func serveAndListen(cmd *cobra.Command, args []string) {
initConfig()
switch logMethod := v.GetString("log"); logMethod {
case "stdout":
log.SetOutput(os.Stdout)
@ -97,6 +129,12 @@ func serveAndListen(cmd *cobra.Command, args []string) {
checkErr(err)
settings, err := st.Settings.Get()
checkErr(err)
// Despite Base URL and Scope being "server" type of
// variables, we persist them to the database because
// they are needed during the execution and not only
// to start up the server.
settings.BaseURL = v.GetString("baseurl")
settings.Scope = scope
err = st.Settings.Save(settings)
checkErr(err)
@ -130,7 +168,7 @@ func quickSetup(cmd *cobra.Command) {
set := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit
BaseURL: "",
BaseURL: v.GetString("baseurl"),
Signup: false,
AuthMethod: auth.MethodJSONAuth,
Defaults: settings.UserDefaults{
@ -157,11 +195,17 @@ func quickSetup(cmd *cobra.Command) {
err = st.Auth.Save(&auth.JSONAuth{})
checkErr(err)
password, err := users.HashPwd("admin")
username := v.GetString("username")
password := v.GetString("password")
if username == "" || password == "" {
checkErr(errors.New("username and password cannot be empty during quick setup"))
}
password, err = users.HashPwd(password)
checkErr(err)
user := &users.User{
Username: "admin",
Username: username,
Password: password,
LockPassword: false,
}
@ -173,7 +217,6 @@ func quickSetup(cmd *cobra.Command) {
checkErr(err)
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile == "" {
home, err := homedir.Dir()
@ -194,8 +237,7 @@ func initConfig() {
if _, ok := err.(v.ConfigParseError); ok {
panic(err)
}
log.Println("No config file provided")
} else {
log.Println("Using config file:", v.ConfigFileUsed())
// TODO: log.Println("No config file provided")
}
// else TODO: log.Println("Using config file:", v.ConfigFileUsed())
}

View File

@ -1,6 +1,8 @@
package cmd
import (
"strconv"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/users"
@ -14,21 +16,39 @@ func init() {
}
var rulesRmCommand = &cobra.Command{
Use: "rm",
Use: "rm <index> [index_end]",
Short: "Remove a global rule or user rule",
Long: `Remove a global rule or user rule.`,
Args: cobra.NoArgs,
Args: func(cmd *cobra.Command, args []string) error {
if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
return err
}
for _, arg := range args {
if _, err := strconv.Atoi(arg); err != nil {
return err
}
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
index := mustGetUint(cmd, "index")
i, err := strconv.Atoi(args[0])
checkErr(err)
f := i
if len(args) == 2 {
f, err = strconv.Atoi(args[1])
checkErr(err)
}
user := func(u *users.User, st *storage.Storage) {
u.Rules = append(u.Rules[:index], u.Rules[index+1:]...)
u.Rules = append(u.Rules[:i], u.Rules[f+1:]...)
err := st.Users.Save(u)
checkErr(err)
}
global := func(s *settings.Settings, st *storage.Storage) {
s.Rules = append(s.Rules[:index], s.Rules[index+1:]...)
s.Rules = append(s.Rules[:i], s.Rules[f+1:]...)
err := st.Settings.Save(s)
checkErr(err)
}

View File

@ -83,9 +83,17 @@ func printRules(rules []rules.Rule, id interface{}) {
for id, rule := range rules {
fmt.Printf("(%d) ", id)
if rule.Regex {
fmt.Printf("Allow: %t\tRegex: %s\n", rule.Allow, rule.Regexp.Raw)
if rule.Allow {
fmt.Printf("Allow Regex: \t%s\n", rule.Regexp.Raw)
} else {
fmt.Printf("Allow: %t\tPath: %s\n", rule.Allow, rule.Path)
fmt.Printf("Disallow Regex: \t%s\n", rule.Regexp.Raw)
}
} else {
if rule.Allow {
fmt.Printf("Allow Path: \t%s\n", rule.Path)
} else {
fmt.Printf("Disallow Path: \t%s\n", rule.Path)
}
}
}
}

View File

@ -1,7 +1,6 @@
package cmd
import (
"errors"
"regexp"
"github.com/filebrowser/filebrowser/v2/rules"
@ -13,41 +12,33 @@ import (
func init() {
rulesCmd.AddCommand(rulesAddCmd)
rulesAddCmd.Flags().BoolP("allow", "a", false, "allow rule instead of disallow")
rulesAddCmd.Flags().StringP("path", "p", "", "path to which the rule applies")
rulesAddCmd.Flags().StringP("regex", "r", "", "regex to which the rule applies")
rulesAddCmd.Flags().BoolP("allow", "a", false, "indicates this is an allow rule")
rulesAddCmd.Flags().BoolP("regex", "r", false, "indicates this is a regex rule")
}
var rulesAddCmd = &cobra.Command{
Use: "add",
Use: "add <path|expression>",
Short: "Add a global rule or user rule",
Long: `Add a global rule or user rule. You must
set either path or regex.`,
Args: cobra.NoArgs,
Long: `Add a global rule or user rule.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
allow := mustGetBool(cmd, "allow")
path := mustGetString(cmd, "path")
regex := mustGetString(cmd, "regex")
regex := mustGetBool(cmd, "regex")
exp := args[0]
if path == "" && regex == "" {
panic(errors.New("you must set either --path or --regex flags"))
}
if path != "" && regex != "" {
panic(errors.New("you can't set --path and --regex flags at the same time"))
}
if regex != "" {
regexp.MustCompile(regex)
if regex {
regexp.MustCompile(exp)
}
rule := rules.Rule{
Allow: allow,
Path: path,
Regex: regex != "",
Regexp: &rules.Regexp{
Raw: regex,
},
Regex: regex,
}
if regex {
rule.Regexp = &rules.Regexp{Raw: exp}
} else {
rule.Path = exp
}
user := func(u *users.User, st *storage.Storage) {

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"strconv"
"text/tabwriter"
"github.com/filebrowser/filebrowser/v2/settings"
@ -53,15 +54,12 @@ func printUsers(users []*users.User) {
w.Flush()
}
func usernameOrIDRequired(cmd *cobra.Command, args []string) error {
username, _ := cmd.Flags().GetString("username")
id, _ := cmd.Flags().GetUint("id")
if username == "" && id == 0 {
return errors.New("'username' of 'id' flag required")
func parseUsernameOrID(arg string) (string, uint) {
id, err := strconv.ParseUint(arg, 10, 0)
if err != nil {
return arg, 0
}
return nil
return "", uint(id)
}
func addUserFlags(cmd *cobra.Command) {

View File

@ -6,20 +6,15 @@ import (
)
func init() {
usersCmd.AddCommand(usersNewCmd)
addUserFlags(usersNewCmd)
usersNewCmd.Flags().StringP("username", "u", "", "new users's username")
usersNewCmd.Flags().StringP("password", "p", "", "new user's password")
usersNewCmd.MarkFlagRequired("username")
usersNewCmd.MarkFlagRequired("password")
usersCmd.AddCommand(usersAddCmd)
addUserFlags(usersAddCmd)
}
var usersNewCmd = &cobra.Command{
Use: "new",
var usersAddCmd = &cobra.Command{
Use: "add <username> <password>",
Short: "Create a new user",
Long: `Create a new user and add it to the database.`,
Args: cobra.NoArgs,
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
@ -29,12 +24,11 @@ var usersNewCmd = &cobra.Command{
checkErr(err)
getUserDefaults(cmd, &s.Defaults, false)
password, _ := cmd.Flags().GetString("password")
password, err = users.HashPwd(password)
password, err := users.HashPwd(args[1])
checkErr(err)
user := &users.User{
Username: mustGetString(cmd, "username"),
Username: args[0],
Password: password,
LockPassword: mustGetBool(cmd, "lockPassword"),
}

View File

@ -8,15 +8,13 @@ import (
func init() {
usersCmd.AddCommand(usersFindCmd)
usersCmd.AddCommand(usersLsCmd)
usersFindCmd.Flags().StringP("username", "u", "", "username to find")
usersFindCmd.Flags().UintP("id", "i", 0, "id to find")
}
var usersFindCmd = &cobra.Command{
Use: "find",
Use: "find <id|username>",
Short: "Find a user by username or id",
Long: `Find a user by username or id. If no flag is set, all users will be printed.`,
Args: cobra.NoArgs,
Args: cobra.ExactArgs(1),
Run: findUsers,
}
@ -32,28 +30,25 @@ var findUsers = func(cmd *cobra.Command, args []string) {
defer db.Close()
st := getStorage(db)
settings, err := st.Settings.Get()
checkErr(err)
username, _ := cmd.Flags().GetString("username")
id, _ := cmd.Flags().GetUint("id")
var list []*users.User
var user *users.User
var (
list []*users.User
user *users.User
err error
)
if len(args) == 1 {
username, id := parseUsernameOrID(args[0])
if username != "" {
user, err = st.Users.Get(settings.Scope, username)
} else if id != 0 {
user, err = st.Users.Get(settings.Scope, id)
user, err = st.Users.Get("", username)
} else {
list, err = st.Users.Gets(settings.Scope)
user, err = st.Users.Get("", id)
}
list = []*users.User{user}
} else {
list, err = st.Users.Gets("")
}
checkErr(err)
if user != nil {
list = []*users.User{user}
}
printUsers(list)
}

View File

@ -8,23 +8,19 @@ import (
func init() {
usersCmd.AddCommand(usersRmCmd)
usersRmCmd.Flags().StringP("username", "u", "", "username to delete")
usersRmCmd.Flags().UintP("id", "i", 0, "id to delete")
}
var usersRmCmd = &cobra.Command{
Use: "rm",
Use: "rm <id|username>",
Short: "Delete a user by username or id",
Long: `Delete a user by username or id`,
Args: usernameOrIDRequired,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getStorage(db)
username, _ := cmd.Flags().GetString("username")
id, _ := cmd.Flags().GetUint("id")
username, id := parseUsernameOrID(args[0])
var err error
if username != "" {

View File

@ -9,18 +9,17 @@ import (
func init() {
usersCmd.AddCommand(usersUpdateCmd)
usersUpdateCmd.Flags().UintP("id", "i", 0, "id of the user")
usersUpdateCmd.Flags().StringP("username", "u", "", "user to change or new username if flag 'id' is set")
usersUpdateCmd.Flags().StringP("password", "p", "", "new password")
usersUpdateCmd.Flags().StringP("username", "u", "", "new username")
addUserFlags(usersUpdateCmd)
}
var usersUpdateCmd = &cobra.Command{
Use: "update",
Use: "update <id|username>",
Short: "Updates an existing user",
Long: `Updates an existing user. Set the flags for the
options you want to change.`,
Args: usernameOrIDRequired,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
@ -29,9 +28,9 @@ options you want to change.`,
set, err := st.Settings.Get()
checkErr(err)
id, _ := cmd.Flags().GetUint("id")
username := mustGetString(cmd, "username")
username, id := parseUsernameOrID(args[0])
password := mustGetString(cmd, "password")
newUsername := mustGetString(cmd, "username")
var user *users.User
@ -60,8 +59,8 @@ options you want to change.`,
user.Sorting = defaults.Sorting
user.LockPassword = mustGetBool(cmd, "lockPassword")
if user.Username != username && username != "" {
user.Username = username
if newUsername != "" {
user.Username = newUsername
}
if password != "" {

View File

@ -55,12 +55,6 @@ func mustGetBool(cmd *cobra.Command, flag string) bool {
return b
}
func mustGetInt(cmd *cobra.Command, flag string) int {
b, err := cmd.Flags().GetInt(flag)
checkErr(err)
return b
}
func mustGetUint(cmd *cobra.Command, flag string) uint {
b, err := cmd.Flags().GetUint(flag)
checkErr(err)