polisher 0.9.1 → 0.10.1

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