module RightPublish class AptRepo < Repo DEFAULT_APT_AUTO = true DEFAULT_APT_DIR = 'apt/' DEFAULT_DESCRIPTION = "Apt Repository" REPO_KEY = :apt_repo REPO_OPTIONS = { :dists => :addr_optional, :description => DEFAULT_DESCRIPTION, :auto => DEFAULT_APT_AUTO, :subdir => DEFAULT_APT_DIR, :gpg_key_id => :attr_optional, :gpg_password => :attr_optional } BIN_EXTENSION = 'deb' SRC_EXTENSION = 'dsc' BIN_ALL_ARCH = 'all' @@supported_archs = [ 'i386', 'amd64' ] @@all_archs = [ 'i386', 'amd64', BIN_ALL_ARCH ] def add(file_or_dir, target) repo_updates = {} # If we specified a target, let's make sure it's in our profile if target fail("specified distribution is not listed in this profile!") unless repo_config[:dists].include?(target) end pkgs = [] get_pkg_list(file_or_dir, [BIN_EXTENSION, SRC_EXTENSION]) do |path| if path.end_with? BIN_EXTENSION and repo_config[:auto] arch = AptRepo.pkg_parts(path)[:arch] || fail("could not determine architecture for package: #{path}") fail("you probably want to specify a distribution target for binary packages!") unless target || arch == BIN_ALL_ARCH end pkgs << path end repo_path = File.join(Profile.config[:local_storage][:cache_dir], repo_config[:subdir]) write_conf_file repo_path if repo_config[:auto] pkgs.each do |pkg| Profile.log("Adding package [#{pkg}]...") if repo_config[:auto] # If source package, remove existing sources so we don't get a hash clash auto_repo_remove(repo_path, pkg, target) auto_repo_add(repo_path, pkg, target) else trivial_repo_add(pkg) end end rebuild_index(repo_config[:subdir]) if not repo_config[:auto] end def annotate(options={}) options[:subdir] ||= File.join(repo_config[:subdir], 'pool', 'main') options[:filter] = ['*.deb'] super(options) end def self.pkg_parts(pkg_name) result = {:name=>nil, :version=>nil, :arch=>nil, :ext=>nil} if pkg_name.end_with?(SRC_EXTENSION) if /([A-Za-z0-9\.\-+]+)_([A-Za-z0-9\-\.:~]+)\.#{SRC_EXTENSION}\Z/.match(pkg_name) result[:name] = $1 result[:version] = $2 result[:ext] = SRC_EXTENSION end else if /([A-Za-z0-9\.\-+]+)_([A-Za-z0-9\-\.:~]+)_(#{@@all_archs.join('|')})\.#{BIN_EXTENSION}\Z/.match(pkg_name) result[:name] = $1 result[:version] = $2 result[:arch] = $3 result[:ext] = BIN_EXTENSION end end result end private def auto_repo_add(repo_path, pkg, target) targets = (target && Array(target)) || repo_config[:dists] targets.each do |t| sub_command = (pkg.end_with?(BIN_EXTENSION) && 'includedeb') || 'includedsc' ask_passphrase = (repo_config[:gpg_key_id]) ? "--ask-passphrase " : "" cmd = "reprepro #{ask_passphrase}-C main -b #{repo_path} #{sub_command} #{t} #{pkg}" if repo_config[:gpg_key_id] exited = shellout_with_password(cmd) else exited = system(cmd) end raise RuntimeError, "apt package installation failed; cannot continue publishing" unless exited end end def auto_repo_remove(repo_path, pkg, target) pkg_name = AptRepo.pkg_parts(pkg)[:name] filterlist = "'$PackageType (== #{ (pkg.end_with?(BIN_EXTENSION) && 'deb') || 'dsc' }), Package (% #{pkg_name})'" Profile.log("Removing any packages files using filterlist #{filterlist}") targets = (target && Array(target)) || repo_config[:dists] targets.each do |t| ask_passphrase = (repo_config[:gpg_key_id]) ? "--ask-passphrase" : "" cmd = "reprepro #{ask_passphrase} -b #{repo_path} removefilter #{t} #{filterlist}" if repo_config[:gpg_key_id] exited = shellout_with_password(cmd) else exited = system(cmd) end end end def rebuild_index(subdir) Profile.log("Rebuilding repository index...") do_in_subdir(subdir) do indexed = system("dpkg-scanpackages binaries /dev/null 2>/dev/null | gzip -c9 > Packages.gz") raise RuntimeError, "apt package installation failed; cannot continue publishing" unless indexed indexed = system("dpkg-scansources sources /dev/null 2>/dev/null | gzip -c9 > Sources.gz") raise RuntimeError, "apt package installation failed; cannot continue publishing" unless indexed end end def trivial_repo_add(pkg) pkg_info = AptRepo.pkg_parts(pkg) if pkg_info[:ext].eql?(BIN_EXTENSION) sub_dir = File.join(repo_config[:subdir], 'binaries') else pkg_name = pkg_info[:name] src_file = Dir.glob("#{File.dirname(pkg)}/#{pkg_name}_*.orig.tar.gz") raise RuntimeError, "could not find original source for #{pkg}, missing or ambiguous." unless src_file.size == 1 diff_file = pkg.sub(/#{SRC_EXTENSION}$/, 'diff.gz') sub_dir = File.join(repo_config[:subdir], 'sources') raise RuntimeError, "missing the debian diff file for #{pkg}." unless File.file?(diff_file) do_in_subdir(sub_dir) { prune_all("#{pkg_info[:name]}*.orig.tar.gz") } install_file(src_file[0], sub_dir) do_in_subdir(sub_dir) { prune_all("#{pkg_info[:name]}*.diff.gz") } install_file(diff_file, sub_dir) end do_in_subdir(sub_dir) { prune_all("#{pkg_info[:name]}_*#{pkg_info[:arch]}.#{pkg_info[:ext]}") } install_file(pkg, sub_dir) end def write_conf_file(repo_path) destination_dir = File.expand_path(File.join(repo_path, 'conf')) FileUtils.mkdir_p destination_dir config_file = open( File.join(destination_dir, 'distributions'), 'wb' ) repo_config[:dists].each { |dist| config_file << dist_conf(dist) } config_file.close end def dist_conf(dist) <