polisher 0.9.1 → 0.10.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.
@@ -0,0 +1,86 @@
1
+ # Polisher Gem State Represenation
2
+ #
3
+ # Licensed under the MIT license
4
+ # Copyright (C) 2014 Red Hat, Inc.
5
+
6
+ require 'polisher/tag_mapper'
7
+
8
+ module Polisher
9
+ module HasState
10
+ def koji_tags
11
+ Koji.tagged_version_for(name)
12
+ end
13
+
14
+ def koji_state(args = {})
15
+ check_dep = args.key?(:check)
16
+
17
+ return :missing if koji_tags.empty?
18
+ return :available unless check_dep
19
+
20
+ koji_tags.each do |tag, version|
21
+ return :available if !version.nil? && args[:check].match?(name, version)
22
+ end
23
+
24
+ return :missing
25
+ end
26
+
27
+ def distgit
28
+ @distgit ||= Git::Pkg.new :name => name
29
+ end
30
+
31
+ def distgit_branches
32
+ tags = []
33
+
34
+ koji_tags.each do |tag, version|
35
+ tag = TagMapper.map(tag)
36
+ tags << tag unless tag.nil?
37
+ end
38
+
39
+ tags.empty? ? distgit.valid_branches : tags
40
+ end
41
+
42
+ def distgit_versions
43
+ distgit_branches.collect do |branch|
44
+ distgit.fetch branch
45
+ distgit.spec.version if distgit.spec?
46
+ end.compact
47
+ end
48
+
49
+ def distgit_state(args = {})
50
+ check_dep = args.key?(:check)
51
+
52
+ begin
53
+ distgit.clone
54
+ rescue
55
+ return :missing_repo
56
+ end
57
+
58
+ return :missing_branch if distgit.valid_branches.empty?
59
+ return :missing_spec if distgit_versions.empty?
60
+ return :available unless check_dep
61
+
62
+ distgit_versions.each do |version|
63
+ return :available if args[:check].match?(name, version)
64
+ end
65
+
66
+ return :missing
67
+ end
68
+
69
+ # Return the 'state' of the gem as inferred by
70
+ # the targets which there are versions for.
71
+ #
72
+ # If optional :check argument is specified, version
73
+ # analysis will be restricted to targets satisfying
74
+ # the specified gem dependency requirements
75
+ def state(args = {})
76
+ return :available if koji_state(args) == :available
77
+
78
+ state = distgit_state(args)
79
+ return :needs_repo if state == :missing_repo
80
+ return :needs_branch if state == :missing_branch
81
+ return :needs_spec if state == :missing_spec
82
+ return :needs_build if state == :available
83
+ return :needs_update
84
+ end
85
+ end
86
+ end
@@ -3,96 +3,94 @@
3
3
  # Licensed under the MIT license
4
4
  # Copyright (C) 2013-2014 Red Hat, Inc.
5
5
 
6
- require 'bundler'
7
-
8
6
  require 'polisher/git'
9
7
  require 'polisher/gem'
8
+ require 'polisher/component'
10
9
  require 'polisher/version_checker'
11
10
 
12
11
  module Polisher
