diff --git a/Library/Homebrew/cask/lib/hbc/artifact/uninstall_base.rb b/Library/Homebrew/cask/lib/hbc/artifact/uninstall_base.rb index 7dc7723806..96243d201a 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/uninstall_base.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/uninstall_base.rb @@ -224,9 +224,14 @@ module Hbc end def uninstall_trash(*paths) - # :trash functionality is stubbed as a synonym for :delete - # TODO: make :trash work differently, moving files to the Trash - uninstall_delete(*paths) + return if paths.empty? + + ohai "Trashing files:" + each_resolved_path(:trash, paths) do |path, resolved_paths| + puts path + resolved_paths.each { |resolved_path| Utils.gain_permissions(resolved_path, ["-R"], @command) } + @command.run!("/usr/bin/xargs", args: ["-0", "--", HOMEBREW_LIBRARY_PATH/"utils/trash.swift"], input: resolved_paths.join("\0")) + end end def uninstall_rmdir(*directories) diff --git a/Library/Homebrew/test/utils/trash_spec.rb b/Library/Homebrew/test/utils/trash_spec.rb new file mode 100644 index 0000000000..9f2f7df153 --- /dev/null +++ b/Library/Homebrew/test/utils/trash_spec.rb @@ -0,0 +1,32 @@ +require "open3" + +describe "trash", :needs_macos do + let(:executable) { HOMEBREW_LIBRARY_PATH/"utils/trash.swift" } + let(:dir) { mktmpdir } + let(:file) { dir/"new_file" } + + it "moves existing files to the trash" do + FileUtils.touch file + + expect(file).to exist + + out, err, status = Open3.capture3(executable, file) + + expect(out).to match %r{moved #{file} to .*/\.Trash/\.*} + expect(err).to be_empty + expect(status).to be_a_success + + expect(file).not_to exist + + trashed_path = out.sub(/^moved #{Regexp.escape(file.to_s)} to (.*)\n$/, '\1') + FileUtils.rm_f trashed_path + end + + it "fails when files don't exist" do + out, err, status = Open3.capture3(executable, file) + + expect(out).to be_empty + expect(err).to eq "could not move #{file} to trash\n" + expect(status).to be_a_failure + end +end diff --git a/Library/Homebrew/utils/trash.swift b/Library/Homebrew/utils/trash.swift new file mode 100755 index 0000000000..f591c3806f --- /dev/null +++ b/Library/Homebrew/utils/trash.swift @@ -0,0 +1,43 @@ +#!/usr/bin/swift + +import Cocoa + +DispatchQueue.main.async { + let arguments = CommandLine.arguments.dropFirst().filter { !$0.isEmpty } + let URLs = arguments.map { URL(fileURLWithPath: $0) } + + #if swift(>=4.0) + let workspace = NSWorkspace.shared + #else + let workspace = NSWorkspace.shared() + #endif + + workspace.recycle(URLs) { (dict, error) in + dict.forEach { + #if swift(>=4.0) + let originalPath = $0.0.path + let trashPath = $0.1.path + #else + let originalPath = $0.path + let trashPath = $1.path + #endif + + print("moved \(originalPath) to \(trashPath)") + } + + if error == nil { + exit(0) + } + + let trashedURLs = dict.keys + let untrashedURLs = URLs.filter { !trashedURLs.contains($0) } + + untrashedURLs.forEach { + fputs("could not move \($0.path) to trash\n", stderr) + } + + exit(1) + } +} + +RunLoop.main.run()