diff --git a/cmd/dbc/install.go b/cmd/dbc/install.go index db46d6b2..dc81caed 100644 --- a/cmd/dbc/install.go +++ b/cmd/dbc/install.go @@ -20,7 +20,7 @@ import ( func parseDriverConstraint(driver string) (string, *semver.Constraints, error) { driver = strings.TrimSpace(driver) - splitIdx := strings.IndexAny(driver, " <>=!") + splitIdx := strings.IndexAny(driver, " ~^<>=!") if splitIdx == -1 { return driver, nil, nil } diff --git a/cmd/dbc/install_test.go b/cmd/dbc/install_test.go index 23441237..576e425f 100644 --- a/cmd/dbc/install_test.go +++ b/cmd/dbc/install_test.go @@ -29,11 +29,30 @@ func (suite *SubcommandTestSuite) TestInstallDriverNotFound() { } func (suite *SubcommandTestSuite) TestInstallWithVersion() { - m := InstallCmd{Driver: "test-driver-1<=1.0.0"}. - GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - out := suite.runCmd(m) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", - "\nInstalled test-driver-1 1.0.0 to "+suite.tempdir+"\n", out) + tests := []struct { + driver string + expectedVersion string + }{ + {"test-driver-1=1.0.0", "1.0.0"}, + {"test-driver-1<=1.0.0", "1.0.0"}, + {"test-driver-1<1.1.0", "1.0.0"}, + {"test-driver-1~1.0", "1.0.0"}, + {"test-driver-1^1.0", "1.1.0"}, + } + + for _, tt := range tests { + suite.Run(tt.driver, func() { + m := InstallCmd{Driver: tt.driver}. + GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) + out := suite.runCmd(m) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-1 "+tt.expectedVersion+" to "+suite.tempdir+"\n", out) + + m = UninstallCmd{Driver: "test-driver-1"}.GetModelCustom( + baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) + suite.runCmd(m) + }) + } } func (suite *SubcommandTestSuite) TestInstallWithVersionLessSpace() { diff --git a/cmd/dbc/sync_test.go b/cmd/dbc/sync_test.go index 591035d0..8626225c 100644 --- a/cmd/dbc/sync_test.go +++ b/cmd/dbc/sync_test.go @@ -28,6 +28,41 @@ func (suite *SubcommandTestSuite) TestSync() { suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", "", suite.runCmd(m)) } +func (suite *SubcommandTestSuite) TestSyncWithVersion() { + tests := []struct { + driver string + expectedVersion string + }{ + {"test-driver-1=1.0.0", "1.0.0"}, + {"test-driver-1<=1.0.0", "1.0.0"}, + {"test-driver-1<1.1.0", "1.0.0"}, + {"test-driver-1~1.0", "1.0.0"}, + {"test-driver-1^1.0", "1.1.0"}, + } + + for _, tt := range tests { + suite.Run(tt.driver, func() { + m := InitCmd{Path: filepath.Join(suite.tempdir, "dbc.toml")}.GetModel() + suite.runCmd(m) + + m = AddCmd{Path: filepath.Join(suite.tempdir, "dbc.toml"), Driver: tt.driver}.GetModel() + suite.runCmd(m) + + m = SyncCmd{ + Path: filepath.Join(suite.tempdir, "dbc.toml"), + }.GetModelCustom( + baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) + suite.validateOutput("✓ test-driver-1-"+tt.expectedVersion+"\r\n\rDone!\r\n", "", suite.runCmd(m)) + suite.FileExists(filepath.Join(suite.tempdir, "test-driver-1.toml")) + suite.FileExists(filepath.Join(suite.tempdir, "dbc.lock")) + + for _, f := range suite.getFilesInTempDir() { + os.Remove(filepath.Join(suite.tempdir, f)) + } + }) + } +} + func (suite *SubcommandTestSuite) TestSyncVirtualEnv() { os.Unsetenv("ADBC_DRIVER_PATH") diff --git a/cmd/dbc/uninstall_test.go b/cmd/dbc/uninstall_test.go index becb8974..1f7fb0fc 100644 --- a/cmd/dbc/uninstall_test.go +++ b/cmd/dbc/uninstall_test.go @@ -19,8 +19,8 @@ func (suite *SubcommandTestSuite) TestUninstallNotFound() { } m := UninstallCmd{Driver: "notfound"}.GetModel() - suite.validateOutput("Error: failed to find driver `notfound` in order to uninstall it: error opening manifest "+ - filepath.Join(suite.tempdir, "notfound.toml")+": open "+filepath.Join(suite.tempdir, "notfound.toml")+": no such file or directory\r\n\r ", "", suite.runCmdErr(m)) + suite.validateOutput("Error: failed to find driver `notfound` in order to uninstall it: searched "+suite.tempdir+ + "\r\n\r ", "", suite.runCmdErr(m)) } func (suite *SubcommandTestSuite) TestUninstallManifestOnly() { diff --git a/config/config.go b/config/config.go index 6f54351e..5500361a 100644 --- a/config/config.go +++ b/config/config.go @@ -317,14 +317,14 @@ func decodeManifest(r io.Reader, driverName string, requireShared bool) (Manifes // Common, non-platform-specific code for uninstalling a driver. Called by // platform-specific UninstallDriver function. -func UninstallDriverShared(cfg Config, info DriverInfo) error { +func UninstallDriverShared(info DriverInfo) error { for sharedPath := range info.Driver.Shared.Paths() { // Run filepath.Clean on sharedPath mainly to catch inner ".." in the path sharedPath = filepath.Clean(sharedPath) // Don't remove anything that isn't contained withing the found driver's // config directory (i.e., avoid malicious driver manifests) - if !strings.HasPrefix(sharedPath, cfg.Location) { + if !strings.HasPrefix(sharedPath, info.FilePath) { continue } @@ -334,9 +334,9 @@ func UninstallDriverShared(cfg Config, info DriverInfo) error { sharedDir := filepath.Dir(sharedPath) // Edge case when manifest is ill-formed: if sharedPath is set to the // folder containing the shared library instead of the shared library - // itself, sharedDir is cfg.Location and we definitely don't want to + // itself, sharedDir is info.FilePath and we definitely don't want to // remove that - if sharedDir == cfg.Location { + if sharedDir == info.FilePath { continue } @@ -371,7 +371,7 @@ func UninstallDriverShared(cfg Config, info DriverInfo) error { // try to remove it e.g., "somedriver_macos_arm64_v1.2.3." extra_folder := fmt.Sprintf("%s_%s_v%s", info.ID, platformTuple, info.Version) extra_folder = filepath.Clean(extra_folder) - extra_path := filepath.Join(cfg.Location, extra_folder) + extra_path := filepath.Join(info.FilePath, extra_folder) finfo, err := os.Stat(extra_path) if err == nil && finfo.IsDir() && extra_path != "." { _ = os.RemoveAll(extra_path) diff --git a/config/dirs_unixlike.go b/config/dirs_unixlike.go index 57069421..83f098d9 100644 --- a/config/dirs_unixlike.go +++ b/config/dirs_unixlike.go @@ -80,6 +80,15 @@ func FindDriverConfigs(lvl ConfigLevel) []DriverInfo { } func GetDriver(cfg Config, driverName string) (DriverInfo, error) { + if cfg.Level == ConfigEnv { + for _, prefix := range filepath.SplitList(cfg.Location) { + if di, err := loadDriverFromManifest(prefix, driverName); err == nil { + return di, nil + } + } + return DriverInfo{}, fmt.Errorf("searched %s", cfg.Location) + } + return loadDriverFromManifest(cfg.Location, driverName) } @@ -91,13 +100,13 @@ func CreateManifest(cfg Config, driver DriverInfo) (err error) { return createDriverManifest(loc, driver) } -func UninstallDriver(cfg Config, info DriverInfo) error { - manifest := filepath.Join(cfg.Location, info.ID+".toml") +func UninstallDriver(_ Config, info DriverInfo) error { + manifest := filepath.Join(info.FilePath, info.ID+".toml") if err := os.Remove(manifest); err != nil { return fmt.Errorf("error removing manifest %s: %w", manifest, err) } - if err := UninstallDriverShared(cfg, info); err != nil { + if err := UninstallDriverShared(info); err != nil { return fmt.Errorf("failed to delete driver shared object: %w", err) } diff --git a/config/dirs_windows.go b/config/dirs_windows.go index 1442b542..3119cce2 100644 --- a/config/dirs_windows.go +++ b/config/dirs_windows.go @@ -207,7 +207,13 @@ func FindDriverConfigs(lvl ConfigLevel) []DriverInfo { func GetDriver(cfg Config, driverName string) (DriverInfo, error) { if cfg.Level == ConfigEnv { - return loadDriverFromManifest(cfg.Location, driverName) + for _, prefix := range filepath.SplitList(cfg.Location) { + if di, err := loadDriverFromManifest(prefix, driverName); err == nil { + return di, nil + } + } + + return DriverInfo{}, fmt.Errorf("driver `%s` not found in env config paths", driverName) } k, err := registry.OpenKey(cfg.Level.key(), regKeyADBC, registry.READ) @@ -299,9 +305,14 @@ func UninstallDriver(cfg Config, info DriverInfo) error { if err := registry.DeleteKey(k, info.ID); err != nil { return fmt.Errorf("failed to delete driver registry key: %w", err) } + } else { + manifest := filepath.Join(info.FilePath, info.ID+".toml") + if err := os.Remove(manifest); err != nil { + return fmt.Errorf("error removing manifest %s: %w", manifest, err) + } } - if err := UninstallDriverShared(cfg, info); err != nil { + if err := UninstallDriverShared(info); err != nil { return fmt.Errorf("failed to delete driver shared object: %w", err) } diff --git a/config/driver.go b/config/driver.go index 78d92be7..941f1bb9 100644 --- a/config/driver.go +++ b/config/driver.go @@ -148,6 +148,7 @@ func loadDriverFromManifest(prefix, driverName string) (DriverInfo, error) { return DriverInfo{}, fmt.Errorf("error decoding manifest %s: %w", manifest, err) } + m.DriverInfo.FilePath = prefix return m.DriverInfo, nil }