php-composer 0.1.0

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.
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