Skip to content

Commit

Permalink
Support parsing home directory-based paths
Browse files Browse the repository at this point in the history
In some cases, like --scope=PATH, the shell won't parse the path. This means we'll need to manually parse the path ourselves, like expanding ~/test to /Users/thomas/test
  • Loading branch information
Piccirello committed Jan 29, 2020
1 parent 384cd59 commit 7e81ec7
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 13 deletions.
17 changes: 4 additions & 13 deletions pkg/configuration/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ func SetVersionCheck(version models.VersionCheck) {

// Get the config at the specified scope
func Get(scope string) models.ScopedOptions {
scope, err := parseScope(scope)
scope, err := utils.ParsePath(scope)
if err != nil {
utils.HandleError(err)
}
scope = filepath.Clean(scope) + string(filepath.Separator)
scope = scope + string(filepath.Separator)
var scopedConfig models.ScopedOptions

for confScope, conf := range configContents.Scoped {
Expand Down Expand Up @@ -233,7 +233,7 @@ func AllConfigs() map[string]models.FileScopedOptions {
func Set(scope string, options map[string]string) {
if scope != "*" {
var err error
scope, err = parseScope(scope)
scope, err = utils.ParsePath(scope)
if err != nil {
utils.HandleError(err)
}
Expand All @@ -256,7 +256,7 @@ func Set(scope string, options map[string]string) {
func Unset(scope string, options []string) {
if scope != "*" {
var err error
scope, err = parseScope(scope)
scope, err = utils.ParsePath(scope)
if err != nil {
utils.HandleError(err)
}
Expand Down Expand Up @@ -310,15 +310,6 @@ func readConfig() models.ConfigFile {
return config
}

func parseScope(scope string) (string, error) {
absScope, err := filepath.Abs(scope)
if err != nil {
return "", err
}

return absScope, nil
}

// IsValidConfigOption whether the specified key is a valid config option
func IsValidConfigOption(key string) bool {
configOptions := map[string]interface{}{
Expand Down
33 changes: 33 additions & 0 deletions pkg/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strconv"
Expand Down Expand Up @@ -55,6 +56,33 @@ func HomeDir() string {
return dir
}

// ParsePath returns an absolute path, parsing ~ . .. etc
func ParsePath(path string) (string, error) {
if path == "" {
return "", errors.New("Path cannot be blank")
}

if strings.HasPrefix(path, "~") {
firstPath := strings.Split(path, string(filepath.Separator))[0]

if firstPath != "~" {
username, err := user.Current()
if err != nil || firstPath != fmt.Sprintf("~%s", username.Username) {
return "", fmt.Errorf("unable to parse path, please specify an absolute path (e.g. /home/%s)", path[1:])
}
}

path = strings.Replace(path, firstPath, HomeDir(), 1)
}

absolutePath, err := filepath.Abs(filepath.Clean(path))
if err != nil {
return "", err
}

return absolutePath, nil
}

// Exists whether path exists and the user has permission
func Exists(path string) bool {
if _, err := os.Stat(path); err != nil {
Expand Down Expand Up @@ -177,6 +205,11 @@ func GetFilePath(fullPath string) (string, error) {
return "", errors.New("Invalid file path")
}

fullPath, err := ParsePath(fullPath)
if err != nil {
return "", errors.New("Invalid file path")
}

parsedPath := filepath.Dir(fullPath)
parsedName := filepath.Base(fullPath)

Expand Down
138 changes: 138 additions & 0 deletions pkg/utils/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
Copyright © 2019 Doppler <support@doppler.com>
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 utils

import (
"fmt"
"os"
"os/user"
"path/filepath"
"testing"
)

var username string
var homeDir string
var cwd string

func init() {
currentUser, err := user.Current()
if err != nil {
panic(err)
}
username = currentUser.Username

homeDir, err = os.UserHomeDir()
if err != nil {
panic(err)
}

cwd, err = filepath.Abs(".")
if err != nil {
panic(err)
}
}

func TestParsePathTilde(t *testing.T) {
path, err := ParsePath("~")
if err != nil || path != homeDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, homeDir))
}

path, err = ParsePath("~/")
if err != nil || path != homeDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, homeDir))
}

path, err = ParsePath(fmt.Sprintf("~%s", username))
if err != nil || path != homeDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, homeDir))
}

path, err = ParsePath(fmt.Sprintf("~%s/", username))
if err != nil || path != homeDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, homeDir))
}

// expect error
path, err = ParsePath(fmt.Sprintf("~%s/", username+"1"))
if err == nil || path != "" {
t.Error(fmt.Sprintf("Got %s, expected error", path))
}

path, err = ParsePath("")
if err == nil || path != "" {
t.Error(fmt.Sprintf("Got %s, expected error", path))
}
}

func TestParsePathRelative(t *testing.T) {
parentDir := filepath.Join(cwd, "..")

path, err := ParsePath(".")
if err != nil || path != cwd {
t.Error(fmt.Sprintf("Got %s, expected %s", path, cwd))
}

path, err = ParsePath("./")
if err != nil || path != cwd {
t.Error(fmt.Sprintf("Got %s, expected %s", path, cwd))
}

path, err = ParsePath("..")
if err != nil || path != parentDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, parentDir))
}

path, err = ParsePath("../")
if err != nil || path != parentDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, parentDir))
}

path, err = ParsePath("./..")
if err != nil || path != parentDir {
t.Error(fmt.Sprintf("Got %s, expected %s", path, parentDir))
}
}

func TestParsePathAbsolute(t *testing.T) {
path, err := ParsePath("/")
if err != nil || path != "/" {
t.Error(fmt.Sprintf("Got %s, expected %s", path, "/"))
}

path, err = ParsePath("/root")
if err != nil || path != "/root" {
t.Error(fmt.Sprintf("Got %s, expected %s", path, "/root"))
}

path, err = ParsePath("root")
if err != nil || path != filepath.Join(cwd, "root") {
t.Error(fmt.Sprintf("Got %s, expected %s", path, filepath.Join(cwd, "root")))
}
}

func TestGetFilePath(t *testing.T) {
expected := filepath.Join(cwd, "doppler.env")
path, err := GetFilePath("./doppler.env")
if err != nil || path != expected {
t.Error(fmt.Sprintf("Got %s, expected %s", path, expected))
}

path, err = GetFilePath("/root/")
if err != nil || path != "/root" {
t.Error(fmt.Sprintf("Got %s, expected %s", path, "/root"))
}
}

0 comments on commit 7e81ec7

Please sign in to comment.