It supports RPM 4.8.0 or later.
RPM is licensed under GNU GPL. This means all libraries and applications which link to RPM must be licensed under GNU GPL. But, Crystal (and standard libraries) are licensed under Apache-2.0, which will be incompatible.
COPYING file in source tarball of RPM says that library part
of RPM (i.e.,
librpm) is licensed under LGPL 2.0 or later too, which
can be compatible with MIT and Apache-2.0.
So currently, crystal-rpm is licensed under both GPLv2 or later and MIT (which should be compatible with LGPL 2.0 and Apache-2.0). We are thinking you do not have a chance to use this library under the conditions of GPLv2, but left to let us to keep in mind.
- Add the dependency to your
dependencies: rpm: github: lugia-kun/crystal-rpm
The development files (pkg-config file) of RPM is
required. Typically, it can be installed by
yum install rpm-devel on
CentOS or Red Hat,
dnf install rpm-devel on Fedora, and
zypper in rpm-devel on openSUSE or SLES.
pkg = RPM::Package.open("foobar-1.0-0.x86_64.rpm") puts pkg[RPM::Tag::Name] # => "foobar" puts pkg[RPM::Tag::Arch] # => "x86_64" puts pkg[RPM::Tag::Summary] # => (Content of Summary) # and so on... pkg.requires # => Array of Requires. pkg.provides # => Array of Provides. pkg.conflicts # => Array of Conflicts. pkg.obsoletes # => Array of Obsolstes.
RPM.transaction do |ts| path = "pkg_to_install-1.0-0.x86_64.rpm" pkg = ts.read_package_file(path) ts.install(pkg, path) # Add installation package. Package path is required. ts.commit # Run Transaction end
RPM::Package.open allocates a
Transaction inside. So if you
have an instance of
Transaction#read_package_file reduces allocations.
Search installed packages
# with given name RPM.transaction do |ts| ts.db_iterator(RPM::DbiTag::Name, "package-name-to-find") do |iter| iter.each do |pkg| # Iterator over matching packages. end end end # with given regexp RPM.transaction do |ts| ts.db_iterator do |iter| # Set condition iter.regexp(RPM::DbiTag::Name, # <= Entry to search (here, Name) RPM::MireMode::REGEX, # <= Default matching method "simple.*") # <= Name to search # Iterate over matching packages. iter.each do |pkg| puts pkg[RPM::Tag::Version].as(String) # => (Version of package "simple") end end end # Iterate over all installed packages RPM.transaction do |ts| ts.db_iterator do |iter| iter.each do |pkg| # ... iterates over all installed packages. end end end # Lookup package(s) which contains a specific file RPM.transaction do |ts| ts.db_iterator(RPM::DbiTag::BaseNames, "/path/to/lookup") do |iter| iter.each do |pkg| # ... iterates over packages contains "/path/to/lookup" end end end # NOTE: Using regexp with BaseNames, it will search packages which # contain a file whose basename is the given name. RPM.transaction do |ts| ts.db_iterator do |iter| iter.regexp(RPM::DbiTag::BaseNames, RPM::MireMode::STRCMP, "README") iter.each do |pkg| # ... iterates over packages which contain a file named "README" end end end
RPM.transaction do |ts| ts.delete(pkg) # Add to removal package ts.order ts.clean ts.commit # Run Transaction end
Using Transaction without block
For installing and/or removing packages, the DB handle is bound to the transaction. So, DB must be closed via transaction.
ts = RPM::Transaction.new begin ts.install(...) ts.delete(...) ts.order ts.clean ts.commit ensure ts.close_db # Must close DB end ts.finalize # Not nesseary, but recommended.
Using DB iterator without block
For searching packages in DB, the DB handle is bound to the iterator. So, DB must be closed via finalizing the iterator.
ts = RPM::Transaction.new begin iter = ts.init_iterator(...) begin iter.each do |item| # work with item end ensure iter.finalize # Must finalize iterator. end end ts.finalize
RPM.transation do |ts| ts.install(...) ts.order ts.clean ts.check if (problems = ts.problems?) problems.each do |problem| puts problem.to_s # => Output install (typically dependency) problems. end end end
spec = RPM::Spec.open("foo.spec") packages = spec.packages packages[RPM::Tag::Name] # => (Name of the first package) packages[RPM::Tag::Name] # => (Name of the second package) # NOTE: The order is undefined. spec.buildrequires # => Array of BuildRequires.
# Steps to be run. # # Here, %prep, %build, %install, %check, %clean and generates the source # and binary packages. # amount = RPM::BuildFlags.flags(PREP, BUILD, INSTALL, CHECK, CLEAN, PACKAGESOURCE, PACKAGEBINARY) # Read specfile spec = RPM::Spec.open("foo.spec") spec.build(build_amount: amount)
The definitions of structs are written by hand. Tests can check their size and member offsets if you have a C compiler (optional).
Alternatively, using Docker is another method to test:
host$ shards install host$ docker build -t [version] -f .travis/Dockerfile.rpm-[version] . host$ docker run -it -v $(pwd):/work -w /work [version] ./.travis.sh
host$ shards install host$ docker build -t [version] -f .travis/Dockerfile.rpm-[version] . host$ docker run -it -v $(pwd):/work -w /work [version] container# useradd -u $(stat -c %u spec/data/simple.spec) crystal || : container# crystal spec [arguments] container# exit
- Git in CentOS 6 is too old and does not work with shards, so shards should be install on the local.
- In Fedora and CentOS, rpmbuild or rpmrc or rpmmacro files requires that the spec files must be owned by a valid user, when building RPMs.
- Fork it (https://github.com/lugia-kun/crystal-rpm/fork)
- Create your feature branch (
git checkout -b my-new-feature)
- Commit your changes (
git commit -am 'Add some feature')
- Push to the branch (
git push origin my-new-feature)
- Create a new Pull Request
- Hajime Yoshimori - creator and maintainer