From 6e6e9bd58cc851f2f85041fb39778cf9c1164ee7 Mon Sep 17 00:00:00 2001 From: Savil Srivastava <676452+savil@users.noreply.github.com> Date: Tue, 8 Aug 2023 11:36:32 -0700 Subject: [PATCH] improve searcher.ParseVersionedPackage, and reuse in implemetation of devconfig.parseVersionedName --- internal/devconfig/packages.go | 26 ++++--------- internal/searcher/parse.go | 17 +++++++-- internal/searcher/parse_test.go | 66 +++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 internal/searcher/parse_test.go diff --git a/internal/devconfig/packages.go b/internal/devconfig/packages.go index dab321c245f..d55a04360a9 100644 --- a/internal/devconfig/packages.go +++ b/internal/devconfig/packages.go @@ -2,10 +2,10 @@ package devconfig import ( "encoding/json" - "strings" "github.com/pkg/errors" orderedmap "github.com/wk8/go-ordered-map/v2" + "go.jetpack.io/devbox/internal/searcher" "golang.org/x/exp/slices" ) @@ -187,25 +187,15 @@ func (p Package) MarshalJSON() ([]byte, error) { // parseVersionedName parses the name and version from package@version representation func parseVersionedName(versionedName string) (name, version string) { - // use the last @ symbol as the version delimiter, some packages have @ in the name - atSymbolIndex := strings.LastIndex(versionedName, "@") - if atSymbolIndex != -1 { - // Common case: package@version - if atSymbolIndex != len(versionedName)-1 { - name, version = versionedName[:atSymbolIndex], versionedName[atSymbolIndex+1:] - } else { - // This case handles packages that end with `@` in the name - // example: `emacsPackages.@` - name = versionedName[:atSymbolIndex] + "@" - } + var found bool + name, version, found = searcher.ParseVersionedPackage(versionedName) + if found { + return name, version } else { - // Case without any @version: package + // Case without any @version in the versionedName name = versionedName - - // We deliberately do not set version to latest so that we don't - // automatically modify the devbox.json file. It should only be modified - // upon `devbox update`. - // version = "latest" + // We deliberately do not set version to `latest` + version = "" } return name, version } diff --git a/internal/searcher/parse.go b/internal/searcher/parse.go index 7239610a087..ef4f34d5c80 100644 --- a/internal/searcher/parse.go +++ b/internal/searcher/parse.go @@ -9,10 +9,19 @@ import ( // ParseVersionedPackage checks if the given package is a versioned package // (`python@3.10`) and returns its name and version -func ParseVersionedPackage(pkg string) (string, string, bool) { - lastIndex := strings.LastIndex(pkg, "@") - if lastIndex == -1 { +func ParseVersionedPackage(versionedName string) (name string, version string, found bool) { + // use the last @ symbol as the version delimiter, some packages have @ in the name + atSymbolIndex := strings.LastIndex(versionedName, "@") + if atSymbolIndex == -1 { return "", "", false } - return pkg[:lastIndex], pkg[lastIndex+1:], true + if atSymbolIndex == len(versionedName)-1 { + // This case handles packages that end with `@` in the name + // example: `emacsPackages.@` + return "", "", false + } + + // Common case: package@version + name, version = versionedName[:atSymbolIndex], versionedName[atSymbolIndex+1:] + return name, version, true } diff --git a/internal/searcher/parse_test.go b/internal/searcher/parse_test.go new file mode 100644 index 00000000000..200865ec6c2 --- /dev/null +++ b/internal/searcher/parse_test.go @@ -0,0 +1,66 @@ +package searcher + +import ( + "testing" +) + +func TestParseVersionedPackage(t *testing.T) { + testCases := []struct { + name string + input string + expectedFound bool + expectedName string + expectedVersion string + }{ + { + name: "no-version", + input: "python", + expectedFound: false, + expectedName: "", + expectedVersion: "", + }, + { + name: "with-version-latest", + input: "python@latest", + expectedFound: true, + expectedName: "python", + expectedVersion: "latest", + }, + { + name: "with-version", + input: "python@1.2.3", + expectedFound: true, + expectedName: "python", + expectedVersion: "1.2.3", + }, + { + name: "with-two-@-signs", + input: "emacsPackages.@@latest", + expectedFound: true, + expectedName: "emacsPackages.@", + expectedVersion: "latest", + }, + { + name: "with-trailing-@-sign", + input: "emacsPackages.@", + expectedFound: false, + expectedName: "", + expectedVersion: "", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + name, version, found := ParseVersionedPackage(testCase.input) + if found != testCase.expectedFound { + t.Errorf("expected: %v, got: %v", testCase.expectedFound, found) + } + if name != testCase.expectedName { + t.Errorf("expected: %v, got: %v", testCase.expectedName, name) + } + if version != testCase.expectedVersion { + t.Errorf("expected: %v, got: %v", testCase.expectedVersion, version) + } + }) + } +}