Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

structured/sectioned .driverc configuration #813

Merged
merged 1 commit into from
Dec 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,8 @@ drive <command> -h
drive push -h
```

and the value is the argument that you'd ordinarily supply on the commandline
and the value is the argument that you'd ordinarily supply on the commandline.
.driverc configurations can be optionally grouped in sections. See https://github.com/odeke-em/drive/issues/778.

For example:

Expand All @@ -1164,6 +1165,20 @@ cat << ! >> ~/.driverc
> exports=doc,pdf
> depth=100
> no-prompt=true
>
> # For pushes
> [list]
> depth=2
> long=true
>
> [push]
> verbose=false
>
> [stat]
> depth=3
>
> [pull/push]
> no-clobber=true
> !

cat << ! >> ~/emm.odeke-drive/.driverc
Expand Down
24 changes: 16 additions & 8 deletions cmd/drive/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@ func translateKeyChecks(definedFlags map[string]*flag.Flag) map[string]bool {
}

type defaultsFiller struct {
command string
from, to interface{}
rcSourcePath string
definedFlags map[string]*flag.Flag
}

func fillWithDefaults(df defaultsFiller) error {
alreadyDefined := translateKeyChecks(df.definedFlags)
jsonStringified, err := drive.JSONStringifySiftedCLITags(df.from, df.rcSourcePath, alreadyDefined)
jsonStringified, err := drive.JSONStringifySiftedCLITags(df.from, df.rcSourcePath, alreadyDefined, df.command)

if err != nil {
return err
Expand Down Expand Up @@ -352,7 +353,8 @@ func (lCmd *listCmd) _run(args []string, definedFlags map[string]*flag.Flag, dis
sources, context, path := preprocessArgsByToggle(args, (*lCmd.ById || *lCmd.Matches))
cmd := listCmd{}
df := defaultsFiller{
from: *lCmd, to: &cmd,
command: "list",
from: *lCmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
Expand Down Expand Up @@ -690,7 +692,8 @@ func (pCmd *pullCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, (*pCmd.ById || *pCmd.Matches || *pCmd.Starred))
cmd := pullCmd{}
df := defaultsFiller{
from: *pCmd, to: &cmd,
command: "pull",
from: *pCmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
Expand Down Expand Up @@ -889,7 +892,8 @@ func (qCmd *qrLinkCmd) Run(args []string, definedFlags map[string]*flag.Flag) {

cmd := qrLinkCmd{}
df := defaultsFiller{
from: *qCmd, to: &cmd,
command: "qr",
from: *qCmd, to: &cmd,
rcSourcePath: path,
definedFlags: definedFlags,
}
Expand Down Expand Up @@ -986,7 +990,8 @@ func exitIfIllogicalFileAndFolder(mask int) {
func (pCmd *pushCmd) createPushOptions(absEntryPath string, definedFlags map[string]*flag.Flag) (*drive.Options, error) {
cmd := pushCmd{}
df := defaultsFiller{
from: *pCmd, to: &cmd,
command: "push",
from: *pCmd, to: &cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
Expand Down Expand Up @@ -1226,7 +1231,8 @@ func (uCmd *unpublishCmd) Run(args []string, definedFlags map[string]*flag.Flag)

cmd := unpublishCmd{}
df := defaultsFiller{
from: *uCmd, to: &cmd,
command: "unpublish",
from: *uCmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
Expand Down Expand Up @@ -1700,7 +1706,8 @@ func (icmd *idCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgs(args)
cmd := idCmd{}
df := defaultsFiller{
from: *icmd, to: &cmd,
command: "id",
from: *icmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
Expand Down Expand Up @@ -1741,7 +1748,8 @@ func (ccmd *clashesCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *ccmd.ById)
cmd := clashesCmd{}
df := defaultsFiller{
from: *ccmd, to: &cmd,
command: "clashes",
from: *ccmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
Expand Down
2 changes: 2 additions & 0 deletions src/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,8 @@ func SiftCliTags(cs *CliSifter) string {
switch elem.Kind() {
case reflect.String:
stringified = fmt.Sprintf("%q", elem)
case reflect.Invalid:
continue
default:
stringified = fmt.Sprintf("%v", elem.Interface())
}
Expand Down
107 changes: 80 additions & 27 deletions src/rc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"os"
"path"
"strings"

"github.com/odeke-em/namespace"
)

var (
Expand All @@ -36,47 +38,70 @@ var (
FsHomeDir = os.Getenv(HomeEnvKey)
)

func kvifyCommentedFile(p, comment string) (kvMap map[string]string, err error) {
var clauses []string
kvMap = make(map[string]string)
clauses, err = readCommentedFile(p, comment)
func kvifyCommentedFile(p, comment string) (map[string]map[string]string, error) {
clauses, err := readCommentedFile(p, comment)
if err != nil {
return
return nil, err
}

for i, clause := range clauses {
kvf, kvErr := splitAndStrip(clause, true)
if kvErr != nil {
err = kvErr
return
linesChan := make(chan string)
go func() {
defer close(linesChan)
for _, clause := range clauses {
linesChan <- clause
}
}()

value, ok := kvf.value.(string)
if !ok {
err = fmt.Errorf("clause %d: expected a string instead got %v", i, kvf.value)
return
}
ns, err := namespace.ParseCh(linesChan)
if err != nil {
return nil, err
}

gkvMap := make(map[string]map[string]string)
for key, clauses := range ns {
kvMap := make(map[string]string)
for i, clause := range clauses {
kvf, kvErr := splitAndStrip(clause, true)
if kvErr != nil {
return nil, kvErr
}

kvMap[kvf.key] = value
value, ok := kvf.value.(string)
if !ok {
err = fmt.Errorf("clause %d: expected a string instead got %v", i, kvf.value)
return nil, err
}

kvMap[kvf.key] = value
}
gkvMap[key] = kvMap
}
return
return gkvMap, nil
}

func ResourceMappings(rcPath string) (parsed map[string]interface{}, err error) {
func ResourceMappings(rcPath string) (map[string]map[string]interface{}, error) {
beginOpts := Options{Path: rcPath}
rcPath, rcErr := beginOpts.rcPath()

if rcErr != nil {
err = rcErr
return
return nil, rcErr
}

rcMap, rErr := kvifyCommentedFile(rcPath, CommentStr)
nsRCMap, rErr := kvifyCommentedFile(rcPath, CommentStr)
if rErr != nil {
err = rErr
return
return nil, rErr
}
return parseRCValues(rcMap)

grouped := make(map[string]map[string]interface{})
for key, ns := range nsRCMap {
parsed, err := parseRCValues(ns)
if err != nil {
return nil, err
}
grouped[key] = parsed
}

return grouped, nil
}

func parseRCValues(rcMap map[string]string) (valueMappings map[string]interface{}, err error) {
Expand Down Expand Up @@ -105,7 +130,7 @@ func parseRCValues(rcMap map[string]string) (valueMappings map[string]interface{
CLIOptionUnified, CLIOptionDiffBaseLocal,
ExportsKey, ExcludeOpsKey, CLIOptionUnifiedShortKey,
CLIOptionNotOwner, ExportsDirKey, CLIOptionExactTitle, AddressKey,
CLIEncryptionPassword, CLIDecryptionPassword,
CLIEncryptionPassword, CLIDecryptionPassword, SortKey,
},
},
{
Expand Down Expand Up @@ -197,17 +222,45 @@ func splitAndStrip(line string, resolveFromEnv bool) (kv keyValue, err error) {
return
}

func JSONStringifySiftedCLITags(from interface{}, rcSourcePath string, defined map[string]bool) (string, error) {
func JSONStringifySiftedCLITags(from interface{}, rcSourcePath string, defined map[string]bool, relevantNamespaces ...string) (string, error) {
rcMappings, err := ResourceMappings(rcSourcePath)
if err != nil && !NotExist(err) {
return "", err
}

cs := CliSifter{
From: from,
Defaults: rcMappings,
Defaults: mergeNamespaces(rcMappings, relevantNamespaces...),
AlreadyDefined: defined,
}

return SiftCliTags(&cs), nil
}

func copyAndOverWriteNs(from, to map[string]interface{}) {
for fK, fV := range from {
to[fK] = fV
}
}

func mergeNamespaces(ns map[string]map[string]interface{}, relevantKeys ...string) map[string]interface{} {
// Start with the global namespace and proceed overwriting from specific keys
var combinedNs map[string]interface{} = ns[namespace.GlobalNamespaceKey]
if combinedNs == nil {
combinedNs = make(map[string]interface{})
}

for _, key := range relevantKeys {
kNs := ns[key]
if len(kNs) < 1 {
// TODO: Decide if not setting anything in the namespace
// means exclude it entirely hence make combinedNs nil?
continue
}

// Now merge them: from -> to
copyAndOverWriteNs(kNs, combinedNs)
}

return combinedNs
}
Loading