Skip to content

Commit

Permalink
allow for / as From path, fixes #5
Browse files Browse the repository at this point in the history
  • Loading branch information
Silas Gyger committed Nov 22, 2023
1 parent b72a661 commit 7d52293
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 58 deletions.
109 changes: 66 additions & 43 deletions cmd/read_conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
)

type pastaConf struct {
KeepDirs bool `yaml:"keep_dirs"`
Deps []copierConf `yaml:"deps"`
KeepDirs bool `yaml:"keep_dirs"`
Deps []*copierConf `yaml:"deps"`

dependencies []pasta.Dependency
}
Expand Down Expand Up @@ -51,7 +51,7 @@ func (conf *copierConf) ToCopierOptions() (*copier.CopyConfig, error) {

return &copier.CopyConfig{
URL: conf.URL,
From: path.Clean(conf.From + "/"),
From: conf.From,
Keep: func(path string) bool {
if len(files) > 0 {
return files[path]
Expand Down Expand Up @@ -110,62 +110,85 @@ func (c *pastaConf) validate() error {
return fmt.Errorf("dependency %v: 'url' is required", i)
}

if config.From == "" {
return fmt.Errorf("dependency %v: 'from' is required", i)
err = validateFromField(config, i)
if err != nil {
return err
}

if config.To == "" {
return fmt.Errorf("dependency %v: 'to' is required", i)
err = validateToField(config, i)
if err != nil {
return err
}

// check from
if filepath.Clean(config.From)+"/" != config.From {
return fmt.Errorf("dependency %v: 'from' must contain a clean path", i)
// files is exclusive with include/exclude
if len(config.Files) > 0 && (config.Include != "" || config.Exclude != "") {
return fmt.Errorf("dependency %v: files and include/exclude are mutually exclusive", i)
}

if !strings.HasSuffix(config.From, "/") {
return fmt.Errorf("dependency %v: 'from' must end with '/'", i)
}
// convert pastaConf to CopierOptions
_, err = config.ToCopierOptions()

if strings.HasPrefix(config.From, "/") {
return fmt.Errorf("dependency %v: 'from' must not start with '/'", i)
if err != nil {
return fmt.Errorf("couldn't parse dependency %v: %v", i, err)
}
}

if config.From == "." {
return fmt.Errorf("dependency %v: 'from' cannot be '.'", i)
}
return err
}

// check to
if config.To == "." {
if len(config.Files) == 0 {
return fmt.Errorf("dependency %v: 'to' is set to '.' so 'files' must be used", i)
}
} else {
if !strings.HasSuffix(config.To, "/") {
return fmt.Errorf("dependency %v: 'to' must end with '/'", i)
}
func validateFromField(config *copierConf, i int) error {
// If From is `/`, we want to copy all files.
// Since file paths dont start with `/`, we set empty string (so hasPrefix returns true).
if config.From == "/" {
config.From = ""
return nil
}

if filepath.Clean(config.To)+"/" != config.To {
return fmt.Errorf("dependency %v: 'to' must contain a clean path", i)
}
if config.From == "" {
return fmt.Errorf("dependency %v: 'from' is required", i)
}

if strings.HasPrefix(config.To, "/") {
return fmt.Errorf("dependency %v: 'to' must not start with '/' or must be '.'", i)
}
}
if filepath.Clean(config.From)+"/" != config.From {
return fmt.Errorf("dependency %v: 'from' must contain a clean path", i)
}

// files is exclusive with include/exclude
if len(config.Files) > 0 && (config.Include != "" || config.Exclude != "") {
return fmt.Errorf("dependency %v: files and include/exclude are mutually exclusive", i)
}
if !strings.HasSuffix(config.From, "/") {
return fmt.Errorf("dependency %v: 'from' must end with '/'", i)
}

// convert pastaConf to CopierOptions
_, err := config.ToCopierOptions()
if strings.HasPrefix(config.From, "/") {
return fmt.Errorf("dependency %v: 'from' must not start with '/'", i)
}

if err != nil {
return fmt.Errorf("couldn't parse dependency %v: %v", i, err)
if config.From == "." {
return fmt.Errorf("dependency %v: 'from' cannot be '.'", i)
}
return nil
}

func validateToField(config *copierConf, i int) error {
if config.To == "." {
if len(config.Files) == 0 {
return fmt.Errorf("dependency %v: 'to' is set to '.' so 'files' must be used", i)
}
return nil
}

return err
if config.To == "" {
return fmt.Errorf("dependency %v: 'to' is required", i)
}

if !strings.HasSuffix(config.To, "/") {
return fmt.Errorf("dependency %v: 'to' must end with '/'", i)
}

if filepath.Clean(config.To)+"/" != config.To {
return fmt.Errorf("dependency %v: 'to' must contain a clean path", i)
}

if strings.HasPrefix(config.To, "/") {
return fmt.Errorf("dependency %v: 'to' must not start with '/' or must be '.'", i)
}

return nil
}
30 changes: 15 additions & 15 deletions cmd/read_conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "valid config",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -27,7 +27,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "missing url",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
From: "path/to/source/",
To: "path/to/destination/",
Expand All @@ -39,7 +39,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "missing from",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
To: "path/to/destination/",
Expand All @@ -51,7 +51,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "missing to",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -63,7 +63,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid from",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "/path/to/source/",
Expand All @@ -76,7 +76,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid to",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -89,7 +89,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "valid dot to with files",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -103,7 +103,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "valid to with files",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -117,7 +117,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid to with leading slash",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -130,7 +130,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid to with dot",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -143,7 +143,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid to with leading slash and dot",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -156,7 +156,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid files with include and exclude",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -172,7 +172,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid to '/' potentially overwriting/removing pasta.yaml",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "foo/",
Expand All @@ -185,7 +185,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid `files` with `include`",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand All @@ -200,7 +200,7 @@ func TestPastaConfValidate(t *testing.T) {
{
name: "invalid `files` with `exclude`",
conf: &pastaConf{
Deps: []copierConf{
Deps: []*copierConf{
{
URL: "https://example.com",
From: "path/to/source/",
Expand Down

0 comments on commit 7d52293

Please sign in to comment.