13
- class Gemfile
14
- include VersionedDependencies
15
-
16
- # always nil, for interface compatability
17
- attr_accessor :version
18
-
19
- attr_accessor :deps
20
- attr_accessor :dev_deps
21
-
22
- # always empty array, for interface compatability
23
- attr_accessor :file_paths
24
-
25
- attr_accessor :definition
26
-
27
- def initialize(args={})
28
- @version = nil
29
- @deps = args[:deps]
30
- @dev_deps = args[:dev_deps]
31
- @definition = args[:definition]
32
- @file_paths = []
33
- end
34
-
35
- # Parse the specified gemfile & return new Gemfile instance from metadata
36
- #
37
- # @param [String] path to gemfile to parse
38
- # @return [Polisher::Gemfile] gemfile instantiated from parsed metadata
39
- def self.parse(path, args={})
40
- groups = args[:groups]
41
-
42
- definition = nil
43
- path,g = File.split(path)
44
- Dir.chdir(path){
45
- begin
46
- definition = Bundler::Definition.build(g, nil, false)
47
- rescue Bundler::GemfileNotFound
48
- raise ArgumentError, "invalid gemfile: #{path}"
49
- end
50
- }
51
-
52
- metadata = {}
53
- metadata[:deps] =
54
- definition.dependencies.select { |d|
55
- groups.nil? || groups.empty? || # groups not specified
56
- groups.any? { |g| d.groups.include?(g.intern) } # dep in any group
57
- }.collect { |d| d.name }
58
-
59
- metadata[:dev_deps] = [] # TODO
60
- metadata[:definition] = definition
61
-
62
- self.new metadata
63
- end
64
-
65
- # Simply alias for all dependencies in Gemfile
66
- def vendored
67
- deps + dev_deps
68
- end
69
-
70
- # Retrieve gems which differ from
71
- # rubygems.org/other upstream sources
72
- def patched
73
- vendored.collect do |dep|
74
- bundler_dep = @definition ?
75
- @definition.dependencies.find { |d| d.name == dep } : nil
76
-
77
- # TODO right now just handling git based alternate sources,
78
- # should be able to handle other types bundler supports
79
- # (path and alternate rubygems src)
80
- next unless bundler_dep && bundler_dep.source.is_a?(Bundler::Source::Git)
81
- src = bundler_dep.source
82
-
83
- # retrieve gem
84
- gem = src.version ?
85
- Polisher::Gem.new(:name => dep, :version => src.version) :
86
- Polisher::Gem.retrieve(dep)
87
-
88
- # retrieve dep
89
- git = Polisher::Git::Repo.new :url => src.uri
90
- git.clone unless git.cloned?
91
- git.checkout src.ref if src.ref
92
-
93
- # diff gem against git
94
- gem.diff(git.path)
95
- end.compact!
96
- end
97
- end # class Gemfile
12
+ Component.verify("Gemfile", 'bundler') do
13
+ class Gemfile
14
+ include VersionedDependencies
15
+
16
+ # always nil, for interface compatability
17
+ attr_accessor :version
18
+
19
+ attr_accessor :deps
20
+ attr_accessor :dev_deps
21
+
22
+ # always empty array, for interface compatability
23
+ attr_accessor :file_paths
24
+
25
+ attr_accessor :definition
26
+
27
+ def initialize(args = {})
28
+ @version = nil
29
+ @deps = args[:deps]
30
+ @dev_deps = args[:dev_deps]
31
+ @definition = args[:definition]
32
+ @file_paths = []
33
+ end
34
+
35
+ # Parse the specified gemfile & return new Gemfile instance from metadata
36
+ #
37
+ # @param [String] path to gemfile to parse
38
+ # @return [Polisher::Gemfile] gemfile instantiated from parsed metadata
39
+ def self.parse(path, args = {})
40
+ groups = args[:groups]
41
+
42
+ definition = nil
43
+ path, gemfile = File.split(path)
44
+ Dir.chdir(path){
45
+ begin
46
+ definition = Bundler::Definition.build(gemfile, nil, false)
47
+ rescue Bundler::GemfileNotFound
48
+ raise ArgumentError, "invalid gemfile: #{path}"
49
+ end
50
+ }
51
+
52
+ metadata = {}
53
+ metadata[:deps] =
54
+ definition.dependencies.select { |d|
55
+ groups.nil? || groups.empty? || # groups not specified
56
+ groups.any? { |g| d.groups.include?(g.intern) } # dep in any group
57
+ }
58
+
59
+ metadata[:dev_deps] = [] # TODO
60
+ metadata[:definition] = definition
61
+
62
+ new metadata
63
+ end
64
+
65
+ # Simply alias for all dependencies in Gemfile
66
+ def vendored
67
+ deps + dev_deps
68
+ end
69
+
70
+ # Retrieve gems which differ from
71
+ # rubygems.org/other upstream sources
72
+ def patched
73
+ vendored.collect do |dep|
74
+ # TODO: right now just handling git based alternate sources,
75
+ # should be able to handle other types bundler supports
76
+ # (path and alternate rubygems src)
77
+ next unless dep.source.is_a?(Bundler::Source::Git)
78
+ src = dep.source
79
+
80
+ # retrieve gem
81
+ gem = src.version ?
82
+ Polisher::Gem.new(:name => dep.name, :version => src.version) :
83
+ Polisher::Gem.retrieve(dep.name)
84
+
85
+ # retrieve dep
86
+ git = Polisher::Git::Repo.new :url => src.uri
87
+ git.clone unless git.cloned?
88
+ git.checkout src.ref if src.ref
89
+
90
+ # diff gem against git
91
+ gem.diff(git.path)
92
+ end.compact!
93
+ end
94
+ end # class Gemfile
95
+ end # Component.verify("Gemfile")
98
96
  end # module Polisher
