php-composer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +1006 -0
  5. data/Gemfile +15 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +35 -0
  8. data/Rakefile +1 -0
  9. data/lib/composer.rb +52 -0
  10. data/lib/composer/error.rb +8 -0
  11. data/lib/composer/json/json_file.rb +270 -0
  12. data/lib/composer/json/json_formatter.rb +159 -0
  13. data/lib/composer/json/json_validaton_error.rb +29 -0
  14. data/lib/composer/manager.rb +79 -0
  15. data/lib/composer/package/alias_package.rb +273 -0
  16. data/lib/composer/package/base_package.rb +130 -0
  17. data/lib/composer/package/complete_package.rb +55 -0
  18. data/lib/composer/package/dumper/hash_dumper.rb +169 -0
  19. data/lib/composer/package/link.rb +51 -0
  20. data/lib/composer/package/link_constraint/base_constraint.rb +36 -0
  21. data/lib/composer/package/link_constraint/empty_constraint.rb +35 -0
  22. data/lib/composer/package/link_constraint/multi_constraint.rb +67 -0
  23. data/lib/composer/package/link_constraint/specific_constraint.rb +41 -0
  24. data/lib/composer/package/link_constraint/version_constraint.rb +221 -0
  25. data/lib/composer/package/loader/hash_loader.rb +316 -0
  26. data/lib/composer/package/loader/json_loader.rb +47 -0
  27. data/lib/composer/package/loader/project_attributes_loader.rb +71 -0
  28. data/lib/composer/package/loader/project_root_package_loader.rb +28 -0
  29. data/lib/composer/package/package.rb +118 -0
  30. data/lib/composer/package/root_alias_package.rb +37 -0
  31. data/lib/composer/package/root_package.rb +37 -0
  32. data/lib/composer/package/version/version_parser.rb +583 -0
  33. data/lib/composer/package/version/version_selector.rb +106 -0
  34. data/lib/composer/provider.rb +94 -0
  35. data/lib/composer/repository/array_repository.rb +195 -0
  36. data/lib/composer/repository/filesystem_repository.rb +86 -0
  37. data/lib/composer/repository/writeable_array_repository.rb +60 -0
  38. data/lib/composer/version.rb +3 -0
  39. data/php-composer.gemspec +31 -0
  40. data/resources/composer-schema.json +421 -0
  41. metadata +188 -0
