diff --git a/cmd/import.go b/cmd/import.go index c1a74c4..6acf044 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -118,18 +118,10 @@ func NewImportCommand(globalClientOpts *connectors.ClientOptions) *cobra.Command // Handle multiple specification files separated by comma. sepSpecificationFiles := strings.Split(specificationFiles, ",") for _, f := range sepSpecificationFiles { - mainArtifact := true - var err error - - // Check if mainArtifact flag is provided. - if strings.Contains(f, ":") { - pathAndMainArtifact := strings.Split(f, ":") - f = pathAndMainArtifact[0] - mainArtifact, err = strconv.ParseBool(pathAndMainArtifact[1]) - if err != nil { - fmt.Printf("Cannot parse '%s' as Bool, default to true\n", pathAndMainArtifact[1]) - } - } + // Parse optional :true / :false suffix. Preserves paths + // containing colons (e.g. Windows C:\Temp\api.yaml). + path, mainArtifact := parseImportEntry(f) + f = path // Try uploading this artifact. msg, err := mc.UploadArtifact(f, mainArtifact) @@ -189,3 +181,25 @@ func NewImportCommand(globalClientOpts *connectors.ClientOptions) *cobra.Command importCmd.Flags().BoolVar(&watch, "watch", false, "Keep watch on file changes and re-import it on change") return importCmd } + +// parseImportEntry parses a single comma-separated entry of the import +// command argument. The accepted forms are "" and +// ":", where is anything strconv.ParseBool accepts +// (true, false, TRUE, FALSE, 1, 0, t, f, ...). Because may +// itself contain colons (e.g. Windows-absolute paths such as +// C:\Temp\api.yaml), the optional boolean suffix is detected from the +// right: only the substring after the last ':' is considered, and +// only when it parses as a bool is it treated as the mainArtifact +// flag. Otherwise the whole input is returned unchanged with +// mainArtifact defaulting to true. +func parseImportEntry(input string) (string, bool) { + idx := strings.LastIndex(input, ":") + if idx < 0 { + return input, true + } + b, err := strconv.ParseBool(input[idx+1:]) + if err != nil { + return input, true + } + return input[:idx], b +} diff --git a/cmd/import_test.go b/cmd/import_test.go new file mode 100644 index 0000000..78cb9fa --- /dev/null +++ b/cmd/import_test.go @@ -0,0 +1,50 @@ +/* + * Copyright The Microcks Authors. + * + * 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 cmd + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseImportEntry(t *testing.T) { + tests := []struct { + name string + input string + wantPath string + wantMainArtifact bool + }{ + {"relative path, no suffix", "./api.yaml", "./api.yaml", true}, + {"relative path, :true suffix", "./api.yaml:true", "./api.yaml", true}, + {"relative path, :false suffix", "./api.yaml:false", "./api.yaml", false}, + {"relative path, :TRUE suffix (ParseBool)", "./api.yaml:TRUE", "./api.yaml", true}, + {"relative path, :0 suffix (ParseBool)", "./api.yaml:0", "./api.yaml", false}, + {"Windows absolute path, no suffix", `C:\Temp\api.yaml`, `C:\Temp\api.yaml`, true}, + {"Windows absolute path, :false suffix", `C:\Temp\api.yaml:false`, `C:\Temp\api.yaml`, false}, + {"Windows absolute path, :true suffix", `C:\Temp\api.yaml:true`, `C:\Temp\api.yaml`, true}, + {"path with multiple colons, no bool suffix", "path:with:colon.yaml", "path:with:colon.yaml", true}, + {"path with multiple colons, :false suffix", "path:with:colon.yaml:false", "path:with:colon.yaml", false}, + {"non-bool trailing segment is part of path", "./api.yaml:notabool", "./api.yaml:notabool", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotPath, gotMain := parseImportEntry(tt.input) + assert.Equal(t, tt.wantPath, gotPath, "path") + assert.Equal(t, tt.wantMainArtifact, gotMain, "mainArtifact") + }) + } +}