polisher 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/bin/binary_gem_resolver.rb +1 -1
- data/bin/gem_dependency_checker.rb +12 -8
- data/bin/git_gem_updater.rb +6 -5
- data/bin/ruby_rpm_spec_updater.rb +1 -1
- data/lib/polisher.rb +3 -1
- data/lib/polisher/core.rb +47 -4
- data/lib/polisher/errata.rb +0 -1
- data/lib/polisher/error.rb +7 -0
- data/lib/polisher/gem.rb +105 -77
- data/lib/polisher/gemfile.rb +43 -27
- data/lib/polisher/git.rb +3 -230
- data/lib/polisher/git/pkg.rb +189 -0
- data/lib/polisher/git/project.rb +23 -0
- data/lib/polisher/git/repo.rb +74 -0
- data/lib/polisher/koji.rb +10 -16
- data/lib/polisher/rpm/patch.rb +44 -0
- data/lib/polisher/rpm/requirement.rb +188 -0
- data/lib/polisher/rpm/spec.rb +381 -0
- data/lib/polisher/vendor.rb +28 -0
- data/lib/polisher/version.rb +1 -1
- data/lib/polisher/version_checker.rb +13 -9
- data/spec/gem_spec.rb +2 -25
- data/spec/gemfile_spec.rb +13 -0
- data/spec/git_spec.rb +34 -10
- data/spec/rpmspec_spec.rb +36 -36
- data/spec/spec_helper.rb +29 -29
- data/spec/vendor_spec.rb +41 -0
- metadata +10 -5
- data/lib/polisher/formatter.rb +0 -1
- data/lib/polisher/gemspec.rb +0 -32
- data/lib/polisher/rpmspec.rb +0 -512
@@ -0,0 +1,23 @@
|
|
1
|
+
# Polisher Git Based Project Representation
|
2
|
+
#
|
3
|
+
# Licensed under the MIT license
|
4
|
+
# Copyright (C) 2013-2014 Red Hat, Inc.
|
5
|
+
|
6
|
+
require 'polisher/vendor'
|
7
|
+
require 'polisher/git/repo'
|
8
|
+
|
9
|
+
module Polisher
|
10
|
+
module Git
|
11
|
+
# Git based project representation
|
12
|
+
class Project < Repo
|
13
|
+
include HasVendoredDeps
|
14
|
+
|
15
|
+
# Override vendored to ensure repo is
|
16
|
+
# cloned before retrieving modules
|
17
|
+
def vendored
|
18
|
+
clone unless cloned?
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end # class Project
|
22
|
+
end # module Git
|
23
|
+
end # module Polisher
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Polisher Git Repo Representation
|
2
|
+
#
|
3
|
+
# Licensed under the MIT license
|
4
|
+
# Copyright (C) 2013-2014 Red Hat, Inc.
|
5
|
+
|
6
|
+
require 'awesome_spawn'
|
7
|
+
require 'polisher/core'
|
8
|
+
require 'polisher/git_cache'
|
9
|
+
|
10
|
+
module Polisher
|
11
|
+
module Git
|
12
|
+
# Git Repository
|
13
|
+
class Repo
|
14
|
+
extend ConfHelpers
|
15
|
+
|
16
|
+
# TODO use ruby git api
|
17
|
+
conf_attr :git_cmd, '/usr/bin/git'
|
18
|
+
|
19
|
+
attr_accessor :url
|
20
|
+
|
21
|
+
def initialize(args={})
|
22
|
+
@url = args[:url]
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
GitCache.path_for(@url)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Clobber the git repo
|
30
|
+
def clobber!
|
31
|
+
FileUtils.rm_rf path
|
32
|
+
end
|
33
|
+
|
34
|
+
def clone
|
35
|
+
AwesomeSpawn.run "#{git_cmd} clone #{url} #{path}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def cloned?
|
39
|
+
File.directory?(path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def in_repo
|
43
|
+
Dir.chdir path do
|
44
|
+
yield
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def file_paths
|
49
|
+
in_repo { Dir['**/*'] }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Note be careful when invoking:
|
53
|
+
def reset!
|
54
|
+
in_repo { AwesomeSpawn.run "#{git_cmd} reset HEAD~ --hard" }
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def pull
|
59
|
+
in_repo { AwesomeSpawn.run "#{git_cmd} pull" }
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def checkout(tgt)
|
64
|
+
in_repo { AwesomeSpawn.run "#{git_cmd} checkout #{tgt}" }
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def commit(msg)
|
69
|
+
in_repo { AwesomeSpawn.run "#{git_cmd} commit -m '#{msg}'" }
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end # class Repo
|
73
|
+
end # module Git
|
74
|
+
end # module Polisher
|
data/lib/polisher/koji.rb
CHANGED
@@ -7,29 +7,23 @@ require 'xmlrpc/client'
|
|
7
7
|
XMLRPC::Config::ENABLE_NIL_PARSER = true
|
8
8
|
XMLRPC::Config::ENABLE_NIL_CREATE = true
|
9
9
|
|
10
|
+
require 'polisher/core'
|
11
|
+
|
10
12
|
module Polisher
|
11
13
|
class Koji
|
12
|
-
|
13
|
-
KOJI_TAG = 'f21'
|
14
|
+
extend ConfHelpers
|
14
15
|
|
15
|
-
#
|
16
|
-
def self.koji_url(value=nil)
|
17
|
-
@koji_url ||= KOJI_URL
|
18
|
-
@koji_url = value unless value.nil?
|
19
|
-
@koji_url
|
20
|
-
end
|
16
|
+
# TODO Koji#build (on class or instance?)
|
21
17
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@koji_tag
|
27
|
-
end
|
18
|
+
# TODO Koji#diff(tag1, tag2)
|
19
|
+
|
20
|
+
conf_attr :koji_url, 'koji.fedoraproject.org/kojihub'
|
21
|
+
conf_attr :koji_tag, 'f21'
|
28
22
|
|
29
23
|
# Retrieve shared instance of xmlrpc client to use
|
30
24
|
def self.client
|
31
25
|
@client ||= begin
|
32
|
-
url =
|
26
|
+
url = koji_url.split('/')
|
33
27
|
XMLRPC::Client.new(url[0..-2].join('/'),
|
34
28
|
"/#{url.last}")
|
35
29
|
end
|
@@ -60,7 +54,7 @@ module Polisher
|
|
60
54
|
# koji xmlrpc call
|
61
55
|
builds =
|
62
56
|
self.client.call('listTagged',
|
63
|
-
|
57
|
+
koji_tag, nil, false, nil, false,
|
64
58
|
"rubygem-#{name}")
|
65
59
|
versions = builds.collect { |b| b['version'] }
|
66
60
|
bl.call(:koji, name, versions) unless(bl.nil?)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Polisher RPM Patch Representation
|
2
|
+
#
|
3
|
+
# Licensed under the MIT license
|
4
|
+
# Copyright (C) 2014 Red Hat, Inc.
|
5
|
+
|
6
|
+
module Polisher
|
7
|
+
module RPM
|
8
|
+
class Patch
|
9
|
+
attr_accessor :title
|
10
|
+
attr_accessor :content
|
11
|
+
|
12
|
+
def initialize(args={})
|
13
|
+
@title = args[:title]
|
14
|
+
@content = args[:content]
|
15
|
+
end
|
16
|
+
|
17
|
+
def spec_line(n=0)
|
18
|
+
"Patch#{n}: #{title}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.from(diff)
|
22
|
+
return diff.collect { |d| self.from(d) } if diff.is_a?(Array)
|
23
|
+
|
24
|
+
result = {}
|
25
|
+
|
26
|
+
in_diff = nil
|
27
|
+
diff.each_line do |line|
|
28
|
+
if line =~ /diff -r ([^\s]+)+ ([^\s]+)+$/
|
29
|
+
result[in_diff] = diff if in_diff
|
30
|
+
in_diff = $1.gsub(/a\//, '')
|
31
|
+
diff = ''
|
32
|
+
elsif line =~ /Only in.*$/
|
33
|
+
in_diff = nil
|
34
|
+
|
35
|
+
else
|
36
|
+
diff += line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
result.collect { |t,c| self.new :title => t, :content => c }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# Polisher RPM Requirement Represenation
|
2
|
+
#
|
3
|
+
# Licensed under the MIT license
|
4
|
+
# Copyright (C) 2013-2014 Red Hat, Inc.
|
5
|
+
|
6
|
+
require 'gem2rpm'
|
7
|
+
require 'versionomy'
|
8
|
+
require 'active_support/core_ext'
|
9
|
+
|
10
|
+
require 'polisher/core'
|
11
|
+
require 'polisher/gem'
|
12
|
+
|
13
|
+
module Polisher
|
14
|
+
module RPM
|
15
|
+
class Requirement
|
16
|
+
# Bool indiciating if req is a BR
|
17
|
+
attr_accessor :br
|
18
|
+
|
19
|
+
# Name of requirement
|
20
|
+
attr_accessor :name
|
21
|
+
|
22
|
+
# Condition, eg >=, =, etc
|
23
|
+
attr_accessor :condition
|
24
|
+
|
25
|
+
# Version number
|
26
|
+
attr_accessor :version
|
27
|
+
|
28
|
+
# Requirement string
|
29
|
+
def str
|
30
|
+
sp = self.specifier
|
31
|
+
sp.nil? ? "#{@name}" : "#{@name} #{sp}"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Specified string
|
35
|
+
def specifier
|
36
|
+
@version.nil? ? nil : "#{@condition} #{@version}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Instantiate / return new rpm spec requirements from string
|
40
|
+
def self.parse(str, opts={})
|
41
|
+
stra = str.split
|
42
|
+
br = str.include?('BuildRequires')
|
43
|
+
name = condition = version = nil
|
44
|
+
|
45
|
+
if str.include?('Requires')
|
46
|
+
name = stra[1]
|
47
|
+
condition = stra[2]
|
48
|
+
version = stra[3]
|
49
|
+
|
50
|
+
else
|
51
|
+
name = stra[0]
|
52
|
+
condition = stra[1]
|
53
|
+
version = stra[2]
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
req = self.new({:name => name,
|
58
|
+
:condition => condition,
|
59
|
+
:version => version,
|
60
|
+
:br => br}.merge(opts))
|
61
|
+
req
|
62
|
+
end
|
63
|
+
|
64
|
+
# Instantiate / return new rpm spec requirements from gem dependency.
|
65
|
+
#
|
66
|
+
# Because a gem dependency may result in multiple spec requirements
|
67
|
+
# this will always return an array of Requirement instances
|
68
|
+
def self.from_gem_dep(gem_dep, br=false)
|
69
|
+
gem_dep.requirement.to_s.split(',').collect { |req|
|
70
|
+
expanded = Gem2Rpm::Helpers.expand_requirement [req.split]
|
71
|
+
expanded.collect { |e|
|
72
|
+
self.new :name => "rubygem(#{gem_dep.name})",
|
73
|
+
:condition => e.first.to_s,
|
74
|
+
:version => e.last.to_s,
|
75
|
+
:br => br
|
76
|
+
}
|
77
|
+
}.flatten
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize(args={})
|
81
|
+
@br = args[:br] || false
|
82
|
+
@name = args[:name]
|
83
|
+
@condition = args[:condition]
|
84
|
+
@version = args[:version]
|
85
|
+
|
86
|
+
@name.strip! unless @name.nil?
|
87
|
+
@condition.strip! unless @condition.nil?
|
88
|
+
@version.strip! unless @version.nil?
|
89
|
+
end
|
90
|
+
|
91
|
+
def ==(other)
|
92
|
+
@br == other.br &&
|
93
|
+
@name == other.name &&
|
94
|
+
@condition == other.condition &&
|
95
|
+
@version == other.version
|
96
|
+
end
|
97
|
+
|
98
|
+
# Greatest Common Denominator,
|
99
|
+
# Max version in list that is less than the local version
|
100
|
+
def gcd(versions)
|
101
|
+
lversion = Versionomy.parse(self.version)
|
102
|
+
versions.collect { |v| Versionomy.parse(v) }.
|
103
|
+
sort { |a,b| a <=> b }.reverse.
|
104
|
+
find { |v| v < lversion }.to_s
|
105
|
+
end
|
106
|
+
|
107
|
+
# Minimum gem version which satisfies this dependency
|
108
|
+
def min_satisfying_version
|
109
|
+
return "0.0" if self.version.nil? ||
|
110
|
+
self.condition == '<' ||
|
111
|
+
self.condition == '<='
|
112
|
+
return self.version if self.condition == '=' ||
|
113
|
+
self.condition == '>='
|
114
|
+
Versionomy.parse(self.version).bump(:tiny).to_s # self.condition == '>'
|
115
|
+
end
|
116
|
+
|
117
|
+
# Max gem version which satisfies this dependency
|
118
|
+
#
|
119
|
+
# Can't automatically deduce in '<' case, so if that is the conditional
|
120
|
+
# we require a version list, and will return the gcd from it
|
121
|
+
def max_satisfying_version(versions=nil)
|
122
|
+
return Float::INFINITY if self.version.nil? ||
|
123
|
+
self.condition == '>' ||
|
124
|
+
self.condition == '>='
|
125
|
+
return self.version if self.condition == '=' ||
|
126
|
+
self.condition == '<='
|
127
|
+
|
128
|
+
raise ArgumentError if versions.nil?
|
129
|
+
self.gcd(versions)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Minimum gem version for which this dependency fails
|
133
|
+
def min_failing_version
|
134
|
+
raise ArgumentError if self.version.nil?
|
135
|
+
return "0.0" if self.condition == '>' ||
|
136
|
+
self.condition == '>='
|
137
|
+
return self.version if self.condition == '<'
|
138
|
+
Versionomy.parse(self.version).bump(:tiny).to_s # self.condition == '<=' and '='
|
139
|
+
end
|
140
|
+
|
141
|
+
# Max gem version for which this dependency fails
|
142
|
+
#
|
143
|
+
# Can't automatically deduce in '>=', and '=' cases, so if that is the
|
144
|
+
# conditional we require a version list, and will return the gcd from it
|
145
|
+
def max_failing_version(versions=nil)
|
146
|
+
raise ArgumentError if self.version.nil? ||
|
147
|
+
self.condition == '<=' ||
|
148
|
+
self.condition == '<'
|
149
|
+
return self.version if self.condition == '>'
|
150
|
+
|
151
|
+
raise ArgumentError if versions.nil?
|
152
|
+
self.gcd(versions)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return bool indicating if requirement matches specified
|
156
|
+
# depedency.
|
157
|
+
#
|
158
|
+
# Comparison mechanism will depend on type of class
|
159
|
+
# passed to this. Valid types include
|
160
|
+
# - Polisher::RPM::Requirements
|
161
|
+
# - ::Gem::Dependency
|
162
|
+
def matches?(dep)
|
163
|
+
return self == dep if dep.is_a?(self.class)
|
164
|
+
raise ArgumentError unless dep.is_a?(::Gem::Dependency)
|
165
|
+
|
166
|
+
return false if !self.gem? || self.gem_name != dep.name
|
167
|
+
return true if self.version.nil?
|
168
|
+
|
169
|
+
Gem2Rpm::Helpers.expand_requirement([dep.requirement.to_s.split]).
|
170
|
+
any?{ |req|
|
171
|
+
req.first == self.condition && req.last.to_s == self.version
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
175
|
+
# Whether or not this requirement specified a ruby gem dependency
|
176
|
+
def gem?
|
177
|
+
!!(self.str =~ RPM::Spec::SPEC_GEM_REQ_MATCHER)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Return the name of the gem which this requirement is for.
|
181
|
+
# Returns nil if this is not a gem requirement
|
182
|
+
def gem_name
|
183
|
+
# XXX need to explicitly run regex here to get $1
|
184
|
+
!!(self.str =~ RPM::Spec::SPEC_GEM_REQ_MATCHER) ? $1 : nil
|
185
|
+
end
|
186
|
+
end # class Requirement
|
187
|
+
end # module RPM
|
188
|
+
end
|
@@ -0,0 +1,381 @@
|
|
1
|
+
# Polisher RPM Spec Represenation
|
2
|
+
#
|
3
|
+
# Licensed under the MIT license
|
4
|
+
# Copyright (C) 2013-2014 Red Hat, Inc.
|
5
|
+
|
6
|
+
require 'gem2rpm'
|
7
|
+
require 'versionomy'
|
8
|
+
require 'active_support/core_ext'
|
9
|
+
|
10
|
+
require 'polisher/core'
|
11
|
+
require 'polisher/gem'
|
12
|
+
require 'polisher/rpm/requirement'
|
13
|
+
|
14
|
+
module Polisher
|
15
|
+
module RPM
|
16
|
+
class Spec
|
17
|
+
AUTHOR = "#{ENV['USER']} <#{ENV['USER']}@localhost.localdomain>"
|
18
|
+
|
19
|
+
COMMENT_MATCHER = /^\s*#.*/
|
20
|
+
GEM_NAME_MATCHER = /^%global\s*gem_name\s(.*)$/
|
21
|
+
SPEC_NAME_MATCHER = /^Name:\s*rubygem-(.*)$/
|
22
|
+
SPEC_VERSION_MATCHER = /^Version:\s*(.*)$/
|
23
|
+
SPEC_RELEASE_MATCHER = /^Release:\s*(.*)$/
|
24
|
+
SPEC_REQUIRES_MATCHER = /^Requires:\s*(.*)$/
|
25
|
+
SPEC_BUILD_REQUIRES_MATCHER = /^BuildRequires:\s*(.*)$/
|
26
|
+
SPEC_GEM_REQ_MATCHER = /^.*\s*rubygem\((.*)\)(\s*(.*))?$/
|
27
|
+
SPEC_SUBPACKAGE_MATCHER = /^%package\s(.*)$/
|
28
|
+
SPEC_CHANGELOG_MATCHER = /^%changelog$/
|
29
|
+
SPEC_FILES_MATCHER = /^%files$/
|
30
|
+
SPEC_SUBPKG_FILES_MATCHER = /^%files\s*(.*)$/
|
31
|
+
SPEC_CHECK_MATCHER = /^%check$/
|
32
|
+
|
33
|
+
FILE_MACRO_MATCHERS =
|
34
|
+
[/^%doc\s/, /^%config\s/, /^%attr\s/,
|
35
|
+
/^%verify\s/, /^%docdir.*/, /^%dir\s/,
|
36
|
+
/^%defattr.*/, /^%exclude\s/, /^%{gem_instdir}\/+/]
|
37
|
+
|
38
|
+
FILE_MACRO_REPLACEMENTS =
|
39
|
+
{"%{_bindir}" => 'bin',
|
40
|
+
"%{gem_libdir}" => 'lib'}
|
41
|
+
|
42
|
+
attr_accessor :metadata
|
43
|
+
|
44
|
+
# Return the currently configured author
|
45
|
+
def self.current_author
|
46
|
+
ENV['POLISHER_AUTHOR'] || AUTHOR
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(metadata={})
|
50
|
+
@metadata = metadata
|
51
|
+
end
|
52
|
+
|
53
|
+
# Dispatch all missing methods to lookup calls in rpm spec metadata
|
54
|
+
def method_missing(method, *args, &block)
|
55
|
+
# proxy to metadata
|
56
|
+
if @metadata.has_key?(method)
|
57
|
+
@metadata[method]
|
58
|
+
|
59
|
+
else
|
60
|
+
super(method, *args, &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return boolean indicating if spec has a %check section
|
65
|
+
def has_check?
|
66
|
+
@metadata.has_key?(:has_check) && @metadata[:has_check]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return all the Requires for the specified gem
|
70
|
+
def requirements_for_gem(gem_name)
|
71
|
+
@metadata[:requires].nil? ? [] :
|
72
|
+
@metadata[:requires].select { |r| r.gem_name == gem_name }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return all the BuildRequires for the specified gem
|
76
|
+
def build_requirements_for_gem(gem_name)
|
77
|
+
@metadata[:build_requires].nil? ? [] :
|
78
|
+
@metadata[:build_requires].select { |r| r.gem_name == gem_name }
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return bool indicating if this spec specifies all the
|
82
|
+
# requirements in the specified gem dependency
|
83
|
+
#
|
84
|
+
# @param [Gem::Dependency] gem_dep dependency which to retreive / compare
|
85
|
+
# requirements
|
86
|
+
def has_all_requirements_for?(gem_dep)
|
87
|
+
reqs = self.requirements_for_gem gem_dep.name
|
88
|
+
# create a spec requirement dependency for each expanded subrequirement,
|
89
|
+
# verify we can find a match for that
|
90
|
+
gem_dep.requirement.to_s.split(',').all? { |greq|
|
91
|
+
Gem2Rpm::Helpers.expand_requirement([greq.split]).all? { |ereq|
|
92
|
+
tereq = Requirement.new :name => "rubygem(#{gem_dep.name})",
|
93
|
+
:condition => ereq.first,
|
94
|
+
:version => ereq.last.to_s
|
95
|
+
reqs.any? { |req| req.matches?(tereq)}
|
96
|
+
}
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return all gem Requires
|
101
|
+
def gem_requirements
|
102
|
+
@metadata[:requires].nil? ? [] :
|
103
|
+
@metadata[:requires].select { |r| r.gem? }
|
104
|
+
end
|
105
|
+
|
106
|
+
# Return all gem BuildRequires
|
107
|
+
def gem_build_requirements
|
108
|
+
@metadata[:build_requires].nil? ? [] :
|
109
|
+
@metadata[:build_requires].select { |r| r.gem? }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Return all non gem Requires
|
113
|
+
def non_gem_requirements
|
114
|
+
@metadata[:requires].nil? ? [] :
|
115
|
+
@metadata[:requires].select { |r| !r.gem? }
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return all non gem BuildRequires
|
119
|
+
def non_gem_build_requirements
|
120
|
+
@metadata[:build_requires].nil? ? [] :
|
121
|
+
@metadata[:build_requires].select { |r| !r.gem? }
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return all gem requirements _not_ in the specified gem
|
125
|
+
def extra_gem_requirements(gem)
|
126
|
+
gem_reqs = gem.deps.collect { |d| requirements_for_gem(d.name) }.flatten
|
127
|
+
gem_requirements - gem_reqs
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return all gem build requirements _not_ in the specified gem
|
131
|
+
def extra_gem_build_requirements(gem)
|
132
|
+
gem_reqs = gem.deps.collect { |d| requirements_for_gem(d.name) }.flatten
|
133
|
+
gem_build_requirements - gem_reqs
|
134
|
+
end
|
135
|
+
|
136
|
+
# Parse the specified rpm spec and return new RPM::Spec instance from metadata
|
137
|
+
#
|
138
|
+
# @param [String] string contents of spec to parse
|
139
|
+
# @return [Polisher::RPM::Spec] spec instantiated from rpmspec metadata
|
140
|
+
def self.parse(spec)
|
141
|
+
in_subpackage = false
|
142
|
+
in_changelog = false
|
143
|
+
in_files = false
|
144
|
+
subpkg_name = nil
|
145
|
+
meta = {:contents => spec}
|
146
|
+
spec.each_line { |l|
|
147
|
+
if l =~ COMMENT_MATCHER
|
148
|
+
;
|
149
|
+
|
150
|
+
# TODO support optional gem prefix
|
151
|
+
elsif l =~ GEM_NAME_MATCHER
|
152
|
+
meta[:gem_name] = $1.strip
|
153
|
+
meta[:gem_name] = $1.strip
|
154
|
+
|
155
|
+
elsif l =~ SPEC_NAME_MATCHER &&
|
156
|
+
$1.strip != "%{gem_name}"
|
157
|
+
meta[:gem_name] = $1.strip
|
158
|
+
|
159
|
+
elsif l =~ SPEC_VERSION_MATCHER
|
160
|
+
meta[:version] = $1.strip
|
161
|
+
|
162
|
+
elsif l =~ SPEC_RELEASE_MATCHER
|
163
|
+
meta[:release] = $1.strip
|
164
|
+
|
165
|
+
elsif l =~ SPEC_SUBPACKAGE_MATCHER
|
166
|
+
subpkg_name = $1.strip
|
167
|
+
in_subpackage = true
|
168
|
+
|
169
|
+
elsif l =~ SPEC_REQUIRES_MATCHER &&
|
170
|
+
!in_subpackage
|
171
|
+
meta[:requires] ||= []
|
172
|
+
meta[:requires] << RPM::Requirement.parse($1.strip)
|
173
|
+
|
174
|
+
elsif l =~ SPEC_BUILD_REQUIRES_MATCHER &&
|
175
|
+
!in_subpackage
|
176
|
+
meta[:build_requires] ||= []
|
177
|
+
meta[:build_requires] << RPM::Requirement.parse($1.strip)
|
178
|
+
|
179
|
+
elsif l =~ SPEC_CHANGELOG_MATCHER
|
180
|
+
in_changelog = true
|
181
|
+
|
182
|
+
elsif l =~ SPEC_FILES_MATCHER
|
183
|
+
subpkg_name = nil
|
184
|
+
in_files = true
|
185
|
+
|
186
|
+
elsif l =~ SPEC_SUBPKG_FILES_MATCHER
|
187
|
+
subpkg_name = $1.strip
|
188
|
+
in_files = true
|
189
|
+
|
190
|
+
elsif l =~ SPEC_CHECK_MATCHER
|
191
|
+
meta[:has_check] = true
|
192
|
+
|
193
|
+
elsif in_changelog
|
194
|
+
meta[:changelog] ||= ""
|
195
|
+
meta[:changelog] << l
|
196
|
+
|
197
|
+
elsif in_files
|
198
|
+
tgt = subpkg_name.nil? ? meta[:gem_name] : subpkg_name
|
199
|
+
meta[:files] ||= {}
|
200
|
+
meta[:files][tgt] ||= []
|
201
|
+
|
202
|
+
sl = l.strip.unrpmize
|
203
|
+
meta[:files][tgt] << sl unless sl.blank?
|
204
|
+
end
|
205
|
+
}
|
206
|
+
|
207
|
+
meta[:changelog_entries] = meta[:changelog] ?
|
208
|
+
meta[:changelog].split("\n\n") : []
|
209
|
+
meta[:changelog_entries].collect! { |c| c.strip }.compact!
|
210
|
+
|
211
|
+
self.new meta
|
212
|
+
end
|
213
|
+
|
214
|
+
# Update RPM::Spec metadata to new gem
|
215
|
+
#
|
216
|
+
# @param [Polisher::Gem] new_source new gem to update rpmspec to
|
217
|
+
def update_to(new_source)
|
218
|
+
update_deps_from(new_source)
|
219
|
+
update_files_from(new_source)
|
220
|
+
update_metadata_from(new_source)
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
# Update spec dependencies from new source
|
226
|
+
def update_deps_from(new_source)
|
227
|
+
@metadata[:requires] =
|
228
|
+
non_gem_requirements +
|
229
|
+
extra_gem_requirements(new_source) +
|
230
|
+
new_source.deps.collect { |r|
|
231
|
+
RPM::Requirement.from_gem_dep(r)
|
232
|
+
}.flatten
|
233
|
+
|
234
|
+
@metadata[:build_requires] =
|
235
|
+
non_gem_build_requirements +
|
236
|
+
extra_gem_build_requirements(new_source) +
|
237
|
+
new_source.dev_deps.collect { |r|
|
238
|
+
RPM::Requirement.from_gem_dep(r, true)
|
239
|
+
}.flatten
|
240
|
+
end
|
241
|
+
|
242
|
+
# Internal helper to update spec files from new source
|
243
|
+
def update_files_from(new_source)
|
244
|
+
to_add = new_source.file_paths
|
245
|
+
@metadata[:files] ||= {}
|
246
|
+
@metadata[:files].each { |pkg,spec_files|
|
247
|
+
(new_source.file_paths & to_add).each { |gem_file|
|
248
|
+
# skip files already included in spec or in dir in spec
|
249
|
+
has_file = spec_files.any? { |sf|
|
250
|
+
gem_file.gsub(sf,'') != gem_file
|
251
|
+
}
|
252
|
+
|
253
|
+
to_add.delete(gem_file)
|
254
|
+
to_add << gem_file.rpmize if !has_file &&
|
255
|
+
!Gem.ignorable_file?(gem_file)
|
256
|
+
}
|
257
|
+
}
|
258
|
+
|
259
|
+
@metadata[:new_files] = to_add
|
260
|
+
end
|
261
|
+
|
262
|
+
# Internal helper to update spec metadata from new source
|
263
|
+
def update_metadata_from(new_source)
|
264
|
+
# update to new version
|
265
|
+
@metadata[:version] = new_source.version
|
266
|
+
@metadata[:release] = "1%{?dist}"
|
267
|
+
|
268
|
+
# add changelog entry
|
269
|
+
changelog_entry = <<EOS
|
270
|
+
* #{Time.now.strftime("%a %b %d %Y")} #{RPM::Spec.current_author} - #{@metadata[:version]}-1
|
271
|
+
- Update to version #{new_source.version}
|
272
|
+
EOS
|
273
|
+
@metadata[:changelog_entries] ||= []
|
274
|
+
@metadata[:changelog_entries].unshift changelog_entry.rstrip
|
275
|
+
end
|
276
|
+
|
277
|
+
public
|
278
|
+
|
279
|
+
# Return properly formatted rpmspec as string
|
280
|
+
#
|
281
|
+
# @return [String] string representation of rpm spec
|
282
|
+
def to_string
|
283
|
+
contents = @metadata[:contents]
|
284
|
+
|
285
|
+
# replace version / release
|
286
|
+
contents.gsub!(SPEC_VERSION_MATCHER, "Version: #{@metadata[:version]}")
|
287
|
+
contents.gsub!(SPEC_RELEASE_MATCHER, "Release: #{@metadata[:release]}")
|
288
|
+
|
289
|
+
# add changelog entry
|
290
|
+
cp = contents.index SPEC_CHANGELOG_MATCHER
|
291
|
+
cpn = contents.index "\n", cp
|
292
|
+
contents = contents[0...cpn+1] +
|
293
|
+
@metadata[:changelog_entries].join("\n\n")
|
294
|
+
|
295
|
+
# update requires/build requires
|
296
|
+
rp = contents.index SPEC_REQUIRES_MATCHER
|
297
|
+
brp = contents.index SPEC_BUILD_REQUIRES_MATCHER
|
298
|
+
tp = rp < brp ? rp : brp
|
299
|
+
|
300
|
+
pp = contents.index SPEC_SUBPACKAGE_MATCHER
|
301
|
+
pp = -1 if pp.nil?
|
302
|
+
|
303
|
+
lrp = contents.rindex SPEC_REQUIRES_MATCHER, pp
|
304
|
+
lbrp = contents.rindex SPEC_BUILD_REQUIRES_MATCHER, pp
|
305
|
+
ltp = lrp > lbrp ? lrp : lbrp
|
306
|
+
|
307
|
+
ltpn = contents.index "\n", ltp
|
308
|
+
|
309
|
+
contents.slice!(tp...ltpn)
|
310
|
+
contents.insert tp,
|
311
|
+
(@metadata[:requires].collect { |r| "Requires: #{r.str}" } +
|
312
|
+
@metadata[:build_requires].collect { |r| "BuildRequires: #{r.str}" }).join("\n")
|
313
|
+
|
314
|
+
# add new files
|
315
|
+
fp = contents.index SPEC_FILES_MATCHER
|
316
|
+
lfp = contents.index SPEC_SUBPKG_FILES_MATCHER, fp + 1
|
317
|
+
lfp = contents.index SPEC_CHANGELOG_MATCHER if lfp.nil?
|
318
|
+
|
319
|
+
contents.insert lfp - 1, @metadata[:new_files].join("\n") + "\n"
|
320
|
+
|
321
|
+
# return new contents
|
322
|
+
contents
|
323
|
+
end
|
324
|
+
|
325
|
+
# Compare this spec to a sepecified upstream gem source
|
326
|
+
# and return result.
|
327
|
+
#
|
328
|
+
# upstream_source should be an instance of Polisher::Gem,
|
329
|
+
# Polisher::Gemfile, or other class defining a 'deps'
|
330
|
+
# accessor that returns an array of Gem::Requirement dependencies
|
331
|
+
#
|
332
|
+
# Result will be a hash containing the shared dependencies as
|
333
|
+
# well as those that differ and their respective differences
|
334
|
+
def compare(upstream_source)
|
335
|
+
same = {}
|
336
|
+
diff = {}
|
337
|
+
upstream_source.deps.each do |d|
|
338
|
+
spec_reqs = self.requirements_for_gem(d.name)
|
339
|
+
spec_reqs_specifier = spec_reqs.empty? ? nil :
|
340
|
+
spec_reqs.collect { |req| req.specifier }
|
341
|
+
|
342
|
+
if spec_reqs.nil?
|
343
|
+
diff[d.name] = {:spec => nil,
|
344
|
+
:upstream => d.requirement.to_s}
|
345
|
+
|
346
|
+
elsif !spec_reqs.any? { |req| req.matches?(d) } ||
|
347
|
+
!self.has_all_requirements_for?(d)
|
348
|
+
diff[d.name] = {:spec => spec_reqs_specifier,
|
349
|
+
:upstream => d.requirement.to_s}
|
350
|
+
|
351
|
+
elsif !diff.has_key?(d.name)
|
352
|
+
same[d.name] = {:spec => spec_reqs_specifier,
|
353
|
+
:upstream => d.requirement.to_s }
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
@metadata[:requires].each do |req|
|
358
|
+
next unless req.gem?
|
359
|
+
|
360
|
+
upstream_dep = upstream_source.deps.find { |d| d.name == req.gem_name }
|
361
|
+
|
362
|
+
if upstream_dep.nil?
|
363
|
+
diff[req.gem_name] = {:spec => req.specifier,
|
364
|
+
:upstream => nil}
|
365
|
+
|
366
|
+
elsif !req.matches?(upstream_dep)
|
367
|
+
diff[req.gem_name] = {:spec => req.specifier,
|
368
|
+
:upstream => upstream_dep.requirement.to_s }
|
369
|
+
|
370
|
+
elsif !diff.has_key?(req.gem_name)
|
371
|
+
same[req.gem_name] = {:spec => req.specifier,
|
372
|
+
:upstream => upstream_dep.requirement.to_s }
|
373
|
+
end
|
374
|
+
end unless @metadata[:requires].nil?
|
375
|
+
|
376
|
+
{:same => same, :diff => diff}
|
377
|
+
end
|
378
|
+
|
379
|
+
end # class Spec
|
380
|
+
end # module RPM
|
381
|
+
end # module Polisher
|