enhancerepo 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +18 -0
- data/Manifest.txt +85 -0
- data/README +10 -0
- data/README.rdoc +15 -0
- data/Rakefile +48 -0
- data/TODO.rdoc +4 -0
- data/bin/enhancerepo +4 -0
- data/lib/enhance_repo.rb +36 -0
- data/lib/enhance_repo/cli.rb +150 -0
- data/lib/enhance_repo/config_opts.rb +98 -0
- data/lib/enhance_repo/logger.rb +67 -0
- data/lib/enhance_repo/other.rb +80 -0
- data/lib/enhance_repo/package_id.rb +81 -0
- data/lib/enhance_repo/product_id.rb +30 -0
- data/lib/enhance_repo/rpm_md.rb +27 -0
- data/lib/enhance_repo/rpm_md/data.rb +55 -0
- data/lib/enhance_repo/rpm_md/delta_info.rb +205 -0
- data/lib/enhance_repo/rpm_md/extra_primary_data.rb +45 -0
- data/lib/enhance_repo/rpm_md/file_lists.rb +81 -0
- data/lib/enhance_repo/rpm_md/index.rb +144 -0
- data/lib/enhance_repo/rpm_md/other.rb +69 -0
- data/lib/enhance_repo/rpm_md/primary.rb +123 -0
- data/lib/enhance_repo/rpm_md/products.rb +142 -0
- data/lib/enhance_repo/rpm_md/repo.rb +202 -0
- data/lib/enhance_repo/rpm_md/resource.rb +44 -0
- data/lib/enhance_repo/rpm_md/suse_data.rb +191 -0
- data/lib/enhance_repo/rpm_md/suse_info.rb +88 -0
- data/lib/enhance_repo/rpm_md/update.rb +141 -0
- data/lib/enhance_repo/rpm_md/update_info.rb +244 -0
- data/lib/enhance_repo/rpm_md/update_smart_fields.rb +127 -0
- data/lib/enhance_repo/xml_comparer.rb +117 -0
- data/lib/tempdir.rb +62 -0
- data/lib/tempdir/tempfile.rb +21 -0
- data/test/all_tests.rb +27 -0
- data/test/data/packages/a-1.0.spec +19 -0
- data/test/data/packages/a-2.0.spec +24 -0
- data/test/data/repodata/update-test-11.1/filelists.xml.gz +0 -0
- data/test/data/repodata/update-test-11.1/other.xml.gz +0 -0
- data/test/data/repodata/update-test-11.1/primary.xml.gz +0 -0
- data/test/data/repodata/update-test-11.1/repomd.xml +21 -0
- data/test/data/repomd.xml +21 -0
- data/test/data/rpms/repo-1/a-1.0-0.x86_64.rpm +0 -0
- data/test/data/rpms/repo-1/a-1.0_2.0-0_0.x86_64.delta.rpm +0 -0
- data/test/data/rpms/repo-1/a-2.0-0.x86_64.rpm +0 -0
- data/test/data/rpms/repo-1/repodata/deltainfo.xml.gz +0 -0
- data/test/data/rpms/repo-1/repodata/deltainfo.xml.gz.gz +0 -0
- data/test/data/rpms/repo-1/repodata/filelists.xml.gz +0 -0
- data/test/data/rpms/repo-1/repodata/other.xml.gz +0 -0
- data/test/data/rpms/repo-1/repodata/primary.xml.gz +0 -0
- data/test/data/rpms/repo-1/repodata/repomd.xml +45 -0
- data/test/data/rpms/repo-1/repodata/susedata.xml.gz +0 -0
- data/test/data/rpms/repo-1/repodata/updateinfo.xml.gz +0 -0
- data/test/data/rpms/repo-1/repoparts/update-a-1.xml +22 -0
- data/test/data/rpms/repo-with-product/a-1.0-0.x86_64.rpm +0 -0
- data/test/data/rpms/repo-with-product/openSUSE-release-11.2-1.6.i586.rpm +0 -0
- data/test/data/rpms/repo-with-product/openSUSE-release-dvd-11.2-1.6.i586.rpm +0 -0
- data/test/data/rpms/repo-with-product/repodata/filelists.xml.gz +0 -0
- data/test/data/rpms/repo-with-product/repodata/other.xml.gz +0 -0
- data/test/data/rpms/repo-with-product/repodata/primary.xml.gz +0 -0
- data/test/data/rpms/repo-with-product/repodata/products.xml.gz +0 -0
- data/test/data/rpms/repo-with-product/repodata/repomd.xml +27 -0
- data/test/data/rpms/update-test-11.1/update-test-affects-package-manager.rpm +0 -0
- data/test/data/rpms/update-test-11.1/update-test-interactive.rpm +0 -0
- data/test/data/rpms/update-test-11.1/update-test-optional.rpm +0 -0
- data/test/data/rpms/update-test-11.1/update-test-reboot-needed.rpm +0 -0
- data/test/data/rpms/update-test-11.1/update-test-security.rpm +0 -0
- data/test/data/rpms/update-test-11.1/update-test-trival.rpm +0 -0
- data/test/data/rpms/update-test-factory/update-test-affects-package-manager-0-9999.1.2.noarch.rpm +0 -0
- data/test/data/rpms/update-test-factory/update-test-interactive-0-9999.1.2.noarch.rpm +0 -0
- data/test/data/rpms/update-test-factory/update-test-optional-0-9999.1.2.noarch.rpm +0 -0
- data/test/data/rpms/update-test-factory/update-test-reboot-needed-0-9999.1.2.noarch.rpm +0 -0
- data/test/data/rpms/update-test-factory/update-test-relogin-suggested-0-9999.1.2.noarch.rpm +0 -0
- data/test/data/rpms/update-test-factory/update-test-security-0-9999.1.2.noarch.rpm +0 -0
- data/test/deltainfo_test.rb +50 -0
- data/test/extensions_test.rb +31 -0
- data/test/index_test.rb +51 -0
- data/test/primary_test.rb +51 -0
- data/test/products_test.rb +51 -0
- data/test/repo_test.rb +72 -0
- data/test/repomdindex_test.rb +58 -0
- data/test/rpmmd_test.rb +60 -0
- data/test/susedata_test.rb +53 -0
- data/test/tempdir_test.rb +62 -0
- data/test/test_helper.rb +53 -0
- data/test/update_test.rb +80 -0
- data/test/updateinfo_test.rb +59 -0
- metadata +267 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# enhancerepo is a rpm-md repository metadata tool.
|
|
4
|
+
# Copyright (C) 2008, 2009 Novell Inc.
|
|
5
|
+
# Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
|
6
|
+
#
|
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with this program; if not, write to the Free Software
|
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
20
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
|
21
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
|
22
|
+
#
|
|
23
|
+
#++
|
|
24
|
+
#
|
|
25
|
+
require 'rpm'
|
|
26
|
+
require 'tempdir'
|
|
27
|
+
require 'pathname'
|
|
28
|
+
require 'nokogiri'
|
|
29
|
+
require 'ftools'
|
|
30
|
+
|
|
31
|
+
module EnhanceRepo
|
|
32
|
+
module RpmMd
|
|
33
|
+
|
|
34
|
+
# products.xml metadata generator
|
|
35
|
+
# reads the release files from a repository
|
|
36
|
+
class Products < Data
|
|
37
|
+
|
|
38
|
+
# Holder for products we read from the
|
|
39
|
+
# release files
|
|
40
|
+
class ProductData
|
|
41
|
+
attr_accessor :name
|
|
42
|
+
attr_accessor :vendor
|
|
43
|
+
attr_accessor :version
|
|
44
|
+
attr_accessor :release
|
|
45
|
+
attr_accessor :arch
|
|
46
|
+
attr_accessor :productline
|
|
47
|
+
attr_accessor :summary
|
|
48
|
+
attr_accessor :description
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def initialize(dir)
|
|
52
|
+
@dir = dir
|
|
53
|
+
@products = []
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def rpm_extract_file(rpmpath, path)
|
|
57
|
+
Tempdir.open do |tmppath|
|
|
58
|
+
File.makedirs(tmppath)
|
|
59
|
+
Dir.chdir(tmppath) do
|
|
60
|
+
`rpm2cpio '#{rpmpath}' | cpio -iv --make-directories #{File.join(".", path)} 2>/dev/null`
|
|
61
|
+
end
|
|
62
|
+
File.open(File.join(tmppath, path)) do |f|
|
|
63
|
+
yield f if block_given?
|
|
64
|
+
return f.read
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def products_in_file_in_rpm(rpmpath, path)
|
|
70
|
+
products = []
|
|
71
|
+
rpm_extract_file(rpmpath, path) do |f|
|
|
72
|
+
doc = Nokogiri::XML(f)
|
|
73
|
+
#print doc.to_s
|
|
74
|
+
product = ProductData.new
|
|
75
|
+
# set attributes of the product based on the xml data
|
|
76
|
+
[:name, :version, :release, :arch, :vendor, :summary, :description].each do |attr|
|
|
77
|
+
product.send("#{attr}=".to_sym, doc.root.xpath("./#{attr}").text)
|
|
78
|
+
end
|
|
79
|
+
products << product
|
|
80
|
+
yield product if block_given?
|
|
81
|
+
end
|
|
82
|
+
products
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# scan the products from the rpm files in the repository
|
|
86
|
+
def read_packages
|
|
87
|
+
# log.info "Looking for product release packages"
|
|
88
|
+
Dir["#{@dir}/**/*-release-*.rpm", "#{@dir}/**/*-migration-*.rpm"].each do |rpmfile|
|
|
89
|
+
pkg = RPM::Package.new(rpmfile)
|
|
90
|
+
# we dont care for packages not providing a product
|
|
91
|
+
next if pkg.provides.select{|x| x.name == "product()"}.empty?
|
|
92
|
+
log.info "Found product release package #{rpmfile}"
|
|
93
|
+
# this package contains a product
|
|
94
|
+
# go over each product file
|
|
95
|
+
pkg.files.map {|x| x.to_s }.each do |path|
|
|
96
|
+
next if not ( File.extname(path) == ".prod" && File.dirname(path) == "/etc/products.d" )
|
|
97
|
+
# we have a product file. Extract it
|
|
98
|
+
log.info "`-> product file : #{path}"
|
|
99
|
+
products_in_file_in_rpm(File.expand_path(rpmfile), File.expand_path(path)) do |product|
|
|
100
|
+
log.info "`-> found product : #{product.name}"
|
|
101
|
+
@products << product
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def empty?
|
|
108
|
+
@products.empty?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def size
|
|
112
|
+
@products.size
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def write(io)
|
|
116
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
|
117
|
+
xml.products do
|
|
118
|
+
@products.each do |product|
|
|
119
|
+
xml.product do
|
|
120
|
+
xml.name product.name
|
|
121
|
+
version = RPM::Version.new("#{product.version}-#{product.release}")
|
|
122
|
+
epoch = version.e
|
|
123
|
+
epoch ||= "0"
|
|
124
|
+
xml.version :epoch => epoch, :ver => version.v, :rel => version.r
|
|
125
|
+
xml.arch product.arch
|
|
126
|
+
xml.vendor product.vendor
|
|
127
|
+
xml.summary product.summary
|
|
128
|
+
xml.description product.description
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
# write the result
|
|
134
|
+
#io.write(builder.to_xml)
|
|
135
|
+
io.write(builder.doc.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML))
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# enhancerepo is a rpm-md repository metadata tool.
|
|
4
|
+
# Copyright (C) 2008, 2009 Novell Inc.
|
|
5
|
+
# Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
|
6
|
+
#
|
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with this program; if not, write to the Free Software
|
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
20
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
|
21
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
|
22
|
+
#
|
|
23
|
+
#++
|
|
24
|
+
#
|
|
25
|
+
require 'rubygems'
|
|
26
|
+
require 'builder'
|
|
27
|
+
require 'rexml/document'
|
|
28
|
+
require 'digest/sha1'
|
|
29
|
+
require 'zlib'
|
|
30
|
+
require 'yaml'
|
|
31
|
+
|
|
32
|
+
require 'enhance_repo/package_id'
|
|
33
|
+
require 'enhance_repo/rpm_md/data'
|
|
34
|
+
require 'enhance_repo/rpm_md/primary'
|
|
35
|
+
require 'enhance_repo/rpm_md/file_lists'
|
|
36
|
+
require 'enhance_repo/rpm_md/other'
|
|
37
|
+
require 'enhance_repo/rpm_md/update_info'
|
|
38
|
+
require 'enhance_repo/rpm_md/suse_info'
|
|
39
|
+
require 'enhance_repo/rpm_md/suse_data'
|
|
40
|
+
require 'enhance_repo/rpm_md/delta_info'
|
|
41
|
+
require 'enhance_repo/rpm_md/products'
|
|
42
|
+
require 'enhance_repo/rpm_md/index'
|
|
43
|
+
|
|
44
|
+
module EnhanceRepo
|
|
45
|
+
module RpmMd
|
|
46
|
+
|
|
47
|
+
include REXML
|
|
48
|
+
|
|
49
|
+
class Repo
|
|
50
|
+
|
|
51
|
+
include Logger
|
|
52
|
+
|
|
53
|
+
attr_accessor :index
|
|
54
|
+
|
|
55
|
+
# extensions
|
|
56
|
+
attr_reader :primary, :other, :filelists, :susedata, :suseinfo, :deltainfo, :updateinfo, :products
|
|
57
|
+
def initialize(config)
|
|
58
|
+
@dir = config.dir
|
|
59
|
+
@outputdir = config.outputdir
|
|
60
|
+
|
|
61
|
+
@index = Index.new
|
|
62
|
+
repomdfile = File.join(@dir, @index.metadata_filename)
|
|
63
|
+
# populate the index
|
|
64
|
+
if File.exist?(repomdfile)
|
|
65
|
+
@index.read_file(File.new(repomdfile))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
@primary = Primary.new(config.dir)
|
|
69
|
+
@primary.indent = config.indent
|
|
70
|
+
|
|
71
|
+
@filelists = FileLists.new(config.dir)
|
|
72
|
+
@other = Other.new(config.dir)
|
|
73
|
+
@susedata = SuseData.new(config.dir)
|
|
74
|
+
@updateinfo = UpdateInfo.new(config)
|
|
75
|
+
@suseinfo = SuseInfo.new(config.dir)
|
|
76
|
+
@deltainfo = DeltaInfo.new(config.dir)
|
|
77
|
+
@products = Products.new(config.dir)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def sign(keyid)
|
|
81
|
+
# check if the index is written to disk
|
|
82
|
+
repomdfile = File.join(@dir, @index.metadata_filename)
|
|
83
|
+
if not File.exist?(repomdfile)
|
|
84
|
+
raise "#{repomdfile} does not exist."
|
|
85
|
+
end
|
|
86
|
+
# call gpg to sign the repository
|
|
87
|
+
`gpg -sab -u #{keyid} -o '#{repomdfile}.asc' '#{repomdfile}'`
|
|
88
|
+
if not File.exists?("#{repomdfile}.asc")
|
|
89
|
+
log.info "Could't not generate signature #{repomdfile}.asc"
|
|
90
|
+
exit(1)
|
|
91
|
+
else
|
|
92
|
+
log.info "#{repomdfile}.asc signature generated"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# now export the public key
|
|
96
|
+
`gpg --export -a -o '#{repomdfile}.key' #{keyid}`
|
|
97
|
+
|
|
98
|
+
if not File.exists?("#{repomdfile}.key")
|
|
99
|
+
log.info "Could't not generate public key #{repomdfile}.key"
|
|
100
|
+
exit(1)
|
|
101
|
+
else
|
|
102
|
+
log.info "#{repomdfile}.key public key generated"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def write
|
|
107
|
+
|
|
108
|
+
datas = [@primary, @filelists, @other, @updateinfo,
|
|
109
|
+
@susedata, @suseinfo, @deltainfo, @products ]
|
|
110
|
+
|
|
111
|
+
# select the datas that are not empty
|
|
112
|
+
# those need to be saved
|
|
113
|
+
non_empty_data = datas.reject { |x| x.empty? }
|
|
114
|
+
# files present in the index, which were changed
|
|
115
|
+
changed_files = []
|
|
116
|
+
# files present on disk, but not in the index
|
|
117
|
+
missing_files = []
|
|
118
|
+
# files present in the index, but not on disk
|
|
119
|
+
superflous_files = []
|
|
120
|
+
|
|
121
|
+
# now look for files that changed or dissapeared
|
|
122
|
+
Dir.chdir(@dir) do
|
|
123
|
+
# look all files except the index itself
|
|
124
|
+
metadata_files = Dir["repodata/*.xml*"].reject do |x|
|
|
125
|
+
x =~ /#{@index.metadata_filename}/ ||
|
|
126
|
+
x =~ /\.key$/ ||
|
|
127
|
+
x =~ /\.asc$/
|
|
128
|
+
end
|
|
129
|
+
# remove datas in the index not present in the disk
|
|
130
|
+
@index.resources.reject! do |resource|
|
|
131
|
+
reject = ! metadata_files.include?(resource.location)
|
|
132
|
+
log.info "Removing not existing #{resource.location} from index" if reject
|
|
133
|
+
reject
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
non_empty_files = non_empty_data.map { |x| x.metadata_filename }
|
|
137
|
+
# ignore it if it is already in the non_empty_list
|
|
138
|
+
# as it will be added to the index anyway
|
|
139
|
+
metadata_files.reject!{ |x| non_empty_files.include?(x) }
|
|
140
|
+
metadata_files.each do |metadata_file|
|
|
141
|
+
# find the indexed resource for this file
|
|
142
|
+
indexed_resource = @index.resources.select { |x| x.location == metadata_file }.first
|
|
143
|
+
# add it to the list of changed resources if the timestamp
|
|
144
|
+
# are differents
|
|
145
|
+
if indexed_resource.nil?
|
|
146
|
+
missing_files << metadata_file
|
|
147
|
+
next
|
|
148
|
+
elsif File.mtime(File.join(@dir, metadata_file)).to_i != indexed_resource.timestamp.to_i
|
|
149
|
+
changed_files << metadata_file
|
|
150
|
+
next
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# write down changed datas
|
|
156
|
+
non_empty_data.each do |data|
|
|
157
|
+
write_gz_extension_file(data)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# update the index
|
|
161
|
+
non_empty_data.each do |d|
|
|
162
|
+
log.info "Adding #{d.metadata_filename} to #{@index.metadata_filename} index"
|
|
163
|
+
@index.add_file_resource(File.join(@outputdir, d.metadata_filename), d.metadata_filename)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
missing_files.each do |f|
|
|
167
|
+
log.info "Adding missing #{f} to #{@index.metadata_filename} index"
|
|
168
|
+
@index.add_file_resource(File.join(@outputdir, f), f)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
changed_files.each do |f|
|
|
172
|
+
log.info "Replacing changed #{f} on #{@index.metadata_filename} index"
|
|
173
|
+
@index.add_file_resource(File.join(@outputdir, f), f)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# now write the index
|
|
177
|
+
File.open((@outputdir + @index.metadata_filename), 'w') do |f|
|
|
178
|
+
log.info "Saving #{@index.metadata_filename} .."
|
|
179
|
+
@index.write(f)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# writes an extension to an xml filename if
|
|
184
|
+
# the extension is not empty
|
|
185
|
+
def write_gz_extension_file(data)
|
|
186
|
+
filename = Pathname.new(File.join(@outputdir, data.metadata_filename))
|
|
187
|
+
FileUtils.mkdir_p filename.dirname
|
|
188
|
+
log.info "Saving #{filename} .."
|
|
189
|
+
if not filename.dirname.exist?
|
|
190
|
+
log.info "Creating non existing #{filename.dirname} .."
|
|
191
|
+
filename.dirname.mkpath
|
|
192
|
+
end
|
|
193
|
+
# compress the output
|
|
194
|
+
Zlib::GzipWriter.open(filename) do |gz|
|
|
195
|
+
data.write(gz)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# enhancerepo is a rpm-md repository metadata tool.
|
|
4
|
+
# Copyright (C) 2008, 2009 Novell Inc.
|
|
5
|
+
# Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
|
6
|
+
#
|
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with this program; if not, write to the Free Software
|
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
20
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
|
21
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
|
22
|
+
#
|
|
23
|
+
#++
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
module EnhanceRepo
|
|
27
|
+
module RpmMd
|
|
28
|
+
|
|
29
|
+
# represents a resource in repomd.xml
|
|
30
|
+
class Resource
|
|
31
|
+
attr_accessor :type
|
|
32
|
+
attr_accessor :location, :checksum, :timestamp, :openchecksum
|
|
33
|
+
|
|
34
|
+
# define equality based on the location
|
|
35
|
+
# as it has no sense to have two resources for the
|
|
36
|
+
#same location
|
|
37
|
+
def ==(other)
|
|
38
|
+
return (location == other.location) if other.is_a?(Resource)
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# enhancerepo is a rpm-md repository metadata tool.
|
|
4
|
+
# Copyright (C) 2008, 2009 Novell Inc.
|
|
5
|
+
# Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
|
6
|
+
#
|
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with this program; if not, write to the Free Software
|
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
20
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
|
21
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
|
22
|
+
#
|
|
23
|
+
#++
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
module EnhanceRepo
|
|
27
|
+
module RpmMd
|
|
28
|
+
|
|
29
|
+
class Property
|
|
30
|
+
attr_accessor :name
|
|
31
|
+
def initialize(name)
|
|
32
|
+
@name = name
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def hash
|
|
36
|
+
@name.hash
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def eql?(other)
|
|
40
|
+
@name.eql?(other.name)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class ValueProperty < Property
|
|
45
|
+
def initialize(name, value)
|
|
46
|
+
super(name)
|
|
47
|
+
@value = value
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def write(builder, pkgid)
|
|
51
|
+
builder.tag!(@name, @value)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class DiskUsageProperty < Property
|
|
56
|
+
|
|
57
|
+
def initialize(pkgid, rpmfile)
|
|
58
|
+
super('diskusage')
|
|
59
|
+
@pkgid = pkgid
|
|
60
|
+
@rpmfile = rpmfile
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def write(builder, pkgid)
|
|
64
|
+
dirsizes = Hash.new
|
|
65
|
+
dircount = Hash.new
|
|
66
|
+
`rpm -q --queryformat \"[%{FILENAMES} %{FILESIZES}\n]\" -p '#{@rpmfile}'`.each_line do |line|
|
|
67
|
+
file, size = line.split
|
|
68
|
+
dirsizes[File.dirname(file)] = 0 if not dirsizes.has_key?(File.dirname(file))
|
|
69
|
+
dircount[File.dirname(file)] = 0 if not dircount.has_key?(File.dirname(file))
|
|
70
|
+
|
|
71
|
+
dirsizes[File.dirname(file)] += size.to_i
|
|
72
|
+
dircount[File.dirname(file)] += 1
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
builder.diskusage do |b|
|
|
76
|
+
b.dirs do |b|
|
|
77
|
+
dirsizes.each do |k, v|
|
|
78
|
+
b.dir('name' => k, 'size' => v, 'count' => dircount[k] )
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# represents SUSE extensions to
|
|
87
|
+
# primary data
|
|
88
|
+
#
|
|
89
|
+
# See:
|
|
90
|
+
# http://en.opensuse.org/Standards/Rpm_Metadata#SUSE_primary_data_.28susedata.xml.29
|
|
91
|
+
#
|
|
92
|
+
class SuseData < Data
|
|
93
|
+
|
|
94
|
+
def initialize(dir)
|
|
95
|
+
@dir = dir
|
|
96
|
+
@diskusage_enabled = false
|
|
97
|
+
|
|
98
|
+
# the following hash automatically creates a sub
|
|
99
|
+
# hash for non found values
|
|
100
|
+
# @properties = Hash.new { |h,v| h[v]= Hash.new }
|
|
101
|
+
@properties = Hash.new
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# add an attribute named name for a
|
|
106
|
+
# package identified with pkgid
|
|
107
|
+
def add_attribute(pkgid, prop)
|
|
108
|
+
if not @properties.has_key?(pkgid)
|
|
109
|
+
@properties.store(pkgid, Hash.new)
|
|
110
|
+
end
|
|
111
|
+
@properties[pkgid][prop.name] = prop
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def add_eulas
|
|
115
|
+
# add eulas
|
|
116
|
+
Dir["#{@dir}/**/*.eula"].each do |eulafile|
|
|
117
|
+
base = File.basename(eulafile, '.eula')
|
|
118
|
+
# => look for all rpms with that name in that dir
|
|
119
|
+
Dir["#{File.dirname(eulafile)}/#{base}*.rpm"].each do | rpmfile |
|
|
120
|
+
pkgid = PackageId.new(rpmfile)
|
|
121
|
+
if pkgid.matches(base)
|
|
122
|
+
eulacontent = File.new(eulafile).read
|
|
123
|
+
add_attribute(pkgid, ValueProperty.new('eula', eulacontent))
|
|
124
|
+
log.info "Adding eula: #{eulafile.to_s} to #{pkgid.to_s}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
# end of directory iteration
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def add_keywords
|
|
132
|
+
# add keywords
|
|
133
|
+
log.info "Adding repository keywords"
|
|
134
|
+
Dir["#{@dir}/**/*.keywords"].each do |keywordfile|
|
|
135
|
+
base = File.basename(keywordfile, '.keywords')
|
|
136
|
+
# => look for all rpms with that name in that dir
|
|
137
|
+
Dir["#{File.dirname(keywordfile)}/#{base}*.rpm"].each do | rpmfile |
|
|
138
|
+
pkgid = PackageId.new(rpmfile)
|
|
139
|
+
if pkgid.matches(base)
|
|
140
|
+
f = File.new(keywordfile)
|
|
141
|
+
f.each_line do |line|
|
|
142
|
+
keyword = line.chop
|
|
143
|
+
add_attribute(pkgid, ValueProperty.new('keyword', keyword)) if not keyword.empty?
|
|
144
|
+
end
|
|
145
|
+
log.info "`-> adding keyword: #{keywordfile.to_s} to #{pkgid.to_s}"
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
# end of directory iteration
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def empty?
|
|
153
|
+
@properties.empty?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def size
|
|
157
|
+
@properties.size
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# write an extension file like other.xml
|
|
161
|
+
def write(file)
|
|
162
|
+
builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
|
|
163
|
+
builder.instruct!
|
|
164
|
+
xml = builder.tag!(name) do |b|
|
|
165
|
+
@properties.each do |pkgid, props|
|
|
166
|
+
#log.info "Dumping package #{pkgid.to_s}"
|
|
167
|
+
b.package('pkgid' => pkgid.checksum, 'name' => pkgid.name) do |b|
|
|
168
|
+
b.version('ver' => pkgid.version.v, 'rel' => pkgid.version.r, 'arch' => pkgid.arch, 'epoch' => 0.to_s )
|
|
169
|
+
props.each do |propname, prop|
|
|
170
|
+
#log.info " -> property #{prop.name}"
|
|
171
|
+
prop.write(builder, pkgid)
|
|
172
|
+
end
|
|
173
|
+
end # end package tag
|
|
174
|
+
end # iterate over properties
|
|
175
|
+
end #done builder
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def add_disk_usage
|
|
179
|
+
@diskusage_enabled = true
|
|
180
|
+
log.info "Calculating disk usage..."
|
|
181
|
+
# build the pkgid hash
|
|
182
|
+
Dir["#{@dir}/**/*.rpm"].each do |rpmfile|
|
|
183
|
+
pkgid = PackageId.new(rpmfile)
|
|
184
|
+
add_attribute(pkgid, DiskUsageProperty.new(pkgid, rpmfile))
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end
|
|
191
|
+
end
|