From 998f87cee34dd8904e4e60772dddd7706a049e83 Mon Sep 17 00:00:00 2001 From: alexey Date: Sat, 15 Mar 2025 00:01:18 +0300 Subject: [PATCH] mock build --- Gemfile | 2 + Gemfile.lock | 1 + classes/db.rb | 16 +- classes/mock.rb | 161 ++++++-- classes/projects.rb | 3 +- classes/repomanage.rb | 15 + classes/utilities.rb | 12 + locallibs/ruby-rpm-ffi/.gitignore | 8 + locallibs/ruby-rpm-ffi/.rubocop.yml | 1 + locallibs/ruby-rpm-ffi/.rubocop_todo.yml | 111 +++++ locallibs/ruby-rpm-ffi/ChangeLog | 10 + locallibs/ruby-rpm-ffi/Gemfile | 9 + locallibs/ruby-rpm-ffi/MIT-LICENSE | 24 ++ locallibs/ruby-rpm-ffi/README.md | 378 ++++++++++++++++++ locallibs/ruby-rpm-ffi/Rakefile | 52 +++ .../ruby-rpm-ffi/_docker/Dockerfile.ubi8 | 8 + .../ruby-rpm-ffi/_docker/Dockerfile.ubi9 | 8 + locallibs/ruby-rpm-ffi/lib/rpm.rb | 88 ++++ locallibs/ruby-rpm-ffi/lib/rpm/c.rb | 49 +++ locallibs/ruby-rpm-ffi/lib/rpm/c/header.rb | 36 ++ .../ruby-rpm-ffi/lib/rpm/c/rpmcallback.rb | 27 ++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcli.rb | 6 + locallibs/ruby-rpm-ffi/lib/rpm/c/rpmdb.rb | 20 + locallibs/ruby-rpm-ffi/lib/rpm/c/rpmds.rb | 43 ++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmfi.rb | 31 ++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmio.rb | 19 + locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlib.rb | 12 + locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlog.rb | 23 ++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmmacro.rb | 33 ++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmprob.rb | 53 +++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmps.rb | 11 + locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtag.rb | 304 ++++++++++++++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtd.rb | 34 ++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmts.rb | 71 ++++ locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtypes.rb | 28 ++ locallibs/ruby-rpm-ffi/lib/rpm/compat.rb | 40 ++ locallibs/ruby-rpm-ffi/lib/rpm/db.rb | 117 ++++++ locallibs/ruby-rpm-ffi/lib/rpm/dependency.rb | 120 ++++++ locallibs/ruby-rpm-ffi/lib/rpm/file.rb | 134 +++++++ locallibs/ruby-rpm-ffi/lib/rpm/gem_version.rb | 7 + .../ruby-rpm-ffi/lib/rpm/match_iterator.rb | 66 +++ locallibs/ruby-rpm-ffi/lib/rpm/package.rb | 333 +++++++++++++++ locallibs/ruby-rpm-ffi/lib/rpm/problem.rb | 65 +++ locallibs/ruby-rpm-ffi/lib/rpm/transaction.rb | 270 +++++++++++++ locallibs/ruby-rpm-ffi/lib/rpm/utils.rb | 7 + locallibs/ruby-rpm-ffi/lib/rpm/version.rb | 146 +++++++ locallibs/ruby-rpm-ffi/rpm.gemspec | 25 ++ locallibs/ruby-rpm-ffi/test/data/a.spec | 49 +++ .../test/data/simple-1.0-0.i586.rpm | Bin 0 -> 2177 bytes locallibs/ruby-rpm-ffi/test/data/simple.spec | 38 ++ .../test/data/simple_with_deps-1.0-0.i586.rpm | Bin 0 -> 2335 bytes .../test/data/simple_with_deps.spec | 41 ++ locallibs/ruby-rpm-ffi/test/helper.rb | 7 + .../ruby-rpm-ffi/test/test_dependency.rb | 28 ++ locallibs/ruby-rpm-ffi/test/test_file.rb | 36 ++ locallibs/ruby-rpm-ffi/test/test_lib.rb | 33 ++ locallibs/ruby-rpm-ffi/test/test_package.rb | 76 ++++ locallibs/ruby-rpm-ffi/test/test_problem.rb | 18 + locallibs/ruby-rpm-ffi/test/test_rpm.rb | 35 ++ .../ruby-rpm-ffi/test/test_transaction.rb | 156 ++++++++ locallibs/ruby-rpm-ffi/test/test_version.rb | 64 +++ 61 files changed, 3581 insertions(+), 37 deletions(-) create mode 100644 locallibs/ruby-rpm-ffi/.gitignore create mode 100644 locallibs/ruby-rpm-ffi/.rubocop.yml create mode 100644 locallibs/ruby-rpm-ffi/.rubocop_todo.yml create mode 100644 locallibs/ruby-rpm-ffi/ChangeLog create mode 100644 locallibs/ruby-rpm-ffi/Gemfile create mode 100644 locallibs/ruby-rpm-ffi/MIT-LICENSE create mode 100644 locallibs/ruby-rpm-ffi/README.md create mode 100644 locallibs/ruby-rpm-ffi/Rakefile create mode 100644 locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi8 create mode 100644 locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi9 create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/header.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcallback.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcli.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmdb.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmds.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmfi.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmio.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlib.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlog.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmmacro.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmprob.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmps.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtag.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtd.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmts.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtypes.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/compat.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/db.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/dependency.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/file.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/gem_version.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/match_iterator.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/package.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/problem.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/transaction.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/utils.rb create mode 100644 locallibs/ruby-rpm-ffi/lib/rpm/version.rb create mode 100644 locallibs/ruby-rpm-ffi/rpm.gemspec create mode 100644 locallibs/ruby-rpm-ffi/test/data/a.spec create mode 100644 locallibs/ruby-rpm-ffi/test/data/simple-1.0-0.i586.rpm create mode 100644 locallibs/ruby-rpm-ffi/test/data/simple.spec create mode 100644 locallibs/ruby-rpm-ffi/test/data/simple_with_deps-1.0-0.i586.rpm create mode 100644 locallibs/ruby-rpm-ffi/test/data/simple_with_deps.spec create mode 100644 locallibs/ruby-rpm-ffi/test/helper.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_dependency.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_file.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_lib.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_package.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_problem.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_rpm.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_transaction.rb create mode 100644 locallibs/ruby-rpm-ffi/test/test_version.rb diff --git a/Gemfile b/Gemfile index 2a1694e..8018e4e 100644 --- a/Gemfile +++ b/Gemfile @@ -32,3 +32,5 @@ gem "sqlite3", "~> 2.5" gem "rugged", "~> 1.9" gem "sequel", "~> 5.89" + +gem "ffi", "~> 1.17" diff --git a/Gemfile.lock b/Gemfile.lock index f0ee0c9..cfa9f60 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,6 +171,7 @@ PLATFORMS DEPENDENCIES carrierwave (~> 3.1) data_mapper (~> 1.2) + ffi (~> 1.17) inifile (~> 3.0) json (~> 1.8) puma (~> 6.6) diff --git a/classes/db.rb b/classes/db.rb index 7fd892b..df9e708 100644 --- a/classes/db.rb +++ b/classes/db.rb @@ -27,6 +27,12 @@ end class BuildTask < Sequel::Model(:buildtask) end +class Rpms < Sequel::Model(:rpms) +end + +class BuildRpms < Sequel::Model(:build_rpm) +end + class DBase attr :error, :last_id, :cfg @@ -34,7 +40,7 @@ class DBase @cfg = cfg end - def creategit(project_name, description, cfg) + def creategit(project_name, description) @error = nil data = Repos.where(reponame: project_name).first if data.nil? @@ -228,7 +234,7 @@ class DBase def create_build_task(prj_id, git_id, proj_path) id = BuildTask.insert(repo_id: git_id.to_i, proj_id: prj_id.to_i, signpath: "", logpath: "", errlogpath: "", result: 0) @last_id = id - BuildTask.where(id: id).update(logpath: File.join(proj_path, "#{id}")) + BuildTask.where(id: id).update(logpath: File.join(proj_path, "#{id}"), errlogpath: File.join(proj_path, "#{id}", "process.log")) end def update_build_task_status(build_id, status) @@ -250,4 +256,10 @@ class DBase def after_fork() Sequel.connect(@cfg.get_db) end + + def save_rpm(build_id, path_to_rpm, rpm_name, git_id) + id = Rpms.insert(savepath: path_to_rpm, rpmname: rpm_name, sign: 0, signpath: "", repo_id: git_id.to_i) + @last_id = id + BuildRpms.insert(build_id: build_id.to_i, rpm_id: id) + end end diff --git a/classes/mock.rb b/classes/mock.rb index cfa4fce..eb116f1 100644 --- a/classes/mock.rb +++ b/classes/mock.rb @@ -2,6 +2,7 @@ require_relative "spork" require_relative "runner" require "fileutils" require "logger" +require_relative "repomanage" BUILD_STRUCTURE = { :SRC => "src", @@ -10,12 +11,10 @@ BUILD_STRUCTURE = { :RESULT_SRPM => "result_srpm", } -#mock -r /home/alexey/workspace/ruby-projects/mock-gui/projects/prjt1.prj/configs/prjt1.cfg result/bayrepo-neuro-farm-0.1-2.src.rpm --resultdir result2/ --isolation simple - class MockManager - attr :path, :config, :error, :last_status, :last_pid, :prep_dir, :db, :resultpath, :process_log, :repo_path, :git_path, :build_id, :log, :recips, :spec, :repo_lock + attr :path, :config, :error, :last_status, :last_pid, :prep_dir, :db, :resultpath, :process_log, :repo_path, :git_path, :build_id, :log, :recips, :spec, :repo_lock, :git_id - def initialize(path, config, cfg_counter_path, db, result_path, repo_path, git_path, build_id, recips, spec_file, repo_lock) + def initialize(path, config, cfg_counter_path, db, result_path, repo_path, git_path, build_id, recips, spec_file, repo_lock, git_id) @error = nil unless File.exist? (path) Dir.mkdir(path) @@ -31,6 +30,7 @@ class MockManager @recips = recips @spec = spec_file @repo_lock = repo_lock + @git_id = git_id File.open(cfg_counter_path, "r+") do |f| f.flock(File::LOCK_EX) @@ -52,10 +52,6 @@ class MockManager @process_log end - def finalize_build_task() - @log.close - end - def clean_build @log.info("Удаление временной сборочной среды #{@path}") FileUtils.rm_rf(@path) @@ -91,7 +87,7 @@ class MockManager @recips.each_with_index do |item, index| @log.info("Формируем рецепт #{item[:filepath]}") rcp_name = "#{index}rcp_#{item[:filepath]}" - File.open(File.join(@prep_dir, BUILD_STRUCTURE[:SRC], rcp_name)) do |f| + File.open(File.join(@prep_dir, BUILD_STRUCTURE[:SRC], rcp_name), "w") do |f| f.write(item[:content]) end Dir.chdir(File.join(@prep_dir, BUILD_STRUCTURE[:SRC])) do @@ -100,6 +96,7 @@ class MockManager cmd = Runner.new(cmd_args, @log) cmd.run_clean @error = true if cmd.exit_status != 0 + @log.error("Ошибка операции") if @error end break if @error end @@ -110,11 +107,11 @@ class MockManager spec_file = File.join(@prep_dir, BUILD_STRUCTURE[:SRC], @spec) if File.exist?(spec_file) Dir.chdir(File.join(@prep_dir, BUILD_STRUCTURE[:SRC])) do - script = File.join(@prep_dir, BUILD_STRUCTURE[:SRC], rcp_name) cmd_args = %Q(/usr/bin/mock -r #{@config} --buildsrpm --spec #{spec_file} --sources #{File.join(@prep_dir, BUILD_STRUCTURE[:SRC])} --resultdir #{File.join(@prep_dir, BUILD_STRUCTURE[:RESULT_SRPM])} --isolation=simple --disable-plugin=ccache") cmd = Runner.new(cmd_args, @log) cmd.run_clean @error = true if cmd.exit_status != 0 + @log.error("Ошибка операции") if @error end else @error = true @@ -123,40 +120,138 @@ class MockManager end def build_rpm() + @log.info("Начало сборки пакетов") + srpm_result_dir = File.join(@prep_dir, BUILD_STRUCTURE[:RESULT_SRPM]) + srpms = get_src_rpm_files_in_dir(srpm_result_dir) + if srpms.nil? || srpms.length == 0 + @error = true + @log.info("Нечего собирать, нет src.rpm пакетов") + else + srpm = srpms.first + path_srpm = File.join(@prep_dir, srpm) + cmd_args = %Q(/usr/bin/mock -r #{@config} #{path_srpm} --resultdir #{File.join(@prep_dir, BUILD_STRUCTURE[:RESULT])} --isolation simple) + cmd = Runner.new(cmd_args, @log) + cmd.run_clean + @error = true if cmd.exit_status != 0 + @log.error("Ошибка операции") if @error + end end def save_logs() + FileUtils.mkdir_p(File.join(@resultpath, "#{@build_id}")) + src_result = File.join(@prep_dir, BUILD_STRUCTURE[:RESULT_SRPM]) + rpm_result = File.join(@prep_dir, BUILD_STRUCTURE[:RESULT]) + if File.exist?(src_result) + logs = get_log_paths(src_result) + logs.each do |item| + src = File.join(src_result, item) + dst_dir = File.dirname(item) + dst_fname = File.basename(item) + dst = File.join(@resultpath, "#{@build_id}", dst_dir, "srpms_build_#{dst_fname}") + FileUtils.cp_r(src, dst, verbose: true, remove_destination: true) + end + end + if File.exist?(rpm_result) + logs = get_log_paths(rpm_result) + logs.each do |item| + src = File.join(rpm_result, item) + dst_dir = File.dirname(item) + dst_fname = File.basename(item) + dst = File.join(@resultpath, "#{@build_id}", dst_dir, "rpm_build_#{dst_fname}") + FileUtils.cp_r(src, dst, verbose: true, remove_destination: true) + end + end end def save_rpms() - File.open(@repo_lock, File::RDWR | File::CREAT) do |f| - f.flock(File::LOCK_EX) - # выклдака пакетов и пересоздание repodata + @log.info("Формирование репозитория") + repo = RepoManager.new(@repo_path) + rpms = get_rpm_paths(File.join(@prep_dir, BUILD_STRUCTURE[:RESULT])) + if rpms.nil? || rpms.length == 0 + @error = true + @log.error("Пакеты не найдены") + else + prep_rpms = [] + rpms.each do |item| + res = {} + rpm_path = File.join(@prep_dir, BUILD_STRUCTURE[:RESULT], item) + result = repo.get_rpm_info(rpm_path) + if result[:error].nil? + res[:src] = rpm_path + res[:name] = result[:pkginfo].to_s + arch = result[:pkginfo].arch + if rpm_path =~ /\.src\.rpm$/ + res[:dst] = File.join(@repo_path, "SRPMS", File.basename(rpm_path)) + elsif rpm_path =~ /(debuginfo.+rpm$)|(debugsource.+rpm$)/ + res[:dst] = File.join(@repo_path, "Debug", File.basename(rpm_path)) + else + if arch.nil? || arch.strip == "" + arch = "noarch" + end + res[:dst] = File.join(@repo_path, arch, File.basename(rpm_path)) + end + prep_rpms << res + else + @error = true + @log.error("Ошибка пакета #{rpm_path}") + break + end + end + if @error == false + File.open(@repo_lock, File::RDWR | File::CREAT) do |f| + f.flock(File::LOCK_EX) + # выклдака пакетов и пересоздание repodata + prep_rpms.each do |item| + FileUtils.cp_r(item[:src], item[:dst], verbose: true, remove_destination: true) + @db.save_rpm(@build_id, item[:dst], item[:name], @git_id) + @log.info("Копируется пакет #{item[:src]} в репозиторий #{item[:dst]}") + end + repo.create_repo + end + end + end + end + + def save_prg_log() + FileUtils.mkdir_p(File.join(@resultpath, "#{@build_id}")) + if File.exist?(@process_log) + dst = File.join(@resultpath, "#{@build_id}") + FileUtils.cp_r(@process_log, dst, verbose: true, remove_destination: true) end end def build_task() @error = false - @db.before_fork - spock = Spork.spork(:logger => log) do - @db.after_fork - $stdout = File.open(@process_log, "w") - @log = Logger.new($stdout) - if @sepc == "" - @error = true - @log.error("Не могу найти spec файл") - end - prepare_structure if @error == false - prepare_src if @error == false - prepare_source if @error == false - prepare_src_rpm if @error == false - build_rpm if @error == false - save_logs - save_rpms if @error == false - clean_build - @log.close + #@db.before_fork + #spock = Spork.spork(:logger => log) do + # @db.after_fork + #$stdout = File.open(@process_log, "w") + @log = Logger.new($stdout) + if @spec == "" + @error = true + @log.error("Не могу найти spec файл") + end + #begin + prepare_structure if @error == false + prepare_src if @error == false + prepare_source if @error == false + prepare_src_rpm if @error == false + build_rpm if @error == false + save_logs + save_rpms if @error == false + #rescue => e + # puts e + #end + save_prg_log + clean_build + @log.close + if @error + @db.update_build_task_status(@build_id, 1) + else + @db.update_build_task_status(@build_id, 2) end - @db.after_fork - spock + #end + #@db.after_fork + #spock end end diff --git a/classes/projects.rb b/classes/projects.rb index 97a0d0b..3aa4a2c 100644 --- a/classes/projects.rb +++ b/classes/projects.rb @@ -305,11 +305,10 @@ class ProjectsActions git_source = File.join(proj_path, PROJECTS_STRUCTURE[:SRC], git_name[:reponame]) @db.create_build_task(prj_id, git_id, build_path) build_id = @db.last_id - mock = MockManager.new(prepare_path, get_project_config(prj_id), counter_file, @db, build_path, repo_path, git_source, build_id, prep_script, spec_file, repo_lock) + mock = MockManager.new(prepare_path, get_project_config(prj_id), counter_file, @db, build_path, repo_path, git_source, build_id, prep_script, spec_file, repo_lock, git_id) bld_id = build_id @db.update_build_task_error_log(build_id, mock.get_build_process_log) mock.build_task - mock.finalize_build_task f.flock(File::LOCK_UN) end end diff --git a/classes/repomanage.rb b/classes/repomanage.rb index adf4f5d..b9efa22 100644 --- a/classes/repomanage.rb +++ b/classes/repomanage.rb @@ -1,3 +1,7 @@ +$LOAD_PATH.unshift File.expand_path(".", "locallibs/ruby-rpm-ffi/lib") + +require "rpm" + require_relative "runner" class RepoManager @@ -22,4 +26,15 @@ class RepoManager @last_status = cmd.exit_status @last_pid = cmd.pid end + + def get_rpm_info(path_to_rpm) + res = { :error => nil } + if File.exist?(path_to_rpm) + pkg = RPM::Package.open(path_to_rpm) + res[:pkginfo] = pkg + else + res[:error] = "#{path_to_rpm} не существует" + end + res + end end diff --git a/classes/utilities.rb b/classes/utilities.rb index 1a02502..c6b016f 100644 --- a/classes/utilities.rb +++ b/classes/utilities.rb @@ -34,3 +34,15 @@ end def get_spec_files_in_dir(directory) Dir.glob(File.join(directory, "**", "*")).reject { |f| File.directory?(f) }.select { |f| File.extname(f) == ".spec" }.map { |f| f.delete_prefix(directory + "/") } end + +def get_src_rpm_files_in_dir(directory) + Dir.glob(File.join(directory, "**", "*")).reject { |f| File.directory?(f) }.select { |f| f.end_with?(".src.rpm") }.map { |f| f.delete_prefix(directory + "/") } +end + +def get_log_paths(directory) + Dir.glob(File.join(directory, "**", "*")).reject { |f| File.directory?(f) }.select { |f| File.extname(f) == ".log" }.map { |f| f.delete_prefix(directory + "/") } +end + +def get_rpm_paths(directory) + Dir.glob(File.join(directory, "**", "*")).reject { |f| File.directory?(f) }.select { |f| File.extname(f) == ".rpm" }.map { |f| f.delete_prefix(directory + "/") } +end diff --git a/locallibs/ruby-rpm-ffi/.gitignore b/locallibs/ruby-rpm-ffi/.gitignore new file mode 100644 index 0000000..d33599c --- /dev/null +++ b/locallibs/ruby-rpm-ffi/.gitignore @@ -0,0 +1,8 @@ +*.gem +.bundle +Gemfile.lock +pkg/* +*.rbc +.yardoc +.idea +test/test_many_files.rb \ No newline at end of file diff --git a/locallibs/ruby-rpm-ffi/.rubocop.yml b/locallibs/ruby-rpm-ffi/.rubocop.yml new file mode 100644 index 0000000..cc32da4 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/.rubocop.yml @@ -0,0 +1 @@ +inherit_from: .rubocop_todo.yml diff --git a/locallibs/ruby-rpm-ffi/.rubocop_todo.yml b/locallibs/ruby-rpm-ffi/.rubocop_todo.yml new file mode 100644 index 0000000..79be16f --- /dev/null +++ b/locallibs/ruby-rpm-ffi/.rubocop_todo.yml @@ -0,0 +1,111 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2016-07-09 11:50:54 +0200 using RuboCop version 0.41.2. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: AlignWith, SupportedStyles, AutoCorrect. +# SupportedStyles: keyword, variable, start_of_line +Lint/EndAlignment: + Exclude: + - 'lib/rpm/dependency.rb' + - 'lib/rpm/file.rb' + - 'lib/rpm/package.rb' + - 'lib/rpm/transaction.rb' + - 'test/test_transaction.rb' + +# Offense count: 1 +Lint/UnreachableCode: + Exclude: + - 'lib/rpm/transaction.rb' + +# Offense count: 11 +Lint/UselessAssignment: + Exclude: + - 'lib/rpm.rb' + - 'lib/rpm/package.rb' + - 'lib/rpm/transaction.rb' + - 'lib/rpm/version.rb' + +# Offense count: 1 +Lint/Void: + Exclude: + - 'test/test_rpm.rb' + +# Offense count: 17 +Metrics/AbcSize: + Max: 74 + +# Offense count: 1 +Metrics/BlockNesting: + Max: 4 + +# Offense count: 3 +# Configuration parameters: CountComments. +Metrics/ClassLength: + Max: 225 + +# Offense count: 3 +Metrics/CyclomaticComplexity: + Max: 17 + +# Offense count: 66 +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes. +# URISchemes: http, https +Metrics/LineLength: + Max: 129 + +# Offense count: 21 +# Configuration parameters: CountComments. +Metrics/MethodLength: + Max: 57 + +# Offense count: 1 +# Configuration parameters: CountComments. +Metrics/ModuleLength: + Max: 295 + +# Offense count: 4 +# Configuration parameters: CountKeywordArgs. +Metrics/ParameterLists: + Max: 11 + +# Offense count: 2 +Metrics/PerceivedComplexity: + Max: 19 + +# Offense count: 2 +Style/AccessorMethodName: + Exclude: + - 'lib/rpm/match_iterator.rb' + +# Offense count: 1 +Style/AsciiComments: + Exclude: + - 'lib/rpm/file.rb' + +# Offense count: 34 +Style/Documentation: + Enabled: false + +# Offense count: 2 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: snake_case, camelCase +Style/MethodName: + Exclude: + - 'lib/rpm/c/rpmprob.rb' + - 'lib/rpm/c/rpmtag.rb' + +# Offense count: 3 +# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. +# NamePrefix: is_, has_, have_ +# NamePrefixBlacklist: is_, has_, have_ +# NameWhitelist: is_a? +Style/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/rpm/file.rb' diff --git a/locallibs/ruby-rpm-ffi/ChangeLog b/locallibs/ruby-rpm-ffi/ChangeLog new file mode 100644 index 0000000..1a68155 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/ChangeLog @@ -0,0 +1,10 @@ + +2013-10-24 Duncan Mac-Vicar P. + +* v0.0.4 +* Bugfix: too many open files on transaction with blocks + +2012-02-23 Duncan Mac-Vicar P. + + * RPM::FFI module is now RPM::C + * implement Trasaction#commit, Trasaction#install, Trasaction#upgrade, diff --git a/locallibs/ruby-rpm-ffi/Gemfile b/locallibs/ruby-rpm-ffi/Gemfile new file mode 100644 index 0000000..e42eaff --- /dev/null +++ b/locallibs/ruby-rpm-ffi/Gemfile @@ -0,0 +1,9 @@ +source 'http://rubygems.org' + +# Specify your gem's dependencies in rpm.gemspec +gemspec + +group :test do + gem 'minitest' + gem 'rake' +end diff --git a/locallibs/ruby-rpm-ffi/MIT-LICENSE b/locallibs/ruby-rpm-ffi/MIT-LICENSE new file mode 100644 index 0000000..13cdff2 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/MIT-LICENSE @@ -0,0 +1,24 @@ + +Copyright © 2011 Duncan Mac-Vicar Prett +Copyright © 2011 SUSE Linux Products GmbH +Copyright © 2002 Kenta Murata + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/locallibs/ruby-rpm-ffi/README.md b/locallibs/ruby-rpm-ffi/README.md new file mode 100644 index 0000000..1927f94 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/README.md @@ -0,0 +1,378 @@ + +# RPM bindings for ruby + +![maintained](https://img.shields.io/maintenance/yes/2016.svg) [![Build Status](https://travis-ci.org/dmacvicar/ruby-rpm-ffi.svg?branch=master)](https://travis-ci.org/dmacvicar/ruby-rpm-ffi) +[![CI](https://github.com/dmacvicar/ruby-rpm-ffi/actions/workflows/ci.yaml/badge.svg)](https://github.com/dmacvicar/ruby-rpm-ffi/actions/workflows/ci.yaml) + +* http://github.com/dmacvicar/ruby-rpm-ffi + + +# WARNING + +This is an alpha release! There is still work to be done + +# Quickstart + +## Working with RPM package files + +```ruby +require 'rpm' + +pkg = RPM::Package.open("file.rpm") +pkg.arch => "x86_64" + +pkg.files.each do |file| + puts file.path +end + +pkg.changelog.each do |entry| + puts "#{entry.name} #{entry.time} #{entry.text}" +end +``` + +## Querying the rpm database + +```ruby +require 'rpm' + +RPM.transaction do |ts| + ts.each do |pkg| + puts pkg + end +end +``` + +## Install a package + +```ruby +require 'rpm' + +pkg = RPM::Package.open('foo.rpm') + +RPM.transaction(rootdir) do |t| + t.install(pkg, 'foo.rpm') + t.commit +end +``` + +## Introduction + +This library is a replacement for the ruby-rpm gem, originally +writen by Kenta Murata around 2002 for the Kondara distribution. Later +mantained by David Lutterkort and myself. + +Why? + +* The original gem supports ancient rpm versions not in use anymore +* The original gem was written in C using MRI API +* The #ifdef'ing required to support multiple rpm versions made the code + hard to maintain + +This gem: + +* Is pure ruby +* Is documented +* Has as a goal to support only the latest rpm version plus the ones in + use some releases back in popular rpm based distros +* Uses FFI, so it should work with other interpreters + (Because https://github.com/rubinius/rubinius/issues/682 it currently does + not work on Rubinius) +* Does not target rpm5, but it may support it someday + +As an example the code that implements RPM::Package was reduced +from 1130 lines of code to 320. + +# Architecture + +The gem is divided in two modules: + +* RPM::C:: which contains the 1:1 mapping to the librpm API + Not all functions are attached, only the ones we actually use. +* RPM:: contains the actual higher level API + +# Status, Compatibility and Differences with ruby-rpm + +* Only rpm 4.11.x or later will be supported +* You can use symbols: instead of RPM::TAG_DESCRIPTION you + can use just :description. 'rpm/compat' is by default loaded + and provides compatibility with the RPM::TAG_* style constants +* RPM::DB is not supported. Use RPM::Transaction +* Spec and Source classes are not implemented yet + +## TESTING + +Unit tests can be run using the `rake test` command. + +### Docker tests + +In order to not damage your system, you can run the testsuite under docker: + +* Build the docker images: + +```console +rake docker_images +``` + +* Run the testsuite under Docker + +```console +rake docker_test +``` + +## TODO + +* Check Package#signature should return String? + => ruby-rpm seems to return symbol +* Food for thought: Package dependencies and changelog + methods could just use []. Calling headerGet directly saves + us from doing one iteration per attribute +* Not sure if Spec can be implemented as it was before with + newer rpms. + +## API Checklist and TODO + +### Low level 1:1 RPM::C API + +* http://rpm.org/wiki/Releases/4.14.0 + - [ ] Add rpmfiVerify() and rpmfilesVerify() + - [ ] Add pmsqPoll(), rpmsqActivate(), rpmsqSetAction(), rpmsqBlock() + - [ ] Add rpmDigestBundleAddID() + - [ ] Add RPMTRANS_FLAG_NOCAPS flag to disable file capabilities + - [ ] Add RPMVSF_NOPAYLOAD flag to disable payload digest verification + - [ ] Add pgpPubkeyKeyID() + - [X] Add rpmPushMacro() and rpmPopMacro() (to replace addMacro() and delMacro()) + - [ ] Remove headerNVR(), headerNEVRA(), headerGetNEVR(), headerGetNEVRA(), headerGetEVR(), headerGetColor(), rpmfiMD5(), expandMacros(), addMacro(), delMacro() + +* http://rpm.org/wiki/Releases/4.13.0 + - [ ] Add rpmsqSetInterruptSafety() + - [ ] Add/Change rpmPkgSign() + - [ ] Add RPMCALLBACK_ELEM_PROGRESS callback type + - [ ] Add rpmExpandMacros() + +* http://rpm.org/wiki/Releases/4.12.0 + - [ ] Add rpmtxnBegin() and rpmtxnEnd() + - [ ] Add rpmtsImportHeader() + - [ ] Add rpmtsAddReinstallElement() + - [ ] Add rpmdbIndexIteratorNextTd() + - [ ] Add file info set iterator functions: rpmfiFLinks(), rpmfiFindFN(), rpmfiStat() + - [ ] Add rpmfiOFN(), rpmfiOBN(), rpmfiODN(), rpmfiFindOFN() + - [ ] Add rpmteFiles() + - [ ] Add rpmdsTagF(), rpmdsTagEVR(), rpmdsD(), rpmdsPutToHeader(), rpmdsTi(), rpmdsTagTi() and rpmdsSinglePoolTix() + +* http://rpm.org/wiki/Releases/4.11.0 + - [ ] Add rpmstrPool object + associated functions + - [ ] Add rpmIsGlob() + - [ ] Add rpmtdToPool() + - [ ] Add rpmGetArchColor() + +### RPM + +- [ ] RPM#expand +- [X] RPM#[] +- [X] RPM#[]= +- [ ] RPM#readrc +- [ ] RPM#init_macros +- [ ] RPM#verbosity +- [ ] RPM#verbosity= + +### RPM::Package + +- [X] Package#open +- [X] Package#new +- [X] Package#create +- [ ] Package#load +- [ ] Package#clear_cache +- [ ] Package#use_cache +- [X] Package#[] +- [ ] Package#delete_tag +- [X] Package#sprintf + [?] Package#signature +- [X] Package#arch +- [X] Package#name +- [X] Package#version +- [X] Package#files +- [X] Package#provides +- [X] Package#requires +- [X] Package#conflicts +- [X] Package#obsoletes +- [X] Package#changelog +- [ ] Package#add_dependency +- [ ] Package#add_string +- [ ] Package#add_string_array +- [ ] Package#add_int32 +- [ ] Package#dump +- [X] Package#to_s +- [ ] Package#inspect +- [ ] Package#copy_to + +### RPM::Dependency + +- [X] Dependency#initialize +- [X] Dependency#name +- [X] Dependency#version +- [X] Dependency#flags +- [X] Dependency#owner +- [X] Dependency#lt? +- [X] Dependency#gt? +- [X] Dependency#eq? +- [X] Dependency#le? +- [X] Dependency#ge? +- [X] Dependency#satisfy? +- [X] Dependency#nametag +- [X] Dependency#versiontag +- [X] Dependency#flagstag + +### RPM::Provide + +- [X] Provide#initialize + +### RPM::Require + +- [X] Require#initialize +- [ ] Require#pre? + +### RPM::Conflict + +- [X] Conflict#initialize + +### RPM::Obsolete + +- [X] Obsolete#initialize + +### RPM::ChangeLog + +- [X] ChangeLog#time +- [X] ChangeLog#name +- [X] ChangeLog#text + +### RPM::Version + +- [X] Version (Comparable) +- [X] Version#initialize +- [X] Version#<=> +- [X] Version#newer? +- [X] Version#older? +- [X] Version#v +- [X] Version#r +- [X] Version#e +- [X] Version#to_s +- [X] Version#to_vre +- [X] Version#inspect +- [X] Version#hash + +### RPM::File + +- [X] File#initialize +- [X] File#path +- [ ] File#to_s (alias path) +- [X] File#md5sum +- [X] File#link_to +- [X] File#size +- [X] File#mtime +- [X] File#owner +- [X] File#group +- [X] File#rdev +- [X] File#mode +- [X] File#attr +- [X] File#state +- [X] File#symlink? +- [X] File#config? +- [X] File#doc? +- [X] File#donotuse? +- [X] File#missingok? +- [X] File#specfile? +- [X] File#ghost? +- [X] File#license? +- [X] File#readme? +- [X] File#exclude? +- [X] File#replaced? +- [X] File#notinstalled? +- [X] File#netshared? + +### RPM::DB + +- [ ] DB (Enumerable) +- [ ] DB#new +- [ ] DB#open +- [ ] DB#init +- [ ] DB#rebuild +- [ ] DB#close +- [ ] DB#closed? +- [ ] DB#root +- [ ] DB#home +- [ ] DB#writable? +- [ ] DB#each_match +- [ ] DB#each +- [ ] DB#transaction +- [ ] DB#init_iterator +- [ ] DB#dup +- [ ] DB#clone + +### RPM::MatchIterator + +- [X] MatchIterator (Enumerable) +- [X] MatchIterator#each +- [X] MatchIterator#next_iterator +- [X] MatchIterator#offset +- [X] MatchIterator#set_iterator_re +- [X] MatchIterator#regexp +- [X] MatchIterator#set_iterator_version +- [X] MatchIterator#version +- [X] MatchIterator#get_iterator_count +- [X] MatchIterator#length + +### RPM::Transaction + +- [ ] Transaction#db +- [ ] Transaction#script_file +- [ ] Transaction#script_file= +- [ ] Transaction#install +- [ ] Transaction#upgrade +- [ ] Transaction#available +- [ ] Transaction#delete +- [ ] Transaction#check +- [ ] Transaction#order +- [ ] Transaction#keys +- [ ] Transaction#commit +- [ ] Transaction#abort +- [ ] Transaction#dup +- [ ] Transaction#clone + +### RPM::Source + +- [ ] Source#initialize +- [ ] Source#fullname +- [ ] Source#to_s (alias fullname) +- [ ] Source#num +- [ ] Source#no? + +### RPM::Patch + +### RPM::Icon + +### RPM::Spec + +- [ ] Spec#open +- [ ] Spec#new +- [ ] Spec#buildroot +- [ ] Spec#buildsubdir +- [ ] Spec#buildarchs +- [ ] Spec#buildrequires +- [ ] Spec#build_restrictions +- [ ] Spec#sources +- [ ] Spec#packages +- [ ] Spec#build +- [ ] Spec#expand_macros +- [ ] Spec#dup +- [ ] Spec#clone + +# LICENSE + +* Copyright © 2011 Duncan Mac-Vicar Prett +* Copyright © 2011 SUSE Linux Products GmbH + +* This gem is a pure-ruby rewrite of ruby-rpm: + Copyright © 2002 Kenta Murata. Relicensed with his permission. + +Licensed under the MIT license. See MIT-LICENSE for details. + diff --git a/locallibs/ruby-rpm-ffi/Rakefile b/locallibs/ruby-rpm-ffi/Rakefile new file mode 100644 index 0000000..889ee9d --- /dev/null +++ b/locallibs/ruby-rpm-ffi/Rakefile @@ -0,0 +1,52 @@ +$LOAD_PATH.push(File.join(File.dirname(__FILE__), 'lib')) +require 'bundler/gem_tasks' +require 'rpm/gem_version' +require 'rake/testtask' + +task default: [:test] + +Rake::TestTask.new do |t| + t.libs << File.expand_path('../test', __FILE__) + t.libs << File.expand_path('../', __FILE__) + t.test_files = FileList['test/test*.rb'] + t.verbose = true + t.loader = :direct +end + +extra_docs = ['README*', 'TODO*', 'CHANGELOG*'] + +begin + require 'yard' + YARD::Rake::YardocTask.new(:doc) do |t| + t.files = ['lib/**/*.rb', *extra_docs] + t.options = ['--no-private'] + end +rescue LoadError + STDERR.puts 'Install yard if you want prettier docs' + begin + require 'rdoc/task' + Rake::RDocTask.new(:doc) do |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.title = "rpm for Ruby #{RPM::GEM_VERSION}" + extra_docs.each { |ex| rdoc.rdoc_files.include ex } + end + rescue LoadError + STDERR.puts 'rdoc not available' + end +end + +desc "Build the docker images for test" +task :docker_images do + Dir.glob('_docker/Dockerfile.*').each do |dockerfile| + tag = 'ruby-rpm-ffi:' + File.extname(dockerfile).delete('.') + sh %(podman build -f #{dockerfile} -t #{tag} .) + end +end + +desc "Run the tests from within the docker images" +task :docker_test do + Dir.glob('_docker/Dockerfile.*').each do |dockerfile| + tag = 'ruby-rpm-ffi:' + File.extname(dockerfile).delete('.') + sh %(podman run -ti -v #{Dir.pwd}:/src #{tag} rake test) + end +end diff --git a/locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi8 b/locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi8 new file mode 100644 index 0000000..55678cd --- /dev/null +++ b/locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi8 @@ -0,0 +1,8 @@ +FROM docker.io/redhat/ubi8:latest +RUN dnf module -y enable ruby:3.1 +RUN dnf install -y ruby git +RUN gem install bundler +WORKDIR /src +RUN ls -lR +COPY ../ /src +RUN bundle install diff --git a/locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi9 b/locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi9 new file mode 100644 index 0000000..c7f00b2 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/_docker/Dockerfile.ubi9 @@ -0,0 +1,8 @@ +FROM docker.io/redhat/ubi9:latest +RUN dnf module -y enable ruby:3.3 +RUN dnf install -y ruby git +RUN gem install bundler +WORKDIR /src +RUN ls -lR +COPY ../ /src +RUN bundle install diff --git a/locallibs/ruby-rpm-ffi/lib/rpm.rb b/locallibs/ruby-rpm-ffi/lib/rpm.rb new file mode 100644 index 0000000..8396cce --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm.rb @@ -0,0 +1,88 @@ + +require 'rpm/c' +require 'rpm/package' +require 'rpm/file' +require 'rpm/db' +require 'rpm/problem' +require 'rpm/transaction' +require 'rpm/match_iterator' +require 'rpm/version' +require 'rpm/dependency' +require 'rpm/utils' + +module RPM + TAG = RPM::C::Tag + LOG = RPM::C::Log + SENSE = RPM::C::Sense + FILE = RPM::C::FileAttrs + FILE_STATE = RPM::C::FileState + TRANS_FLAG = RPM::C::TransFlags + PROB_FILTER = RPM::C::ProbFilter + MIRE = RPM::C::RegexpMode + + # Creates a new transaction and pass it + # to the given block + # + # @param [String] root dir, default '/' + # + # @example + # RPM.transaction do |ts| + # ... + # end + # + def self.transaction(root = '/') + ts = Transaction.new + ts.root_dir = root + yield ts + ensure + ts.ptr.free + end + + # @param [String] name Name of the macro + # @return [String] value of macro +name+ + def self.[](name) + if C::rpm_version_code >= ((4 << 16) + (14 << 8) + (0 << 0)) + obuf = ::FFI::MemoryPointer.new(:pointer, 1) + sbuf = FFI::MemoryPointer.from_string("%{#{name}}") + ret = RPM::C.rpmExpandMacros(nil, sbuf, obuf, 0) + raise if ret < 0 + + val = obuf.read_pointer + val.nil? ? nil : val.read_string + else + buffer = ::FFI::MemoryPointer.new(:pointer, 1024) + buffer.write_string("%{#{name}}") + ret = RPM::C.expandMacros(nil, nil, buffer, 1024) + raise if ret < 0 + + buffer.read_string + end + end + + # Setup a macro + # @param [String] name Name of the macro + # @param [String] value Value of the macro or +nil+ to delete it + def self.[]=(name, value) + if value.nil? + if C::rpm_version_code >= ((4 << 16) + (14 << 8) + (0 << 0)) + RPM::C.rpmPopMacro(nil, name.to_s) + else + RPM::C.delMacro(nil, name.to_s) + end + else + if C::rpm_version_code >= ((4 << 16) + (14 << 8) + (0 << 0)) + RPM::C.rpmPushMacro(nil, name.to_s, '', value.to_s, RPM::C::RMIL_DEFAULT) + else + RPM::C.addMacro(nil, name.to_s, '', value.to_s, RPM::C::RMIL_DEFAULT) + end + end + end +end + +RPM::C.rpmReadConfigFiles(nil, nil) +RPM::C.rpmInitMacros(nil, RPM::C.MACROFILES) + +# TODO +# set verbosity + +require 'rpm/compat' diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c.rb new file mode 100644 index 0000000..9cef46e --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c.rb @@ -0,0 +1,49 @@ +require 'ffi' + +module RPM + module C + extend ::FFI::Library + + begin + ffi_lib ['rpm', + 'librpm.so.9', + 'librpm.so.8', # Tumbleweed + 'librpm.so.7', # fedora 23 + 'librpm.so.3', 'librpm.so.2', 'librpm.so.1'] + rescue LoadError => e + raise( + "Can't find rpm libs on your system: #{e.message}" + ) + end + end +end + +require 'rpm/c/rpmtypes' +require 'rpm/c/rpmcallback' +require 'rpm/c/rpmtag' +require 'rpm/c/rpmlib' + +module RPM + module C + + def self.rpm_version_code + ver = ::RPM::C.RPMVERSION.split('.', 3) + return (ver[0].to_i<<16) + (ver[1].to_i<<8) + (ver[2].to_i<<0) + end + + end +end + +require 'rpm/c/rpmlog' +require 'rpm/c/rpmmacro' +require 'rpm/c/rpmio' +require 'rpm/c/header' +require 'rpm/c/rpmprob' +require 'rpm/c/rpmps' +require 'rpm/c/rpmfi' +require 'rpm/c/rpmdb' +require 'rpm/c/rpmcallback' +require 'rpm/c/rpmcli' +require 'rpm/c/rpmts' +require 'rpm/c/rpmds' +require 'rpm/c/rpmtd' diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/header.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/header.rb new file mode 100644 index 0000000..c9a6434 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/header.rb @@ -0,0 +1,36 @@ + +module RPM + module C + typedef :pointer, :header + + attach_function 'headerNew', [], :header + attach_function 'headerFree', [:header], :header + attach_function 'headerLink', [:header], :header + # .. + HEADERGET_DEFAULT = [0, + HEADERGET_MINMEM = (1 << 0)].freeze + HEADERGET_EXT = (1 << 1) + HEADERGET_RAW = (1 << 2) + HEADERGET_ALLOC = (1 << 3) + HEADERGET_ARGV = (1 << 4) + + # .. + attach_function 'headerGet', %i[header rpmTagVal pointer uint32], :int + attach_function 'headerPut', %i[header pointer uint32], :int + # ... + attach_function 'headerFormat', %i[header string pointer], :pointer + # ... + # http://rpm.org/wiki/Releases/4.14.0 deprecated addMacro/delMacro + unless rpm_version_code >= ((4 << 16) + (14 << 8) + (0 << 0)) + attach_function 'headerNVR', [:header, :pointer, :pointer, :pointer], :int + end + # ... + attach_function 'headerGetAsString', %i[header rpmTagVal], :string + # ... + attach_function 'headerPutString', %i[header rpmTagVal string], :int + # ... + attach_function 'headerPutUint32', %i[header rpmTagVal pointer rpm_count_t], :int + # ... + attach_function 'rpmReadPackageFile', %i[header FD_t string pointer], Rc + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcallback.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcallback.rb new file mode 100644 index 0000000..bee3657 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcallback.rb @@ -0,0 +1,27 @@ + +module RPM + module C + CallbackType = enum(:rpmCallbackType, [ + :unknown, 0, + :inst_progress, (1 << 0), + :inst_start, (1 << 1), + :inst_open_file, (1 << 2), + :inst_close_file, (1 << 3), + :trans_progress, (1 << 4), + :trans_start, (1 << 5), + :trans_stop, (1 << 6), + :uninst_progress, (1 << 7), + :uninst_start, (1 << 8), + :uninst_stop, (1 << 9), + :repackage_progress, (1 << 10), + :repackage_start, (1 << 11), + :repackage_stop, (1 << 12), + :unpack_error, (1 << 13), + :cpio_error, (1 << 14), + :script_error, (1 << 15) + ]) + + typedef :pointer, :rpmCallbackData + callback :rpmCallbackFunction, %i[pointer rpmCallbackType rpm_loff_t rpm_loff_t fnpyKey rpmCallbackData], :pointer + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcli.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcli.rb new file mode 100644 index 0000000..da49cdd --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmcli.rb @@ -0,0 +1,6 @@ + +module RPM + module C + attach_function 'rpmShowProgress', %i[pointer rpmCallbackType rpm_loff_t rpm_loff_t fnpyKey pointer], :pointer + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmdb.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmdb.rb new file mode 100644 index 0000000..76ee9b4 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmdb.rb @@ -0,0 +1,20 @@ +module RPM + module C + typedef :pointer, :rpmdb + typedef :pointer, :rpmdbMatchIterator + + RegexpMode = enum(:rpmMireMode, %i[ + default strcmp regex glob + ]) + + attach_function 'rpmdbCountPackages', %i[rpmdb string], :int + attach_function 'rpmdbGetIteratorOffset', [:rpmdbMatchIterator], :uint + attach_function 'rpmdbGetIteratorCount', [:rpmdbMatchIterator], :int + attach_function 'rpmdbSetIteratorRE', %i[rpmdbMatchIterator rpmTagVal rpmMireMode string], :int + + attach_function 'rpmdbInitIterator', %i[rpmdb rpmDbiTagVal pointer size_t], :rpmdbMatchIterator + + attach_function 'rpmdbNextIterator', [:rpmdb], :header + attach_function 'rpmdbFreeIterator', [:rpmdb], :rpmdbMatchIterator + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmds.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmds.rb new file mode 100644 index 0000000..3021a52 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmds.rb @@ -0,0 +1,43 @@ + +module RPM + module C + typedef :pointer, :rpmds + + Sense = enum(:rpmsenseFlags_e, [ + :any, 0, + :less, (1 << 1), + :greater, (1 << 2), + :equal, (1 << 3), + # bit 4 unused + :posttrans, (1 << 5), + :prereq, (1 << 6), + # + :pretrans, (1 << 7), + :interp, (1 << 8), + :script_pre, (1 << 9), + :script_post, (1 << 10), + :script_preun, (1 << 11), + :script_postun, (1 << 12), + :script_verify, (1 << 13), + :find_requires, (1 << 14), + :find_provides, (1 << 15), + # + :triggerin, (1 << 16), + :triggerun, (1 << 17), + :triggerpostun, (1 << 18), + :missingok, (1 << 19), + # 20 23 unused + :rpmlib, (1 << 24), + :triggerprein, (1 << 25), + :keyring, (1 << 26), + :strong, (1 << 27), + :config, (1 << 28) + ]) + typedef :rpmFlags, :rpmsenseFlags + + # ... + attach_function 'rpmdsSingle', %i[rpmTagVal string string rpmsenseFlags], :rpmds + # ... + attach_function 'rpmdsCompare', %i[rpmds rpmds], :int + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmfi.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmfi.rb new file mode 100644 index 0000000..d375c19 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmfi.rb @@ -0,0 +1,31 @@ + +module RPM + module C + FileAttrs = enum(:rpmfileAttrs, [ + :none, 0, + :config, (1 << 0), + :doc, (1 << 1), + :icon, (1 << 2), + :missingok, (1 << 3), + :noreplace, (1 << 4), + :specfile, (1 << 5), + :ghost, (1 << 6), + :license, (1 << 7), + :readme, (1 << 8), + :exclude, (1 << 9), + :unpatched, (1 << 10), + :pubkey, (1 << 11) + ]) + typedef :rpmFlags, :rpmfileAttrs + + FileState = enum(:rpmfileState, + :missing, -1, + :normal, 0, + :replaced, 1, + :notinstalled, 2, + :netshared, 3, + :wrongcolor, 4) + + typedef :pointer, :rpmRelocation + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmio.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmio.rb new file mode 100644 index 0000000..9ae85cd --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmio.rb @@ -0,0 +1,19 @@ +module RPM + module C + typedef :pointer, :FD_t + # RPMIO + attach_function 'Fstrerror', [:FD_t], :string + # ... + attach_function 'Fclose', [:FD_t], :int + # ... + attach_function 'Fopen', %i[string string], :FD_t + # ... + attach_function 'Ferror', [:FD_t], :int + + attach_function 'fdDup', [:int], :FD_t + + attach_function 'Fstrerror', [:FD_t], :string + + attach_function 'fdLink', [:pointer], :FD_t + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlib.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlib.rb new file mode 100644 index 0000000..778633a --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlib.rb @@ -0,0 +1,12 @@ + +module RPM + module C + attach_variable :RPMVERSION, :RPMVERSION, :string + attach_variable :RPMEVR, :rpmEVR, :string + + attach_function 'rpmReadConfigFiles', %i[string string], :int + + # ... + attach_function 'rpmvercmp', %i[string string], :int + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlog.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlog.rb new file mode 100644 index 0000000..f8a3fef --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmlog.rb @@ -0,0 +1,23 @@ + +module RPM + module C + # rpmlog + RPMLOG_PRIMASK = 0x07 + + Log = enum( + :emerg, 0, + :alert, 1, + :crit, 2, + :err, 3, + :warning, 4, + :notice, 5, + :info, 6, + :debug, 7 + ) + + attach_function 'rpmlogSetMask', [:int], :int + # TODO: defines to set verbosity + # ... + attach_function 'rpmlogMessage', [], :string + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmmacro.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmmacro.rb new file mode 100644 index 0000000..bfd0a5a --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmmacro.rb @@ -0,0 +1,33 @@ + +module RPM + module C + attach_variable :MACROFILES, :macrofiles, :string + # ... + + # Markers for sources of macros added throughout rpm. + RMIL_DEFAULT = -15 + RMIL_MACROFILES = -13 + RMIL_RPMRC = -11 + RMIL_CMDLINE = -7 + RMIL_TARBALL = -5 + RMIL_SPEC = -3 + RMIL_OLDSPEC = -1 + RMIL_GLOBAL = 0 + + # ... + # http://rpm.org/wiki/Releases/4.14.0 deprecated addMacro/delMacro + if rpm_version_code >= ((4 << 16) + (14 << 8) + (0 << 0)) + attach_function 'rpmPushMacro', [:pointer, :string, :string, :string, :int], :void + attach_function 'rpmPopMacro', [:pointer, :string], :void + attach_function 'rpmExpandMacros', [:pointer, :pointer, :pointer, :int], :int + else + attach_function 'addMacro', [:pointer, :string, :string, :string, :int], :void + attach_function 'delMacro', [:pointer, :string], :void + attach_function 'expandMacros', [:pointer, :pointer, :pointer, :size_t], :int + end + # ... + # ... + attach_function 'rpmInitMacros', %i[pointer string], :void + # ... + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmprob.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmprob.rb new file mode 100644 index 0000000..7a9400a --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmprob.rb @@ -0,0 +1,53 @@ + +module RPM + module C + typedef :pointer, :rpmProblem + + ProbFilter = enum(:rpmprobFilterFlags_e, [ + :none, 0, + :ignoreos, (1 << 0), + :ignorearch, (1 << 1), + :replacepkg, (1 << 2), + :forcerelocate, (1 << 3), + :replacenewfiles, (1 << 4), + :replaceoldfiles, (1 << 5), + :oldpackage, (1 << 6), + :diskspace, (1 << 7), + :disknodes, (1 << 8) + ]) + + typedef :rpmFlags, :rpmprobFilterFlags + + ProblemType = enum(:rpmProblemType, %i[ + badarch + bados + pkg_installed + badrelocate + requires + conflict + new_file_conflict + file_conflict + oldpackage + diskspace + disknodes + obsoletes + ]) + + attach_function 'rpmProblemCreate', %i[rpmProblemType string fnpyKey string string uint64], :rpmProblem + attach_function 'rpmProblemFree', [:rpmProblem], :rpmProblem + attach_function 'rpmProblemLink', [:rpmProblem], :rpmProblem + attach_function 'rpmProblemGetType', [:rpmProblem], :rpmProblemType + attach_function 'rpmProblemGetKey', [:rpmProblem], :fnpyKey + attach_function 'rpmProblemGetStr', [:rpmProblem], :string + attach_function 'rpmProblemString', [:rpmProblem], :string + + begin + attach_function 'rpmProblemCompare', %i[rpmProblem rpmProblem], :int + rescue ::FFI::NotFoundError + # TODO: Implement this for librpm 4.8. + def self.rpmProblemCompare(_a, _b) + raise NotImplementedError, 'rpmProblemCompare is not present in librpm 4.8 and below' + end + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmps.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmps.rb new file mode 100644 index 0000000..6410f30 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmps.rb @@ -0,0 +1,11 @@ +module RPM + module C + typedef :pointer, :rpmps + typedef :pointer, :rpmpsi + + attach_function 'rpmpsInitIterator', [:rpmps], :rpmpsi + attach_function 'rpmpsNextIterator', [:rpmpsi], :int + attach_function 'rpmpsGetProblem', [:rpmpsi], :rpmProblem + attach_function 'rpmpsFree', [:rpmps], :rpmps + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtag.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtag.rb new file mode 100644 index 0000000..af6a852 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtag.rb @@ -0,0 +1,304 @@ +module RPM + module C + Tag = enum(:rpmTag, [ + :not_found, -1, + :headerimage, 61, + :headersignatures, 62, + :headerimmutable, 63, + :headerregions, 64, + :headeri18ntable, 100, + :sig_base, 256, + :sigsize, 256 + 1, + :siglemd5_1, 256 + 2, + :sigpgp, 256 + 3, + :siglemd5_2, 256 + 4, + :sigmd5, 256 + 5, + :siggpg, 256 + 6, + :sigpgp5, 256 + 7, + :badsha1_1, 256 + 8, + :badsha1_2, 256 + 9, + :pubkeys, 256 + 10, + :dsaheader, 256 + 11, + :rsaheader, 256 + 12, + :sha1header, 256 + 13, + :longsigsize, 256 + 14, + :longarchivesize, 256 + 15, + :name, 1000, + :version, 1001, + :release, 1002, + :epoch, 1003, + :summary, 1004, + :description, 1005, + :buildtime, 1006, + :buildhost, 1007, + :installtime, 1008, + :size, 1009, + :distribution, 1010, + :vendor, 1011, + :gif, 1012, + :xpm, 1013, + :license, 1014, + :packager, 1015, + :group, 1016, + :changelog, 1017, + :source, 1018, + :patch, 1019, + :url, 1020, + :os, 1021, + :arch, 1022, + :prein, 1023, + :postin, 1024, + :preun, 1025, + :postun, 1026, + :oldfilenames, 1027, + :filesizes, 1028, + :filestates, 1029, + :filemodes, 1030, + :fileuids, 1031, + :filegids, 1032, + :filerdevs, 1033, + :filemtimes, 1034, + :filedigests, 1035, + :filemd5s, 1035, + :filelinktos, 1036, + :fileflags, 1037, + :root, 1038, + :fileusername, 1039, + :filegroupname, 1040, + :exclude, 1041, + :exclusive, 1042, + :icon, 1043, + :sourcerpm, 1044, + :fileverifyflags, 1045, + :archivesize, 1046, + :providename, 1047, + :requireflags, 1048, + :requirename, 1049, + :requireversion, 1050, + :nosource, 1051, + :nopatch, 1052, + :conflictflags, 1053, + :conflictname, 1054, + :conflictversion, 1055, + :defaultprefix, 1056, + :buildroot, 1057, + :installprefix, 1058, + :excludearch, 1059, + :excludeos, 1060, + :exclusivearch, 1061, + :exclusiveos, 1062, + :autoreqprov, 1063, + :rpmversion, 1064, + :triggerscripts, 1065, + :triggername, 1066, + :triggerversion, 1067, + :triggerflags, 1068, + :triggerindex, 1069, + :verifyscript, 1079, + :changelogtime, 1080, + :changelogname, 1081, + :changelogtext, 1082, + :brokenmd5, 1083, + :prereq, 1084, + :preinprog, 1085, + :postinprog, 1086, + :preunprog, 1087, + :postunprog, 1088, + :buildarchs, 1089, + :obsoletename, 1090, + :verifyscriptprog, 1091, + :triggerscriptprog, 1092, + :docdir, 1093, + :cookie, 1094, + :filedevices, 1095, + :fileinodes, 1096, + :filelangs, 1097, + :prefixes, 1098, + :instprefixes, 1099, + :triggerin, 1100, + :triggerun, 1101, + :triggerpostun, 1102, + :autoreq, 1103, + :autoprov, 1104, + :capability, 1105, + :sourcepackage, 1106, + :oldorigfilenames, 1107, + :buildprereq, 1108, + :buildrequires, 1109, + :buildconflicts, 1110, + :buildmacros, 1111, + :provideflags, 1112, + :provideversion, 1113, + :obsoleteflags, 1114, + :obsoleteversion, 1115, + :dirindexes, 1116, + :basenames, 1117, + :dirnames, 1118, + :origdirindexes, 1119, + :origbasenames, 1120, + :origdirnames, 1121, + :optflags, 1122, + :disturl, 1123, + :payloadformat, 1124, + :payloadcompressor, 1125, + :payloadflags, 1126, + :installcolor, 1127, + :installtid, 1128, + :removetid, 1129, + :sha1rhn, 1130, + :rhnplatform, 1131, + :platform, 1132, + :patchesname, 1133, + :patchesflags, 1134, + :patchesversion, 1135, + :cachectime, 1136, + :cachepkgpath, 1137, + :cachepkgsize, 1138, + :cachepkgmtime, 1139, + :filecolors, 1140, + :fileclass, 1141, + :classdict, 1142, + :filedependsx, 1143, + :filedependsn, 1144, + :dependsdict, 1145, + :sourcepkgid, 1146, + :filecontexts, 1147, + :fscontexts, 1148, + :recontexts, 1149, + :policies, 1150, + :pretrans, 1151, + :posttrans, 1152, + :pretransprog, 1153, + :posttransprog, 1154, + :disttag, 1155, + :suggestsname, 1156, + :suggestsversion, 1157, + :suggestsflags, 1158, + :enhancesname, 1159, + :enhancesversion, 1160, + :enhancesflags, 1161, + :priority, 1162, + :cvsid, 1163, + :blinkpkgid, 1164, + :blinkhdrid, 1165, + :blinknevra, 1166, + :flinkpkgid, 1167, + :flinkhdrid, 1168, + :flinknevra, 1169, + :packageorigin, 1170, + :triggerprein, 1171, + :buildsuggests, 1172, + :buildenhances, 1173, + :scriptstates, 1174, + :scriptmetrics, 1175, + :buildcpuclock, 1176, + :filedigestalgos, 1177, + :variants, 1178, + :xmajor, 1179, + :xminor, 1180, + :repotag, 1181, + :keywords, 1182, + :buildplatforms, 1183, + :packagecolor, 1184, + :packageprefcolor, 1185, + :xattrsdict, 1186, + :filexattrsx, 1187, + :depattrsdict, 1188, + :conflictattrsx, 1189, + :obsoleteattrsx, 1190, + :provideattrsx, 1191, + :requireattrsx, 1192, + :buildprovides, 1193, + :buildobsoletes, 1194, + :dbinstance, 1195, + :nvra, 1196, + :filenames, 5000, + :fileprovide, 5001, + :filerequire, 5002, + :fsnames, 5003, + :fssizes, 5004, + :triggerconds, 5005, + :triggertype, 5006, + :origfilenames, 5007, + :longfilesizes, 5008, + :longsize, 5009, + :filecaps, 5010, + :filedigestalgo, 5011, + :bugurl, 5012, + :evr, 5013, + :nvr, 5014, + :nevr, 5015, + :nevra, 5016, + :headercolor, 5017, + :verbose, 5018, + :epochnum, 5019, + :preinflags, 5020, + :postinflags, 5021, + :preunflags, 5022, + :postunflags, 5023, + :pretransflags, 5024, + :posttransflags, 5025, + :verifyscriptflags, 5026, + :triggerscriptflags, 5027, + :collections, 5029, + :policynames, 5030, + :policytypes, 5031, + :policytypesindexes, 5032, + :policyflags, 5033, + :vcs, 5034, + :ordername, 5035, + :orderversion, 5036, + :orderflags, 5037, + :firstfree_tag + ]) + + Dbi = enum(:rpmDbiTag_e, [ + :packages, 0, + :label, 2, + :name, Tag[:name], + :basenames, Tag[:basenames], + :group, Tag[:group], + :requirename, Tag[:requirename], + :providename, Tag[:providename], + :conflictname, Tag[:conflictname], + :obsoletename, Tag[:obsoletename], + :triggername, Tag[:triggername], + :dirnames, Tag[:dirnames], + :installtid, Tag[:installtid], + :sigmd5, Tag[:sigmd5], + :sha1header, Tag[:sha1header] + ]) + + TagType = enum(:rpmTagType, [ + :null_type, 0, + :char_type, 1, + :int8_type, 2, + :int16_type, 3, + :int32_type, 4, + :int64_type, 5, + :string_type, 6, + :bin_type, 7, + :string_array_type, 8, + :i18nstring_type, 9 + ]) + + TagReturnType = enum(:rpmTagReturnType_e, [ + :any_return_type, 0, + :scalar_return_type, 0x00010000, + :array_return_type, 0x00020000, + :mapping_return_type, 0x00040000, + :mask_return_type, 0xffff0000 + ]) + typedef :rpmFlags, :rpmTagReturnType + + begin + attach_function 'rpmTagGetReturnType', [:rpmTagVal], :rpmTagReturnType + rescue ::FFI::NotFoundError + attach_function 'rpmTagGetType', [:rpmTagVal], :rpmTagType + + def self.rpmTagGetReturnType(tag) + TagReturnType[rpmTagGetType(tag) & TagReturnType[:mask_return_type]] + end + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtd.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtd.rb new file mode 100644 index 0000000..d4d876b --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtd.rb @@ -0,0 +1,34 @@ +module RPM + module C + typedef :pointer, :rpmtd + + attach_function 'rpmtdNew', [], :pointer + attach_function 'rpmtdFree', [:rpmtd], :pointer + attach_function 'rpmtdReset', [:rpmtd], :void + attach_function 'rpmtdFreeData', [:rpmtd], :void + attach_function 'rpmtdCount', [:rpmtd], :uint32 + attach_function 'rpmtdTag', [:rpmtd], :rpmTagVal + attach_function 'rpmtdType', [:rpmtd], TagType + # ... + attach_function 'rpmtdInit', [:rpmtd], :int + attach_function 'rpmtdNext', [:rpmtd], :int + # ... + attach_function 'rpmtdNextUint32', [:rpmtd], :pointer + attach_function 'rpmtdNextUint64', [:rpmtd], :pointer + attach_function 'rpmtdNextString', [:rpmtd], :string + attach_function 'rpmtdGetChar', [:rpmtd], :pointer + attach_function 'rpmtdGetUint16', [:rpmtd], :pointer + attach_function 'rpmtdGetUint32', [:rpmtd], :pointer + attach_function 'rpmtdGetUint64', [:rpmtd], :pointer + attach_function 'rpmtdGetString', [:rpmtd], :string + attach_function 'rpmtdGetNumber', [:rpmtd], :uint64 + # ... + attach_function 'rpmtdFromUint8', %i[rpmtd rpmTagVal pointer rpm_count_t], :int + attach_function 'rpmtdFromUint16', %i[rpmtd rpmTagVal pointer rpm_count_t], :int + attach_function 'rpmtdFromUint32', %i[rpmtd rpmTagVal pointer rpm_count_t], :int + attach_function 'rpmtdFromUint64', %i[rpmtd rpmTagVal pointer rpm_count_t], :int + attach_function 'rpmtdFromString', %i[rpmtd rpmTagVal string], :int + attach_function 'rpmtdFromStringArray', %i[rpmtd rpmTagVal pointer rpm_count_t], :int + # ... + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmts.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmts.rb new file mode 100644 index 0000000..6f8e657 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmts.rb @@ -0,0 +1,71 @@ +module RPM + module C + TransFlags = enum(:rpmtransFlags_e, [ + :none, 0, + :test, (1 << 0), + :build_probs, (1 << 1), + :noscripts, (1 << 2), + :justdb, (1 << 3), + :notriggers, (1 << 4), + :nodocs, (1 << 5), + :allfiles, (1 << 6), + # bit 7 unused + :nocontexts, (1 << 8), + # bits 9-15 unused + :notriggerprein, (1 << 16), + :nopre, (1 << 17), + :nopost, (1 << 18), + :notriggerin, (1 << 19), + :notriggerun, (1 << 20), + :nopreun, (1 << 21), + :nopostun, (1 << 22), + :notriggerpostun, (11 << 23), + # bits 24-25 unused + :nocollections, (1 << 26), + :nomd5, (1 << 27), + :nofiledigest, (1 << 27), + # bits 28-29 unused + :noconfigs, (1 << 30), + :deploops, (1 << 31) + ]) + + typedef :pointer, :rpmts + typedef :pointer, :rpmps + typedef :rpmFlags, :rpmtransFlags + + attach_function 'rpmtsCheck', [:rpmts], :int + attach_function 'rpmtsOrder', [:rpmts], :int + attach_function 'rpmtsRun', %i[rpmts rpmps int], :int + attach_function 'rpmtsLink', [:rpmts], :rpmts + attach_function 'rpmtsCloseDB', [:rpmts], :int + attach_function 'rpmtsOpenDB', %i[rpmts int], :int + attach_function 'rpmtsInitDB', %i[rpmts int], :int + attach_function 'rpmtsGetDBMode', [:rpmts], :int + attach_function 'rpmtsSetDBMode', %i[rpmts int], :int + attach_function 'rpmtsRebuildDB', [:rpmts], :int + attach_function 'rpmtsVerifyDB', [:rpmts], :int + attach_function 'rpmtsInitIterator', %i[rpmts rpmDbiTagVal pointer int], :rpmdbMatchIterator + # ... + attach_function 'rpmtsProblems', [:rpmts], :rpmps + # ... + attach_function 'rpmtsClean', [:rpmts], :void + # more... + attach_function 'rpmtsFree', [:rpmts], :pointer + # .. + attach_function 'rpmtsSetNotifyCallback', %i[rpmts rpmCallbackFunction rpmCallbackData], :int + # ... + attach_function 'rpmtsRootDir', [:rpmts], :string + attach_function 'rpmtsSetRootDir', %i[rpmts string], :int + # ... + attach_function 'rpmtsGetRdb', [:rpmts], :rpmdb + # .. + attach_function 'rpmtsFlags', [:rpmts], :rpmtransFlags + attach_function 'rpmtsSetFlags', %i[rpmts rpmtransFlags], :rpmtransFlags + # ... + attach_function 'rpmtsSetNotifyCallback', %i[rpmts rpmCallbackFunction rpmCallbackData], :int + # ... + attach_function 'rpmtsCreate', [], :rpmts + attach_function 'rpmtsAddInstallElement', %i[rpmts header fnpyKey int rpmRelocation], :int + attach_function 'rpmtsAddEraseElement', %i[rpmts header int], :int + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtypes.rb b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtypes.rb new file mode 100644 index 0000000..45f0079 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/c/rpmtypes.rb @@ -0,0 +1,28 @@ + +module RPM + module C + Rc = enum( + :ok, 0, + :notfound, 1, + :fail, 2, + :nottrusted, 3, + :nokey, 4 + ) + + typedef :int32, :rpm_tag_t + typedef :uint32, :rpm_tagtype_t + typedef :uint32, :rpm_count_t + typedef :rpm_tag_t, :rpmTagVal + typedef :rpm_tag_t, :rpmDbiTagVal + + typedef :uint32, :rpmFlags + typedef :uint32, :rpm_off_t + typedef :uint64, :rpm_loff_t + + typedef :pointer, :FD_t + typedef :pointer, :fnpyKey + typedef :pointer, :rpmCallbackData + + typedef :uint64, :rpm_loff_t + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/compat.rb b/locallibs/ruby-rpm-ffi/lib/rpm/compat.rb new file mode 100644 index 0000000..7e98c67 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/compat.rb @@ -0,0 +1,40 @@ + +module RPM + # compatibility + TAG.to_h.each do |k, v| + const_set "TAG_#{k.to_s.upcase}", v.to_i + end + + LOG.to_h.each do |k, v| + const_set "LOG_#{k.to_s.upcase}", v.to_i + end + + SENSE.to_h.each do |k, v| + const_set "SENSE_#{k.to_s.upcase}", v.to_i + end + + # RPMFILE_* + FILE.to_h.each do |k, v| + const_set "FILE_#{k.to_s.upcase}", v.to_i + end + + # RPMFILE_STATE_* + FILE_STATE.to_h.each do |k, v| + const_set "FILE_STATE_#{k.to_s.upcase}", v.to_i + end + + # RPMTRANS_FLAG_* + TRANS_FLAG.to_h.each do |k, v| + const_set "TRANS_FLAG_#{k.to_s.upcase}", v.to_i + end + + # RPMPROB_FILTER_* + PROB_FILTER.to_h.each do |k, v| + const_set "PROB_FILTER_#{k.to_s.upcase}", v.to_i + end + + # RPMPROB_FILTER_* + MIRE.to_h.each do |k, v| + const_set "MIRE_#{k.to_s.upcase}", v.to_i + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/db.rb b/locallibs/ruby-rpm-ffi/lib/rpm/db.rb new file mode 100644 index 0000000..8215495 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/db.rb @@ -0,0 +1,117 @@ +require 'fcntl' + +module RPM + class DB + include Enumerable + + # @visibility private + # @param ts [Transaction] transaction object + def initialize(ts, opts = {}) + opts[:writable] ||= false + + @ts = ts + RPM::C.rpmtsOpenDB(@ts.ptr, opts[:writable] ? Fcntl::O_RDWR | Fcntl::O_CREAT : Fcntl::O_RDONLY) + end + + # @return [RPM::MatchIterator] Creates an iterator for +tag+ and +val+ + def init_iterator(tag, val) + @ts.init_iterator(tag, val) + end + + # + # @yield [Package] Called for each match + # @param [Number] key RPM tag key + # @param [String] val Value to match + # @example + # RPM.transaction do |t| + # t.each_match(RPM::TAG_ARCH, "x86_64") do |pkg| + # puts pkg.name + # end + # end + # + def each_match(key, val, &block) + @ts.each_match(key, val, &block) + end + + # + # @yield [Package] Called for each package in the database + # @example + # db.each do |pkg| + # puts pkg.name + # end + # + def each(&block) + @ts.each(&block) + end + + # @visibility private + def ptr + RPM::C.rpmtsGetRdb(@ts.ptr) + end + + def close + RPM::C.rpmtsCloseDB(@ts.ptr) + end + + def closed? + ptr.null? + end + + # + # The package database is opened, but transactional processing + # (@see RPM::DB#transaction) cannot be done for when +writable+ is false. + # When +writable+ is +false+ then the generated object gets freezed. + # @param [Boolean] writable Whether the database is writable. Default is +false+. + # @param [String] root Root path for the database, default is empty. + # @return [RPM::DB] + # + # @example + # db = RPM::DB.open + # db.each do |pkg| + # puts pkg.name + # end + # + def self.open(_writable = false, root = '/', &block) + open_for_transaction(Transaction.new(root: root), writable: false, &block) + end + + # @visibility private + def self.open_for_transaction(ts, opts = {}) + db = new(ts, opts) + return db unless block_given? + + begin + yield db + ensure + db.close unless db.closed? + end + end + + # @deprecated Not possible to get home value in + # newer RPM versions + def home + raise NotImplementedError + end + + # @return [String] The root path of the database + def root + RPM::C.rpmtsRootDir(@ts.ptr) + end + + # @deprecated Use RPM::Transaction#each + def self.each + DB.open do |db| + it = MatchIterator.from_ptr(RPM::C.rpmdbInitIterator(db.ptr, 0, nil, 0)) + if block_given? + it.each do |pkg| + yield pkg + end + end + end + end + + # @return number of instances of +name+ in the + # database + def count_packages(name); end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/dependency.rb b/locallibs/ruby-rpm-ffi/lib/rpm/dependency.rb new file mode 100644 index 0000000..16d205b --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/dependency.rb @@ -0,0 +1,120 @@ + +module RPM + class Dependency + # @return [String] dependency name + attr_accessor :name + # @return [String] dependency version + attr_accessor :version + # @return [String] dependency flags + attr_accessor :flags + # @return [Package] package this dependency belongs to + attr_accessor :owner + + attr_accessor :nametag + attr_accessor :versiontag + attr_accessor :flagstag + + def initialize(name, version, flags, owner) + RPM::Utils.check_type(version, RPM::Version) + + @name = name + @version = version + @flags = flags + @owner = owner + end + + # @param [Package, Dependency, Version] other + # @return [Boolean] true if +other+ satisfies this dependency + def satisfy?(other) + case other + when RPM::Package then + other.provides.each do |prov| + return true if satisfy?(prov) + end + false + when RPM::Dependency then + RPM::C.rpmdsCompare( + RPM::C.rpmdsSingle(:providename, other.name, + other.version.to_vre, other.flags), + RPM::C.rpmdsSingle(:providename, name, + version.to_vre, flags) + ) != 0 + when RPM::Version then + RPM::C.rpmdsCompare( + RPM::C.rpmdsSingle(:providename, name, + other.to_vre, other.to_vre.empty? ? 0 : :equal), + RPM::C.rpmdsSingle(:providename, name, + version.to_vre, flags) + ) != 0 + else + raise(TypeError, "#{other} is not a Version or Dependency") + end + end + + # @return [Boolean] true if '<' or '=<' are used to compare the version + def lt? + flags & RPM::SENSE[:less] + end + + # @return [Boolean] true if '>' or '>=' are used to compare the version + def gt? + flags & RPM::SENSE[:greater] + end + + # @return [Boolean] true if '=', '=<' or '>=' are used to compare the version + def eq? + flags & RPM::SENSE[:equal] + end + + # @return [Boolean] true if '=<' is used to compare the version + def le? + (flags & RPM::SENSE[:less]) && (flags & RPM::SENSE[:equal]) + end + + # @return [Boolean] true if '>=' is used to compare the version + def ge? + (flags & RPM::SENSE[:greater]) && (flags & RPM::SENSE[:equal]) + end + + # @return [Boolean] true if this is a pre-requires + def pre? + flags & RPM::SENSE[:prereq] + end + end + + class Provide < Dependency + def initialize(name, version, flags, owner) + super(name, version, flags, owner) + @nametag = RPM::TAG[:providename] + @versiontag = RPM::TAG[:provideversion] + @flagstag = RPM::TAG[:provideflags] + end + end + + class Require < Dependency + def initialize(name, version, flags, owner) + super(name, version, flags, owner) + @nametag = RPM::TAG[:requirename] + @versiontag = RPM::TAG[:requireversion] + @flagstag = RPM::TAG[:requireflags] + end + end + + class Conflict < Dependency + def initialize(name, version, flags, owner) + super(name, version, flags, owner) + @nametag = RPM::TAG[:conflictname] + @versiontag = RPM::TAG[:conflictversion] + @flagstag = RPM::TAG[:conflictflags] + end + end + + class Obsolete < Dependency + def initialize(name, version, flags, owner) + super(name, version, flags, owner) + @nametag = RPM::TAG[:obsoletename] + @versiontag = RPM::TAG[:obsoleteversion] + @flagstag = RPM::TAG[:obsoleteflags] + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/file.rb b/locallibs/ruby-rpm-ffi/lib/rpm/file.rb new file mode 100644 index 0000000..769ba4e --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/file.rb @@ -0,0 +1,134 @@ +# coding: utf-8 + +module RPM + class File + # @return [String] file path + attr_accessor :path + # @return [String] md5sum as string + attr_accessor :md5sum + # @return [String] Path to the destination if the file is a symbolic link + # @note + # This path is sometimes relative. To convert an absolute path from relative path: + # File.expand_path (file.link_to, File.dirname (file.path)) + attr_accessor :link_to + # @return [Number] File size + attr_accessor :size + # @return [Time] File modification time. + attr_accessor :mtime + # @return [String] File owner. Nil may be returned. + attr_accessor :owner + # @return [String] Group that owns the file. Nil may be returned. + attr_accessor :group + # @return [Number] Device type of the file + attr_accessor :mode + + attr_accessor :attr + attr_accessor :state + attr_accessor :rdev + + # @return [Boolean] True if the file is a symbolic link + def symlink? + !@link_to.nil? + end + + # @return [Boolean] True if the file is marked as a configuration file + def config? + !(@attr & RPM::C::FileAttrs[:config]).zero? + end + + # @return [Boolean] True if the file is marked as documentation + def doc? + !(@attr & RPM::C::FileAttrs[:doc]).zero? + end + + # @return [Boolean] True if the file is marked as do not use + # @deprecated RPMFILE_DONOTUSE was removed in recent versions of RPM. + def donotuse? + msg = 'RPMFILE_DONOTUSE was removed in recent versions of RPM.' + warn "#{Kernel.caller.first} #{msg}" + raise NotImplementedError + end + + # @return [Boolean] True if the file is marked that can be missing on disk + # + # This modifier is used for files or links that are created during the %post scripts + # but will need to be removed if the package is removed + def is_missingok? + !(@attr & RPM::C::FileAttrs[:missingok]).zero? + end + + # @return [Boolean] True if the file is marked as configuration not to be replaced + # + # This flag is used to protect local modifications. + # If used, the file will not overwrite an existing file that has been modified. + # If the file has not been modified on disk, the rpm command will overwrite the file. But, + # if the file has been modified on disk, the rpm command will copy the new file with an extra + # file-name extension of .rpmnew. + def is_noreplace? + !(@attr & RPM::C::FileAttrs[:noreplace]).zero? + end + + # @return [Boolean] True if the file is marked as a spec file + def is_specfile? + !(@attr & RPM::C::FileAttrs[:specfile]).zero? + end + + # @return [Boolean] True if the file is marked as ghost + # + # This flag indicates the file should not be included in the package. + # It can be used to name the needed attributes for a file that the program, when installed, + # will create. + # For example, you may want to ensure that a program’s log file has certain attributes. + def ghost? + !(@attr & RPM::C::FileAttrs[:ghost]).zero? + end + + # @return [Boolean] True if the file is a license + def license? + !(@attr & RPM::C::FileAttrs[:license]).zero? + end + + # @return [Boolean] True if the file is a README + def readme? + !(@attr & RPM::C::FileAttrs[:readme]).zero? + end + + # @raise NotImplementedError + # @deprecated RPMFILE_EXCLUDE was removed in recent versions of RPM. + def exclude? + msg = 'RPMFILE_EXCLUDE was removed in recent versions of RPM.' + warn "#{Kernel.caller.first} #{msg}" + raise NotImplementedError + end + + # @return [Boolean] True if the file is replaced during installation + def replaced? + !(@attr & RPM::C::FileState[:replaced]).zero? + end + + # @return [Boolean] True if the file is not installed + def notinstalled? + !(@attr & RPM::C::FileState[:notinstalled]).zero? + end + + # @return [Boolean] True if the file is shared over the network + def netshared? + !(@attr & RPM::C::FileState[:netshared]).zero? + end + + def initialize(path, md5sum, link_to, size, mtime, owner, group, rdev, mode, attr, state) + @path = path + @md5sum = md5sum + # If link_to is "" save it as nil + @link_to = (link_to && link_to.empty? ? nil : link_to) + @size = size + @mtime = mtime + @owner = owner + @group = group + @rdev = rdev + @mode = mode + @attr = attr + @state = state + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/gem_version.rb b/locallibs/ruby-rpm-ffi/lib/rpm/gem_version.rb new file mode 100644 index 0000000..a91972b --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/gem_version.rb @@ -0,0 +1,7 @@ + +# The reason this file is gem_version.rb and not version.rb +# is because it conflicts with the version.rb class +module RPM + PKG_NAME = 'ruby-rpm'.freeze + GEM_VERSION = '0.0.5'.freeze +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/match_iterator.rb b/locallibs/ruby-rpm-ffi/lib/rpm/match_iterator.rb new file mode 100644 index 0000000..ed792f1 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/match_iterator.rb @@ -0,0 +1,66 @@ + +module RPM + class MatchIterator + include Enumerable + + # @visibility private + def self.release(ptr) + RPM::C.rpmdbFreeIterator(ptr) + end + + # Creates a managed MatchIterator from a raw pointer + # @visibility private + def self.from_ptr(ptr) + new(::FFI::AutoPointer.new(ptr, MatchIterator.method(:release))) + end + + def initialize(ptr) + @ptr = ptr + end + + def each + while (pkg = next_iterator) + yield pkg + end + end + + def next_iterator + pkg_ptr = RPM::C.rpmdbNextIterator(@ptr) + return RPM::Package.new(pkg_ptr) unless pkg_ptr.null? + nil + end + + # @ return header join key for current position of rpm + # database iterator + def offset + RPM::C.rpmdbGetIteratorOffset(@ptr) + end + + def set_iterator_re(tag, mode, string) + ret = RPM::C.rpmdbSetIteratorRE(@ptr, tag, mode, string) + raise "Error when setting regular expression '#{string}'" if ret != 0 + self + end + + alias regexp set_iterator_re + + def set_iterator_version(version) + unless version.is_a?(RPM::Version) + raise TypeError, 'illegal argument type' + end + + set_iterator_re(:version, :default, version.v) + set_iterator_re(:release, :default, version.r) if version.r + self + end + + alias version set_iterator_version + + def get_iterator_count + RPM::C.rpmdbGetIteratorCount(@ptr) + end + + alias count get_iterator_count + alias length get_iterator_count + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/package.rb b/locallibs/ruby-rpm-ffi/lib/rpm/package.rb new file mode 100644 index 0000000..65f68a2 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/package.rb @@ -0,0 +1,333 @@ + +module RPM + class ChangeLog + attr_accessor :time, :name, :text + end + + class Package + # Create a new package object from data + # @param [String] str Header data + # @return [Package] + def load(_data) + raise NotImplementedError + end + + def self.create(name, version) + unless name.is_a?(String) + raise TypeError, 'illegal argument type: name should be String' + end + unless version.is_a?(RPM::Version) + raise TypeError, 'illegal argument type: version should be RPM::Version' + end + hdr = RPM::C.headerNew + if RPM::C.headerPutString(hdr, :name, name) != 1 + raise "Can't set package name: #{name}" + end + if RPM::C.headerPutString(hdr, :version, version.v) != 1 + raise "Can't set package version: #{version.v}" + end + if version.e + if RPM::C.headerPutUint32(hdr, :epoch, version.e) != 1 + raise "Can't set package epoch: #{version.e}" + end + end + Package.new(hdr) + end + + # Add a dependency to the package header + # @param [Dependency] dep Dependency to add + def add_dependency(dep) + unless dep.is_a?(Dependency) + raise TypeError, 'illegal argument type: must be a Dependency' + end + + raise NotImplementedError + end + + # Add a int32 value to the package header + # @param [Number] tag Tag + # @param [Number] val Value + def add_int32(_tag, _val) + raise NotImplementedError + end + + # Add a list of strings to the package header + # @param [Number] tag Tag + # @param [Array] val Strings to add + def add_string_array(_tag, _val) + raise NotImplementedError + end + + # Add a binary value to the package header + # @param [Number] tag Tag + # @param [String] val String to add + def add_string(_tag, _val) + raise NotImplementedError + end + + # Add a binary value to the package header + # @param [Number] tag Tag + # @param [String] val Value + def add_binary(_tag, _val) + raise NotImplementedError + end + + # Deletes a tag of the package header + # @param [Number] tag Tag + def delete_tag(_tag) + raise NotImplementedError + end + + # @return a formated string + # @example + # pkg.sprintf("%{name}") => "apache2" + def sprintf(fmt) + error = ::FFI::MemoryPointer.new(:pointer, 1) + val = RPM::C.headerFormat(@hdr, fmt, error) + raise error.get_pointer(0).read_string if val.null? + val.read_string + end + + # @return [Number] This package signature + def signature + sprintf('%{sigmd5}') + end + + # @return [Array] File list for this package + def files + basenames = self[:basenames] + + return [] if basenames.nil? + + dirnames = self[:dirnames] + diridxs = self[:dirindexes] + statelist = self[:filestates] + flaglist = self[:fileflags] + sizelist = self[:filesizes] + modelist = self[:filemodes] + mtimelist = self[:filemtimes] + rdevlist = self[:filerdevs] + linklist = self[:filelinktos] + md5list = self[:filemd5s] + ownerlist = self[:fileusername] + grouplist = self[:filegroupname] + + ret = [] + + basenames.each_with_index do |_basename, i| + file = RPM::File.new("#{dirnames[diridxs[i]]}#{basenames[i]}", + md5list[i], + linklist[i], + sizelist[i], + mtimelist[i], + ownerlist[i], + grouplist[i], + rdevlist[i], + modelist[i], + flaglist.nil? ? RPM::C::FileAttrs[:none] : flaglist[i], + statelist.nil? ? RPM::C::FileState[:normal] : statelist[i]) + ret << file + end + ret + end + + # @return [Array] Dependencies for +klass+ + # @example + # dependencies(RPM::Provide, :providename, :provideversion, :provideflags) + # + # @visibility private + def dependencies(klass, nametag, versiontag, flagtag) + deps = [] + + nametd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + versiontd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + flagtd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + + min = RPM::C::HEADERGET_MINMEM + return deps if RPM::C.headerGet(@hdr, nametag, nametd, min) != 1 + return deps if RPM::C.headerGet(@hdr, versiontag, versiontd, min) != 1 + return deps if RPM::C.headerGet(@hdr, flagtag, flagtd, min) != 1 + + RPM::C.rpmtdInit(nametd) + while RPM::C.rpmtdNext(nametd) != -1 + deps << klass.new(RPM::C.rpmtdGetString(nametd), + RPM::Version.new(RPM::C.rpmtdNextString(versiontd)), + RPM::C.rpmtdNextUint32(flagtd).read_uint, self) + end + deps + end + + # @return [Array] Provides list for this package + def provides + dependencies(RPM::Provide, :providename, :provideversion, :provideflags) + end + + # @return [Array] Requires list for this package + def requires + dependencies(RPM::Require, :requirename, :requireversion, :requireflags) + end + + # @return [Array] Conflicts list for this package + def conflicts + dependencies(RPM::Conflict, :conflictname, :conflictversion, :conflictflags) + end + + # @return [Array] Obsoletes list for this package + def obsoletes + dependencies(RPM::Obsolete, :obsoletename, :obsoleteversion, :obsoleteflags) + end + + # @return [Array] changelog of the package as an array + def changelog + entries = [] + nametd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + timetd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + texttd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + + min = RPM::C::HEADERGET_MINMEM + return deps if RPM::C.headerGet(@hdr, :changelogtime, timetd, min) != 1 + return deps if RPM::C.headerGet(@hdr, :changelogname, nametd, min) != 1 + return deps if RPM::C.headerGet(@hdr, :changelogtext, texttd, min) != 1 + + RPM::C.rpmtdInit(timetd) + while RPM::C.rpmtdNext(timetd) != -1 + entry = RPM::ChangeLog.new + entry.time = RPM::C.rpmtdGetUint32(timetd) + entry.name = RPM::C.rpmtdNextString(nametd) + entry.text = RPM::C.rpmtdNextString(texttd) + entries << entry + end + entries + end + + # Access a header entry + # @param [Number] tag Tag to return + # @return [] Value of the entry + # @example + # pkg => #> + # pkg[:name] => "xmlgraphics-fop" + # + # or if you have the old ruby-rpm compat loaded + # + # require 'rpm/compat' + # pkg[RPM::TAG_NAME] => "xmlgraphics-fop" + # + # @return [String, Fixnum, Array, Array, nil] + # The value of the entry + def [](tag) + val = nil + tagc = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td)) + + return nil if RPM::C.headerGet(ptr, tag, tagc, + RPM::C::HEADERGET_MINMEM) == 0 + + type = RPM::C.rpmtdType(tagc) + count = RPM::C.rpmtdCount(tagc) + ret_type = RPM::C.rpmTagGetReturnType(tag) + + method_name = case type + when :int8_type, :char_type, :int16_type, :int32_type, :int64_type then :rpmtdGetNumber + when :string_type, :string_array_type, :bin_type then :rpmtdGetString + else raise NotImplementedError, "Don't know how to retrieve type '#{type}'" + end + + is_array = if count > 1 then true + elsif ret_type == :array_return_type then true + elsif type == :string_array_type then true + else false + end + + if is_array + ret = [] + RPM::C.rpmtdInit(tagc) + ret << RPM::C.send(method_name, tagc) while RPM::C.rpmtdNext(tagc) != -1 + return ret + end + + RPM::C.send(method_name, tagc) + end + + # @return [String] This package name + def name + self[:name] + end + + # @return [String] This package architecture + def arch + self[:arch] + end + + # TODO: signature + + # @return [Version] Version for this package + def version + Version.new(self[:version], self[:release], self[:epoch]) + end + + # String representation of the package: "name-version-release-arch" + # @return [String] + def to_s + return '' if name.nil? + return name if version.nil? + return "#{name}-#{version}" if arch.nil? + "#{name}-#{version}-#{arch}" + end + + def self.open(filename) + Package.new(filename) + end + + # @visibility private + def self.release(ptr) + RPM::C.headerFree(ptr) + end + + # @visibility private + def self.release_td(ptr) + RPM::C.rpmtdFree(ptr) + end + + # @visibility private + def initialize(what) + case what + when String then initialize_from_filename(what) + else initialize_from_header(what) + end + end + + # @visibility private + def initialize_from_header(hdr = nil) + if hdr.nil? + @hdr = ::FFI::AutoPointer.new(RPM::C.headerNew, Header.method(:release)) + elsif hdr.is_a?(::FFI::Pointer) + # ref + hdr = RPM::C.headerLink(hdr) + @hdr = ::FFI::AutoPointer.new(hdr, Package.method(:release)) + else + raise "Can't initialize header with '#{hdr}'" + end + end + + def initialize_from_filename(filename) + # it sucks not using the std File.open here + hdr = ::FFI::MemoryPointer.new(:pointer) + fd = nil + begin + fd = RPM::C.Fopen(filename, 'r') + raise "#{filename} : #{RPM::C.Fstrerror(fd)}" if RPM::C.Ferror(fd) != 0 + RPM.transaction do |ts| + rc = RPM::C.rpmReadPackageFile(ts.ptr, fd, filename, hdr) + end + ensure + RPM::C.Fclose(fd) unless fd.nil? + end + initialize_from_header(hdr.get_pointer(0)) + end + + # @return [RPM::C::Header] header pointer + # @visibility private + def ptr + @hdr + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/problem.rb b/locallibs/ruby-rpm-ffi/lib/rpm/problem.rb new file mode 100644 index 0000000..82be14f --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/problem.rb @@ -0,0 +1,65 @@ + +module RPM + class Problem + def self.release(ptr) + RPM::C.rpmProblemFree(ptr) + end + + # Creates a problem from an existing C pointer, refcounting it + # first. + # @param [FFI::Pointer] ptr existing C pointer + # @return [RPM::Problem] wrapped object + def self.from_ptr(ptr) + case ptr + when FFI::Pointer + new(FFI::AutoPointer.new(RPM::C.rpmProblemLink(ptr), Problem.method(:release))) + else + raise "Can't initialize header with '#{ptr}'" + end + end + + # Create a problem item. + # @param [RPM::ProblemType] type problem type + # @param [String] pkg_nver name-version-edition-release of the related package + # @param [String] key key of the related package + # @param [String] alt_nver name-version-edition-release of the other related package + # @param [String] str generic data string from a problem + def self.create(type, pkg_nevr, key, alt_nevr, str, number) + ptr = ::FFI::AutoPointer.new(RPM::C.rpmProblemCreate(type, pkg_nevr, key, alt_nevr, str, number), Problem.method(:release)) + new(ptr) + end + + # @visibility private + def initialize(ptr) + @ptr = ptr + end + + # @return [RPM::ProblemType] type of problem (dependency, diskpace etc). + def type + RPM::C.rpmProblemGetType(@ptr) + end + + # @return [String] filename or python object address of a problem. + def key + RPM::C.rpmProblemGetKey(@ptr).read_string + end + + # @return [String] a generic data string from a problem. + def str + RPM::C.rpmProblemGetStr(@ptr) + end + + # @return [String] formatted string representation of a problem + def to_s + RPM::C.rpmProblemString(@ptr) + end + + # @return [Fixnum] compare two problems for equality. + def <=>(other) + RPM::C.rpmProblemCompare(@ptr, other.ptr) + end + + # @visibility private + attr_reader :ptr + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/transaction.rb b/locallibs/ruby-rpm-ffi/lib/rpm/transaction.rb new file mode 100644 index 0000000..6b57d88 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/transaction.rb @@ -0,0 +1,270 @@ + +module RPM + CallbackData = Struct.new(:type, :key, :package, :amount, :total) do + def to_s + "#{type} #{key} #{package} #{amount} #{total}" + end + end + + class Transaction + def self.release(ptr) + RPM::C.rpmtsFree(ptr) + end + + def initialize(opts = {}) + # http://markmail.org/message/ypsiqxop442p7rzz + # The key pointer needs to stay valid during commit + # so we keep a reference to them mapping from + # object_id to ruby object. + @keys = {} + opts[:root] ||= '/' + + @ptr = ::FFI::AutoPointer.new(RPM::C.rpmtsCreate, Transaction.method(:release)) + RPM::C.rpmtsSetRootDir(@ptr, opts[:root]) + end + + # @return [RPM::MatchIterator] Creates an iterator for +tag+ and +val+ + def init_iterator(tag, val) + raise TypeError if val && !val.is_a?(String) + + it_ptr = RPM::C.rpmtsInitIterator(@ptr, tag.nil? ? 0 : tag, val, 0) + + raise "Can't init iterator for [#{tag}] -> '#{val}'" if it_ptr.null? + MatchIterator.from_ptr(it_ptr) + end + + # @visibility private + attr_reader :ptr + + # + # @yield [Package] Called for each match + # @param [Number] key RPM tag key + # @param [String] val Value to match + # @example + # RPM.transaction do |t| + # t.each_match(RPM::TAG_ARCH, "x86_64") do |pkg| + # puts pkg.name + # end + # end + # + def each_match(key, val, &block) + it = init_iterator(key, val) + + return it unless block_given? + + it.each(&block) + end + + # + # @yield [Package] Called for each package in the database + # @example + # db.each do |pkg| + # puts pkg.name + # end + # + def each(&block) + each_match(0, nil, &block) + end + + # Add a install operation to the transaction + # @param [Package] pkg Package to install + # @param [String] key e.g. filename where to install from + def install(pkg, key) + install_element(pkg, key, upgrade: false) + end + + # Add an upgrade operation to the transaction + # @param [Package] pkg Package to upgrade + # @param [String] key e.g. filename where to install from + def upgrade(pkg, key) + install_element(pkg, key, upgrade: true) + end + + # Add a delete operation to the transaction + # @param [String, Package, Dependency] pkg Package to delete + def delete(pkg) + iterator = case pkg + when Package + pkg[:sigmd5] ? each_match(:sigmd5, pkg[:sigmd5]) : each_match(:label, pkg[:label]) + when String + each_match(:label, pkg) + when Dependency + each_match(:label, pkg.name).set_iterator_version(pkg.version) + else + raise TypeError, 'illegal argument type' + end + + iterator.each do |header| + ret = RPM::C.rpmtsAddEraseElement(@ptr, header.ptr, iterator.offset) + raise "Error while adding erase/#{pkg} to transaction" if ret != 0 + end + end + + # Sets the root directory for this transaction + # @param [String] root directory + def root_dir=(dir) + rc = RPM::C.rpmtsSetRootDir(@ptr, dir) + raise "Can't set #{dir} as root directory" if rc < 0 + end + + # @return [String ] the root directory for this transaction + def root_dir + RPM::C.rpmtsRootDir(@ptr) + end + + def flags=(fl) + RPM::C.rpmtsSetFlags(@ptr, fl) + end + + def flags + RPM::C.rpmtsFlags(@ptr) + end + + # Determine package order in the transaction according to dependencies + # + # The final order ends up as installed packages followed by removed + # packages, with packages removed for upgrades immediately following + # the new package to be installed. + # + # @returns [Fixnum] no. of (added) packages that could not be ordered + def order + RPM::C.rpmtsOrder(@ptr) + end + + # Free memory needed only for dependency checks and ordering. + def clean + RPM::C.rpmtsClean(@ptr) + end + + def check + rc = RPM::C.rpmtsCheck(@ptr) + probs = RPM::C.rpmtsProblems(@ptr) + + return if rc < 0 + begin + psi = RPM::C.rpmpsInitIterator(probs) + while RPM::C.rpmpsNextIterator(psi) >= 0 + problem = Problem.from_ptr(RPM::C.rpmpsGetProblem(psi)) + yield problem + end + ensure + RPM::C.rpmpsFree(probs) + end + end + + # Performs the transaction. + # @param [Number] flag Transaction flags, default +RPM::TRANS_FLAG_NONE+ + # @param [Number] filter Transaction filter, default +RPM::PROB_FILTER_NONE+ + # @example + # transaction.commit + # You can supply your own callback + # @example + # transaction.commit do |data| + # end + # end + # @yield [CallbackData] sig Transaction progress + def commit + flags = RPM::C::TransFlags[:none] + + callback = proc do |hdr, type, amount, total, key_ptr, data_ignored| + key_id = key_ptr.address + key = @keys.include?(key_id) ? @keys[key_id] : nil + + if block_given? + package = hdr.null? ? nil : Package.new(hdr) + data = CallbackData.new(type, key, package, amount, total) + yield(data) + else + RPM::C.rpmShowProgress(hdr, type, amount, total, key, data_ignored) + end + end + # We create a callback to pass to the C method and we + # call the user supplied callback from there + # + # The C callback expects you to return a file handle, + # We expect from the user to get a File, which we + # then convert to a file handle to return. + callback = proc do |hdr, type, amount, total, key_ptr, data_ignored| + key_id = key_ptr.address + key = @keys.include?(key_id) ? @keys[key_id] : nil + + if block_given? + package = hdr.null? ? nil : Package.new(hdr) + data = CallbackData.new(type, key, package, amount, total) + ret = yield(data) + + # For OPEN_FILE we need to do some type conversion + # for certain callback types we need to do some + case type + when :inst_open_file + # For :inst_open_file the user callback has to + # return the open file + unless ret.is_a?(::File) + raise TypeError, "illegal return value type #{ret.class}. Expected File." + end + fdt = RPM::C.fdDup(ret.to_i) + if fdt.null? || RPM::C.Ferror(fdt) != 0 + raise "Can't use opened file #{data.key}: #{RPM::C.Fstrerror(fdt)}" + RPM::C.Fclose(fdt) unless fdt.nil? + else + fdt = RPM::C.fdLink(fdt) + @fdt = fdt + end + # return the (RPM type) file handle + fdt + when :inst_close_file + fdt = @fdt + RPM::C.Fclose(fdt) + @fdt = nil + else + ret + end + else + # No custom callback given, use the default to show progress + RPM::C.rpmShowProgress(hdr, type, amount, total, key, data_ignored) + end + end + + rc = RPM::C.rpmtsSetNotifyCallback(@ptr, callback, nil) + raise "Can't set commit callback" if rc != 0 + + rc = RPM::C.rpmtsRun(@ptr, nil, :none) + + raise "#{self}: #{RPM::C.rpmlogMessage}" if rc < 0 + + if rc > 0 + ps = RPM::C.rpmtsProblems(@ptr) + psi = RPM::C.rpmpsInitIterator(ps) + while RPM::C.rpmpsNextIterator(psi) >= 0 + problem = Problem.from_ptr(RPM::C.rpmpsGetProblem(psi)) + STDERR.puts problem + end + RPM::C.rpmpsFree(ps) + end + end + + # @return [DB] the database associated with this transaction + def db + RPM::DB.new(self) + end + + private + + # @param [Package] pkg package to install + # @param [String] key e.g. filename where to install from + # @param opts options + # @option :upgrade Upgrade packages if true + def install_element(pkg, key, opts = {}) + raise TypeError, 'illegal argument type' unless pkg.is_a?(RPM::Package) + raise ArgumentError, "#{self}: key '#{key}' must be unique" if @keys.include?(key.object_id) + + # keep a reference to the key as rpmtsAddInstallElement will keep a copy + # of the passed pointer (we pass the object_id) + @keys[key.object_id] = key + + ret = RPM::C.rpmtsAddInstallElement(@ptr, pkg.ptr, FFI::Pointer.new(key.object_id), opts[:upgrade] ? 1 : 0, nil) + raise RuntimeError if ret != 0 + nil + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/utils.rb b/locallibs/ruby-rpm-ffi/lib/rpm/utils.rb new file mode 100644 index 0000000..a85b9e8 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/utils.rb @@ -0,0 +1,7 @@ +module RPM + module Utils + def self.check_type(var, type) + raise(TypeError, "wrong argument type #{var.class} (expected #{type.class})") unless var.is_a?(type) + end + end +end diff --git a/locallibs/ruby-rpm-ffi/lib/rpm/version.rb b/locallibs/ruby-rpm-ffi/lib/rpm/version.rb new file mode 100644 index 0000000..ef2a361 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/lib/rpm/version.rb @@ -0,0 +1,146 @@ + +module RPM + class Version + include Comparable + + # Parses a "epoch:version-release" string + # @return [Array] tuple [epoch, version, release] + def self.parse_evr(evr) + raise ArgumentError, "version can't be nil" if evr.nil? + version = evr + epoch = nil + release = nil + + idx = version.rindex('-') + if idx + release = version[idx + 1..-1] + version = version[0..idx - 1] + end + + idx = version.index(/\D/) + if idx && version[idx] == ':' + epoch = version[0..idx - 1] + version = version[idx + 1..-1] + end + [epoch ? epoch.to_i : nil, version, release] + end + + # + # @overload new(vr, e = nil) + # Creates a version object from a string representation + # @param [String] vr version and release in the form "v-r" + # @param [Number] e epoch + # @return [Version] + # @overload new(v, r, e = nil) + # Creates a version object from a string representation + # @param [String] v version + # @param [String] r release + # @param [Number] e epoch + # @return [Version] + # @example + # RPM:: Version.new "1.0.0-3" + # RPM:: Version.new "1.04" + # RPM:: Version.new "1.0.0-3k", 1 + # RPM:: Version.new "2.0.3", "5k" + # + def initialize(*argv) + case argv.size + when 0 + raise(ArgumentError('wrong number of arguments (0 for 1..3)')) + when 1 + RPM::Utils.check_type(argv[0], String) + @e, @v, @r = RPM::Version.parse_evr(argv[0]) + when 2 + # (vr, e) + RPM::Utils.check_type(argv[0], String) + @e, @v, @r = RPM::Version.parse_evr(argv[0]) + raise(TypeError, 'illegal argument value') unless e.nil? + @e = argv[1].to_i + when 3 + RPM::Utils.check_type(argv[0], String) + RPM::Utils.check_type(argv[1], String) + @v = argv[0] + @r = argv[1] + @e = argv[2].to_i + else + raise(ArgumentError("too many arguments (#{args.size} for 1..3)")) + end + end + + # @return [String] the version component + attr_reader :v + + # @return [String] the release component + # or +nil+ + attr_reader :r + + # @return [String] the epoch component + # or +nil+ + attr_reader :e + + # Comparison between versions + # @param [Version] other + # @return [Number] -1 if +other+ is greater than, 0 if +other+ is equal to, + # and +1 if other is less than version. + # + # @example + # v1 = RPM::Version.new("3.0-0",1) + # v2 = RPM::Version.new("3.1-0",1) + # v1 <=> v2 + # => -1 + # + def <=>(other) + RPM::Utils.check_type(other, RPM::Version) + ret = RPM::C.rpmvercmp(to_vre_epoch_zero, other.to_vre_epoch_zero) + end + + # @param [Version] other Version to compare against + # @return [Boolean] true if the version is newer than +other+ + def newer?(other) + self > other + end + + # @param [Version] other Version to compare against + # @return [Boolean] true if the version is older than +other+ + def older?(other) + self < other + end + + # String representation in the form "v-r" + # @return [String] + # @note The epoch is not included + def to_vr + vr = @r.nil? ? @v.to_s : "#{@v}-#{@r}" + end + + # String representation in the form "e:v-r" + # @return [String] + # @note The epoch is included if present + def to_vre(_opts = {}) + vr = to_vr + vre = @e.nil? ? vr : "#{@e}:#{vr}" + end + + # Alias for +to_vr+ + # @see Version#to_vr + def to_s + to_vr + end + + # Hash based on the version content + # @return [String] + def hash + h = @e.nil? ? 0 : @e + h = (h << 1) ^ @r.hash + h = (h << 1) ^ @v.hash + end + + # String representation in the form "e:v-r" + # @return [String] + # @note The epoch is included always. As 0 if not present + def to_vre_epoch_zero + vr = to_vr + vre = @e.nil? ? "0:#{vr}" : "#{@e}:#{vr}" + end + end +end diff --git a/locallibs/ruby-rpm-ffi/rpm.gemspec b/locallibs/ruby-rpm-ffi/rpm.gemspec new file mode 100644 index 0000000..57f2545 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/rpm.gemspec @@ -0,0 +1,25 @@ +# -*- encoding: utf-8 -*- + +$LOAD_PATH.push File.expand_path('../lib', __FILE__) +require 'rpm/gem_version' + +Gem::Specification.new do |s| + s.name = 'rpm' + s.version = RPM::GEM_VERSION + s.authors = ['Duncan Mac-Vicar P.'] + s.email = ['dmacvicar@suse.de'] + s.homepage = '' + s.summary = 'Ruby bindings for rpm (package manager)' + s.description = 'Ruby bindings for rpm. Almost a drop-in replacement for ruby-rpm. Uses FFI.' + + s.rubyforge_project = 'rpm' + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } + s.require_paths = ['lib'] + + # specify any dependencies here; for example: + s.add_development_dependency 'rake' + s.add_runtime_dependency 'ffi' +end diff --git a/locallibs/ruby-rpm-ffi/test/data/a.spec b/locallibs/ruby-rpm-ffi/test/data/a.spec new file mode 100644 index 0000000..f5de203 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/data/a.spec @@ -0,0 +1,49 @@ +Name: a +Version: 1.0 +Release: 0 +License: GPLv2 +Summary: Minimal package example +Url: http://www.a.com +Group: Development +Source: a-1.0.tar.gz +BuildRequires: c d +Provides: something +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +Description + +%package devel +Summary: Development part +%description devel +Development headers + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} + +%install +%make_install + +%clean +%{?buildroot:%__rm -rf "%{buildroot}"} + +%post + +%postun + +%files +%defattr(-,root,root) +%doc ChangeLog README COPYING +%{_datadir}/a/README + +%files devel +%{_includedir}/a.h + + + +%changelog + diff --git a/locallibs/ruby-rpm-ffi/test/data/simple-1.0-0.i586.rpm b/locallibs/ruby-rpm-ffi/test/data/simple-1.0-0.i586.rpm new file mode 100644 index 0000000000000000000000000000000000000000..62b37570468f1049210822ddf53197d96903576a GIT binary patch literal 2177 zcmbW2YiJx*6vyvAYGRvWDXooSWx$qZ(V2bBK3mf!X0vUeN!Fx33Tk?H_D*(mXJ$Jy z`wD(YA)tX!6cj~>#t=%O2x>{Nl446y@OCg<5P{t4P$u^_<-sNrNB63upfG zyXTyH&wVg+{mkMw9sKJdFXgWdtQ4GjG^K+)IH;3jR~&}3@jh2!erL#pKab>F3g9H5C% zSWRSTgsO5v$tY?-jYnhAU_6wF$D@gCMxluqY;Nesbzq&iPOS4s&Mlm;amL)$b>0c@Tfs2@Iw*1{=S5IlC(g6F zZX7?y`Dak{S2+I$ivH(0FM;BCqnwvP(Lcd?h4VD$zc`<6uouTh!##oeyqJqu?1y(d zDCT#7V*CzJj6cM=6%_r)K%q|WJ)r2%bH11JdCoX4j{hYnjvoib{BJ>V`~)cGU*WvB z!R|2UgP;)aeu^{Jft=;s0}A{aGnIkdNZI< zzZ=gB8RrG|V4cW}Gu~rlm2;9a)`jsY&P7m|--C5xy(Lhn-*XHU_p=O&{?&R>kw-z@ zU4+@B@kt@@Ng)9;SpU8V*`lsjg#uNcqr;4(>G2|Sn9zt6vP{s6%yukFlK&dFCV-Ii z;#arwno+EX)sbhZWNQvCk!(7cK1`CV#PViAXNE&^j#Jp{_m|6M31`=!sVC`hXiJ22K2sk!cAfd)sAfyIEi9m*hg260}1!6Q5jjF+joRLXfiHGHo5{ZOl zB_07+geh_+NSRDCax{#ayxJ_&bjZ5L+OMu;TZ&{Abc}~@QN8gkY)D%r9u?(~5BzX| z8&?fd@>-^?%hU@Nvu&15X?fO1b!Phr_oZnyZ_>KMK153_Z824=tata=hevekBeE2b z!eWqw;a`ByuoSIpLJCSDLi*-P7y4#*cO;93LJgspD&pgsLMjzB83M_ra<=X1)2OHq~3wM(=H-2BY|HKBm zJCnWLq#+XAOMlU}{C197%-`5pKN0&wf;cRQx(upQOUbq4)qr=WXs~uIitj3HsSVdw z%rj%y$+ZUrF*%g#A2`yJIyyAi|JXoRcRQr3wgcB&ELf()6vwonr)ZQlBP%*IlV>(C zwX24bvrNM*+Tv|aq7*cfP~-}tQirJG~p zlb636_uu+xe#$@lhtm2)|Hr|LpPrc;^6e~5&VT>lj=Mc?z5Ro6?&hg;@1Jd|{dwhL F;%}Bquo(aV literal 0 HcmV?d00001 diff --git a/locallibs/ruby-rpm-ffi/test/data/simple.spec b/locallibs/ruby-rpm-ffi/test/data/simple.spec new file mode 100644 index 0000000..b56b23f --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/data/simple.spec @@ -0,0 +1,38 @@ +Name: simple +Version: 1.0 +Release: 0 +License: GPL +Summary: Simple dummy package +Summary(es): Paquete simple de muestra +Url: http://www.dummmy.com +Group: Development +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +Dummy package + +%description -l es +Paquete de muestra + +%prep + +%build +mkdir -p %{buildroot}%{_datadir}/%{name} +echo "Hello" > %{buildroot}%{_datadir}/%{name}/README +echo "Hola" > %{buildroot}%{_datadir}/%{name}/README.es + +%install + +%clean +%{?buildroot:%__rm -rf "%{buildroot}"} + +%files +%defattr(-,root,root) +%{_datadir}/%{name}/README +%{_datadir}/%{name}/README.es + +%changelog +* Wed Nov 06 2011 Duncan Mac-Vicar P. +- Fix something +* Tue Nov 05 2011 Duncan Mac-Vicar P. +- Fix something else diff --git a/locallibs/ruby-rpm-ffi/test/data/simple_with_deps-1.0-0.i586.rpm b/locallibs/ruby-rpm-ffi/test/data/simple_with_deps-1.0-0.i586.rpm new file mode 100644 index 0000000000000000000000000000000000000000..927a916c8e62683af0036b1d7923e7dcb1eb2159 GIT binary patch literal 2335 zcma)-YiJx*6vyvow@qxVMvSIbt7D~*f-{-fS2m@oY4d1RBg zzxm(ixp(iJKYrmmFN5N7Oe>QVBYD$Jj2I&0$eNm1r+7pLG+oYTt6$_)I5F&X>U zyqjUnGw|vj2$+}mQ&6m9K-55Bse<>o4xA^h6X*Fe@y*1)5N{yHbzTE;8}WH!4HWyk z0E+9xoR!y&{SOf@fuf%vz6gqblK2uR_MahM21Wk>@nzx{iT@&=EU^#!#&{J1=HtV* zcvRjb#=eoKiPwN)eas=&Uki%)!Tcg$OZ+D>?km>Ed7*zjDAf1hJ7ml;@^!?x|1by7 zdQixR?

F>xqzG4~q3$iLoB~m=D+!-z}i%PY~liAfF}P2#WQ81I6)gC;t-h9mM7N zHUQ&%FmE^?oCmb8f$>bK(YN{@^=%zK->k2{Y?@N zk$;4EnEWZ?z2wh;V*d}4{~qx}Ob0ZA>_<^2%axWigfY z7jH7j$XeEzl;Qe*J}OxI6%^%Ee>u z+Fj8-tXK zo8wJF^~W_oTt>pLX$Egno47w5j%%SnEWjdqBpC4Pp^!hIM?zqQgdT`#Tm*P55DsEe z%f(KoT~_g^OiAe$R~%bc?2N@2+;PQHS?@o&Y$!y+a=^c(JQ(C2HhoPwIEyjpFlojb z+R|3W7LFr~PBSTbxFwt|WiQIdl4)KvoZUPpqPB>eg-W~2*)wi&7z+0sfe zKlltPVbF5Xi`Q;Y(Nx8c?|RSP_E z7-BmdgR842OPyvxa?+M?6J~0ZRj?$Ij$ozDfRy0>p%`#Ziv`Xxt0{dz|Nk@E*Ri9$ zyMvWPfwSD0b?inb!EMo4xi^hW?)6LZs3cnfP>b7oq6H5c{C2Y`(PD=2cN`M$z)_cz zA~otJT2x7HAL;Dv8|dmB9_jBL>}%_2f#z|?g};QHvD2>5-LwsFvZ=h8GGv#>lEMMz z&R9xM*y&U{>&RD_OwX8UmW176q2gJWF|%^%?8BN%dDzk4*3~7sqTn*aw2PyRmGV;g zEPhj0R+ckh)WQWc@y`Ke>(_nn(~sD<=3bj^Sjr8l?}m=Pv}rt+`||Y6fo%)R6Njg( z@0z>&bl=zAlfxfx2qIY(zZaDP$@-g$?w`SfMnEz(lvtV4_=lt;cvtNBS{rsjAqbrL? Hrw9KA?f%Fv literal 0 HcmV?d00001 diff --git a/locallibs/ruby-rpm-ffi/test/data/simple_with_deps.spec b/locallibs/ruby-rpm-ffi/test/data/simple_with_deps.spec new file mode 100644 index 0000000..e1ffaf3 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/data/simple_with_deps.spec @@ -0,0 +1,41 @@ +Name: simple_with_deps +Version: 1.0 +Release: 0 +License: GPL +Summary: Simple dummy package +Url: http://www.dummmy.com +Group: Development +Requires: a +Requires: b > 1.0 +Conflicts: c d +Obsoletes: f +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +Dummy package + +%description -l es +Paquete de muestra + +%prep + +%build +mkdir -p %{buildroot}%{_datadir}/%{name} +echo "Hello" > %{buildroot}%{_datadir}/%{name}/README +echo "Hola" > %{buildroot}%{_datadir}/%{name}/README.es + +%install + +%clean +%{?buildroot:%__rm -rf "%{buildroot}"} + +%files +%defattr(-,root,root) +%{_datadir}/%{name}/README +%{_datadir}/%{name}/README.es + +%changelog +* Wed Nov 06 2011 Duncan Mac-Vicar P. +- Fix something +* Tue Nov 05 2011 Duncan Mac-Vicar P. +- Fix something else diff --git a/locallibs/ruby-rpm-ffi/test/helper.rb b/locallibs/ruby-rpm-ffi/test/helper.rb new file mode 100644 index 0000000..db451cb --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/helper.rb @@ -0,0 +1,7 @@ +$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib') +require 'minitest/autorun' +require 'rpm' + +def fixture(name) + File.expand_path(File.join(File.dirname(__FILE__), 'data', name)) +end diff --git a/locallibs/ruby-rpm-ffi/test/test_dependency.rb b/locallibs/ruby-rpm-ffi/test/test_dependency.rb new file mode 100644 index 0000000..46b9248 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_dependency.rb @@ -0,0 +1,28 @@ +require_relative('helper') +require 'rpm/compat' + +class RPMDependencyTests < Minitest::Test + EQ = RPM::SENSE_EQUAL + LT = RPM::SENSE_LESS + GT = RPM::SENSE_GREATER + + def test_satisfy + prv = provides('foo', '2', '1', 0, EQ) + req = requires('foo', '1', '1', 0, EQ | GT) + assert(req.satisfy?(prv)) + assert(prv.satisfy?(req)) + + # Different names don't overlap + prv = provides('foo', '2', '1', 0, EQ) + req = requires('bar', '1', '1', 0, EQ | GT) + assert(!req.satisfy?(prv)) + end + + def provides(name, v, r, e, sense) + RPM::Provide.new(name, RPM::Version.new(v, r, e), sense, nil) + end + + def requires(name, v, r, e, sense) + RPM::Require.new(name, RPM::Version.new(v, r, e), sense, nil) + end +end diff --git a/locallibs/ruby-rpm-ffi/test/test_file.rb b/locallibs/ruby-rpm-ffi/test/test_file.rb new file mode 100644 index 0000000..cfee96b --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_file.rb @@ -0,0 +1,36 @@ +require File.join(File.dirname(__FILE__), 'helper') + +class RPMFileTests < Minitest::Test + def test_link_to + f = RPM::File.new('path', 'md5sum', nil, 42, 1, + 'owner', 'group', 43, 0o777, 44, 45) + assert_equal(nil, f.link_to) + f = RPM::File.new('path', 'md5sum', 'link_to', 42, 1, + 'owner', 'group', 43, 0o777, 44, 45) + assert_equal('link_to', f.link_to) + end + + def test_flags + f = RPM::File.new('path', 'md5sum', nil, 42, 1, + 'owner', 'group', 43, 0o777, 44, 45) + f.config? + f.doc? + f.is_missingok? + f.is_noreplace? + f.is_specfile? + f.ghost? + f.license? + f.readme? + f.replaced? + f.notinstalled? + f.netshared? + + assert_raises NotImplementedError do + f.exclude? + end + + assert_raises NotImplementedError do + f.donotuse? + end + end +end diff --git a/locallibs/ruby-rpm-ffi/test/test_lib.rb b/locallibs/ruby-rpm-ffi/test/test_lib.rb new file mode 100644 index 0000000..ad39a8b --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_lib.rb @@ -0,0 +1,33 @@ +require File.join(File.dirname(__FILE__), 'helper') + +class RPMLibTests < Minitest::Test + def test_lib_lib + assert_kind_of String, RPM::C.RPMVERSION + # "x.y.z" + assert(RPM::C.RPMVERSION.size >= 5) + assert_kind_of Integer, RPM::C.rpm_version_code + # >= 4.0.0 + assert(RPM::C.rpm_version_code >= ((4 << 16) + (0 << 8) + (0 << 0))) + end + + def test_lib_header + ptr = RPM::C.headerNew + RPM::C.headerFree(ptr) + end + + def test_lib_ts + ts = RPM::C.rpmtsCreate + RPM::C.rpmtsSetRootDir(ts, '/') + it = RPM::C.rpmtsInitIterator(ts, 0, nil, 0) + hdrs = [] + until (hdr = RPM::C.rpmdbNextIterator(it)).null? + hdrs << hdr + assert_kind_of String, RPM::C.headerGetAsString(hdr, :name) + end + RPM::C.rpmdbFreeIterator(it) + end + + def test_lib_macros + assert_kind_of String, RPM::C.MACROFILES + end +end diff --git a/locallibs/ruby-rpm-ffi/test/test_package.rb b/locallibs/ruby-rpm-ffi/test/test_package.rb new file mode 100644 index 0000000..523ec03 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_package.rb @@ -0,0 +1,76 @@ +require File.join(File.dirname(__FILE__), 'helper') + +class RPMHeaderTests < Minitest::Test + def test_create + pkg = RPM::Package.create('foo', RPM::Version.new('1.0')) + assert_equal 'foo', pkg.name + assert_equal '(none)', pkg.signature + end + + def test_open + pkg = RPM::Package.open(fixture('simple-1.0-0.i586.rpm')) + + req = RPM::Require.new('simple', RPM::Version.new('1.0', '0'), RPM::SENSE_GREATER | RPM::SENSE_EQUAL, nil) + assert req.satisfy?(pkg) + + assert_equal 'simple-1.0-0-i586', pkg.to_s + + assert_equal '3b5f9d468c877166532c662e29f43bc3', pkg.signature + + assert_kind_of RPM::Package, pkg + assert_equal 'simple', pkg[:name] + assert_equal 'i586', pkg[:arch] + assert_kind_of RPM::Version, pkg.version + assert_equal '1.0-0', pkg.version.to_s + + backup_lang = ENV['LC_ALL'] + + ENV['LC_ALL'] = 'C' + assert_equal 'Simple dummy package', pkg[:summary] + assert_equal 'Dummy package', pkg[:description] + + ENV['LC_ALL'] = 'es_ES.UTF-8' + assert_equal 'Paquete simple de muestra', pkg[:summary] + assert_equal 'Paquete de muestra', pkg[:description] + + ENV['LC_ALL'] = backup_lang + + # Arrays + assert_equal %w[root root], pkg[:fileusername] + assert_equal [6, 5], pkg[:filesizes] + + assert pkg.provides.map(&:name).include?('simple(x86-32)') + assert pkg.provides.map(&:name).include?('simple') + + assert pkg.files.map(&:path).include?('/usr/share/simple/README') + assert pkg.files.map(&:path).include?('/usr/share/simple/README.es') + + assert pkg.conflicts.empty? + assert pkg.requires.map(&:name).include?('rpmlib(PayloadIsLzma)') + assert pkg.obsoletes.empty? + + file = pkg.files.select { |x| x.path == '/usr/share/simple/README' }.first + assert_nil file.link_to + assert !file.symlink? + + assert_equal ['- Fix something', '- Fix something else'], pkg.changelog.map(&:text) + end + + def test_dependencies + pkg = RPM::Package.open(fixture('simple_with_deps-1.0-0.i586.rpm')) + assert_equal 'simple_with_deps', pkg.name + + assert pkg.provides.map(&:name).include?('simple_with_deps(x86-32)') + assert pkg.provides.map(&:name).include?('simple_with_deps') + + assert pkg.requires.map(&:name).include?('a') + b = pkg.requires.find { |x| x.name == 'b' } + assert b + assert_equal '1.0', b.version.to_s + + assert pkg.conflicts.map(&:name).include?('c') + assert pkg.conflicts.map(&:name).include?('d') + + assert pkg.obsoletes.map(&:name).include?('f') + end +end diff --git a/locallibs/ruby-rpm-ffi/test/test_problem.rb b/locallibs/ruby-rpm-ffi/test/test_problem.rb new file mode 100644 index 0000000..2d87f41 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_problem.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), 'helper') + +class RPMHeaderTests < Minitest::Test + def test_create + problem = RPM::Problem.create(:requires, 'foo-1.0-0', 'foo.rpm', 'bar-1.0-0', 'Hello', 1) + assert_equal 'foo.rpm', problem.key + assert_equal :requires, problem.type + assert_equal 'Hello', problem.str + assert_equal 'Hello is needed by (installed) bar-1.0-0', problem.to_s + + # Create a RPM::Problem from an existing pointer + problem2 = RPM::Problem.new(problem.ptr) + assert_equal problem.key, problem2.key + assert_equal problem.type, problem2.type + assert_equal problem.str, problem2.str + assert_equal problem.to_s, problem2.to_s + end +end diff --git a/locallibs/ruby-rpm-ffi/test/test_rpm.rb b/locallibs/ruby-rpm-ffi/test/test_rpm.rb new file mode 100644 index 0000000..62304bc --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_rpm.rb @@ -0,0 +1,35 @@ +require File.join(File.dirname(__FILE__), 'helper') + +class RPMRPMTests < Minitest::Test + def test_enum + assert RPM::TAG[:not_found] + end + + def test_compat + # puts RPM::LOG_ALERT + # assert_raise(NameError) { RPM::LOG_ALERT } + + # require 'rpm/compat' + # Nothing should be raised by the following statement + RPM::LOG_ALERT + assert_equal RPM::LOG_ALERT, RPM::LOG[:alert] + end + + def test_iterator + RPM.transaction do |t| + assert_kind_of RPM::Transaction, t + # t.each do |pkg| + # puts pkg[:name] + # end + end + end + + def test_macro_read + assert_equal '/usr', RPM['_usr'] + end + + def test_macro_write + RPM['hoge'] = 'hoge' + assert_equal(RPM['hoge'], 'hoge') + end +end # class RPM_RPM_Tests < Test::Unit::TestCase diff --git a/locallibs/ruby-rpm-ffi/test/test_transaction.rb b/locallibs/ruby-rpm-ffi/test/test_transaction.rb new file mode 100644 index 0000000..1eb35c9 --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_transaction.rb @@ -0,0 +1,156 @@ +require_relative('helper') +require 'tmpdir' +require 'pathname' + +class RPMTransactionTests < Minitest::Test + PACKAGE_FILENAME = 'simple-1.0-0.i586.rpm'.freeze + + def test_flags + RPM.transaction do |t| + assert_equal RPM::TRANS_FLAG_NONE, t.flags + t.flags = RPM::TRANS_FLAG_TEST + assert_equal RPM::TRANS_FLAG_TEST, t.flags + end + end + + def test_iterator + RPM.transaction do |t| + it = t.init_iterator(nil, nil) + assert_kind_of RPM::MatchIterator, it + # assert it.count > 0 + end + + RPM.transaction do |t| + it = t.init_iterator(nil, nil) + it.regexp(:name, :glob, '*audio*') + it.each do |pkg| + assert pkg.name.include?('audio'), "'#{pkg.name}' contains 'audio'" + end + end + end + + # FIXME: this is not working + def test_iterator_version + RPM.transaction do |t| + it = t.init_iterator(nil, nil) + it.version(RPM::Version.new('2.1')) + it.each do |sig| + # FIXME: check that this worked + end + end + end + + def test_basic_transaction_setters + Dir.mktmpdir do |dir| + RPM.transaction do |t| + assert_equal '/', t.root_dir + t.root_dir = dir + assert_equal dir + '/', t.root_dir + end + end + + Dir.mktmpdir do |dir| + RPM.transaction(dir) do |t| + assert_equal dir + '/', t.root_dir + end + end + end + + def test_test_flag_install + pkg = RPM::Package.open(fixture(PACKAGE_FILENAME)) + + Dir.mktmpdir do |dir| + RPM.transaction(dir) do |t| + t.flags = RPM::TRANS_FLAG_TEST + t.install(pkg, fixture(PACKAGE_FILENAME)) + t.commit + + rpmdb_file = RPM::C.rpmvercmp(RPM::C.RPMVERSION, '4.16.0') >= 0 ? 'rpmdb.sqlite' : 'Packages' + + assert File.exist?(File.join(dir, RPM['_dbpath'], rpmdb_file)), 'rpm db exists' + assert !File.exist?('/usr/share/simple/README'), "package #{pkg} was not installed" + ensure + # Force close so that RPM does not try to do it + # when the tmpdir is deleted + t.db.close + end + end + end + + def test_install_and_remove + pkg = RPM::Package.open(fixture(PACKAGE_FILENAME)) + + Dir.mktmpdir do |dir| + RPM.transaction(dir) do |t| + begin + t.install(pkg, fixture(PACKAGE_FILENAME)) + t.commit + + rpmdb_file = RPM::C.rpmvercmp(RPM::C.RPMVERSION, '4.16.0') >= 0 ? 'rpmdb.sqlite' : 'Packages' + + assert File.exist?(File.join(dir, RPM['_dbpath'], rpmdb_file)), 'rpm db exists' + assert File.exist?(File.join(dir, '/usr/share/simple/README')), "package #{pkg} should be installed" + ensure + # Force close so that RPM does not try to do it + # when the tmpdir is deleted + t.db.close + end + end + + skip("Commit hangs on package delete") + + RPM.transaction(dir) do |t| + begin + assert_raises TypeError do + t.delete(Object.new) + end + + t.delete(pkg) + t.order + t.clean + t.commit + + assert !File.exist?(File.join(dir, '/usr/share/simple/README')), "package #{pkg} should not be installed" + ensure + # Force close so that RPM does not try to do it + # when the tmpdir is deleted + t.db.close + end + end + end + end + + def test_install_with_custom_callback + pkg = RPM::Package.open(fixture(PACKAGE_FILENAME)) + + Dir.mktmpdir do |dir| + RPM.transaction(dir) do |t| + begin + t.install(pkg, fixture(PACKAGE_FILENAME)) + + t.check do |problem| + STDERR.puts "Problem: #{problem}" + end + + t.order + t.clean + + t.commit do |data| + next case data.type + when :inst_open_file then + @f = File.open(data.key, 'r') + when :inst_close_file then @f.close + end + end + + assert File.exist?(File.join(dir, '/usr/share/simple/README')), + "package #{pkg} should be installed" + ensure + # Force close so that RPM does not try to do it + # when the tmpdir is deleted + t.db.close + end + end + end + end +end diff --git a/locallibs/ruby-rpm-ffi/test/test_version.rb b/locallibs/ruby-rpm-ffi/test/test_version.rb new file mode 100644 index 0000000..3dfe1fa --- /dev/null +++ b/locallibs/ruby-rpm-ffi/test/test_version.rb @@ -0,0 +1,64 @@ +require File.join(File.dirname(__FILE__), 'helper') + +class RPMVersionTests < Minitest::Test + def setup + @a = RPM::Version.new('1.0.0-0.1m') + @b = RPM::Version.new('0.9.0-1m') + @c = RPM::Version.new('1.0.0-0.11m') + @d = RPM::Version.new('0.9.0-1m', 1) + end + + def test_parse_evr + assert_equal [23, '1.0.3', '1suse'], + RPM::Version.parse_evr('23:1.0.3-1suse') + assert_equal [nil, '1.0', nil], + RPM::Version.parse_evr('1.0') + assert_equal [nil, '2.0', '3'], + RPM::Version.parse_evr('2.0-3') + end + + def test_version_compare + assert(@a > @b) + assert(@a < @c) + assert(@a < @d) + end + + def test_version_newer? + assert(@a.newer?(@b)) + assert(@c.newer?(@a)) + assert(@d.newer?(@a)) + assert(!@a.newer?(@a)) + end + + def test_version_older? + assert(@b.older?(@a)) + assert(@a.older?(@c)) + assert(@a.older?(@d)) + assert(!@a.older?(@a)) + end + + def test_vre + assert_equal('0.9.0', @d.v) + assert_equal('1m', @d.r) + assert_equal(1, @d.e) + end + + def test_to_s + assert_equal('0.9.0-1m', @b.to_s) + assert_equal('0.9.0-1m', @d.to_s) + end + + def test_to_vre + assert_equal('0.9.0-1m', @b.to_vre) + assert_equal('1:0.9.0-1m', @d.to_vre) + end + + def test_epoch_none_zero + v1 = RPM::Version.new('1-2') + v2 = RPM::Version.new('0:1-2') + assert_nil v1.e + assert_equal(0, v2.e) + assert(v1 == v2) + assert_equal(v1.hash, v2.hash) + end +end