enhancerepo 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|