enhancerepo 0.4.1

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