%PDF- %PDF-
Direktori : /home/waritko/go/src/github.com/odeke-em/drive/src/ |
Current File : //home/waritko/go/src/github.com/odeke-em/drive/src/rc.go |
// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package drive import ( "encoding/json" "errors" "fmt" "os" "path" "strings" "github.com/odeke-em/namespace" ) var ( ErrRcNoKeysMatched = errors.New("rcMapping: no keys matched") ) const ( DriveResourceConfiguration = ".driverc" ) var ( HomeEnvKey = "HOME" HomeShellEnvKey = "$" + HomeEnvKey FsHomeDir = os.Getenv(HomeEnvKey) ) func kvifyCommentedFile(p, comment string) (map[string]map[string]string, error) { clauses, err := readCommentedFile(p, comment) if err != nil { return nil, err } linesChan := make(chan string) go func() { defer close(linesChan) for _, clause := range clauses { linesChan <- clause } }() 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 } 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 gkvMap, nil } func ResourceMappings(rcPath string) (map[string]map[string]interface{}, error) { beginOpts := Options{Path: rcPath} rcPath, rcErr := beginOpts.rcPath() if rcErr != nil { DebugPrintf("tried to read from rcPath: %s got err: %v", rcPath, rcErr) return nil, rcErr } DebugPrintf("RCPath: %s", rcPath) nsRCMap, rErr := kvifyCommentedFile(rcPath, CommentStr) if rErr != nil { return nil, rErr } 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 } if jsonRepr, err := json.MarshalIndent(grouped, "", " "); err == nil { DebugPrintf("parsedContent from %q\n%s", rcPath, jsonRepr) } else { DebugPrintf("parsedContent from %q\n%s", rcPath, grouped) } return grouped, nil } func parseRCValues(rcMap map[string]string) (valueMappings map[string]interface{}, err error) { valueMappings = make(map[string]interface{}) targetKeys := []struct { resolver resolverEmitter keys []string }{ { resolver: _boolfer, keys: []string{ OcrKey, ConvertKey, CLIOptionFileBrowser, CLIOptionWebBrowser, CLIOptionVerboseKey, RecursiveKey, CLIOptionFiles, CLIOptionLongFmt, ForceKey, QuietKey, HiddenKey, NoPromptKey, NoClobberKey, IgnoreConflictKey, CLIOptionIgnoreNameClashes, CLIOptionIgnoreChecksum, CLIOptionFixClashesKey, CLIOptionDesktopLinks, CLIOptionExportsDumpToSameDirectory, CLIOptionTrashed, CLIOptionStarred, CLIOptionPiped, CLIOptionExplicitlyExport, CLIOptionDirectories, CLIOptionAllStarred, }, }, { resolver: _intfer, keys: []string{ PageSizeKey, DepthKey, CLIOptionRetryCount, }, }, { resolver: _stringfer, keys: []string{ CLIOptionUnified, CLIOptionDiffBaseLocal, ExportsKey, ExcludeOpsKey, CLIOptionUnifiedShortKey, CLIEncryptionPassword, CLIDecryptionPassword, SortKey, CLIOptionNotOwner, ExportsDirKey, CLIOptionExactTitle, AddressKey, CLIOptionPushDestination, CLIOptionSkipMime, CLIOptionMatchMime, ExportsKey, }, }, { resolver: _stringArrayfer, keys: []string{ // Add items that might need string array parsing and conversion here }, }, } accepted := make(map[string]typeResolver) for _, item := range targetKeys { resolver := item.resolver keys := item.keys for _, key := range keys { lowerKey := strings.ToLower(key) retr, ok := rcMap[lowerKey] if !ok { continue } tr := typeResolver{key: key, value: retr, resolver: resolver} accepted[lowerKey] = tr } } if false && len(accepted) < 1 { err = ErrRcNoKeysMatched return } for lowerKey, tResolver := range accepted { if value, err := tResolver.resolver(lowerKey, tResolver.value); err == nil { valueMappings[lowerKey] = value } else { fmt.Fprintf(os.Stderr, "rc: %s err %v\n", lowerKey, err) } } return } func rcMapToOptions(rcMap map[string]string) (*Options, error) { opts := &Options{} return opts, nil } func rcPath(absDirPath string) string { return path.Join(absDirPath, DriveResourceConfiguration) } func globalRcFile() string { ps := rcPath(FsHomeDir) return ps } func splitAndStrip(line string, resolveFromEnv bool) (kv keyValue, err error) { line = strings.Trim(line, " ") subStrCount := 2 splits := strings.SplitN(line, "=", subStrCount) splitsLen := len(splits) if splitsLen < subStrCount-1 { return } if splitsLen < subStrCount { err = fmt.Errorf("expected <key>=<value> instead got %v", splits[:splitsLen]) return } key, value := splits[0], splits[1:] joinedValue := strings.Join(NonEmptyTrimmedStrings(value...), " ") joinedValue = strings.Trim(joinedValue, " ") resolvedValue := joinedValue if resolveFromEnv { resolvedValue = os.ExpandEnv(resolvedValue) } if resolvedValue != "" && joinedValue != "" { joinedValue = resolvedValue } kv.key = key kv.value = joinedValue return } 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: 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 }