polisher 0.4 → 0.5.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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -661
  3. data/README.md +39 -0
  4. data/Rakefile +11 -88
  5. data/bin/binary_gem_resolver.rb +95 -0
  6. data/bin/gem_dependency_checker.rb +165 -0
  7. data/bin/git_gem_updater.rb +86 -0
  8. data/bin/ruby_rpm_spec_updater.rb +29 -0
  9. data/lib/polisher.rb +19 -0
  10. data/lib/polisher/apt.rb +12 -0
  11. data/lib/polisher/bodhi.rb +21 -0
  12. data/lib/polisher/bugzilla.rb +9 -0
  13. data/lib/polisher/core.rb +33 -0
  14. data/lib/polisher/errata.rb +43 -0
  15. data/lib/polisher/fedora.rb +43 -0
  16. data/lib/polisher/gem.rb +155 -0
  17. data/lib/polisher/gemfile.rb +72 -0
  18. data/lib/polisher/gemspec.rb +32 -0
  19. data/lib/polisher/git.rb +135 -0
  20. data/lib/polisher/koji.rb +54 -0
  21. data/lib/polisher/rhn.rb +14 -0
  22. data/lib/polisher/rpmspec.rb +254 -0
  23. data/lib/polisher/upstream.rb +29 -0
  24. data/lib/polisher/vendor.rb +9 -0
  25. data/lib/polisher/version_checker.rb +100 -0
  26. data/lib/polisher/yum.rb +28 -0
  27. data/spec/core_spec.rb +64 -0
  28. data/spec/fedora_spec.rb +14 -0
  29. data/spec/gem_spec.rb +82 -0
  30. data/spec/gemfile_spec.rb +45 -0
  31. data/spec/git_spec.rb +74 -0
  32. data/spec/rpmspec_spec.rb +105 -0
  33. data/spec/spec_helper.rb +50 -37
  34. data/spec/upstream_spec.rb +39 -0
  35. metadata +173 -179
  36. data/COPYING +0 -8
  37. data/README.rdoc +0 -105
  38. data/TODO +0 -7
  39. data/bin/server +0 -4
  40. data/config.ru +0 -25
  41. data/config/database.yml +0 -13
  42. data/config/polisher.yml +0 -5
  43. data/db/connection.rb +0 -52
  44. data/db/migrations/001_create_projects.rb +0 -23
  45. data/db/migrations/002_create_sources.rb +0 -25
  46. data/db/migrations/003_create_project_source_versions.rb +0 -28
  47. data/db/migrations/004_create_events.rb +0 -27
  48. data/db/migrations/005_create_project_dependencies.rb +0 -28
  49. data/db/models/event.rb +0 -87
  50. data/db/models/project.rb +0 -110
  51. data/db/models/project_dependency.rb +0 -27
  52. data/db/models/project_source_version.rb +0 -31
  53. data/db/models/source.rb +0 -101
  54. data/lib/common.rb +0 -71
  55. data/lib/dsl.rb +0 -292
  56. data/lib/event_handlers.rb +0 -166
  57. data/lib/gem_adapter.rb +0 -94
  58. data/lib/sinatra/url_for.rb +0 -40
  59. data/polisher.rb +0 -372
  60. data/public/stylesheets/style.css +0 -67
  61. data/spec/common_spec.rb +0 -28
  62. data/spec/dsl_spec.rb +0 -357
  63. data/spec/event_handlers_spec.rb +0 -300
  64. data/spec/gem_adapter_spec.rb +0 -89
  65. data/spec/models_spec.rb +0 -721
  66. data/spec/polisher_spec.rb +0 -573
  67. data/views/layout.haml +0 -22
  68. data/views/projects/index.haml +0 -42
  69. data/views/projects/index.html.haml +0 -38
  70. data/views/result.haml +0 -9
  71. data/views/sources/index.haml +0 -24
  72. data/views/sources/index.html.haml +0 -26
