polisher 0.4 → 0.5.1

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