@@ -3,189 +3,246 @@
3
3
  # Licensed under the MIT license
4
4
  # Copyright (C) 2013-2014 Red Hat, Inc.
5
5
 
6
- require 'awesome_spawn'
6
+ require 'fileutils'
7
7
 
8
8
  require 'polisher/error'
9
9
  require 'polisher/git/repo'
10
10
  require 'polisher/rpm/spec'
11
+ require 'polisher/component'
12
+ require 'polisher/koji'
13
+ require 'polisher/logger'
11
14
 
12
15
  module Polisher
13
16
  module Git
14
- # Git Repository
15
- class Pkg < Repo
16
- attr_accessor :name
17
- attr_accessor :version
18
-
19
- conf_attr :rpm_prefix, 'rubygem-'
20
- conf_attr :pkg_cmd, '/usr/bin/fedpkg'
21
- conf_attr :build_cmd, '/usr/bin/koji'
22
- conf_attr :build_tgt, 'rawhide'
23
- conf_attr :md5sum_cmd, '/usr/bin/md5sum'
24
- conf_attr :dist_git_url, 'git://pkgs.fedoraproject.org/'
25
- conf_attr :fetch_tgt, 'master'
26
-
27
- def initialize(args={})
28
- @name = args[:name]
29
- @version = args[:version]
30
- super(args)
31
- end
32
-
33
- # Return full rpm name of package containing optional prefix
34
- def rpm_name
35
- @rpm_name ||= "#{rpm_prefix}#{self.name}"
36
- end
37
-
38
- # Return full srpm file name of package
39
- def srpm
40
- @srpm ||= "#{rpm_name}-#{self.version}-1.*.src.rpm"
41
- end
42
-
43
- # Return full spec file name
44
- def spec_file
45
- @spec_path ||= "#{rpm_name}.spec"
46
- end
47
-
48
- # Return handle to instance of Polisher::RPM::Spec corresponding to spec
49
- def spec
50
- @spec ||= in_repo { Polisher::RPM::Spec.parse File.read(spec_file) }
51
- end
52
-
53
- # Files representing pkg tracked by git
54
- def pkg_files
55
- @pkg_files ||= [spec_file, 'sources', '.gitignore']
56
- end
57
-
58
- # Override path to reference pkg name
59
- # @override
60
- def path
61
- GitCache.path_for(rpm_name)
62
- end
63
-
64
- # Alias orig clone method to git_clone
65
- alias :git_clone :clone
66
-
67
- # Override clone to use PKG_PCMD
68
- # @override
69
- def clone
70
- self.clobber!
71
- Dir.mkdir path unless File.directory? path
72
- in_repo do
73
- result = AwesomeSpawn.run "#{pkg_cmd} clone #{rpm_name}"
74
- raise PolisherError,
75
- "could not clone #{rpm_name}" unless result.exit_status == 0
76
-
77
- # pkg_cmd will clone into the rpm_name subdir,
78
- # move everything up a dir
79
- Dir.foreach("#{rpm_name}/") do |f|
80
- orig = "#{rpm_name}/#{f}"
81
- skip = ['.', '..'].include?(f)
82
- FileUtils.move orig, '.' unless skip
17
+ Component.verify("Git::Pkg", 'awesome_spawn') do
18
+ # Git Based Package
19
+ class Pkg < Repo
20
+ extend Logging
21
+
22
+ attr_accessor :name
23
+ attr_accessor :version
24
+
25
+ conf_attr :rpm_prefix, 'rubygem-'
26
+ conf_attr :pkg_cmd, '/usr/bin/fedpkg'
27
+ conf_attr :md5sum_cmd, '/usr/bin/md5sum'
28
+ conf_attr :dist_git_url, 'git://pkgs.fedoraproject.org/'
29
+ conf_attr :fetch_tgt, 'master'
30
+
31
+ def self.fetch_tgts
32
+ [fetch_tgt].flatten
33
+ end
34
+
35
+ def initialize(args = {})
36
+ @name = args[:name]
37
+ @version = args[:version]
38
+ super(args)
39
+ end
40
+
41
+ # Return full rpm name of package containing optional prefix
42
+ def rpm_name
43
+ @rpm_name ||= "#{rpm_prefix}#{name}"
44
+ end
45
+
46
+ # Return full srpm file name of package
47
+ def srpm
48
+ @srpm ||= "#{rpm_name}-#{version}-1.*.src.rpm"
49
+ end
50
+
51
+ # Return full spec file name
52
+ def spec_file
53
+ @spec_path ||= "#{rpm_name}.spec"
54
+ end
55
+
56
+ # Return boolean indicating if spec file exists
57
+ def spec?
58
+ include? spec_file
59
+ end
60
+
61
+ # Return handle to instance of Polisher::RPM::Spec corresponding to spec
62
+ def spec
63
+ @spec, @dirty_spec = nil, false if @dirty_spec
64
+ @spec ||= in_repo { Polisher::RPM::Spec.parse File.read(spec_file) }
65
+ end
66
+
67
+ # Files representing pkg tracked by git
68
+ def pkg_files
69
+ @pkg_files ||= [spec_file, 'sources', '.gitignore']
70
+ end
71
+
72
+ # Override path to reference pkg name
73
+ # @override
74
+ def path
75
+ GitCache.path_for(rpm_name)
76
+ end
77
+
78
+ # Alias orig clone method to git_clone
79
+ alias :git_clone :clone
80
+
81
+ # Override clone to use PKG_PCMD
82
+ # @override
83
+ def clone
84
+ require_cmd! pkg_cmd
85
+ clobber!
86
+ Dir.mkdir path unless File.directory? path
87
+ in_repo do
88
+ result = AwesomeSpawn.run "#{pkg_cmd} clone #{rpm_name}"
89
+ raise PolisherError,
90
+ "could not clone #{rpm_name}" unless result.exit_status == 0
91
+
92
+ # pkg_cmd will clone into the rpm_name subdir,
93
+ # move everything up a dir
94
+ Dir.foreach("#{rpm_name}/") do |f|
95
+ orig = "#{rpm_name}/#{f}"
96
+ skip = ['.', '..'].include?(f)
97
+ FileUtils.move orig, '.' unless skip
98
+ end
99
+
100
+ FileUtils.rm_rf rpm_name
101
+ end
102
+
103
+ self
104
+ end
105
+
106
+ # Return boolean indicating if package is marked as dead (retired/obsolete/etc)
107
+ def dead?
108
+ in_repo { File.exist?('dead.package') }
109
+ end
110
+
111
+ # Fetch specified target or configured fetch_tgt if not specified
112
+ def fetch(target = nil)
113
+ target = self.class.fetch_tgts.first if target.nil?
114
+ clone unless cloned?
115
+ raise Exception, "Dead package detected" if dead?
116
+ checkout target
117
+ reset!
118
+ pull
119
+
120
+ self
121
+ end
122
+
123
+ # Return the valid targets, eg those which we can fetch
124
+ def valid_targets
125
+ valid = []
126
+ self.class.fetch_tgts.collect do |target|
127
+ begin
128
+ fetch target
129
+ valid << target
130
+ rescue
131
+ # noop
132
+ end
83
133
  end