@@ -0,0 +1,221 @@
1
+ #
2
+ # This file was ported to ruby from Composer php source code file.
3
+ # Original Source: Composer\Package\LinkConstraint\VersionConstraint.php
4
+ #
5
+ # (c) Nils Adermann <naderman@naderman.de>
6
+ # Jordi Boggiano <j.boggiano@seld.be>
7
+ #
8
+ # For the full copyright and license information, please view the LICENSE
9
+ # file that was distributed with this source code.
10
+ #
11
+
12
+ module Composer
13
+ module Package
14
+ module LinkConstraint
15
+ class VersionConstraint < SpecificConstraint
16
+ attr_reader :operator, :version
17
+
18
+ @@cache = nil
19
+
20
+ # Sets operator and version to compare a package with
21
+ # @param string $operator A comparison operator
22
+ # @param string $version A version to compare to
23
+ def initialize(operator, version)
24
+ if operator === '='
25
+ operator = '=='
26
+ end
27
+
28
+ if operator === '<>'
29
+ operator = '!='
30
+ end
31
+
32
+ @operator = operator
33
+ @version = version
34
+ end
35
+
36
+ def version_compare(a, b, operator, compare_branches = false)
37
+
38
+ a_is_branch = 'dev-' === a[0...4]
39
+ b_is_branch = 'dev-' === b[0...4]
40
+ if a_is_branch && b_is_branch
41
+ return operator == '==' && a === b
42
+ end
43
+
44
+ # when branches are not comparable, we make sure dev branches never match anything
45
+ if !compare_branches && (a_is_branch || b_is_branch)
46
+ return false
47
+ end
48
+
49
+ # Standardise versions
50
+ ver_a = a.strip.gsub(/([\-?\_?\+?])/, '.').gsub(/([^0-9\.]+)/, '.$1.').gsub(/\.\./, '.').split('.')
51
+ ver_b = b.strip.gsub(/([\-?\_?\+?])/, '.').gsub(/([^0-9\.]+)/, '.$1.').gsub(/\.\./, '.').split('.')
52
+
53
+ # Replace empty entries at the start of the array
54
+ while ver_a[0] && ver_a[0].empty?
55
+ ver_a.shift
56
+ end
57
+ while ver_b[0] && ver_b[0].empty?
58
+ ver_b.shift
59
+ end
60
+
61
+ # Release state order
62
+ # '#' stands for any number
63
+ versions = {
64
+ 'dev' => 0,
65
+ 'alpha' => 1,
66
+ 'a' => 1,
67
+ 'beta' => 2,
68
+ 'b' => 2,
69
+ 'RC' => 3,
70
+ '#' => 4,
71
+ 'p' => 5,
72
+ 'pl' => 5
73
+ }
74
+
75
+ # Loop through each segment in the version string
76
+ compare = 0
77
+ for i in 0..([ver_a.length, ver_b.length].min - 1)
78
+ # for (i = 0, $x = [ver_a.length, ver_b.length].min; i < $x; i++) {
79
+
80
+ next if ver_a[i] == ver_b[i]
81
+
82
+ i1 = ver_a[i]
83
+ i2 = ver_b[i]
84
+
85
+ i1_is_numeric = true if Float(i1) rescue false
86
+ i2_is_numeric = true if Float(i2) rescue false
87
+
88
+ if i1_is_numeric && i2_is_numeric
89
+ compare = (i1 < i2) ? -1 : 1
90
+ break
91
+ end
92
+
93
+ # We use the position of '#' in the versions list
94
+ # for numbers... (so take care of # in original string)
95
+ if i1 == '#'
96
+ i1 = ''
97
+ elsif i1_is_numeric
98
+ i1 = '#';
99
+ end
100
+
101
+ if i2 == '#'
102
+ i2 = ''
103
+ elsif i2_is_numeric
104
+ i2 = '#'
105
+ end
106
+
107
+ if !versions[i1].nil? && versions[i2].nil?
108
+ compare = versions[i1] < versions[i2] ? -1 : 1
109
+ elsif !versions[i1].nil?
110
+ compare = 1;
111
+ elsif !versions[i2].nil?
112
+ compare = -1;
113
+ else
114
+ compare = 0;
115
+ end
116
+
117
+ break;
118
+
119
+ end
120
+
121
+ # If previous loop didn't find anything, compare the "extra" segments
122
+ if compare == 0
123
+ if ver_b.length > ver_a.length
124
+ if !ver_b[i].nil && !versions[ver_b[i]].nil
125
+ compare = (versions[ver_b[i]] < 4) ? 1 : -1;
126
+ else
127
+ compare = -1;
128
+ end
129
+ elsif ver_b.length < ver_a.length
130
+ if !ver_a[i].nil && !versions[ver_a[i]].nil
131
+ compare = (versions[ver_a[i]] < 4) ? -1 : 1;
132
+ else
133
+ compare = 1;
134
+ end
135
+ end
136
+ end
137
+
138
+ # Compare the versions
139
+ case operator
140
+ when '>', 'gt'
141
+ return compare > 0
142
+ when '>=', 'ge'
143
+ return compare >= 0
144
+ when '<=', 'le'
145
+ return compare <= 0
146
+ when '==', '=', 'eq'
147
+ return compare == 0
148
+ when '<>', '!=', 'ne'
149
+ return compare != 0
150
+ when '', '<', 'lt'
151
+ return compare < 0
152
+ end
153
+
154
+ false
155
+ end
156
+
157
+ # @param VersionConstraint provider
158
+ # @param bool compare_branches
159
+ # @return bool
160
+ def match_specific(provider, compare_branches = false)
161
+ @@cache = {} unless @@cache
162
+ @@cache[@operator] = {} unless @@cache.key?(@operator)
163
+ @@cache[@operator][@version] = {} unless @@cache[@operator].key?(@version)
164
+ @@cache[@operator][@version][provider.operator] = {} unless @@cache[@operator][@version].key?(provider.operator)
165
+ @@cache[@operator][@version][provider.operator][provider.version] = {} unless @@cache[@operator][@version][provider.operator].key?(provider.version)
166
+
167
+ if @@cache[@operator][@version][provider.operator][provider.version].key?(compare_branches)
168
+ return @@cache[@operator][@version][provider.operator][provider.version][compare_branches]
169
+ end
170
+
171
+ (@@cache[@operator][@version][provider.operator][provider.version][compare_branches] = do_match_specific(provider, compare_branches))
172
+ end
173
+
174
+ def to_s
175
+ "#{@operator} #{@version}"
176
+ end
177
+
178
+ private
179
+
180
+ # /**
181
+ # * @param VersionConstraint provider
182
+ # * @param bool compare_branches
183
+ # * @return bool
184
+ def do_match_specific(provider, compare_branches = false)
185
+ self_op_ne = @operator.gsub('=', '')
186
+ provider_op_ne = provider.operator.gsub('=', '')
187
+
188
+ self_op_is_eq = '==' === @operator
189
+ self_op_is_ne = '!=' === @operator
190
+ provider_op_is_eq = '==' === provider.operator
191
+ provider_op_is_ne = '!=' === provider.operator
192
+
193
+ # '!=' operator is match when other operator is not '==' operator or version is not match
194
+ # these kinds of comparisons always have a solution
195
+ if self_op_is_ne || provider_op_is_ne
196
+ return !self_op_is_eq && !provider_op_is_eq ||
197
+ version_compare(provider.version, @version, '!=', compare_branches)
198
+ end
199
+
200
+ # an example for the condition is <= 2.0 & < 1.0
201
+ # these kinds of comparisons always have a solution
202
+ if @operator != '==' && self_op_ne == provider_op_ne
203
+ return true
204
+ end
205
+
206
+ if version_compare(provider.version, @version, @operator, compare_branches)
207
+ # special case, e.g. require >= 1.0 and provide < 1.0
208
+ # 1.0 >= 1.0 but 1.0 is outside of the provided interval
209
+ if provider.version == @version && provider.operator == provider_op_ne && @operator != self_op_ne
210
+ return false
211
+ end
212
+
213
+ return true
214
+ end
215
+
216
+ false
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,316 @@
1
+ #
2
+ # This file was ported to ruby from Composer php source code.
3
+ # Original Source: Composer\Package\Loader\ArrayLoader.php
4
+ #
5
+ # (c) Nils Adermann <naderman@naderman.de>
6
+ # Jordi Boggiano <j.boggiano@seld.be>
7
+ #
8
+ # For the full copyright and license information, please view the LICENSE
9
+ # file that was distributed with this source code.
10
+ #
11
+
12
+ module Composer
13
+ module Package
14
+ module Loader
15
+ # Loads a package from a hash
16
+ #
17
+ # PHP Authors:
18
+ # Konstantin Kudryashiv <ever.zet@gmail.com>
19
+ # Jordi Boggiano <j.boggiano@seld.be>
20
+ #
21
+ # Ruby Authors:
22
+ # Ioannis Kappas <ikappas@devworks.gr>
23
+ class HashLoader
24
+ def initialize(parser = nil, load_options = false)
25
+ parser = Composer::Package::Version::VersionParser.new unless parser
26
+ @version_parser = parser
27
+ @load_options = load_options
28
+ end
29
+
30
+ def load(config, class_name = 'Composer::Package::CompletePackage')
31
+ unless config
32
+ raise ArgumentError,
33
+ 'Invalid package configuration supplied.'
34
+ end
35
+
36
+ unless config.key?('name')
37
+ raise UnexpectedValueError,
38
+ "Unknown package has no name defined (#{config.to_json})."
39
+ end
40
+
41
+ unless config.key?('version')
42
+ raise UnexpectedValueError,
43
+ "Package #{config['name']} has no version defined."
44
+ end
45
+
46
+ # handle already normalized versions
47
+ if config.key?('version_normalized')
48
+ version = config['version_normalized']
49
+ else
50
+ version = @version_parser.normalize(config['version'])
51
+ end
52
+
53
+ package = Object.const_get(class_name).new(
54
+ config['name'],
55
+ version,
56
+ config['version']
57
+ )
58
+
59
+ # parse type
60
+ if config.key?('type')
61
+ package.type = config['type'].downcase
62
+ else
63
+ package.type = 'library'
64
+ end
65
+
66
+ # parse target-dir
67
+ if config.key?('target-dir')
68
+ package.target_dir = config['target-dir']
69
+ end
70
+
71
+ # parse extra
72
+ if config.key?('extra') && config['extra'].is_a?(Hash)
73
+ package.extra = config['extra']
74
+ end
75
+
76
+ # parse bin
77
+ if config.key?('bin')
78
+ unless config['bin'].is_a?(Array)
79
+ raise UnexpectedValueError,
80
+ "Package #{config['name']}'s bin key should be an hash, \
81
+ #{config['bin'].class.name} given."
82
+ end
83
+ config['bin'].each do |bin|
84
+ bin.gsub!(/^\/+/, '')
85
+ end
86
+ package.binaries = config['bin']
87
+ end
88
+
89
+ # parse installation source
90
+ if config.key?('installation-source')
91
+ package.installation_source = config['installation-source']
92
+ end
93
+
94
+ # parse source
95
+ if config.key?('source')
96
+ if [:type, :url, :reference].all? {|k| config['source'].key? k}
97
+ raise UnexpectedValueError,
98
+ "Package #{config['name']}'s source key should be \
99
+ specified as \
100
+ {\"type\": ..., \"url\": ..., \"reference\": ...}, \n
101
+ #{config['source'].to_json} given."
102
+ end
103
+ package.source_type = config['source']['type']
104
+ package.source_url = config['source']['url']
105
+ package.source_reference = config['source']['reference']
106
+ if config['source'].key?('mirrors')
107
+ package.source_mirrors = config['source']['mirrors']
108
+ end
109
+ end
110
+
111
+ #parse dist
112
+ if config.key?('dist')
113
+ if [:type, :url].all? {|k| config['dist'].key? k}
114
+ raise UnexpectedValueError,
115
+ "Package #{config['name']}'s dist key should be \
116
+ specified as \
117
+ {\"type\": ..., \"url\": ..., \"reference\": ..., \"shasum\": ...},\n
118
+ #{config['dist'].to_json} given."
119
+ end
120
+ package.dist_type = config['dist']['type']
121
+ package.dist_url = config['dist']['url']
122
+
123
+ package.dist_reference = config['dist'].key?('reference') ?
124
+ config['dist']['reference'] : nil
125
+
126
+ package.dist_sha1_checksum = config['dist'].key?('shasum') ?
127
+ config['dist']['shasum'] : nil
128
+
129
+ if config['dist'].key?('mirrors')
130
+ package.dist_mirrors = config['dist']['mirrors']
131
+ end
132
+ end
133
+
134
+ # parse supported link types
135
+ Composer::Package::BasePackage::SUPPORTED_LINK_TYPES.each do |type, opts|
136
+ next if !config.key?(type)
137
+ package.send(
138
+ "#{opts['method']}=",
139
+ @version_parser.parse_links(
140
+ package.name,
141
+ package.pretty_version,
142
+ opts['description'],
143
+ config[type]
144
+ )
145
+ )
146
+ end
147
+
148
+ # parse suggest
149
+ if config.key?('suggest') && config['suggest'].is_a?(Hash)
150
+ config['suggest'].each do |target, reason|
151
+ if 'self.version' === reason.strip!
152
+ config['suggest'][target] = package.pretty_version
153
+ end
154
+ end
155
+ package.suggests = config['suggest']
156
+ end
157
+
158
+ # parse autoload
159
+ if config.key? 'autoload'
160
+ package.autoload = config['autoload']
161
+ end
162
+
163
+ # parse autoload-dev
164
+ if config.key? 'autoload-dev'
165
+ package.dev_autoload = config['autoload-dev']
166
+ end
167
+
168
+ # parse include-path
169
+ if config.key? 'include-path'
170
+ package.include_paths = config['include-path']
171
+ end
172
+
173
+ # parse time
174
+ if !is_empty?(config, 'time')
175
+ time = is_numeric?(config['time']) ? "@#{config['time']}" : config['time']
176
+ begin
177
+ date = Time.zone.parse(time)
178
+ package.release_date = date
179
+ rescue Exception => e
180
+ log("Time Exception #{e}")
181
+ end
182
+ end
183
+
184
+ # parse notification url
185
+ if !is_empty?(config, 'notification-url')
186
+ package.notification_url = config['notification-url']
187
+ end
188
+
189
+ # parse archive excludes
190
+ if config.key?('archive') &&
191
+ config['archive'].key?('exclude') &&
192
+ !config['archive']['exclude'].empty?
193
+ package.archive_excludes = config['archive']['exclude']
194
+ end
195
+
196
+ if package.instance_of?(Composer::Package::CompletePackage)
197
+
198
+ # parse scripts
199
+ if config.key?('scripts') && config['scripts'].is_a?(Array)
200
+ config['scripts'].each do |event, listeners|
201
+ config['scripts'][event] = Array(listeners)
202
+ end
203
+ package.scripts = config['scripts']
204
+ end
205
+
206
+ # parse description
207
+ if !is_empty?(config, 'description') && config['description'].is_a?(String)
208
+ package.description = config['description']
209
+ end
210
+
211
+ # parse homepage
212
+ if !is_empty?(config, 'homepage') && config['homepage'].is_a?(String)
213
+ package.homepage = config['homepage']
214
+ end
215
+
216
+ # parse keywords
217
+ if !is_empty?(config, 'keywords') && config['keywords'].is_a?(Array)
218
+ package.keywords = config['keywords']
219
+ end
220
+
221
+ # parse license
222
+ if !is_empty?(config, 'license')
223
+ package.license = config['license'].is_a?(Array) ? config['license'] : [config['license']]
224
+ end
225
+
226
+ # parse authors
227
+ if !is_empty?(config, 'authors') && config['authors'].is_a?(Array)
228
+ package.authors = config['authors']
229
+ end
230
+
231
+ # parse support
232
+ if config.key?('support')
233
+ package.support = config['support']
234
+ end
235
+
236
+ # parse abandoned
237
+ if config.key?('abandoned')
238
+ package.abandoned = config['abandoned']
239
+ end
240
+
241
+ end
242
+
243
+ if alias_normalized = get_branch_alias(config)
244
+ if package.instance_of?(Composer::Package::RootPackage)
245
+ package = Composer::Package::RootAliasPackage.new(
246
+ package,
247
+ alias_normalized,
248
+ alias_normalized.gsub(/(\.9{7})+/, '.x')
249
+ )
250
+ else
251
+ package = Composer::Package::AliasPackage.new(
252
+ package,
253
+ alias_normalized,
254
+ alias_normalized.gsub(/(\.9{7})+/, '.x')
255
+ )
256
+ end
257
+ end
258
+
259
+ if @load_options && config.key?('transport-options')
260
+ package.transport_options = config['transport-options']
261
+ end
262
+
263
+ package
264
+ end
265
+
266
+ # Retrieves a branch alias
267
+ # (dev-master => 1.0.x-dev for example) if it exists
268
+ #
269
+ # Params:
270
+ # +config+ array The entire package config
271
+ #
272
+ # Returns:
273
+ # string|nil normalized version of the branch alias
274
+ # or null if there is none
275
+ def get_branch_alias(config)
276
+ return nil unless
277
+ (config['version'].start_with?('dev-') || config['version'].end_with?('-dev')) &&
278
+ config.key?('extra') &&
279
+ config['extra'].key?('branch-alias') &&
280
+ config['extra']['branch-alias'].is_a?(Hash)
281
+
282
+ config['extra']['branch-alias'].each do |source_branch, target_branch|
283
+ # ensure it is an alias to a -dev package
284
+ next if !target_branch.end_with?('-dev')
285
+
286
+ # normalize without -dev and ensure it's a numeric branch that is parseable
287
+ validated_target_branch = @version_parser.normalize_branch(target_branch[0..-5])
288
+ next if !validated_target_branch.end_with?('-dev')
289
+
290
+ # ensure that it is the current branch aliasing itself
291
+ next if config['version'].downcase != source_branch.downcase
292
+
293
+ # If using numeric aliases ensure the alias is a valid subversion
294
+ source_prefix = @version_parser.parse_numeric_alias_prefix(source_branch)
295
+ target_prefix = @version_parser.parse_numeric_alias_prefix(target_branch)
296
+ next if source_prefix && target_prefix && target_prefix.index(source_prefix) != 0 #(stripos($targetPrefix, $sourcePrefix) !== 0)
297
+
298
+ return validated_target_branch
299
+ end
300
+ nil
301
+ end
302
+
303
+ private
304
+
305
+ def is_numeric?(value)
306
+ true if Float(value) rescue false
307
+ end
308
+
309
+ def is_empty?(config, key)
310
+ config.key?(key) ? config[key].empty? : true
311
+ end
312
+
313
+ end
314
+ end
315
+ end
316
+ end