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.
Files changed (87) hide show
  1. data/CHANGELOG.rdoc +18 -0
  2. data/Manifest.txt +85 -0
  3. data/README +10 -0
  4. data/README.rdoc +15 -0
  5. data/Rakefile +48 -0
  6. data/TODO.rdoc +4 -0
  7. data/bin/enhancerepo +4 -0
  8. data/lib/enhance_repo.rb +36 -0
  9. data/lib/enhance_repo/cli.rb +150 -0
  10. data/lib/enhance_repo/config_opts.rb +98 -0
  11. data/lib/enhance_repo/logger.rb +67 -0
  12. data/lib/enhance_repo/other.rb +80 -0
  13. data/lib/enhance_repo/package_id.rb +81 -0
  14. data/lib/enhance_repo/product_id.rb +30 -0
  15. data/lib/enhance_repo/rpm_md.rb +27 -0
  16. data/lib/enhance_repo/rpm_md/data.rb +55 -0
  17. data/lib/enhance_repo/rpm_md/delta_info.rb +205 -0
  18. data/lib/enhance_repo/rpm_md/extra_primary_data.rb +45 -0
  19. data/lib/enhance_repo/rpm_md/file_lists.rb +81 -0
  20. data/lib/enhance_repo/rpm_md/index.rb +144 -0
  21. data/lib/enhance_repo/rpm_md/other.rb +69 -0
  22. data/lib/enhance_repo/rpm_md/primary.rb +123 -0
  23. data/lib/enhance_repo/rpm_md/products.rb +142 -0
  24. data/lib/enhance_repo/rpm_md/repo.rb +202 -0
  25. data/lib/enhance_repo/rpm_md/resource.rb +44 -0
  26. data/lib/enhance_repo/rpm_md/suse_data.rb +191 -0
  27. data/lib/enhance_repo/rpm_md/suse_info.rb +88 -0
  28. data/lib/enhance_repo/rpm_md/update.rb +141 -0
  29. data/lib/enhance_repo/rpm_md/update_info.rb +244 -0
  30. data/lib/enhance_repo/rpm_md/update_smart_fields.rb +127 -0
  31. data/lib/enhance_repo/xml_comparer.rb +117 -0
  32. data/lib/tempdir.rb +62 -0
  33. data/lib/tempdir/tempfile.rb +21 -0
  34. data/test/all_tests.rb +27 -0
  35. data/test/data/packages/a-1.0.spec +19 -0
  36. data/test/data/packages/a-2.0.spec +24 -0
  37. data/test/data/repodata/update-test-11.1/filelists.xml.gz +0 -0
  38. data/test/data/repodata/update-test-11.1/other.xml.gz +0 -0
  39. data/test/data/repodata/update-test-11.1/primary.xml.gz +0 -0
  40. data/test/data/repodata/update-test-11.1/repomd.xml +21 -0
  41. data/test/data/repomd.xml +21 -0
  42. data/test/data/rpms/repo-1/a-1.0-0.x86_64.rpm +0 -0
  43. data/test/data/rpms/repo-1/a-1.0_2.0-0_0.x86_64.delta.rpm +0 -0
  44. data/test/data/rpms/repo-1/a-2.0-0.x86_64.rpm +0 -0
  45. data/test/data/rpms/repo-1/repodata/deltainfo.xml.gz +0 -0
  46. data/test/data/rpms/repo-1/repodata/deltainfo.xml.gz.gz +0 -0
  47. data/test/data/rpms/repo-1/repodata/filelists.xml.gz +0 -0
  48. data/test/data/rpms/repo-1/repodata/other.xml.gz +0 -0
  49. data/test/data/rpms/repo-1/repodata/primary.xml.gz +0 -0
  50. data/test/data/rpms/repo-1/repodata/repomd.xml +45 -0
  51. data/test/data/rpms/repo-1/repodata/susedata.xml.gz +0 -0
  52. data/test/data/rpms/repo-1/repodata/updateinfo.xml.gz +0 -0
  53. data/test/data/rpms/repo-1/repoparts/update-a-1.xml +22 -0
  54. data/test/data/rpms/repo-with-product/a-1.0-0.x86_64.rpm +0 -0
  55. data/test/data/rpms/repo-with-product/openSUSE-release-11.2-1.6.i586.rpm +0 -0
  56. data/test/data/rpms/repo-with-product/openSUSE-release-dvd-11.2-1.6.i586.rpm +0 -0
  57. data/test/data/rpms/repo-with-product/repodata/filelists.xml.gz +0 -0
  58. data/test/data/rpms/repo-with-product/repodata/other.xml.gz +0 -0
  59. data/test/data/rpms/repo-with-product/repodata/primary.xml.gz +0 -0
  60. data/test/data/rpms/repo-with-product/repodata/products.xml.gz +0 -0
  61. data/test/data/rpms/repo-with-product/repodata/repomd.xml +27 -0
  62. data/test/data/rpms/update-test-11.1/update-test-affects-package-manager.rpm +0 -0
  63. data/test/data/rpms/update-test-11.1/update-test-interactive.rpm +0 -0
  64. data/test/data/rpms/update-test-11.1/update-test-optional.rpm +0 -0
  65. data/test/data/rpms/update-test-11.1/update-test-reboot-needed.rpm +0 -0
  66. data/test/data/rpms/update-test-11.1/update-test-security.rpm +0 -0
  67. data/test/data/rpms/update-test-11.1/update-test-trival.rpm +0 -0
  68. data/test/data/rpms/update-test-factory/update-test-affects-package-manager-0-9999.1.2.noarch.rpm +0 -0
  69. data/test/data/rpms/update-test-factory/update-test-interactive-0-9999.1.2.noarch.rpm +0 -0
  70. data/test/data/rpms/update-test-factory/update-test-optional-0-9999.1.2.noarch.rpm +0 -0
  71. data/test/data/rpms/update-test-factory/update-test-reboot-needed-0-9999.1.2.noarch.rpm +0 -0
  72. data/test/data/rpms/update-test-factory/update-test-relogin-suggested-0-9999.1.2.noarch.rpm +0 -0
  73. data/test/data/rpms/update-test-factory/update-test-security-0-9999.1.2.noarch.rpm +0 -0
  74. data/test/deltainfo_test.rb +50 -0
  75. data/test/extensions_test.rb +31 -0
  76. data/test/index_test.rb +51 -0
  77. data/test/primary_test.rb +51 -0
  78. data/test/products_test.rb +51 -0
  79. data/test/repo_test.rb +72 -0
  80. data/test/repomdindex_test.rb +58 -0
  81. data/test/rpmmd_test.rb +60 -0
  82. data/test/susedata_test.rb +53 -0
  83. data/test/tempdir_test.rb +62 -0
  84. data/test/test_helper.rb +53 -0
  85. data/test/update_test.rb +80 -0
  86. data/test/updateinfo_test.rb +59 -0
  87. 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