134
+ valid
135
+ end
84
136
 
85
- FileUtils.rm_rf rpm_name
86
- end
87
-
88
- self
89
- end
90
-
91
- # Return boolean indicating if package is marked as dead (retired/obsolete/etc)
92
- def dead?
93
- in_repo { File.exists?('dead.package') }
94
- end
95
-
96
- # Clone / init GitPkg
97
- def fetch
98
- clone unless cloned?
99
- raise Exception, "Dead package detected" if dead?
100
- checkout fetch_tgt
101
- reset!
102
- pull
103
-
104
- self
105
- end
106
-
107
- # Update the local spec to the specified gem version
108
- def update_spec_to(gem)
109
- in_repo do
110
- spec.update_to(gem)
111
- File.write(spec_file, spec.to_string)
112
- end
113
- end
114
-
115
- # Generate new sources file
116
- def gen_sources_for(gem)
117
- in_repo do
118
- AwesomeSpawn.run "#{md5sum_cmd} #{gem.gem_path} > sources"
119
- File.write('sources', File.read('sources').gsub("#{GemCache::DIR}/", ''))
120
- end
121
- end
122
-
123
- # Update git ignore to ignore gem
124
- def ignore(gem)
125
- in_repo do
126
- nl = File.exists?('.gitignore') ? "\n" : ''
127
- content = "#{nl}#{gem.name}-#{gem.version}.gem"
128
- File.open(".gitignore", 'a') { |f| f.write content }
129
- end
130
- end
131
-
132
- # Update the local pkg to specified gem
133
- #
134
- # @param [Polisher::Gem] gem instance of gem containing metadata to update to
135
- def update_to(gem)
136
- update_spec_to gem
137
- gen_sources_for gem
138
- ignore gem
139
- self
140
- end
141
-
142
- # Override commit, generate a default msg, always add pkg files
143
- # @override
144
- def commit(msg=nil)
145
- in_repo { AwesomeSpawn.run "#{git_cmd} add #{pkg_files.join(' ')}" }
146
- super(msg.nil? ? "updated to #{version}" : msg)
147
- self
148
- end
149
-
150
- # Build the srpm
151
- def build_srpm
152
- in_repo { AwesomeSpawn.run "#{pkg_cmd} srpm" }
153
- self
154
- end
155
-
156
- # Run a scratch build
157
- def scratch_build
158
- # TODO if build fails, raise error, else return output
159
- cmd = "#{build_cmd} build --scratch #{build_tgt} #{srpm}"
160
- in_repo { AwesomeSpawn.run(cmd) }
161
- self
162
- end
163
-
164
- # Build the pkg
165
- def build
166
- build_srpm
167
- scratch_build
168
- self
169
- end
170
-
171
- # Retrieve list of the version of the specified package in git
172
- #
173
- # @param [String] name name of package to lookup
174
- # @param [Callable] bl optional block to invoke with version retrieved
175
- # @return [String] version retrieved, or nil if none found
176
- def self.version_for(name, &bl)
177
- version = nil
178
- gitpkg = self.new :name => name
179
- gitpkg.url = "#{dist_git_url}#{gitpkg.rpm_name}.git"
180
- gitpkg.git_clone
181
- begin
182
- version = gitpkg.spec.version
183
- rescue => e
184
- end
185
-
186
- bl.call(:git, name, [version]) unless(bl.nil?)
187
- version
188
- end
189
- end # module Pkg
137
+ alias :valid_branches :valid_targets
138
+
139
+ def update_metadata(gem)
140
+ @version = gem.version
141
+ end
142
+
143
+ # Update the local spec to the specified gem version
144
+ def update_spec_to(gem)
145
+ in_repo do
146
+ spec.update_to(gem)
147
+ File.write(spec_file, spec.to_string)
148
+ @dirty_spec = true
149
+ end
150
+ end
151
+
152
+ # Generate new sources file
153
+ def gen_sources_for(gem)
154
+ require_cmd! md5sum_cmd
155
+ in_repo do
156
+ AwesomeSpawn.run "#{md5sum_cmd} #{gem.gem_path} > sources"
157
+ File.write('sources', File.read('sources').gsub("#{GemCache::DIR}/", ''))
158
+ end
159
+ end
160
+
161
+ # Update git ignore to ignore gem
162
+ def ignore(gem)
163
+ in_repo do
164
+ nl = File.exist?('.gitignore') ? "\n" : ''
165
+ content = "#{nl}#{gem.name}-#{gem.version}.gem"
166
+ File.open(".gitignore", 'a') { |f| f.write content }
167
+ end
168
+ end
169
+
170
+ # Update the local pkg to specified gem
171
+ #
172
+ # @param [Polisher::Gem] gem instance of gem containing metadata to update to
173
+ def update_to(gem)
174
+ update_metadata gem
175
+ update_spec_to gem
176
+ gen_sources_for gem
177
+ ignore gem
178
+ self
179
+ end
180
+
181
+ # Override commit, generate a default msg, always add pkg files
182
+ # @override
183
+ def commit(msg = nil)
184
+ require_cmd! git_cmd
185
+ in_repo { AwesomeSpawn.run "#{git_cmd} add #{pkg_files.join(' ')}" }
186
+ super(msg.nil? ? "updated to #{version}" : msg)
187
+ self
188
+ end
189
+
190
+ # Build the srpm
191
+ def build_srpm
192
+ require_cmd! pkg_cmd
193
+ in_repo do
194
+ begin
195
+ gem = spec.upstream_gem
196
+ FileUtils.rm_f gem.file_name if File.exist?(gem.file_name)
197
+ FileUtils.ln_s gem.gem_path, gem.file_name
198
+ result = AwesomeSpawn.run "#{pkg_cmd} srpm"
199
+ raise result.error unless result.exit_status == 0
200
+ ensure
201
+ FileUtils.rm_f gem.file_name if File.exist?(gem.file_name)
202
+ end
203
+ end
204
+ self
205
+ end
206
+
207
+ # Run a scratch build
208
+ def scratch_build
209
+ in_repo do
210
+ Koji.build :srpm => srpm,
211
+ :scratch => true
212
+ end
213
+ self
214
+ end
215
+
216
+ # Build the pkg
217
+ def build
218
+ build_srpm
219
+ scratch_build
220
+ self
221
+ end
222
+
223
+ # Retrieve list of the versions of the specified package in git
224
+ #
225
+ # @param [String] name name of package to lookup
226
+ # @param [Callable] bl optional block to invoke with version retrieved
227
+ # @return [Array<String>] versions retrieved, or empty array if none found
228
+ def self.versions_for(name, &bl)
229
+ version = nil
230
+ gitpkg = new :name => name
231
+ gitpkg.url = "#{dist_git_url}#{gitpkg.rpm_name}.git"
232
+ versions = []
233
+ fetch_tgts.each do |tgt|
234
+ begin
235
+ gitpkg.fetch tgt
236
+ versions << gitpkg.spec.version
237
+ rescue => e
238
+ logger.warn "error retrieving #{name} from #{gitpkg.url}/#{tgt}(distgit): #{e}"
239
+ end
240
+ end
241
+
242
+ bl.call(:git, name, versions) unless bl.nil?
243
+ versions
244
+ end
245
+ end # module Pkg
246
+ end # Component.verify("Git::Pkg")
190
247
  end # module Git
191
248
  end # module Polisher