@@ -11,7 +11,6 @@ import (
1111 "io/fs"
1212 "maps"
1313 "os"
14- "path"
1514 "path/filepath"
1615 "runtime"
1716 "slices"
@@ -201,7 +200,7 @@ func InstallDriver(cfg Config, shortName string, downloaded *os.File) (Manifest,
201200 if loc , err = EnsureLocation (cfg ); err != nil {
202201 return Manifest {}, fmt .Errorf ("could not ensure config location: %w" , err )
203202 }
204- base := strings .TrimSuffix (path .Base (downloaded .Name ()), ".tar.gz" )
203+ base := strings .TrimSuffix (filepath .Base (downloaded .Name ()), ".tar.gz" )
205204 finalDir := filepath .Join (loc , base )
206205
207206 if err := os .MkdirAll (finalDir , 0o755 ); err != nil {
@@ -315,3 +314,60 @@ func decodeManifest(r io.Reader, driverName string, requireShared bool) (Manifes
315314
316315 return result , nil
317316}
317+
318+ // Common, non-platform-specific code for uninstalling a driver. Called by
319+ // platform-specific UninstallDriver function.
320+ func UninstallDriverShared (cfg Config , info DriverInfo ) error {
321+ for sharedPath := range info .Driver .Shared .Paths () {
322+ // Run filepath.Clean on sharedPath mainly to catch inner ".." in the path
323+ sharedPath = filepath .Clean (sharedPath )
324+
325+ // Don't remove anything that isn't contained withing the found driver's
326+ // config directory (i.e., avoid malicious driver manifests)
327+ if ! strings .HasPrefix (sharedPath , cfg .Location ) {
328+ continue
329+ }
330+
331+ // dbc installs drivers in a folder, other tools may not so we handle each
332+ // differently.
333+ if info .Source == "dbc" {
334+ if err := os .RemoveAll (filepath .Dir (sharedPath )); err != nil {
335+ // Ignore only when not found. This supports manifest-only drivers.
336+ // TODO: Come up with a better mechanism to handle manifest-only drivers
337+ // and remove this continue when we do
338+ if errors .Is (err , fs .ErrNotExist ) {
339+ continue
340+ }
341+ return fmt .Errorf ("error removing driver %s: %w" , info .ID , err )
342+ }
343+ } else {
344+ if err := os .Remove (sharedPath ); err != nil {
345+ // Ignore only when not found. This supports manifest-only drivers.
346+ // TODO: Come up with a better mechanism to handle manifest-only drivers
347+ // and remove this continue when we do
348+ if errors .Is (err , fs .ErrNotExist ) {
349+ continue
350+ }
351+ return fmt .Errorf ("error removing driver %s: %w" , info .ID , err )
352+ }
353+ }
354+ }
355+
356+ // Manifest only drivers can come with extra files such as a LICENSE and we
357+ // create a folder next to the driver manifest to store them, same as we'd
358+ // store the actual driver shared library. Above, we find the path of this
359+ // folder by looking at the Driver.shared path. For manifest-only drivers,
360+ // Driver.shared is not a valid path (it's just a name), so this trick doesn't
361+ // work. We do want to clean this folder up so here we guess what it is and
362+ // try to remove it e.g., "somedriver_macos_arm64_v1.2.3."
363+ extra_folder := fmt .Sprintf ("%s_%s_v%s" , info .ID , platformTuple , info .Version )
364+ extra_folder = filepath .Clean (extra_folder )
365+ extra_path := filepath .Join (cfg .Location , extra_folder )
366+ finfo , err := os .Stat (extra_path )
367+ if err == nil && finfo .IsDir () && extra_path != "." {
368+ _ = os .RemoveAll (extra_path )
369+ // ignore errors
370+ }
371+
372+ return nil
373+ }
0 commit comments