diff --git a/builder.go b/builder.go index f4f4801..3814fa2 100644 --- a/builder.go +++ b/builder.go @@ -140,13 +140,34 @@ type Dependency struct { Version string `json:"version,omitempty"` } +// ReplacementPath represents an old or new path component +// within a Go module replacement directive. +type ReplacementPath string + +// Param reformats a go.mod replace directive to be +// compatible with the `go mod edit` command. +func (r ReplacementPath) Param() string { + return strings.Replace(string(r), " ", "@", 1) +} + +func (r ReplacementPath) String() string { return string(r) } + // Replace represents a Go module replacement. type Replace struct { // The import path of the module being replaced. - Old string `json:"old,omitempty"` + Old ReplacementPath `json:"old,omitempty"` // The path to the replacement module. - New string `json:"new,omitempty"` + New ReplacementPath `json:"new,omitempty"` +} + +// NewReplace creates a new instance of Replace provided old and +// new Go module paths +func NewReplace(old, new string) Replace { + return Replace{ + Old: ReplacementPath(old), + New: ReplacementPath(new), + } } // newTempFolder creates a new folder in a temporary location. diff --git a/builder_test.go b/builder_test.go new file mode 100644 index 0000000..a8308f4 --- /dev/null +++ b/builder_test.go @@ -0,0 +1,88 @@ +// Copyright 2020 Matthew Holt +// +// 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 xcaddy + +import ( + "fmt" + "reflect" + "testing" +) + +func TestReplacementPath_Param(t *testing.T) { + tests := []struct { + name string + r ReplacementPath + want string + }{ + { + "Empty", + ReplacementPath(""), + "", + }, + { + "ModulePath", + ReplacementPath("github.com/x/y"), + "github.com/x/y", + }, + { + "ModulePath Version Pinned", + ReplacementPath("github.com/x/y v0.0.0-20200101000000-xxxxxxxxxxxx"), + "github.com/x/y@v0.0.0-20200101000000-xxxxxxxxxxxx", + }, + { + "FilePath", + ReplacementPath("/x/y/z"), + "/x/y/z", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fmt.Println(tt.r.Param()) + if got := tt.r.Param(); got != tt.want { + t.Errorf("ReplacementPath.Param() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewReplace(t *testing.T) { + type args struct { + old string + new string + } + tests := []struct { + name string + args args + want Replace + }{ + { + "Empty", + args{"", ""}, + Replace{"", ""}, + }, + { + "Constructor", + args{"a", "b"}, + Replace{"a", "b"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := NewReplace(tt.args.old, tt.args.new); !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewReplace() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/xcaddy/main.go b/cmd/xcaddy/main.go index 950a3d5..50def87 100644 --- a/cmd/xcaddy/main.go +++ b/cmd/xcaddy/main.go @@ -74,10 +74,7 @@ func runBuild(ctx context.Context, args []string) error { Version: ver, }) if repl != "" { - replacements = append(replacements, xcaddy.Replace{ - Old: mod, - New: repl, - }) + replacements = append(replacements, xcaddy.NewReplace(mod, repl)) } case "--output": @@ -168,10 +165,7 @@ func runDev(ctx context.Context, args []string) error { // make sure the module being developed is replaced // so that the local copy is used replacements := []xcaddy.Replace{ - { - Old: currentModule, - New: moduleDir, - }, + xcaddy.NewReplace(currentModule, moduleDir), } // replace directives only apply to the top-level/main go.mod, @@ -189,10 +183,10 @@ func runDev(ctx context.Context, args []string) error { if len(parts) != 2 || parts[0] == "" || parts[1] == "" { continue } - replacements = append(replacements, xcaddy.Replace{ - Old: strings.TrimSpace(parts[0]), - New: strings.TrimSpace(parts[1]), - }) + replacements = append(replacements, xcaddy.NewReplace( + strings.TrimSpace(parts[0]), + strings.TrimSpace(parts[1]), + )) } // reconcile remaining path segments; for example if a module foo/a diff --git a/environment.go b/environment.go index c00d33f..7b5f6c8 100644 --- a/environment.go +++ b/environment.go @@ -109,14 +109,14 @@ func (b Builder) newEnvironment(ctx context.Context) (*environment, error) { // specify module replacements before pinning versions replaced := make(map[string]string) for _, r := range b.Replacements { - log.Printf("[INFO] Replace %s => %s", r.Old, r.New) + log.Printf("[INFO] Replace %s => %s", r.Old.String(), r.New.String()) cmd := env.newCommand("go", "mod", "edit", - "-replace", fmt.Sprintf("%s=%s", r.Old, r.New)) + "-replace", fmt.Sprintf("%s=%s", r.Old.Param(), r.New.Param())) err := env.runCommand(ctx, cmd, 10*time.Second) if err != nil { return nil, err } - replaced[r.Old] = r.New + replaced[r.Old.String()] = r.New.String() } // check for early abort