#!/usr/bin/ruby def usage puts "Usage: #{$0} [options]" puts "Moves obsolete packages" puts puts "-h, --help show this help" puts "-a, --archs ,,... list of architectures to clean" puts "-a, --auto do not ask confirmation" puts "-p, --base base path to the repository" puts "-m, --media ,,... list of media to clean (default: core/release,tainted/release,nonfree/release)" puts "-d, --destination path to the old packages storage" puts "-v, --version version to clean (default: cauldron)" end require 'fileutils' require 'getoptlong' require 'readline' def process opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--archs', '-a', GetoptLong::REQUIRED_ARGUMENT ], [ '--auto', '-A', GetoptLong::NO_ARGUMENT ], [ '--base', '-p', GetoptLong::REQUIRED_ARGUMENT ], [ '--media', '-m', GetoptLong::REQUIRED_ARGUMENT ], [ '--destination', '-d', GetoptLong::REQUIRED_ARGUMENT ], [ '--version', '-v', GetoptLong::REQUIRED_ARGUMENT ], [ '--lockfile', '-l', GetoptLong::REQUIRED_ARGUMENT ], ) base_path = "<%= scope.lookupvar('buildsystem::var::repository::bootstrap_root') %>/distrib" archs = [ "x86_64", "i686", "aarch64", "armv7hl" ] medias = ["core/release", "tainted/release", "nonfree/release"] old_path = "<%= scope.lookupvar('buildsystem::var::youri::packages_archivedir') %>" version = "cauldron" auto = false lockfile = nil opts.each do |opt, arg| case opt when '--help' usage exit 0 when '--destination' old_path = arg when '--media' medias = arg.split(",") when '--archs' archs = arg.split(",") when '--auto' auto = true when '--base' base_path = arg when '--version' version = arg when '--lockfile' lockfile = arg end end take_upload_lock(lockfile) if lockfile medias.each{|media| src_path = "#{base_path}/#{version}/SRPMS/#{media}" $used_srcs = {} $old_srcs = {} $srcs = {} $srcages = {} $noarch = {} # Get a list of all src.rpm and their build time `urpmf --synthesis "#{src_path}/media_info/synthesis.hdlist.cz" --qf '%filename:%buildtime:%buildarchs' "."`.each_line{|l| l2 = l.split(':') filename = l2[0] buildtime = l2[1].to_i buildarch = l2[2].rstrip name = name_from_filename(filename) if $srcages[name] then if buildtime < $srcages[name][1] then # This src.rpm is older, ignore it and store it in the list to be deleted $old_srcs[filename] = true next else # This src.rpm has an older version, ignore that version and store it in the list to be deleted old_filename = $srcages[name][0] $old_srcs[old_filename] = true $srcs.delete(old_filename) end end $srcages[name] = [ filename, buildtime ] $srcs[filename] = true $noarch[name] = true if buildarch == 'noarch' } archs.each{|arch| bin_path = "#{base_path}/#{version}/#{arch}/media/#{media}" debug_path = bin_path.sub("/media/", "/media/debug/") old_packages = check_binaries(arch, $srcs, $srcages, src_path, bin_path, $used_srcs) old_debug_packages = check_binaries(arch, $srcs, {}, src_path, debug_path, nil) move_packages(bin_path, old_path, old_packages, auto) move_packages(debug_path, old_path, old_debug_packages, auto) } $used_srcs.keys.each{|s| $srcs.delete(s)} move_packages(src_path, old_path, $srcs.keys + $old_srcs.keys, auto) } end def take_upload_lock(path) start_time = Time.new has_lock = false at_exit { if File.exists?(path) if File.readlines(path)[0].to_i == Process.pid File.delete(path) end end } until has_lock while File.exists?(path) if Time.new - start_time > 2*3600.0 puts "Could not acquire upload lock for more than 2h, giving up" end sleep(5) end File.write(path, Process.pid) if File.readlines(path)[0].to_i == Process.pid has_lock = true end end end def move_packages(src, dst, list, auto) list.reject!{|f| !File.exist?(src + "/" + f)} return if list.empty? list.each{|b| puts b } puts "The #{list.length} listed packages will be moved from #{src} to #{dst}." line = Readline::readline('Are you sure [Yn]? ') unless auto if auto || line =~ /^y?$/i list.each{|s| oldfile = src + "/" + s newfile = dst + "/" + s next unless File.exist?(oldfile) if (File.exist?(newfile)) File.unlink(oldfile) else FileUtils.mv(oldfile, newfile) end } end end # For each binary media: # - Check if we have the src.rpm (else the binary package is obsolete) # * If we don't have the src.rpm, check if we have a newer version # - If there is a new version: # * check if this architecture has packages from it to avoid deleting armv7hl packages before the new one get rebuilt # * check if the new version is old enough to allow rebuilding everything (7d?) # - Mark used src.rpm (if one is never marked, the src.rpm is obsolete) def packages(path) `urpmf --synthesis "#{path}/media_info/synthesis.hdlist.cz" --qf '%sourcerpm:%filename:%buildtime' ":"`.each_line{|l| l2 = l.split(':') sourcerpm = l2[0] filename = l2[1] buildtime = l2[2].to_i yield(sourcerpm, filename, buildtime) } end def name_from_filename(filename) filename.sub(/-[^-]*-[^-]*$/, '') end def arch_wanted(src, arch) exclusive_arch = `rpmquery -p #{src} --qf '[%{EXCLUSIVEARCH} ]'`.rstrip if exclusive_arch != "" then if !exclusive_arch.split(/ /).include?(arch) then return false end end exclude_arch = `rpmquery -p #{src} --qf '[%{EXCLUDEARCH} ]'`.rstrip if exclude_arch != "" then if exclude_arch.split(/ /).include?(arch) then return false end end return true end def check_binaries(arch, srcs, srcages, src_path, path, used_srcs) used_here_srcs = {} all_versions = {} packages(path) {|src, filename, buildtime| used_srcs[src] = true if used_srcs != nil if filename =~ /noarch.rpm$/ then # We need to mark the src.rpm present on this arch only for full noarch packages used_here_srcs[src] = true if $noarch[name_from_filename(src)] else used_here_srcs[src] = true end name = name_from_filename(filename) if all_versions[name] then all_versions[name] << src else all_versions[name] = [src] end } old_binaries = [] packages(path) {|src, filename, buildtime| if ! srcs[src] then srcname = name_from_filename(src) if srcages[srcname] then # The src.rpm is gone but there is a different version of it latestsrc = srcages[srcname][0] # Only delete old binaries after 7d or if there is a new version name = name_from_filename(filename) next unless (srcages[srcname][1] < Time.now.to_i - 24*60*60*7 || all_versions[name].include?(latestsrc)) # Do not delete if the new version of the package hasn't been built for this arch yet # but still delete it if it is no longer expected to be built. next unless (used_here_srcs[latestsrc] || !arch_wanted("#{src_path}/#{latestsrc}", arch)) end old_binaries << filename end } old_binaries end if __FILE__ == $0 then process end