├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitlab-ci.yml ├── Gemfile ├── History.md ├── LICENSE ├── README.md ├── Rakefile ├── apt-pkg.gemspec ├── ext └── apt_pkg │ ├── apt-pkg.cpp │ ├── apt-pkg.h │ ├── configuration.cpp │ ├── configuration.h │ ├── extconf.rb │ ├── pkgcache.cpp │ └── pkgcache.h ├── lib └── debian │ ├── apt_pkg.rb │ └── apt_pkg │ ├── gem_version.rb │ └── package.rb └── test ├── apt_pkg_cache_not_init_integration.rb ├── apt_pkg_configuration_test.rb ├── apt_pkg_test.rb ├── debian └── apt_pkg │ ├── package_test.rb │ └── pkg_cache_test.rb └── test_helper.rb /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [**] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | [**.rb] 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [**.{c,cc,cpp,h,hpp}] 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [Makefile] 17 | indent_style = tab 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 4 | on: 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | ruby: ['2.6', '2.7', '3.0', '3.1', '3.2'] 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Ruby 20 | uses: ruby/setup-ruby@v1 21 | with: 22 | bundler-cache: true 23 | ruby-version: ${{ matrix.ruby }} 24 | - name: Install libapt-pkg-dev 25 | run: sudo apt-get install libapt-pkg-dev 26 | - name: Install dependencies 27 | run: bundle install -j 3 28 | - name: Run tests 29 | run: bundle exec rake 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | html/ 3 | public/ 4 | *.gem 5 | Gemfile.lock 6 | .gdb_history 7 | Dockerfile 8 | docker-compose.yml 9 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | stages: 3 | - lint 4 | - test 5 | - doc 6 | 7 | cache: 8 | paths: 9 | - vendor/ 10 | 11 | before_script: 12 | - bundle config set path 'vendor' 13 | 14 | .tests: 15 | before_script: 16 | - apt-get update -qy 17 | - apt-get install -y libapt-pkg-dev 18 | - ruby -v 19 | - which ruby 20 | - gem install bundler --no-document 21 | - bundle install --jobs "$(nproc)" "${FLAGS[@]}" 22 | script: bundle exec rake 23 | stage: test 24 | 25 | test:3.0: 26 | extends: .tests 27 | image: 'ruby:3.0' 28 | 29 | test:3.1: 30 | extends: .tests 31 | image: 'ruby:3.1' 32 | 33 | test:3.2: 34 | extends: .tests 35 | image: 'ruby:3.2' 36 | 37 | lint: 38 | image: 'ruby:3.2-slim' 39 | before_script: 40 | - apt-get update -qy 41 | - apt-get install -y libapt-pkg-dev cppcheck 42 | - ruby -v 43 | - which ruby 44 | - gem install bundler --no-document 45 | - bundle install --jobs "$(nproc)" "${FLAGS[@]}" 46 | script: 47 | - bundle exec rake cppcheck 48 | stage: lint 49 | 50 | audit: 51 | image: 'ruby:3.2-slim' 52 | before_script: 53 | - apt-get update -qy 54 | - apt-get install -y git 55 | - gem install bundler bundler-audit --no-document 56 | - bundle install --jobs "$(nproc)" "${FLAGS[@]}" 57 | allow_failure: true 58 | script: 59 | - bundle-audit update 60 | - bundle-audit check 61 | stage: lint 62 | 63 | pages: 64 | image: 'ruby:3.2-slim' 65 | before_script: 66 | - gem install bundler --no-document 67 | - bundle install --jobs "$(nproc)" "${FLAGS[@]}" 68 | script: 69 | - bundle exec rake rdoc 70 | artifacts: 71 | paths: 72 | - public 73 | rules: 74 | - if: '$CI_COMMIT_BRANCH == "master"' 75 | stage: doc 76 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.5.0 / 2020-07-22 3 | ================== 4 | 5 | * Debian::AptPkg::PkgCache.pkg_names deprecated 6 | * Add all maintained Rubies on gitlab-ci 7 | * Init listing packages on cache 8 | * Quick fix gitlab ci 9 | * Add .gitlab-ci.yml 10 | * Rename lib/debian/apt_pkg/{version,gem_version}.rb 11 | * Update README 12 | * Tidy tests remove should 13 | * Debian::AptPkg.init returns a boolean 14 | * Fix mimitest warnings 15 | * Remove cppcheck on CI version conflict 16 | * Fix code lint 17 | * Fix CI and update Rubies 18 | * Fix libapt-pkg 2.1 compat 19 | * Update apt-pkg deps 20 | * Update doc Debian::AptPkg::InitError 21 | * README: Bundler is not needed 22 | * Use Debian::AptPkg::InitError instead of RuntimeError 23 | * Fix rb_mDebianAptPkgCache name 24 | 25 | 0.4.0 / 2016-10-06 26 | ================== 27 | 28 | * Raise RuntimeError instead of returning `nil` 29 | 30 | 0.3.0 / 2016-01-23 31 | ================== 32 | 33 | * Prefer prefix ++/-- operators for non-primitive types 34 | * Add Debian::AptPkg::PkgCache.update 35 | 36 | 0.2.0 / 2016-01-04 37 | ================== 38 | 39 | * Fix cache count methods when not init 40 | * Add init, init_{config,system} 41 | * Add PkgCache.is_multi_arch method 42 | 43 | 0.1.0 / 2015-12-20 44 | ================== 45 | 46 | * Change VERSION, APT_VERSION and LIBAPT_PKG_VERSION 47 | * Add cache count methods 48 | * Fix rake lint task exit status 49 | * Fix syntax offences 50 | 51 | 0.0.4 / 2015-12-19 52 | ================== 53 | 54 | * Simple search with `Debian::AptPkg::PkgCache.pkg_names("vim")` 55 | * Documentation update 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014-2020 Laurent Arnoud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby interface to apt-pkg 2 | 3 | Goal of this project is to have a proper Ruby binding to APT like in 4 | [Python](https://tracker.debian.org/pkg/python-apt). 5 | 6 | Currently install, remove packages commands are **not** implemented. 7 | 8 | ## INSTALL 9 | 10 | ``` 11 | apt install build-essential ruby-dev libapt-pkg-dev (>= 1.0) 12 | gem install apt-pkg 13 | ``` 14 | 15 | ## USING 16 | 17 | Basic usage: 18 | 19 | ``` ruby 20 | require 'debian/apt_pkg' 21 | 22 | # Initialize the configuration and system of apt 23 | Debian::AptPkg.init 24 | 25 | # Update the index files used by the cache 26 | Debian::AptPkg::PkgCache.update 27 | 28 | # List packages stored in the cache 29 | Debian::AptPkg::PkgCache.packages 30 | 31 | # List installed packages 32 | Debian::AptPkg::PkgCache.packages.select { |pkg| pkg.is_installed } 33 | ``` 34 | 35 | [Documentation](http://www.rubydoc.info/gems/apt-pkg) 36 | 37 | ## BUILD 38 | 39 | ``` console 40 | rake compile 41 | ``` 42 | 43 | ## TEST 44 | 45 | ``` console 46 | rake test 47 | ``` 48 | 49 | ## LICENSE 50 | 51 | The MIT License 52 | 53 | Copyright (c) 2014-2020 Laurent Arnoud 54 | 55 | --- 56 | [![Build](https://img.shields.io/gitlab/pipeline/spkdev/ruby-apt-pkg/master)](https://gitlab.com/spkdev/ruby-apt-pkg/-/commits/master) 57 | [![Version](https://img.shields.io/gem/v/apt-pkg.svg)](https://rubygems.org/gems/apt-pkg) 58 | [![Documentation](https://img.shields.io/badge/doc-rubydoc-blue.svg)](http://www.rubydoc.info/gems/apt-pkg) 59 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT "MIT") 60 | [![Project status](https://img.shields.io/badge/status-experimental-red)](https://github.com/spk/ruby-apt-pkg) 61 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/extensiontask' 2 | require 'rake/testtask' 3 | require 'rdoc/task' 4 | 5 | Rake::ExtensionTask.new('apt_pkg') 6 | 7 | namespace :test do 8 | Rake::TestTask.new :unit do |t| 9 | t.pattern = 'test/**/*_test.rb' 10 | end 11 | Rake::Task['unit'].prerequisites << :clean 12 | Rake::Task['unit'].prerequisites << :compile 13 | 14 | Rake::TestTask.new :integration do |t| 15 | t.pattern = 'test/**/*_integration.rb' 16 | end 17 | Rake::Task['integration'].prerequisites << :clean 18 | Rake::Task['integration'].prerequisites << :compile 19 | end 20 | 21 | RDoc::Task.new do |rd| 22 | rd.main = 'README.md' 23 | rd.rdoc_files.include('README.md', 'ext/**/*.cpp', 'lib/**/*.rb') 24 | rd.rdoc_dir = 'public' 25 | rd.options << '--all' 26 | rd.title = 'ruby-apt-pkg' 27 | end 28 | 29 | desc 'cppcheck - Tool for static C/C++ code analysis' 30 | task :cppcheck do 31 | cppcheck_opts = '--error-exitcode=1 --quiet --enable=all --inconclusive' \ 32 | ' --suppress=missingIncludeSystem --inline-suppr' \ 33 | ' --template "[{file}:{line}] {severity} ({id}): {message}"' 34 | sh("cppcheck #{cppcheck_opts} ext/apt_pkg") do |ok, res| 35 | ok || puts("lint error (status = #{res.exitstatus})") 36 | exit(res.exitstatus) 37 | end 38 | end 39 | 40 | task default: ['test:unit', 'test:integration'] 41 | task test: ['test:unit'] 42 | -------------------------------------------------------------------------------- /apt-pkg.gemspec: -------------------------------------------------------------------------------- 1 | version_file = 'lib/debian/apt_pkg/gem_version' 2 | require File.expand_path("../#{version_file}", __FILE__) 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'apt-pkg' 6 | s.version = Debian::AptPkg::VERSION 7 | 8 | s.authors = ['Laurent Arnoud'] 9 | s.email = 'laurent@spkdev.net' 10 | 11 | s.description = 'Ruby interface to Debian apt-pkg' 12 | s.summary = 'Ruby interface to Debian libapt-pkg' 13 | s.homepage = 'https://github.com/spk/ruby-apt-pkg' 14 | s.license = 'MIT' 15 | 16 | s.extensions = ['ext/apt_pkg/extconf.rb'] 17 | s.extra_rdoc_files = Dir['*.md', 'ext/**/*.cpp'] 18 | s.files = Dir['LICENSE', 'README.md', 'History.md', 'Gemfile', 'lib/**/*.rb', 19 | 'ext/**/*', 'test/**/*'] 20 | s.rdoc_options = ['--charset=UTF-8'] 21 | s.require_paths = ['lib'] 22 | s.add_development_dependency('rake', '~> 13.0') 23 | s.add_development_dependency('rake-compiler', '~> 1.0') 24 | s.add_development_dependency('minitest', '~> 5.13') 25 | end 26 | -------------------------------------------------------------------------------- /ext/apt_pkg/apt-pkg.cpp: -------------------------------------------------------------------------------- 1 | #include "apt-pkg.h" 2 | #include "configuration.h" 3 | #include "pkgcache.h" 4 | 5 | /* 6 | * call-seq: init() -> bool 7 | * 8 | * Shorthand for doing init_config() and init_system(). 9 | * 10 | * Debian::AptPkg.init # => true 11 | * 12 | **/ 13 | static VALUE 14 | init(VALUE self) 15 | { 16 | int res = pkgInitConfig(*_config) && pkgInitSystem(*_config, _system); 17 | return INT2BOOL(res); 18 | } 19 | 20 | /* 21 | * call-seq: init_config() -> bool 22 | * 23 | * Load the default configuration and the config file. 24 | * 25 | * Debian::AptPkg.init_config # => false 26 | * 27 | **/ 28 | static VALUE 29 | init_config(VALUE self) 30 | { 31 | int res = pkgInitConfig(*_config); 32 | return INT2BOOL(res); 33 | } 34 | 35 | /* 36 | * call-seq: init_system() -> bool 37 | * 38 | * Construct the apt_pkg system. 39 | * 40 | * Debian::AptPkg.init_system # => false 41 | * 42 | **/ 43 | static VALUE 44 | init_system(VALUE self) 45 | { 46 | int res = pkgInitSystem(*_config, _system); 47 | return INT2BOOL(res); 48 | } 49 | 50 | /* 51 | * call-seq: cmp_version(pkg_version_a, pkg_version_b) -> int 52 | * 53 | * Compare the given versions. 54 | * 55 | * Return a strictly negative value if 'a' is smaller than 'b', 0 if they 56 | * are equal, and a strictly positive value if 'a' is larger than 'b'. 57 | * 58 | * Debian::AptPkg.cmp_version('1.1', '1.0') # => 1 59 | * Debian::AptPkg.cmp_version('1.0', '1.0') # => 0 60 | * Debian::AptPkg.cmp_version('1.0', '1.1') # => -1 61 | * 62 | **/ 63 | static VALUE 64 | cmp_version(VALUE self, VALUE pkg_version_a, VALUE pkg_version_b) 65 | { 66 | int res = debVS.CmpVersion(StringValuePtr(pkg_version_a), 67 | StringValuePtr(pkg_version_b)); 68 | return INT2FIX(res); 69 | } 70 | 71 | /* 72 | * call-seq: check_dep(pkg_version_a, op, pkg_version_b) -> bool 73 | * 74 | * Compare the given versions with an operator. 75 | * 76 | * Params: 77 | * 78 | * +pkg_version_a+:: Version to compare from. 79 | * +op+:: See operators const or string (<, >, <=, >=, =) 80 | * +pkg_version_b+:: Version to compare to. 81 | * 82 | * Debian::AptPkg.check_dep('1', '<', '2') # => true 83 | * Debian::AptPkg.check_dep('1', Debian::AptPkg::NOT_EQUALS, '2') # => true 84 | * 85 | **/ 86 | static VALUE 87 | check_dep(VALUE self, VALUE pkg_version_a, VALUE cmp_type, VALUE pkg_version_b) 88 | { 89 | unsigned int op = 0; 90 | if (TYPE(cmp_type) == T_FIXNUM) { 91 | op = NUM2INT(cmp_type); 92 | } else { 93 | const char *op_str = StringValuePtr(cmp_type); 94 | if (strcmp(op_str, ">") == 0) 95 | op_str = ">>"; 96 | if (strcmp(op_str, "<") == 0) 97 | op_str = "<<"; 98 | if (*debListParser::ConvertRelation(op_str, op) != 0) { 99 | rb_raise(rb_eArgError, "Bad comparison operation"); 100 | return 0; 101 | } 102 | } 103 | int res = debVS.CheckDep(StringValuePtr(pkg_version_a), op, 104 | StringValuePtr(pkg_version_b)); 105 | return INT2BOOL(res); 106 | } 107 | 108 | /* 109 | * call-seq: uri_to_filename(uri) -> string 110 | * 111 | * Return a filename which can be used to store the file. 112 | * 113 | * Debian::AptPkg.uri_to_filename('http://debian.org/index.html') # => 'debian.org_index.html' 114 | * 115 | **/ 116 | static VALUE 117 | uri_to_filename(VALUE self, VALUE uri) 118 | { 119 | return rb_str_new2(URItoFileName(StringValuePtr(uri)).c_str()); 120 | } 121 | 122 | /* 123 | * call-seq: upstream_version(ver) -> string 124 | * 125 | * Return the upstream version for the Debian package version given by version. 126 | * 127 | * Debian::AptPkg.upstream_version('3.4.15-1+b1') # => '3.4.15' 128 | * 129 | **/ 130 | static VALUE 131 | upstream_version(VALUE self, VALUE ver) 132 | { 133 | return rb_str_new2(debVS.UpstreamVersion(StringValuePtr(ver)).c_str()); 134 | } 135 | 136 | /* 137 | * call-seq: time_to_str(secondes) -> string 138 | * 139 | * Format a given duration in human-readable manner. 140 | * 141 | * Debian::AptPkg.time_to_str(3601) # => '1h 0min 1s' 142 | * 143 | **/ 144 | static VALUE 145 | time_to_str(VALUE self, VALUE secondes) 146 | { 147 | return rb_str_new2(TimeToStr(NUM2INT(secondes)).c_str()); 148 | } 149 | 150 | /* 151 | * call-seq: size_to_str(size) -> string 152 | * 153 | * Return a string describing the size in a human-readable manner. 154 | * 155 | * Debian::AptPkg.size_to_str(10000) # => '10.0 k' 156 | * 157 | **/ 158 | static VALUE 159 | size_to_str(VALUE self, VALUE size) 160 | { 161 | return rb_str_new2(SizeToStr(NUM2INT(size)).c_str()); 162 | } 163 | 164 | /* 165 | * call-seq: string_to_bool(text) -> int 166 | * 167 | * Parse the string input and return a boolean. 168 | * 169 | * Debian::AptPkg.string_to_bool('yes') # => true 170 | * Debian::AptPkg.string_to_bool('no') # => false 171 | * Debian::AptPkg.string_to_bool('no-recognized') # => false 172 | * 173 | **/ 174 | static VALUE 175 | string_to_bool(VALUE self, VALUE text) 176 | { 177 | return INT2BOOL(StringToBool(StringValuePtr(text)) == 1); 178 | } 179 | 180 | /* 181 | * call-seq: check_domain_list(host, list) -> bool 182 | * 183 | * See if the host name given by host is one of the domains given. 184 | * 185 | * Debian::AptPkg.check_domain_list("alioth.debian.org", "debian.net,debian.org") # => true 186 | * 187 | **/ 188 | static VALUE 189 | check_domain_list(VALUE self, VALUE host, VALUE list) 190 | { 191 | int res = CheckDomainList(StringValuePtr(host), StringValuePtr(list)); 192 | return INT2BOOL(res); 193 | } 194 | 195 | void 196 | // cppcheck-suppress[unusedFunction,unmatchedSuppression] 197 | Init_apt_pkg() 198 | { 199 | VALUE rb_mDebian = rb_define_module("Debian"); 200 | VALUE rb_mDebianAptPkg = rb_define_module_under(rb_mDebian, "AptPkg"); 201 | 202 | rb_define_singleton_method(rb_mDebianAptPkg, "init", 203 | RUBY_METHOD_FUNC(init), 0); 204 | rb_define_singleton_method(rb_mDebianAptPkg, "init_config", 205 | RUBY_METHOD_FUNC(init_config), 0); 206 | rb_define_singleton_method(rb_mDebianAptPkg, "init_system", 207 | RUBY_METHOD_FUNC(init_system), 0); 208 | 209 | rb_define_singleton_method(rb_mDebianAptPkg, "uri_to_filename", 210 | RUBY_METHOD_FUNC(uri_to_filename), 1); 211 | rb_define_singleton_method(rb_mDebianAptPkg, "time_to_str", 212 | RUBY_METHOD_FUNC(time_to_str), 1); 213 | rb_define_singleton_method(rb_mDebianAptPkg, "size_to_str", 214 | RUBY_METHOD_FUNC(size_to_str), 1); 215 | rb_define_singleton_method(rb_mDebianAptPkg, "string_to_bool", 216 | RUBY_METHOD_FUNC(string_to_bool), 1); 217 | rb_define_singleton_method(rb_mDebianAptPkg, "check_domain_list", 218 | RUBY_METHOD_FUNC(check_domain_list), 2); 219 | rb_define_singleton_method(rb_mDebianAptPkg, "cmp_version", 220 | RUBY_METHOD_FUNC(cmp_version), 2); 221 | rb_define_singleton_method(rb_mDebianAptPkg, "check_dep", 222 | RUBY_METHOD_FUNC(check_dep), 3); 223 | rb_define_singleton_method(rb_mDebianAptPkg, "upstream_version", 224 | RUBY_METHOD_FUNC(upstream_version), 1); 225 | 226 | /* Represents less equal operator. */ 227 | rb_define_const(rb_mDebianAptPkg, "LESS_EQ", INT2FIX(pkgCache::Dep::LessEq)); 228 | /* Represents greater equal operator. */ 229 | rb_define_const(rb_mDebianAptPkg, "GREATER_EQ", 230 | INT2FIX(pkgCache::Dep::GreaterEq)); 231 | /* Represents less operator. */ 232 | rb_define_const(rb_mDebianAptPkg, "LESS", INT2FIX(pkgCache::Dep::Less)); 233 | /* Represents greater operator. */ 234 | rb_define_const(rb_mDebianAptPkg, "GREATER", INT2FIX(pkgCache::Dep::Greater)); 235 | /* Represents equals operator. */ 236 | rb_define_const(rb_mDebianAptPkg, "EQUALS", INT2FIX(pkgCache::Dep::Equals)); 237 | /* Represents not equals operator. */ 238 | rb_define_const(rb_mDebianAptPkg, "NOT_EQUALS", 239 | INT2FIX(pkgCache::Dep::NotEquals)); 240 | 241 | /* Represents the version of apt. */ 242 | rb_define_const(rb_mDebianAptPkg, "APT_VERSION", rb_str_new2(pkgVersion)); 243 | /* Represents the version of apt_pkg library. */ 244 | rb_define_const(rb_mDebianAptPkg, "LIBAPT_PKG_VERSION", 245 | rb_str_new2(pkgLibVersion)); 246 | 247 | init_apt_pkg_configuration(); 248 | init_apt_pkg_pkgcache(); 249 | } 250 | -------------------------------------------------------------------------------- /ext/apt_pkg/apt-pkg.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* from '' */ 10 | #define INT2BOOL(x) ((x) ? Qtrue : Qfalse) 11 | 12 | using namespace std; 13 | 14 | /* function prototypes */ 15 | extern "C" void Init_apt_pkg(); 16 | /* String functions */ 17 | static VALUE uri_to_filename(VALUE self, VALUE uri); 18 | static VALUE time_to_str(VALUE self, VALUE secondes); 19 | static VALUE size_to_str(VALUE self, VALUE size); 20 | static VALUE string_to_bool(VALUE self, VALUE text); 21 | static VALUE check_domain_list(VALUE self, VALUE host, VALUE list); 22 | /* Versioning */ 23 | static VALUE cmp_version(VALUE self, VALUE pkg_version_a, VALUE pkg_version_b); 24 | static VALUE check_dep(VALUE self, VALUE pkg_version_a, VALUE cmp_type, 25 | VALUE pkg_version_b); 26 | static VALUE upstream_version(VALUE self, VALUE ver); 27 | -------------------------------------------------------------------------------- /ext/apt_pkg/configuration.cpp: -------------------------------------------------------------------------------- 1 | #include "configuration.h" 2 | 3 | /* 4 | * call-seq: architecture() -> string 5 | * 6 | * Return the native architecture for this system. 7 | * 8 | * Debian::AptPkg::Configuration.architecture # => "amd64" 9 | * 10 | **/ 11 | static VALUE 12 | architecture(VALUE self) 13 | { 14 | return rb_str_new2(_config->Find("APT::Architecture").c_str()); 15 | } 16 | 17 | /* 18 | * call-seq: architectures() -> array 19 | * 20 | * Return the list of architectures supported on this system. 21 | * 22 | * Debian::AptPkg::Configuration.architectures # => ["amd64"] 23 | * 24 | **/ 25 | static VALUE 26 | architectures(VALUE self) 27 | { 28 | VALUE result = rb_ary_new(); 29 | std::vector < std::string > arches = APT::Configuration::getArchitectures(); 30 | std::vector < std::string >::const_iterator I; 31 | for (I = arches.begin(); I != arches.end(); ++I) { 32 | rb_ary_push(result, rb_str_new2((*I).c_str())); 33 | } 34 | return result; 35 | } 36 | 37 | /* 38 | * call-seq: check_architecture(arch) -> bool 39 | * 40 | * Are we interested in the given Architecture. 41 | * 42 | * Debian::AptPkg::Configuration.check_architecture("all") # => true 43 | * 44 | **/ 45 | static VALUE 46 | check_architecture(VALUE self, VALUE arch) 47 | { 48 | int res = APT::Configuration::checkArchitecture(StringValuePtr(arch)); 49 | return INT2BOOL(res); 50 | } 51 | 52 | /* 53 | * call-seq: languages() -> array 54 | * 55 | * Return the list of languages code. 56 | * 57 | * Params: 58 | * 59 | * +all+:: All languages code or short for false. 60 | * 61 | * Debian::AptPkg::Configuration.languages # => ["en", "none", "fr"] 62 | * Debian::AptPkg::Configuration.languages(false) # => ["en"] 63 | * 64 | **/ 65 | static VALUE 66 | languages(int argc, VALUE *argv, VALUE self) 67 | { 68 | VALUE all; 69 | rb_scan_args(argc, argv, "01", &all); 70 | VALUE result = rb_ary_new(); 71 | std::vector < std::string > const langs = 72 | APT::Configuration::getLanguages(all); 73 | std::vector < std::string >::const_iterator I; 74 | for (I = langs.begin(); I != langs.end(); ++I) { 75 | rb_ary_push(result, rb_str_new2((*I).c_str())); 76 | } 77 | return result; 78 | } 79 | 80 | /* 81 | * call-seq: check_language(lang, all) -> bool 82 | * 83 | * Are we interested in the given language. 84 | * 85 | * Debian::AptPkg::Configuration.check_language("fr") # => true 86 | * 87 | **/ 88 | static VALUE 89 | check_language(int argc, VALUE *argv, VALUE self) 90 | { 91 | if (argc > 2 || argc == 0) { 92 | rb_raise(rb_eArgError, "wrong number of arguments"); 93 | } 94 | VALUE lang, all; 95 | rb_scan_args(argc, argv, "11", &lang, &all); 96 | int res = APT::Configuration::checkLanguage(StringValuePtr(lang), all); 97 | return INT2BOOL(res); 98 | } 99 | 100 | /* 101 | * call-seq: compressors() -> array 102 | * 103 | * Return the list of compressors supported on this system. 104 | * 105 | * Debian::AptPkg::Configuration.compressors # => ["gz"] 106 | * 107 | **/ 108 | static VALUE 109 | compressors(VALUE self) 110 | { 111 | VALUE result = rb_ary_new(); 112 | std::vector < std::string > cmps = APT::Configuration::getCompressionTypes(); 113 | std::vector < std::string >::const_iterator I; 114 | for (I = cmps.begin(); I != cmps.end(); ++I) { 115 | rb_ary_push(result, rb_str_new2((*I).c_str())); 116 | } 117 | return result; 118 | } 119 | 120 | /* 121 | * call-seq: config_find(name, default_key = '') -> string 122 | * 123 | * Return the value stored at the option named key, or the value given by the 124 | * string default if the option in question is not set. 125 | * 126 | * Params: 127 | * 128 | * +name+:: Key name. 129 | * +default_key+:: Default key when config option not set. 130 | * 131 | * Debian::AptPkg::Configuration.config_find('Dir::Etc::main') # => "apt.conf" 132 | * 133 | **/ 134 | static VALUE 135 | config_find(int argc, VALUE *argv, VALUE self) 136 | { 137 | if (argc > 2 || argc == 0) { 138 | rb_raise(rb_eArgError, "wrong number of arguments"); 139 | } 140 | VALUE name, default_key; 141 | rb_scan_args(argc, argv, "11", &name, &default_key); 142 | if (NIL_P(default_key)) 143 | default_key = rb_str_new2(""); 144 | return rb_str_new2(_config->Find(StringValuePtr(name), 145 | StringValuePtr(default_key)).c_str()); 146 | } 147 | 148 | /* 149 | * call-seq: config_find_file(name, default_key = '') -> string 150 | * 151 | * Locate the given key using find() and return the path to the file/directory. 152 | * This uses a special algorithms which moves upwards in the configuration space 153 | * and prepends the values of the options to the result. These methods are 154 | * generally used for the options stored in the ‘Dir’ section of the 155 | * configuration. 156 | * 157 | * Params: 158 | * 159 | * +name+:: Key name. 160 | * +default_key+:: Default key when config option not set. 161 | * 162 | * Debian::AptPkg::Configuration.config_find_file('Dir::Etc::main') # => "/etc/apt/apt.conf" 163 | * 164 | **/ 165 | static VALUE 166 | config_find_file(int argc, VALUE *argv, VALUE self) 167 | { 168 | if (argc > 2 || argc == 0) { 169 | rb_raise(rb_eArgError, "wrong number of arguments"); 170 | } 171 | VALUE name, default_key; 172 | rb_scan_args(argc, argv, "11", &name, &default_key); 173 | if (NIL_P(default_key)) 174 | default_key = rb_str_new2(""); 175 | return rb_str_new2(_config->FindFile(StringValuePtr(name), 176 | StringValuePtr(default_key)).c_str()); 177 | } 178 | 179 | void 180 | init_apt_pkg_configuration() 181 | { 182 | VALUE rb_mDebian = rb_define_module("Debian"); 183 | VALUE rb_mDebianAptPkg = rb_define_module_under(rb_mDebian, "AptPkg"); 184 | VALUE rb_mDebianAptPkgConfiguration = 185 | rb_define_module_under(rb_mDebianAptPkg, "Configuration"); 186 | 187 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, "architecture", 188 | RUBY_METHOD_FUNC(architecture), 0); 189 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, "architectures", 190 | RUBY_METHOD_FUNC(architectures), 0); 191 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, 192 | "check_architecture", 193 | RUBY_METHOD_FUNC(check_architecture), 1); 194 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, "languages", 195 | RUBY_METHOD_FUNC(languages), -1); 196 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, "check_language", 197 | RUBY_METHOD_FUNC(check_language), -1); 198 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, "compressors", 199 | RUBY_METHOD_FUNC(compressors), 0); 200 | 201 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, "config_find", 202 | RUBY_METHOD_FUNC(config_find), -1); 203 | rb_define_singleton_method(rb_mDebianAptPkgConfiguration, 204 | "config_find_file", 205 | RUBY_METHOD_FUNC(config_find_file), -1); 206 | } 207 | -------------------------------------------------------------------------------- /ext/apt_pkg/configuration.h: -------------------------------------------------------------------------------- 1 | #include "apt-pkg.h" 2 | #include 3 | #include 4 | 5 | void init_apt_pkg_configuration(); 6 | -------------------------------------------------------------------------------- /ext/apt_pkg/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | have_library('stdc++') 3 | have_library('apt-pkg') 4 | dir_config('apt_pkg') 5 | create_makefile('apt_pkg') 6 | -------------------------------------------------------------------------------- /ext/apt_pkg/pkgcache.cpp: -------------------------------------------------------------------------------- 1 | #include "pkgcache.h" 2 | 3 | static VALUE e_mDebianAptPkgInitError, rb_cPackage, rb_cVersion; 4 | 5 | /* 6 | * private 7 | */ 8 | bool 9 | config_system_initialized() 10 | { 11 | string const arch = _config->Find("APT::Architecture"); 12 | if (arch.empty()) { 13 | return false; 14 | } 15 | return true; 16 | } 17 | 18 | /* 19 | * call-seq: gen_caches() -> bool 20 | * 21 | * Call the main cache generator. 22 | * 23 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 24 | * configured. 25 | * 26 | * Debian::AptPkg::PkgCache.gen_caches # => false 27 | * 28 | **/ 29 | static VALUE 30 | gen_caches(VALUE self) 31 | { 32 | if (!config_system_initialized()) { 33 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 34 | } 35 | pkgCacheFile CacheFile; 36 | int res = CacheFile.BuildCaches(NULL, true); 37 | return INT2BOOL(res); 38 | } 39 | 40 | /* 41 | * call-seq: update() -> bool 42 | * 43 | * Update the index files used by the cache. 44 | * 45 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 46 | * configured. 47 | * 48 | * Debian::AptPkg::PkgCache.update # => false 49 | * 50 | **/ 51 | static VALUE 52 | update(VALUE self) 53 | { 54 | if (!config_system_initialized()) { 55 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 56 | } 57 | pkgCacheFile CacheFile; 58 | // Get the source list 59 | if (CacheFile.BuildSourceList() == false) { 60 | return Qnil; 61 | } 62 | pkgAcquireStatus *Stat(NULL); 63 | pkgSourceList *List = CacheFile.GetSourceList(); 64 | int res = ListUpdate(*Stat, *List); 65 | return INT2BOOL(res); 66 | } 67 | 68 | /* 69 | * call-seq: is_multi_arch() -> bool 70 | * 71 | * An attribute determining whether the cache supports multi-arch. 72 | * 73 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 74 | * configured. 75 | * 76 | * Debian::AptPkg::PkgCache.is_multi_arch # => false 77 | * 78 | **/ 79 | static VALUE 80 | is_multi_arch(VALUE self) 81 | { 82 | if (!config_system_initialized()) { 83 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 84 | } 85 | pkgCacheFile CacheFile; 86 | pkgCache *Cache = CacheFile.GetPkgCache(); 87 | if (Cache == NULL) { 88 | return Qnil; 89 | } 90 | int res = Cache->MultiArchCache(); 91 | return INT2BOOL(res); 92 | } 93 | 94 | /* 95 | * call-seq: packages() -> array 96 | * 97 | * A list of Debian::AptPkg::Package objects stored in the cache 98 | * 99 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 100 | * configured. 101 | * 102 | * Debian::AptPkg::PkgCache.packages # => [#] 103 | * 104 | **/ 105 | static VALUE 106 | packages(VALUE self) 107 | { 108 | if (!config_system_initialized()) { 109 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 110 | } 111 | VALUE result = rb_ary_new(); 112 | pkgCacheFile CacheFile; 113 | pkgCache *Cache = CacheFile.GetPkgCache(); 114 | if (Cache == NULL) { 115 | return Qnil; 116 | } 117 | for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); not Pkg.end(); ++Pkg) { 118 | VALUE current_version; 119 | VALUE current_version_section; 120 | if (Pkg->CurrentVer == 0) { 121 | current_version = Qnil; 122 | } else { 123 | if (Pkg.CurrentVer().Section() != NULL) { 124 | current_version_section = rb_str_new2(Pkg.CurrentVer().Section()); 125 | } else { 126 | current_version_section = Qnil; 127 | } 128 | current_version = rb_struct_new(rb_cVersion, 129 | rb_str_new2(Pkg.CurrentVer().ParentPkg().Name()), 130 | rb_str_new2(Pkg.CurrentVer().VerStr()), 131 | current_version_section, 132 | rb_str_new2(Pkg.CurrentVer().Arch()), 133 | INT2FIX(Pkg.CurrentVer()->Size), 134 | INT2FIX(Pkg.CurrentVer()->InstalledSize), 135 | INT2FIX(Pkg.CurrentVer()->Hash), 136 | INT2FIX(Pkg.CurrentVer()->ID), 137 | INT2FIX(Pkg.CurrentVer()->Priority) 138 | ); 139 | } 140 | VALUE rb_cPackage_args[7]; 141 | rb_cPackage_args[0] = INT2FIX(Pkg->ID); 142 | rb_cPackage_args[1] = rb_str_new2(Pkg.Name()); 143 | rb_cPackage_args[2] = rb_str_new2(Pkg.FullName().c_str()); 144 | rb_cPackage_args[3] = rb_str_new2(Pkg.Arch()); 145 | rb_cPackage_args[4] = INT2BOOL((Pkg->Flags & pkgCache::Flag::Essential) != 0); 146 | rb_cPackage_args[5] = INT2BOOL((Pkg->Flags & pkgCache::Flag::Important) != 0); 147 | rb_cPackage_args[6] = current_version; 148 | rb_ary_push(result, rb_class_new_instance(7, 149 | rb_cPackage_args, 150 | rb_cPackage 151 | )); 152 | } 153 | return result; 154 | } 155 | 156 | /* 157 | * call-seq: pkg_names(name) -> array, nil 158 | * 159 | * *Deprecated and will removed in 0.6.0* 160 | * 161 | * List the names of all packages in the system. 162 | * 163 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 164 | * configured. 165 | * 166 | * Debian::AptPkg::PkgCache.pkg_names('gcolor2') # => ["gcolor2"] 167 | * 168 | **/ 169 | static VALUE 170 | pkg_names(int argc, VALUE *argv, VALUE self) 171 | { 172 | rb_warn("Debian::AptPkg::PkgCache.pkg_names is deprecated; " \ 173 | "use Debian::AptPkg::PkgCache.packages instead"); 174 | if (!config_system_initialized()) { 175 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 176 | } 177 | if (argc > 1 || argc == 0) { 178 | rb_raise(rb_eArgError, "You must give at least one search argument"); 179 | } 180 | VALUE name; 181 | rb_scan_args(argc, argv, "01", &name); 182 | if (NIL_P(name) || RSTRING_LEN(name) < 1) { 183 | rb_raise(rb_eArgError, "You must give at least one search pattern"); 184 | } 185 | VALUE result = rb_ary_new(); 186 | 187 | pkgCacheFile CacheFile; 188 | if (CacheFile.GetPkgCache() == 0) { 189 | return Qnil; 190 | } 191 | pkgCache::GrpIterator I = CacheFile.GetPkgCache()->GrpBegin(); 192 | 193 | const char *pkgname = StringValuePtr(name); 194 | for (; I.end() != true; ++I) { 195 | if (strncmp(I.Name(), pkgname, strlen(pkgname)) == 0) { 196 | rb_ary_push(result, rb_str_new2(I.Name())); 197 | } 198 | } 199 | return result; 200 | } 201 | 202 | /* 203 | * call-seq: package_count() -> int, nil 204 | * 205 | * The total number of packages available in the cache. 206 | * 207 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 208 | * configured. 209 | * 210 | * Debian::AptPkg::PkgCache.package_count # => 69511 211 | * 212 | **/ 213 | static VALUE 214 | package_count(VALUE self) 215 | { 216 | if (!config_system_initialized()) { 217 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 218 | } 219 | pkgCacheFile CacheFile; 220 | pkgCache *Cache = CacheFile.GetPkgCache(); 221 | if (Cache == NULL) { 222 | return Qnil; 223 | } 224 | return INT2FIX(Cache->HeaderP->PackageCount); 225 | } 226 | 227 | /* 228 | * call-seq: version_count() -> int, nil 229 | * 230 | * The total number of package versions available in the cache. 231 | * 232 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 233 | * configured. 234 | * 235 | * Debian::AptPkg::PkgCache.version_count # => 84630 236 | * 237 | **/ 238 | static VALUE 239 | version_count(VALUE self) 240 | { 241 | if (!config_system_initialized()) { 242 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 243 | } 244 | pkgCacheFile CacheFile; 245 | pkgCache *Cache = CacheFile.GetPkgCache(); 246 | if (Cache == NULL) { 247 | return Qnil; 248 | } 249 | return INT2FIX(Cache->HeaderP->VersionCount); 250 | } 251 | 252 | /* 253 | * call-seq: depends_count() -> int, nil 254 | * 255 | * The total number of dependencies stored in the cache. 256 | * 257 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 258 | * configured. 259 | * 260 | * Debian::AptPkg::PkgCache.depends_count # => 551983 261 | * 262 | **/ 263 | static VALUE 264 | depends_count(VALUE self) 265 | { 266 | if (!config_system_initialized()) { 267 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 268 | } 269 | pkgCacheFile CacheFile; 270 | pkgCache *Cache = CacheFile.GetPkgCache(); 271 | if (Cache == NULL) { 272 | return Qnil; 273 | } 274 | return INT2FIX(Cache->HeaderP->DependsCount); 275 | } 276 | 277 | /* 278 | * call-seq: package_file_count() -> int, nil 279 | * 280 | * The total number of packages files available. 281 | * 282 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 283 | * configured. 284 | * 285 | * Debian::AptPkg::PkgCache.package_file_count # => 17 286 | * 287 | **/ 288 | static VALUE 289 | package_file_count(VALUE self) 290 | { 291 | if (!config_system_initialized()) { 292 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 293 | } 294 | pkgCacheFile CacheFile; 295 | pkgCache *Cache = CacheFile.GetPkgCache(); 296 | if (Cache == NULL) { 297 | return Qnil; 298 | } 299 | return INT2FIX(Cache->HeaderP->PackageFileCount); 300 | } 301 | 302 | /* 303 | * call-seq: ver_file_count() -> int, nil 304 | * 305 | * The total number of version and package file relations stored in the cache. 306 | * 307 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 308 | * configured. 309 | * 310 | * Debian::AptPkg::PkgCache.ver_file_count # => 11274 311 | * 312 | **/ 313 | static VALUE 314 | ver_file_count(VALUE self) 315 | { 316 | if (!config_system_initialized()) { 317 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 318 | } 319 | pkgCacheFile CacheFile; 320 | pkgCache *Cache = CacheFile.GetPkgCache(); 321 | if (Cache == NULL) { 322 | return Qnil; 323 | } 324 | return INT2FIX(Cache->HeaderP->VerFileCount); 325 | } 326 | 327 | /* 328 | * call-seq: provides_count() -> int, nil 329 | * 330 | * The number of provided packages. 331 | * 332 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 333 | * configured. 334 | * 335 | * Debian::AptPkg::PkgCache.provides_count # => 69511 336 | * 337 | **/ 338 | static VALUE 339 | provides_count(VALUE self) 340 | { 341 | if (!config_system_initialized()) { 342 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 343 | } 344 | pkgCacheFile CacheFile; 345 | pkgCache *Cache = CacheFile.GetPkgCache(); 346 | if (Cache == NULL) { 347 | return Qnil; 348 | } 349 | return INT2FIX(Cache->HeaderP->ProvidesCount); 350 | } 351 | 352 | /* 353 | * call-seq: group_count() -> int, nil 354 | * 355 | * The number of groups in the cache. 356 | * 357 | * Raise `Debian::AptPkg::InitError` when config, system, cache is not 358 | * configured. 359 | * 360 | * Debian::AptPkg::PkgCache.group_count # => 16730 361 | * 362 | **/ 363 | static VALUE 364 | group_count(VALUE self) 365 | { 366 | if (!config_system_initialized()) { 367 | rb_raise(e_mDebianAptPkgInitError, "System not initialized"); 368 | } 369 | pkgCacheFile CacheFile; 370 | pkgCache *Cache = CacheFile.GetPkgCache(); 371 | if (Cache == NULL) { 372 | return Qnil; 373 | } 374 | return INT2FIX(Cache->HeaderP->GroupCount); 375 | } 376 | 377 | void 378 | init_apt_pkg_pkgcache() 379 | { 380 | VALUE rb_mDebian = rb_define_module("Debian"); 381 | VALUE rb_mDebianAptPkg = rb_define_module_under(rb_mDebian, "AptPkg"); 382 | VALUE rb_mDebianAptPkgCache = rb_define_module_under(rb_mDebianAptPkg, 383 | "PkgCache"); 384 | e_mDebianAptPkgInitError = rb_define_class_under(rb_mDebianAptPkg, 385 | "InitError", 386 | rb_eRuntimeError); 387 | rb_cPackage = rb_const_get_at(rb_mDebianAptPkg, rb_intern("Package")); 388 | rb_cVersion = rb_struct_define_under(rb_mDebianAptPkg, "Version", 389 | "parent_package_name", 390 | "version_string", 391 | "section", 392 | "arch", 393 | "size", 394 | "installed_size", 395 | "hash", 396 | "id", 397 | "priority", 398 | NULL); 399 | 400 | rb_define_singleton_method(rb_mDebianAptPkgCache, "gen_caches", 401 | RUBY_METHOD_FUNC(gen_caches), 0); 402 | rb_define_singleton_method(rb_mDebianAptPkgCache, "update", 403 | RUBY_METHOD_FUNC(update), 0); 404 | rb_define_singleton_method(rb_mDebianAptPkgCache, "is_multi_arch", 405 | RUBY_METHOD_FUNC(is_multi_arch), 0); 406 | rb_define_singleton_method(rb_mDebianAptPkgCache, "packages", 407 | RUBY_METHOD_FUNC(packages), 0); 408 | rb_define_singleton_method(rb_mDebianAptPkgCache, "pkg_names", 409 | RUBY_METHOD_FUNC(pkg_names), -1); 410 | 411 | rb_define_singleton_method(rb_mDebianAptPkgCache, "package_count", 412 | RUBY_METHOD_FUNC(package_count), 0); 413 | rb_define_singleton_method(rb_mDebianAptPkgCache, "version_count", 414 | RUBY_METHOD_FUNC(version_count), 0); 415 | rb_define_singleton_method(rb_mDebianAptPkgCache, "depends_count", 416 | RUBY_METHOD_FUNC(depends_count), 0); 417 | rb_define_singleton_method(rb_mDebianAptPkgCache, 418 | "package_file_count", 419 | RUBY_METHOD_FUNC(package_file_count), 0); 420 | rb_define_singleton_method(rb_mDebianAptPkgCache, "ver_file_count", 421 | RUBY_METHOD_FUNC(ver_file_count), 0); 422 | rb_define_singleton_method(rb_mDebianAptPkgCache, "provides_count", 423 | RUBY_METHOD_FUNC(provides_count), 0); 424 | rb_define_singleton_method(rb_mDebianAptPkgCache, "group_count", 425 | RUBY_METHOD_FUNC(group_count), 0); 426 | } 427 | -------------------------------------------------------------------------------- /ext/apt_pkg/pkgcache.h: -------------------------------------------------------------------------------- 1 | #include "apt-pkg.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void init_apt_pkg_pkgcache(); 9 | -------------------------------------------------------------------------------- /lib/debian/apt_pkg.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'debian/apt_pkg/package' 3 | require 'apt_pkg' 4 | require 'debian/apt_pkg/gem_version' 5 | -------------------------------------------------------------------------------- /lib/debian/apt_pkg/gem_version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Debian::AptPkg const VERSION file 3 | module Debian 4 | # AptPkg base module 5 | module AptPkg 6 | # Gem version 7 | VERSION = '0.5.0'.freeze 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/debian/apt_pkg/package.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Debian::AptPkg::Package file 3 | module Debian 4 | # AptPkg base module 5 | module AptPkg 6 | # Debian::AptPkg::Package class 7 | # Representation of a package in a cache 8 | class Package 9 | attr_accessor :id, :name, :full_name, :arch, :essential, :important, 10 | :current_version 11 | 12 | # Initialize the Package class 13 | # 14 | # +id+:: [Integer] The numeric ID of the package 15 | # 16 | # +name+:: [String] The name of the package 17 | # 18 | # +full_name+:: [String] Get the full name of the package, including the 19 | # architecture 20 | # 21 | # +arch+:: [String] The architecture of the package 22 | # 23 | # +essential+:: [Boolean] Boolean value determining whether the package is 24 | # essential 25 | # 26 | # +important+:: [Boolean] Boolean value determining whether the package 27 | # has the 'important' flag set ('Important: yes' 28 | # in the Packages file) 29 | # 30 | # +current_version+:: [Version,NilClass] The version of the package 31 | # currently installed or nil 32 | # 33 | # Returns a Package instance 34 | # 35 | # new(42, "ed", "ed:amd64", "amd64", false, false, nil) # => Package 36 | # 37 | def initialize(id, name, full_name, arch, essential, important, 38 | current_version) 39 | @id = id 40 | @name = name 41 | @full_name = full_name 42 | @arch = arch 43 | @essential = essential 44 | @important = important 45 | @current_version = current_version 46 | end 47 | 48 | # call-seq: is_installed -> bool 49 | # 50 | # Return +true+ if the package is installed 51 | # 52 | # Debian::AptPkg::Package.new(id, pkg_name, full_name, arch, 53 | # essential, important, 54 | # current_version).is_installed # => true 55 | def is_installed 56 | return false unless current_version 57 | 58 | true 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /test/apt_pkg_cache_not_init_integration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require_relative 'test_helper' 3 | 4 | describe Debian::AptPkg::PkgCache do 5 | describe 'not init' do 6 | describe '.update' do 7 | it 'can be called' do 8 | _(lambda do 9 | Debian::AptPkg::PkgCache.update 10 | end).must_raise Debian::AptPkg::InitError 11 | end 12 | end 13 | 14 | %i(package version depends package_file ver_file provides group).each do |m| 15 | describe ".#{m}_count" do 16 | it 'can be called' do 17 | _(lambda do 18 | Debian::AptPkg::PkgCache.public_send("#{m}_count") 19 | end).must_raise Debian::AptPkg::InitError 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/apt_pkg_configuration_test.rb: -------------------------------------------------------------------------------- 1 | require_relative 'test_helper' 2 | 3 | describe Debian::AptPkg::Configuration do 4 | before :all do 5 | Debian::AptPkg.init 6 | end 7 | 8 | it 'architecture return a string' do 9 | arch = Debian::AptPkg::Configuration.architecture 10 | _(arch).must_be_instance_of String 11 | _(arch).wont_be_empty 12 | end 13 | 14 | it 'architectures return an array' do 15 | arches = Debian::AptPkg::Configuration.architectures 16 | _(arches).must_be_instance_of Array 17 | _(arches).wont_be_empty 18 | end 19 | 20 | it 'languages return an array' do 21 | all_langs = Debian::AptPkg::Configuration.languages 22 | _(all_langs).must_be_instance_of Array 23 | _(all_langs).wont_be_empty 24 | 25 | langs = Debian::AptPkg::Configuration.languages(false) 26 | _(langs).must_be_instance_of Array 27 | end 28 | 29 | it 'check_architecture' do 30 | _(Debian::AptPkg::Configuration.check_architecture('all')).must_equal true 31 | 32 | arches = Debian::AptPkg::Configuration.architectures 33 | c = Debian::AptPkg::Configuration.check_architecture(arches.first) 34 | _(c).must_equal true 35 | 36 | # http://buildd.debian-ports.org/status/fetch.php?pkg=ruby2.1&arch=m68k&ver=2.1.2-2&stamp=1400604298 37 | _(Debian::AptPkg::Configuration.check_architecture('m68k')).must_equal false 38 | end 39 | 40 | it 'check_language' do 41 | _(lambda do 42 | Debian::AptPkg::Configuration.check_language 43 | end).must_raise ArgumentError 44 | 45 | langs = Debian::AptPkg::Configuration.languages 46 | _(Debian::AptPkg::Configuration.check_language(langs.first)).must_equal true 47 | 48 | c = Debian::AptPkg::Configuration.check_language('gallifreyan') 49 | _(c).must_equal false 50 | end 51 | 52 | it 'compressors return an array' do 53 | cmps = Debian::AptPkg::Configuration.compressors 54 | _(cmps).must_be_instance_of Array 55 | _(cmps).wont_be_empty 56 | _(cmps).must_include 'gz' 57 | end 58 | 59 | it 'find configuration value' do 60 | _(lambda do 61 | Debian::AptPkg::Configuration.config_find 62 | end).must_raise ArgumentError 63 | 64 | _(Debian::AptPkg::Configuration.config_find('Dir::Etc::main')) 65 | .must_equal 'apt.conf' 66 | _(Debian::AptPkg::Configuration.config_find('Dir::Etc::netrc')) 67 | .must_equal 'auth.conf' 68 | _(Debian::AptPkg::Configuration.config_find('Dir::Etc::parts')) 69 | .must_equal 'apt.conf.d' 70 | _(Debian::AptPkg::Configuration.config_find('Spk', 'DebianUser')) 71 | .must_equal 'DebianUser' 72 | end 73 | 74 | it 'find file' do 75 | _(lambda do 76 | Debian::AptPkg::Configuration.config_find_file 77 | end).must_raise ArgumentError 78 | 79 | _(Debian::AptPkg::Configuration.config_find_file('Dir::Etc::main')) 80 | .must_match '/etc/apt/apt.conf' 81 | _(Debian::AptPkg::Configuration.config_find_file('Dir::Etc::netrc')) 82 | .must_match '/etc/apt/auth.conf' 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /test/apt_pkg_test.rb: -------------------------------------------------------------------------------- 1 | require_relative 'test_helper' 2 | 3 | describe Debian::AptPkg do 4 | it 'gem has a version number' do 5 | refute_nil Debian::AptPkg::VERSION 6 | end 7 | 8 | it 'apt has a version number' do 9 | refute_nil Debian::AptPkg::APT_VERSION 10 | end 11 | 12 | it 'libapt-pkg has a version number' do 13 | refute_nil Debian::AptPkg::LIBAPT_PKG_VERSION 14 | end 15 | 16 | describe '.init' do 17 | it 'returns a bool' do 18 | _(Debian::AptPkg.init).must_equal true 19 | end 20 | end 21 | 22 | describe '.cmp_version' do 23 | it 'compare version' do 24 | _(Debian::AptPkg.cmp_version('1.1', '1.0')).must_be :>, 0 25 | _(Debian::AptPkg.cmp_version('1.0', '1.0')).must_be :==, 0 26 | _(Debian::AptPkg.cmp_version('1.0', '1.1')).must_be :<, 0 27 | end 28 | end 29 | 30 | describe '.check_dep' do 31 | describe 'LessEq' do 32 | it 'compare Debian version' do 33 | _(Debian::AptPkg.check_dep('1', '<=', '2')).must_equal true 34 | _(Debian::AptPkg.check_dep('2', '<=', '1')).must_equal false 35 | _(Debian::AptPkg.check_dep('1', '<=', '1')).must_equal true 36 | end 37 | end 38 | 39 | describe 'GreaterEq' do 40 | it 'compare Debian version' do 41 | _(Debian::AptPkg.check_dep('1', '>=', '2')).must_equal false 42 | _(Debian::AptPkg.check_dep('2', '>=', '1')).must_equal true 43 | _(Debian::AptPkg.check_dep('1', '>=', '1')).must_equal true 44 | end 45 | end 46 | 47 | describe 'Less' do 48 | it 'compare Debian version' do 49 | _(Debian::AptPkg.check_dep('1', '<', '2')).must_equal true 50 | _(Debian::AptPkg.check_dep('2', '<', '1')).must_equal false 51 | _(Debian::AptPkg.check_dep('1', '<', '1')).must_equal false 52 | end 53 | end 54 | 55 | describe 'Greater' do 56 | it 'compare Debian version' do 57 | _(Debian::AptPkg.check_dep('1', '>', '2')).must_equal false 58 | _(Debian::AptPkg.check_dep('2', '>', '1')).must_equal true 59 | _(Debian::AptPkg.check_dep('1', '>', '1')).must_equal false 60 | end 61 | end 62 | 63 | describe 'Equals' do 64 | it 'compare Debian version' do 65 | _(Debian::AptPkg.check_dep('1', '=', '2')).must_equal false 66 | _(Debian::AptPkg.check_dep('2', '=', '1')).must_equal false 67 | _(Debian::AptPkg.check_dep('1', '=', '1')).must_equal true 68 | end 69 | end 70 | 71 | describe 'NotEquals' do 72 | it 'compare Debian version' do 73 | _(Debian::AptPkg.check_dep('1', Debian::AptPkg::NOT_EQUALS, '2')) 74 | .must_equal true 75 | _(Debian::AptPkg.check_dep('2', Debian::AptPkg::NOT_EQUALS, '1')) 76 | .must_equal true 77 | _(Debian::AptPkg.check_dep('1', Debian::AptPkg::NOT_EQUALS, '1')) 78 | .must_equal false 79 | end 80 | end 81 | 82 | describe 'Errors' do 83 | it 'raise argument error with bad comparison' do 84 | _(lambda do 85 | Debian::AptPkg.check_dep('1', 'bad', '2') 86 | end).must_raise ArgumentError 87 | end 88 | end 89 | end 90 | 91 | describe '.uri_to_filename' do 92 | it 'return a filename which can be used to store the file' do 93 | _(Debian::AptPkg.uri_to_filename('http://debian.org/index.html')) 94 | .must_equal 'debian.org_index.html' 95 | end 96 | end 97 | 98 | describe '.upstream_version' do 99 | it 'Return the upstream version for the Debian package version' do 100 | _(Debian::AptPkg.upstream_version('3.4.15-1+b1')).must_equal '3.4.15' 101 | end 102 | end 103 | 104 | describe '.time_to_str' do 105 | it 'Format a given duration in human-readable manner' do 106 | _(Debian::AptPkg.time_to_str(3601)).must_equal '1h 0min 1s' 107 | end 108 | end 109 | 110 | describe '.size_to_str' do 111 | it 'Return a string describing the size in a human-readable manner' do 112 | _(Debian::AptPkg.size_to_str(10_000)).must_equal '10.0 k' 113 | end 114 | end 115 | 116 | describe '.string_to_bool' do 117 | it 'Parse the string input and return a boolean' do 118 | _(Debian::AptPkg.string_to_bool('yes')).must_equal true 119 | _(Debian::AptPkg.string_to_bool('no')).must_equal false 120 | _(Debian::AptPkg.string_to_bool('no-recognized')).must_equal false 121 | end 122 | end 123 | 124 | describe '.check_domain_list' do 125 | it 'See if the host name given by host is one of the domains given' do 126 | _(Debian::AptPkg.check_domain_list('alioth.debian.org', 127 | 'debian.net,debian.org')) 128 | .must_equal true 129 | _(Debian::AptPkg.check_domain_list('git.debian.org', 130 | 'spkdev.net')) 131 | .must_equal false 132 | end 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /test/debian/apt_pkg/package_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require_relative '../../test_helper' 3 | 4 | describe Debian::AptPkg::Package do 5 | let(:id) { 42 } 6 | let(:pkg_name) { "ed" } 7 | let(:full_name) { "ed:i386" } 8 | let(:arch) { "i386" } 9 | let(:essential) { false } 10 | let(:important) { false } 11 | let(:current_version) { nil } 12 | 13 | describe '.new' do 14 | describe 'with correct number of arguments' do 15 | it 'can initialize a Package class' do 16 | Debian::AptPkg::Package.new(id, pkg_name, full_name, arch, 17 | essential, important, current_version) 18 | end 19 | end 20 | 21 | describe 'with wrong number of arguments' do 22 | it 'cannot initialize a Package class' do 23 | _(lambda do 24 | Debian::AptPkg::Package.new(id, pkg_name, full_name, arch, 25 | essential, important) 26 | end).must_raise ArgumentError 27 | end 28 | end 29 | end 30 | 31 | describe '#is_installed' do 32 | subject do 33 | Debian::AptPkg::Package.new(id, pkg_name, full_name, arch, 34 | essential, important, 35 | current_version).is_installed 36 | end 37 | 38 | describe 'when current_version is present' do 39 | let(:current_version) do 40 | Debian::AptPkg::Version.new("ed", "1", "editors", "i386", 0, 0, 0, 0, 4) 41 | end 42 | 43 | it 'returns true' do 44 | _(subject).must_equal true 45 | end 46 | end 47 | 48 | describe 'when current_version is not present' do 49 | let(:current_version) { nil } 50 | 51 | it 'returns false' do 52 | _(subject).must_equal false 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /test/debian/apt_pkg/pkg_cache_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require_relative '../../test_helper' 3 | 4 | describe Debian::AptPkg::PkgCache do 5 | before :all do 6 | Debian::AptPkg.init 7 | end 8 | 9 | describe '.update' do 10 | it 'can be called' do 11 | Debian::AptPkg::PkgCache.update 12 | end 13 | end 14 | 15 | describe '.gen_caches' do 16 | it 'return boolean' do 17 | if Process.uid == 0 18 | _(Debian::AptPkg::PkgCache.gen_caches).must_equal true 19 | else 20 | _(Debian::AptPkg::PkgCache.gen_caches).must_equal false 21 | end 22 | end 23 | end 24 | 25 | describe '.is_multi_arch' do 26 | it 'can be called' do 27 | Debian::AptPkg::PkgCache.is_multi_arch 28 | end 29 | 30 | it 'returns a boolean' do 31 | _([true, false]).must_include Debian::AptPkg::PkgCache.is_multi_arch 32 | end 33 | end 34 | 35 | describe '.packages' do 36 | it 'returns an array of Package' do 37 | packages = Debian::AptPkg::PkgCache.packages 38 | _(packages).must_be_kind_of Array 39 | # apt update is not possible on the system or has not been performed 40 | if packages.first 41 | _(packages.first).must_be_kind_of Debian::AptPkg::Package 42 | libapt = packages.find { |pkg| pkg.name == 'libapt-pkg-dev' } 43 | if libapt 44 | _(libapt.id).must_be_kind_of Numeric 45 | _(libapt.name).must_equal 'libapt-pkg-dev' 46 | _(libapt.full_name).must_match(/libapt-pkg-dev:(\w)/) 47 | _(libapt.arch).must_match(/(\w)/) 48 | _([true, false]).must_include libapt.essential 49 | _([true, false]).must_include libapt.important 50 | _(libapt.current_version).must_be_kind_of Debian::AptPkg::Version 51 | _(libapt.current_version.parent_package_name).must_equal libapt.name 52 | _(libapt.current_version.version_string).must_be_kind_of String 53 | _(libapt.current_version.section).must_equal 'libdevel' 54 | _(libapt.current_version.arch).must_equal libapt.arch 55 | _(libapt.current_version.size).must_be_kind_of Numeric 56 | _(libapt.current_version.installed_size).must_be_kind_of Numeric 57 | _(libapt.current_version.hash).must_be_kind_of Numeric 58 | _(libapt.current_version.id).must_be_kind_of Numeric 59 | _(libapt.current_version.priority).must_be_kind_of Numeric 60 | end 61 | end 62 | end 63 | end 64 | 65 | describe '.pkg_names' do 66 | it 'is deprecated' do 67 | out, err = capture_io do 68 | Debian::AptPkg::PkgCache.pkg_names('libapt-pkg-dev') 69 | end 70 | _(out).must_equal '' 71 | regexp = /warning:\sDebian::AptPkg::PkgCache\.pkg_names\sis\sdeprecated;\s 72 | use\sDebian::AptPkg::PkgCache\.packages\sinstead/x 73 | _(err).must_match(regexp) 74 | end 75 | 76 | it 'no argument' do 77 | _(lambda do 78 | capture_io do 79 | Debian::AptPkg::PkgCache.pkg_names 80 | end 81 | end).must_raise ArgumentError 82 | end 83 | 84 | it 'nil argument' do 85 | _(lambda do 86 | capture_io do 87 | Debian::AptPkg::PkgCache.pkg_names(nil) 88 | end 89 | end).must_raise ArgumentError 90 | end 91 | 92 | it 'blank argument' do 93 | _(lambda do 94 | capture_io do 95 | Debian::AptPkg::PkgCache.pkg_names('') 96 | end 97 | end).must_raise ArgumentError 98 | end 99 | 100 | it 'be filtered' do 101 | capture_io do 102 | search = Debian::AptPkg::PkgCache.pkg_names('libapt-pkg-dev') 103 | # CI specific cache can not be present 104 | unless search.nil? || search.empty? 105 | _(search).must_include 'libapt-pkg-dev' 106 | _(search).wont_include 'apt' 107 | end 108 | end 109 | end 110 | end 111 | 112 | %i(package version depends package_file ver_file provides group).each do |m| 113 | describe ".#{m}_count" do 114 | it 'return an int' do 115 | if Process.uid == 0 116 | _(Debian::AptPkg::PkgCache.public_send("#{m}_count")).must_be :>=, 0 117 | end 118 | end 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'pp' 3 | 4 | require_relative '../lib/debian/apt_pkg' 5 | --------------------------------------------------------------------------------