@@ -43,23 +43,18 @@ func removeBinaries(config *config, bEntries []binaryEntry) error {
4343 go func (bEntry binaryEntry ) {
4444 defer wg .Done ()
4545
46- installPath := filepath .Join (installDir , filepath .Base (bEntry .Name ))
47- licensePath := filepath .Join (config .LicenseDir , fmt .Sprintf ("%s_LICENSE" , parseBinaryEntry (bEntry , false )))
48-
49- trackedBEntry , err := readEmbeddedBEntry (installPath )
46+ // Try to find the binary by name or by matching user.FullName
47+ binaryPath , trackedBEntry , err := findBinaryByNameOrFullName (installDir , bEntry .Name )
5048 if err != nil {
5149 if verbosityLevel >= normalVerbosity {
52- fmt .Fprintf (os .Stderr , "Warning: Failed to retrieve full name for '%s'. Skipping removal because this program may not have been installed by dbin. \n " , parseBinaryEntry ( bEntry , true ) )
50+ fmt .Fprintf (os .Stderr , "Warning: '%s' does not exist or was not installed by dbin: %v \n " , bEntry . Name , err )
5351 }
5452 return
5553 }
5654
57- if filepath .Base (bEntry .Name ) != filepath .Base (trackedBEntry .Name ) {
58- installPath = filepath .Join (installDir , filepath .Base (trackedBEntry .Name ))
59- licensePath = filepath .Join (config .LicenseDir , fmt .Sprintf ("%s_LICENSE" , filepath .Base (parseBinaryEntry (trackedBEntry , false ))))
60- }
55+ licensePath := filepath .Join (config .LicenseDir , fmt .Sprintf ("%s_LICENSE" , filepath .Base (parseBinaryEntry (trackedBEntry , false ))))
6156
62- if ! fileExists (installPath ) {
57+ if ! fileExists (binaryPath ) {
6358 if verbosityLevel >= normalVerbosity {
6459 fmt .Fprintf (os .Stderr , "Warning: '%s' does not exist in %s\n " , bEntry .Name , installDir )
6560 }
@@ -68,25 +63,25 @@ func removeBinaries(config *config, bEntries []binaryEntry) error {
6863
6964 if trackedBEntry .PkgID == "" {
7065 if verbosityLevel >= normalVerbosity {
71- fmt .Fprintf (os .Stderr , "Skipping '%s': it was not installed by dbin\n " , bEntry .Name )
66+ fmt .Fprintf (os .Stderr , "Warning: '%s' was not installed by dbin\n " , bEntry .Name )
7267 }
7368 return
7469 }
7570
76- if err := runDeintegrationHooks (config , installPath ); err != nil {
71+ if err := runDeintegrationHooks (config , binaryPath ); err != nil {
7772 if verbosityLevel >= silentVerbosityWithErrors {
78- fmt .Fprintf (os .Stderr , "%s \n " , err )
73+ fmt .Fprintf (os .Stderr , "Error running deintegration hooks for '%s': %v \n " , bEntry . Name , err )
7974 }
8075 mutex .Lock ()
8176 removeErrors = append (removeErrors , err .Error ())
8277 mutex .Unlock ()
8378 return
8479 }
8580
86- err = os .Remove (installPath )
81+ err = os .Remove (binaryPath )
8782 if err != nil {
8883 if verbosityLevel >= silentVerbosityWithErrors {
89- fmt .Fprintf (os .Stderr , "failed to remove '%s' from %s. %v\n " , bEntry .Name , installDir , err )
84+ fmt .Fprintf (os .Stderr , "Failed to remove '%s' from %s: %v\n " , bEntry .Name , installDir , err )
9085 }
9186 mutex .Lock ()
9287 removeErrors = append (removeErrors , fmt .Sprintf ("failed to remove '%s' from %s: %v" , bEntry .Name , installDir , err ))
@@ -119,6 +114,50 @@ func removeBinaries(config *config, bEntries []binaryEntry) error {
119114 return nil
120115}
121116
117+ // findBinaryByNameOrFullName searches for a binary in installDir by its name or by matching the user.FullName xattr.
118+ func findBinaryByNameOrFullName (installDir , name string ) (string , binaryEntry , error ) {
119+ // First, try direct path
120+ binaryPath := filepath .Join (installDir , filepath .Base (name ))
121+ if fileExists (binaryPath ) {
122+ trackedBEntry , err := readEmbeddedBEntry (binaryPath )
123+ if err == nil && trackedBEntry .Name != "" {
124+ return binaryPath , trackedBEntry , nil
125+ }
126+ }
127+
128+ // If direct path fails, scan directory for matching user.FullName
129+ entries , err := os .ReadDir (installDir )
130+ if err != nil {
131+ return "" , binaryEntry {}, errFileAccess .Wrap (err )
132+ }
133+
134+ // Normalize the input name for comparison
135+ inputBEntry := stringToBinaryEntry (name )
136+ inputFullName := parseBinaryEntry (inputBEntry , false )
137+
138+ for _ , entry := range entries {
139+ if entry .IsDir () {
140+ continue
141+ }
142+ binaryPath = filepath .Join (installDir , entry .Name ())
143+ if ! isExecutable (binaryPath ) || isSymlink (binaryPath ) {
144+ continue
145+ }
146+
147+ trackedBEntry , err := readEmbeddedBEntry (binaryPath )
148+ if err != nil || trackedBEntry .Name == "" {
149+ continue
150+ }
151+
152+ trackedFullName := parseBinaryEntry (trackedBEntry , false )
153+ if trackedFullName == inputFullName || trackedBEntry .Name == filepath .Base (name ) {
154+ return binaryPath , trackedBEntry , nil
155+ }
156+ }
157+
158+ return "" , binaryEntry {}, errFileNotFound .New ("binary '%s' not found in %s" , name , installDir )
159+ }
160+
122161func runDeintegrationHooks (config * config , binaryPath string ) error {
123162 if config .UseIntegrationHooks {
124163 ext := filepath .Ext (binaryPath )
0 commit comments