@@ -0,0 +1,32 @@
1
+ # Polisher Gemspec Represenation
2
+ #
3
+ # Licensed under the MIT license
4
+ # Copyright (C) 2013 Red Hat, Inc.
5
+
6
+ require 'polisher/version_checker'
7
+
8
+ module Polisher
9
+ class Gemspec
10
+ include VersionedDependencies
11
+
12
+ attr_accessor :deps
13
+
14
+ def initialize(args={})
15
+ @deps = args[:deps]
16
+ end
17
+
18
+ # Parse the specified gemspec & return new Gemspec instance from metadata
19
+ #
20
+ # @param [String] path to gemspec to parse
21
+ # @return [Polisher::Gemspec] gemspec instantiated from parsed metadata
22
+ def self.parse(path)
23
+ parser = Gemnasium::Parser.gemspec(File.read(path))
24
+ metadata = {:deps => [], :dev_deps => []}
25
+ parser.dependencies.each { |dep|
26
+ metadata[:deps] << dep.name
27
+ }
28
+
29
+ self.new metadata
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,135 @@
1
+ # Polisher DistGit Package Representation
2
+ #
3
+ # Licensed under the MIT license
4
+ # Copyright (C) 2013 Red Hat, Inc.
5
+
6
+ # TODO use ruby git api and others
7
+
8
+ require 'polisher/rpmspec'
9
+
10
+ module Polisher
11
+ class GitPackage
12
+ attr_accessor :name
13
+ attr_accessor :version
14
+
15
+ # TODO these should be to be configurable
16
+ PKG_CMD = '/usr/bin/fedpkg'
17
+ GIT_CMD = '/usr/bin/git'
18
+ BUILD_CMD = '/usr/bin/koji'
19
+ BUILD_TGT = 'rawhide'
20
+ MD5SUM_CMD = '/usr/bin/md5sum'
21
+ SED_CMD = '/usr/bin/sed'
22
+ RPM_PREFIX = 'rubygem-'
23
+ DIST_GIT_URL = 'git://pkgs.fedoraproject.org/'
24
+
25
+ def initialize(args={})
26
+ @name = args[:name]
27
+ @version = args[:version]
28
+ end
29
+
30
+ # Return full rpm name of package containing optional prefix
31
+ def rpm_name
32
+ "#{RPM_PREFIX}#{self.name}"
33
+ end
34
+
35
+ # Return full srpm file name of package
36
+ def srpm
37
+ "#{rpm_name}-#{self.version}-1.*.src.rpm"
38
+ end
39
+
40
+ # Return full spec file name
41
+ def spec
42
+ "#{rpm_name}.spec"
43
+ end
44
+
45
+ # Clone git package
46
+ #
47
+ # @param [String] name name of package to clone
48
+ # @return [Polisher::GitPackage] git package instance representing cloned package
49
+ def self.clone(name)
50
+ rpm_name = "#{RPM_PREFIX}#{name}"
51
+
52
+ unless File.directory? rpm_name
53
+ `#{PKG_CMD} clone #{rpm_name}`
54
+ end
55
+
56
+ # cd into working directory
57
+ Dir.chdir rpm_name
58
+
59
+ if File.exists? 'dead.package'
60
+ raise Exception, "Dead package detected"
61
+ end
62
+
63
+ # checkout the latest rawhide
64
+ # TODO allow other branches to be specified
65
+ `#{GIT_CMD} checkout master`
66
+ `#{GIT_CMD} reset HEAD~ --hard`
67
+ `#{GIT_CMD} pull`
68
+
69
+ self.new :name => name
70
+ end
71
+
72
+ # Update the locally cloned package to the specified gem version
73
+ #
74
+ # @param [Polisher::Gem] gem instance of gem containing metadata to update to
75
+ def update_to(gem)
76
+ # TODO use Polisher::RPMSpec to update spec
77
+ `#{SED_CMD} -i "s/Version.*/Version: #{gem.version}/" #{spec}`
78
+ `#{SED_CMD} -i "s/Release:.*/Release: 1%{?dist}/" #{spec}`
79
+ `#{MD5SUM_CMD} #{gem.name}-#{gem.version}.gem > sources`
80
+ File.open(".gitignore", "w") { |f| f.write "#{gem.name}-#{gem.version}.gem" }
81
+ end
82
+
83
+ # Build the locally cloned package using the configured build command
84
+ def build
85
+ # build srpm
86
+ `#{PKG_CMD} srpm`
87
+
88
+ # attempt to build packages
89
+ `#{BUILD_CMD} build --scratch #{BUILD_TGT} #{srpm}`
90
+ # TODO if build fails, spit out error, exit
91
+ end
92
+
93
+ # Return boolean indicating if package spec has a %check section
94
+ #
95
+ # @return [Boolean] true/false depending on whether or not spec has %check
96
+ def has_check?
97
+ open(spec, "r") do |spec|
98
+ spec.lines.any? { |line| line.include?("%check") }
99
+ end
100
+ end
101
+
102
+ # Command the local package to the local git repo
103
+ def commit
104
+ # git add spec, git commit w/ message
105
+ `#{GIT_CMD} add #{spec} sources .gitignore`
106
+ #`git add #{gem_name}-#{version}.gem`
107
+ `#{GIT_CMD} commit -m 'updated to #{self.version}'`
108
+ end
109
+
110
+ # Retrieve list of the version of the specified package in git
111
+ #
112
+ # @param [String] name name of package to lookup
113
+ # @param [Callable] bl optional block to invoke with version retrieved
114
+ # @return [String] version retrieved, or nil if none found
115
+ def self.version_for(name, &bl)
116
+ rpm_name = "#{RPM_PREFIX}#{name}"
117
+ version = nil
118
+
119
+ Dir.mktmpdir do |dir|
120
+ Dir.chdir(dir) do |path|
121
+ version = nil
122
+ `#{GIT_CMD} clone #{DIST_GIT_URL}#{rpm_name}.git . >& /dev/null`
123
+ begin
124
+ spec = Polisher::RPMSpec.parse(File.read("#{rpm_name}.spec"))
125
+ version = spec.version
126
+ rescue => e
127
+ end
128
+ end
129
+ end
130
+
131
+ bl.call(:git, name, [version]) unless(bl.nil?)
132
+ version
133
+ end
134
+ end # class GitPackage
135
+ end # module Polisher
@@ -0,0 +1,54 @@
1
+ # Polisher Koji Operations
2
+ #
3
+ # Licensed under the MIT license
4
+ # Copyright (C) 2013 Red Hat, Inc.
5
+
6
+ require 'xmlrpc/client'
7
+ XMLRPC::Config::ENABLE_NIL_PARSER = true
8
+ XMLRPC::Config::ENABLE_NIL_CREATE = true
9
+
10
+ module Polisher
11
+ class Koji
12
+ KOJI_URL = 'koji.fedoraproject.org/kojihub'
13
+ KOJI_TAG = 'f21'
14
+
15
+ # Get/Set the koji url
16
+ def self.koji_url(value=nil)
17
+ @koji_url ||= KOJI_URL
18
+ @koji_url = value unless value.nil?
19
+ @koji_url
20
+ end
21
+
22
+ # Get/Set the koji tag to use
23
+ def self.koji_tag(value=nil)
24
+ @koji_tag ||= KOJI_TAG
25
+ @koji_tag = value unless value.nil?
26
+ @koji_tag
27
+ end
28
+
29
+ # Retrieve shared instance of xmlrpc client to use
30
+ def self.client
31
+ @client ||= begin
32
+ url = self.koji_url.split('/')
33
+ XMLRPC::Client.new(url[0..-2].join('/'),
34
+ "/#{url.last}")
35
+ end
36
+ end
37
+
38
+ # Retrieve list of the version of the specified package in koji
39
+ #
40
+ # @param [String] name name of package to lookup
41
+ # @param [Callable] bl optional block to invoke with versions retrieved
42
+ # @return [String] versions retrieved, or nil if none found
43
+ def self.versions_for(name, &bl)
44
+ # koji xmlrpc call
45
+ builds =
46
+ self.client.call('listTagged',
47
+ self.koji_tag, nil, false, nil, false,
48
+ "rubygem-#{name}")
49
+ versions = builds.collect { |b| b['version'] }
50
+ bl.call(:koji, name, versions) unless(bl.nil?)
51
+ versions
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ # Polisher RHN Operations
2
+ #
3
+ # Licensed under the MIT license
4
+ # Copyright (C) 2013 Red Hat, Inc.
5
+
6
+ require 'pkgwat'
7
+
8
+ module Polisher
9
+ class RHN
10
+ def self.version_for(name)
11
+ # TODO
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,254 @@
1
+ # Polisher RPM Spec Represenation
2
+ #
3
+ # Licensed under the MIT license
4
+ # Copyright (C) 2013 Red Hat, Inc.
5
+
6
+ require 'polisher/core'
7
+
8
+ module Polisher
9
+ class RPMSpec
10
+ AUTHOR = "#{ENV['USER']} <#{ENV['USER']}@localhost.localdomain>"
11
+
12
+ COMMENT_MATCHER = /^\s*#.*/
13
+ GEM_NAME_MATCHER = /^%global\s*gem_name\s(.*)$/
14
+ SPEC_NAME_MATCHER = /^Name:\s*rubygem-(.*)$/
15
+ SPEC_VERSION_MATCHER = /^Version:\s*(.*)$/
16
+ SPEC_RELEASE_MATCHER = /^Release:\s*(.*)$/
17
+ SPEC_REQUIRES_MATCHER = /^Requires:\s*(.*)$/
18
+ SPEC_BUILD_REQUIRES_MATCHER = /^BuildRequires:\s*(.*)$/
19
+ SPEC_GEM_REQ_MATCHER = /^.*\s*rubygem\((.*)\)$/
20
+ SPEC_SUBPACKAGE_MATCHER = /^%package\s(.*)$/
21
+ SPEC_CHANGELOG_MATCHER = /^%changelog$/
22
+ SPEC_FILES_MATCHER = /^%files$/
23
+ SPEC_SUBPKG_FILES_MATCHER = /^%files\s*(.*)$/
24
+
25
+ FILE_MACRO_MATCHERS =
26
+ [/^%doc\s/, /^%config\s/, /^%attr\s/,
27
+ /^%verify\s/, /^%docdir.*/, /^%dir\s/,
28
+ /^%defattr.*/, /^%exclude\s/, /^%{gem_instdir}/]
29
+
30
+ FILE_MACRO_REPLACEMENTS =
31
+ {"%{_bindir}" => '/bin',
32
+ "%{gem_libdir}" => '/lib'}
33
+
34
+ attr_accessor :metadata
35
+
36
+ def initialize(metadata={})
37
+ @metadata = metadata
38
+ end
39
+
40
+ # Dispatch all missing methods to lookup calls in rpm spec metadata
41
+ def method_missing(method, *args, &block)
42
+ # proxy to metadata
43
+ if @metadata.has_key?(method)
44
+ @metadata[method]
45
+
46
+ else
47
+ super(method, *args, &block)
48
+ end
49
+ end
50
+
51
+ # Parse the specified rpm spec and return new RPMSpec instance from metadata
52
+ #
53
+ # @param [String] string contents of spec to parse
54
+ # @return [Polisher::RPMSpec] spec instantiated from rpmspec metadata
55
+ def self.parse(spec)
56
+ in_subpackage = false
57
+ in_changelog = false
58
+ in_files = false
59
+ subpkg_name = nil
60
+ meta = {:contents => spec}
61
+ spec.each_line { |l|
62
+ if l =~ COMMENT_MATCHER
63
+ ;
64
+
65
+ # TODO support optional gem prefix
66
+ elsif l =~ GEM_NAME_MATCHER
67
+ meta[:gem_name] = $1.strip
68
+ meta[:gem_name] = $1.strip
69
+
70
+ elsif l =~ SPEC_NAME_MATCHER &&
71
+ $1.strip != "%{gem_name}"
72
+ meta[:gem_name] = $1.strip
73
+
74
+ elsif l =~ SPEC_VERSION_MATCHER
75
+ meta[:version] = $1.strip
76
+
77
+ elsif l =~ SPEC_RELEASE_MATCHER
78
+ meta[:release] = $1.strip
79
+
80
+ elsif l =~ SPEC_SUBPACKAGE_MATCHER
81
+ subpkg_name = $1.strip
82
+ in_subpackage = true
83
+
84
+ elsif l =~ SPEC_REQUIRES_MATCHER &&
85
+ !in_subpackage
86
+ meta[:requires] ||= []
87
+ meta[:requires] << $1.strip
88
+
89
+ elsif l =~ SPEC_BUILD_REQUIRES_MATCHER &&
90
+ !in_subpackage
91
+ meta[:build_requires] ||= []
92
+ meta[:build_requires] << $1.strip
93
+
94
+ elsif l =~ SPEC_CHANGELOG_MATCHER
95
+ in_changelog = true
96
+
97
+ elsif l =~ SPEC_FILES_MATCHER
98
+ subpkg_name = nil
99
+ in_files = true
100
+
101
+ elsif l =~ SPEC_SUBPKG_FILES_MATCHER
102
+ subpkg_name = $1.strip
103
+ in_files = true
104
+
105
+ elsif in_changelog
106
+ meta[:changelog] ||= ""
107
+ meta[:changelog] << l
108
+
109
+ elsif in_files
110
+ tgt = subpkg_name.nil? ? meta[:gem_name] : subpkg_name
111
+ meta[:files] ||= {}
112
+ meta[:files][tgt] ||= []
113
+
114
+ sl = l.strip.unrpmize
115
+ meta[:files][tgt] << sl unless sl.blank?
116
+ end
117
+ }
118
+
119
+ meta[:changelog_entries] = meta[:changelog] ?
120
+ meta[:changelog].split("\n\n") : []
121
+ meta[:changelog_entries].collect! { |c| c.strip }.compact!
122
+
123
+ self.new meta
124
+ end
125
+
126
+ # Update RPMSpec metadata to new gem
127
+ #
128
+ # @param [Polisher::Gem] new_source new gem to update rpmspec to
129
+ def update_to(new_source)
130
+ update_deps_from(new_source)
131
+ update_files_from(new_source)
132
+ update_metadata_from(new_source)
133
+ end
134
+
135
+ private
136
+
137
+ def update_deps_from(new_source)
138
+ non_gem_requires = []
139
+ non_gem_brequires = []
140
+ extra_gem_requires = []
141
+ extra_gem_brequires = []
142
+
143
+ @metadata[:requires] ||= []
144
+ @metadata[:requires].each { |r|
145
+ if r !~ SPEC_GEM_REQ_MATCHER
146
+ non_gem_requires << r
147
+ elsif !new_source.deps.include?($1)
148
+ extra_gem_requires << r
149
+ end
150
+ }
151
+
152
+ @metadata[:build_requires] ||= []
153
+ @metadata[:build_requires].each { |r|
154
+ if r !~ SPEC_GEM_REQ_MATCHER
155
+ non_gem_brequires << r
156
+ elsif !new_source.dev_deps.include?($1)
157
+ extra_gem_brequires << r
158
+ end
159
+ }
160
+
161
+ @metadata[:requires] =
162
+ non_gem_requires + extra_gem_requires +
163
+ new_source.deps.collect { |r| "rubygem(#{r})" }
164
+
165
+ @metadata[:build_requires] =
166
+ non_gem_brequires + extra_gem_brequires +
167
+ new_source.dev_deps.collect { |r| "rubygem(#{r})" }
168
+ end
169
+
170
+ def update_files_from(new_source)
171
+ to_add = new_source.files
172
+ @metadata[:files] ||= {}
173
+ @metadata[:files].each { |pkg,spec_files|
174
+ (new_source.files & to_add).each { |gem_file|
175
+ # skip files already included in spec or in dir in spec
176
+ has_file = spec_files.any? { |sf|
177
+ gem_file.gsub(sf,'') != gem_file
178
+ }
179
+
180
+ to_add.delete(gem_file)
181
+ to_add << gem_file.rpmize if !has_file
182
+ }
183
+ }
184
+
185
+ @metadata[:new_files] = to_add
186
+ end
187
+
188
+ def update_metadata_from(new_source)
189
+ # update to new version
190
+ @metadata[:version] = new_source.version
191
+
192
+ # better release updating ?
193
+ release = "1%{?dist}"
194
+ @metadata[:release] = release
195
+
196
+ # add changelog entry
197
+ changelog_entry = <<EOS
198
+ * #{Time.now.strftime("%a %b %d %Y")} #{AUTHOR} - #{$version}-#{release}
199
+ - Update to version #{new_source.version}
200
+ EOS
201
+ @metadata[:changelog_entries] ||= []
202
+ @metadata[:changelog_entries].unshift changelog_entry.rstrip
203
+ end
204
+
205
+ public
206
+
207
+ # Return properly formatted rpmspec as string
208
+ #
209
+ # @return [String] string representation of rpm spec
210
+ def to_string
211
+ contents = @metadata[:contents]
212
+
213
+ # replace version / release
214
+ contents.gsub!(SPEC_VERSION_MATCHER, "Version: #{@metadata[:version]}")
215
+ contents.gsub!(SPEC_RELEASE_MATCHER, "Release: #{@metadata[:release]}")
216
+
217
+ # add changelog entry
218
+ cp = contents.index SPEC_CHANGELOG_MATCHER
219
+ cpn = contents.index "\n", cp
220
+ contents = contents[0...cpn+1] +
221
+ @metadata[:changelog_entries].join("\n\n")
222
+
223
+ # update requires/build requires
224
+ rp = contents.index SPEC_REQUIRES_MATCHER
225
+ brp = contents.index SPEC_BUILD_REQUIRES_MATCHER
226
+ tp = rp < brp ? rp : brp
227
+
228
+ pp = contents.index SPEC_SUBPACKAGE_MATCHER
229
+ pp = -1 if pp.nil?
230
+
231
+ lrp = contents.rindex SPEC_REQUIRES_MATCHER, pp
232
+ lbrp = contents.rindex SPEC_BUILD_REQUIRES_MATCHER, pp
233
+ ltp = lrp > lbrp ? lrp : lbrp
234
+
235
+ ltpn = contents.index "\n", ltp
236
+
237
+ contents.slice!(tp...ltpn)
238
+ contents.insert tp,
239
+ (@metadata[:requires].collect { |r| "Requires: #{r}" } +
240
+ @metadata[:build_requires].collect { |r| "BuildRequires: #{r}" }).join("\n")
241
+
242
+ # add new files
243
+ fp = contents.index SPEC_FILES_MATCHER
244
+ lfp = contents.index SPEC_SUBPKG_FILES_MATCHER, fp + 1
245
+ lfp = contents.index SPEC_CHANGELOG_MATCHER if lfp.nil?
246
+
247
+ contents.insert lfp - 1, @metadata[:new_files].join("\n") + "\n"
248
+
249
+ # return new contents
250
+ contents
251
+ end
252
+
253
+ end # class RPMSpec
254
+ end # module Polisher