diff --git a/bin/crew b/bin/crew index 9dd9c7e2f..cb7aab538 100755 --- a/bin/crew +++ b/bin/crew @@ -766,29 +766,6 @@ def compress_doc(dir) end end -def determine_conflicts(dir, pkg) - conflicts = [] - if File.file?("#{dir}/filelist") - if File.file?(File.join(CREW_META_PATH, "#{pkg}.filelist")) - puts 'Checking for conflicts with files from installed packages...'.orange - conflictscmd = `grep --exclude=#{File.join(CREW_META_PATH, "#{pkg}.filelist")} --exclude=#{CREW_META_PATH}/\\\*_build.filelist -Fxf #{dir}/filelist #{CREW_META_PATH}/*.filelist` - conflicts = conflictscmd.gsub(/(\.filelist|#{CREW_META_PATH})/, '').split("\n") - conflicts.reject!(&:empty?) - end - elsif File.file?(File.join(CREW_META_PATH, "#{pkg}.filelist")) - puts "Checking for conflicts of #{pkg} with files from installed packages...".orange - conflictscmd = `grep --exclude=#{File.join(CREW_META_PATH, "#{pkg}.filelist")} --exclude=#{CREW_META_PATH}/\\\*_build.filelist -Fxf #{File.join(CREW_META_PATH, "#{pkg}.filelist")} #{CREW_META_PATH}/*.filelist` - conflicts = conflictscmd.gsub(/(\.filelist|#{CREW_META_PATH})/, '').split("\n") - conflicts.reject!(&:empty?) - end - if conflicts.any? - puts 'There is a conflict with the same file in another package:'.orange - puts conflicts.to_s.orange - end - conflicts.map! { |x| x.to_s.partition(':').last } - return conflicts -end - def prepare_package(destdir) # Create the destdir if it does not exist to avoid having to have # this single line in no_compile_needed packages. @@ -858,15 +835,24 @@ def prepare_package(destdir) end # check for conflicts with other installed files - conflicts = determine_conflicts(Dir.pwd, @pkg.name) + conflicts = ConvenienceFunctions.determine_conflicts(@pkg.name, File.join(Dir.pwd, 'filelist'), '_build', verbose: CREW_VERBOSE) + if conflicts.any? if CREW_CONFLICTS_ONLY_ADVISORY || @pkg.conflicts_ok? - puts 'Warning: There is a conflict with the same file in another package.'.orange + puts "Warning: There is a conflict with the same file in another package:\n".orange else - puts 'Error: There is a conflict with the same file in another package.'.lightred + puts "Error: There is a conflict with the same file in another package:\n".lightred errors = true end - puts conflicts + + conflicts.each_pair do |pkgName, conflictFiles| + if errors + conflictFiles.each {|file| puts "#{pkgName}: #{file}".lightred } + else + conflictFiles.each {|file| puts "#{pkgName}: #{file}".orange } + end + puts + end end # abort if errors encountered diff --git a/commands/remove.rb b/commands/remove.rb index ae4cdd749..00c457bdf 100644 --- a/commands/remove.rb +++ b/commands/remove.rb @@ -50,38 +50,38 @@ class Command # Remove the files and directories installed by the package. unless pkg.is_fake? Dir.chdir CREW_CONFIG_PATH do - # Remove all files installed by the package in CREW_PREFIX and - # HOME. + # Remove all files installed by the package in CREW_PREFIX and HOME. + # # Exceptions: # 1. The file exists in another installed package. - # 2. The file is in one of the filelists for packages CREW_ESSENTIAL_PACKAGES. - flist = File.join(CREW_META_PATH, "#{pkg.name}.filelist") - if File.file?(flist) + filelist_path = File.join(CREW_META_PATH, "#{pkg.name}.filelist") + if File.file?(filelist_path) + filelist = File.readlines(filelist_path, chomp: true) + overlap_files = ConvenienceFunctions.determine_conflicts(pkg.name, filelist_path, verbose: verbose) + essential_files = CREW_ESSENTIAL_PACKAGES.flat_map {|f| File.readlines(File.join(CREW_META_PATH, "#{f}.filelist"), chomp: true)} + overlap_essential_files = filelist & essential_files + files_to_remove = filelist - overlap_files.values.flatten - overlap_essential_files - # When searching for files to delete we exclude the files from CREW_ESSENTIAL_PACKAGES. - essential_packages_exclude_froms = '' - unless force - essential_packages_exclude_froms = CREW_ESSENTIAL_PACKAGES.map { |i| File.file?("#{File.join(CREW_META_PATH, i.to_s)}.filelist") ? "--exclude-from=#{File.join(CREW_META_PATH, i.to_s)}.filelist" : '' }.join(' ') + if overlap_essential_files.any? + warn "The following file(s) will not be deleted as they are required for Chromebrew to work properly:\n".orange + warn overlap_essential_files.join("\n").orange + warn "\n\n" end - package_files = `grep -h #{essential_packages_exclude_froms} \"^#{CREW_PREFIX}\\|^#{HOME}\" #{flist}`.split("\n").uniq.sort - all_other_files = `grep -h --exclude #{pkg.name}.filelist \"^#{CREW_PREFIX}\\|^#{HOME}\" #{CREW_META_PATH}/*.filelist 2>/dev/null`.split("\n").uniq.sort - - # We want the difference of these arrays. - unique_to_package_files = package_files - all_other_files - - # We want the intersection of these arrays. - package_files_that_overlap = all_other_files & package_files - - unless package_files_that_overlap.empty? - puts "The following file(s) in other packages will not be deleted during the removal of #{pkg.name}:".orange - puts package_files_that_overlap.join("\n").orange + if overlap_files.any? + warn "The following file(s) in other packages will not be deleted during the removal of #{pkg.name}:\n".orange + overlap_files.each_pair do |pkgName, files| + files.each {|file| puts "#{pkgName}: #{file}".orange } + end + puts end - unique_to_package_files.each do |file| + + files_to_remove.each do |file| puts "Removing file #{file}".yellow if verbose FileUtils.remove_file file, exception: false end - FileUtils.remove_file flist + + FileUtils.remove_file filelist_path end # Remove all directories installed by the package. diff --git a/lib/const.rb b/lib/const.rb index 3304105ad..036ec9c35 100644 --- a/lib/const.rb +++ b/lib/const.rb @@ -3,7 +3,7 @@ require 'etc' OLD_CREW_VERSION ||= defined?(CREW_VERSION) ? CREW_VERSION : '1.0' -CREW_VERSION ||= '1.58.2' unless defined?(CREW_VERSION) && CREW_VERSION == OLD_CREW_VERSION +CREW_VERSION ||= '1.58.3' unless defined?(CREW_VERSION) && CREW_VERSION == OLD_CREW_VERSION # Kernel architecture. KERN_ARCH ||= Etc.uname[:machine] diff --git a/lib/convenience_functions.rb b/lib/convenience_functions.rb index fb889a339..a151903a4 100644 --- a/lib/convenience_functions.rb +++ b/lib/convenience_functions.rb @@ -7,6 +7,26 @@ require_relative 'crewlog' require_relative 'downloader' class ConvenienceFunctions + def self.determine_conflicts(pkgName, filelist = File.join(CREW_META_PATH, "#{pkgName}.filelist"), excludeSuffix = nil, verbose: false) + conflicts = {} + target_filelist = File.readlines(filelist, chomp: true) + + puts 'Checking for conflicts with files from installed packages...'.orange if verbose + + Dir[File.join(CREW_META_PATH, "*.filelist")].each do |filelist| + filelist_name = File.basename(filelist, ".filelist") + + # skip filelist belongs to the same package/explicitly excluded + next if pkgName == filelist_name || (excludeSuffix && filelist_name.end_with?(excludeSuffix)) + + # find out identical file paths with intersection + conflict = (target_filelist & File.readlines(filelist, chomp: true)).reject(&:empty?) + conflicts[filelist_name] = conflict if conflict.any? + end + + return conflicts + end + def self.load_symbolized_json return JSON.load_file(File.join(CREW_CONFIG_PATH, 'device.json'), symbolize_names: true).transform_values! { |val| val.is_a?(String) ? val.to_sym : val } end diff --git a/tests/commands/remove.rb b/tests/commands/remove.rb index f71c38495..16470b548 100644 --- a/tests/commands/remove.rb +++ b/tests/commands/remove.rb @@ -55,6 +55,7 @@ class RemoveCommandTest < Minitest::Test puts 'Testing the verbose removal of normal package xxd_standalone. This should succeed.' expected_output = <<~EOT + Checking for conflicts with files from installed packages... Removing file #{CREW_PREFIX}/bin/xxd Removing file #{CREW_PREFIX}/share/man/man1/xxd.1.zst Removing package xxd_standalone from device.json