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
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in composer.gemspec
4
+ gemspec
5
+
6
+ gem 'json', '>= 1.7', :platforms => [:mri_18, :mri_19]
7
+ gem 'json-schema', '>= 2.5.0'
8
+ # gem 'version_compare', '~> 0.0.2'
9
+ gem 'digest-crc'
10
+
11
+ group :development, :test do
12
+ gem 'rubocop', '>= 0.28.0', require: false
13
+ gem 'rspec'
14
+ gem 'simplecov', '>= 0.9.2'
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015, Ioannis Kappas <ikappas@devworks.gr>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # PHP Composer Ruby Gem
2
+
3
+ A ruby gem library for consistent interactions with php composer dependency manager.
4
+
5
+ This is a partial port of the [Composer - Dependency Management for PHP](https://github.com/composer/composer) project as a library that enables consistent interactions with php composer.
6
+
7
+ See [https://getcomposer.org/](https://getcomposer.org/) for more information.
8
+
9
+ ## Installation / Usage
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'php-composer'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install php-composer
23
+
24
+ ## Authors
25
+ Ioannis Kappas - <ikappas@devworks.gr>
26
+
27
+ ## License
28
+ PHP Composer Ruby Gem is licensed under the MIT License - see the LICENSE file for details
29
+
30
+ ## Contributing
31
+ 1. Fork it ( https://github.com/ikappas/php-composer/fork )
32
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
33
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
34
+ 4. Push to the branch (`git push origin my-new-feature`)
35
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/lib/composer.rb ADDED
@@ -0,0 +1,52 @@
1
+ # external
2
+ require 'json'
3
+ require 'json-schema'
4
+
5
+ # /
6
+ require 'composer/version'
7
+ require 'composer/error'
8
+
9
+ # /json
10
+ require 'composer/json/json_validaton_error'
11
+ require 'composer/json/json_file'
12
+ require 'composer/json/json_formatter'
13
+
14
+ # /package
15
+ require 'composer/package/base_package'
16
+ require 'composer/package/package'
17
+ require 'composer/package/complete_package'
18
+ require 'composer/package/alias_package'
19
+ require 'composer/package/root_alias_package'
20
+ require 'composer/package/root_package'
21
+ require 'composer/package/link'
22
+
23
+ # /package/dumper
24
+ require 'composer/package/dumper/hash_dumper'
25
+
26
+ # /package/link_constraint
27
+ require 'composer/package/link_constraint/base_constraint'
28
+ require 'composer/package/link_constraint/empty_constraint'
29
+ require 'composer/package/link_constraint/specific_constraint'
30
+ require 'composer/package/link_constraint/version_constraint'
31
+ require 'composer/package/link_constraint/multi_constraint'
32
+
33
+ # /package/loader
34
+ require 'composer/package/loader/hash_loader'
35
+ require 'composer/package/loader/json_loader'
36
+
37
+ # /package/version
38
+ require 'composer/package/version/version_parser'
39
+ require 'composer/package/version/version_selector'
40
+
41
+ # Dir[File.join(File.dirname(__FILE__), "composer/package/dumper/*.rb")].each {|file| require file }
42
+ # Dir[File.join(File.dirname(__FILE__), "composer/package/link_constraint/*.rb")].each {|file| require file }
43
+ # Dir[File.join(File.dirname(__FILE__), "composer/package/loader/*.rb")].each {|file| require file }
44
+ # Dir[File.join(File.dirname(__FILE__), "composer/package/version/*.rb")].each {|file| require file }
45
+
46
+ # /repository
47
+ require 'composer/repository/array_repository'
48
+ require 'composer/repository/writeable_array_repository'
49
+ require 'composer/repository/filesystem_repository'
50
+
51
+ module Composer
52
+ end
@@ -0,0 +1,8 @@
1
+ module Composer
2
+ class Error < ::StandardError; end
3
+ class ArgumentError < Error; end
4
+ class TypeError < Error; end
5
+ class UnexpectedValueError < Error; end
6
+ class LogicError < Error; end
7
+ class InvalidRepositoryError < Error; end
8
+ end
@@ -0,0 +1,270 @@
1
+ #
2
+ # This file was ported to ruby from Composer php source code file.
3
+ # Original Source: Composer\Json\JsonFile.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 Json
14
+ # Reads/writes json files.
15
+ #
16
+ # PHP Authors:
17
+ # Konstantin Kudryashiv <ever.zet@gmail.com>
18
+ # Jordi Boggiano <j.boggiano@seld.be>
19
+ #
20
+ # Ruby Authors:
21
+ # Ioannis Kappas <ikappas@devworks.gr>
22
+ class JsonFile
23
+ attr_reader :path
24
+
25
+ LAX_SCHEMA = 1
26
+ STRICT_SCHEMA = 2
27
+
28
+ JSON_ERROR_NONE = 0
29
+ JSON_ERROR_DEPTH = 1
30
+ JSON_ERROR_STATE_MISMATCH = 2
31
+ JSON_ERROR_CTRL_CHAR = 3
32
+ JSON_ERROR_SYNTAX = 4
33
+ JSON_ERROR_UTF8 = 5
34
+ JSON_ERROR_RECURSION = 6
35
+ JSON_ERROR_INF_OR_NAN = 7
36
+ JSON_ERROR_UNSUPPORTED_TYPE = 8
37
+
38
+ # Initializes json file reader/parser.
39
+ # @param [String] path path to a json file
40
+ # @param [RemoteFileSystem] rfs The remote filesystem to use for http/https json files
41
+ # @raise [ArgumentError]
42
+ def initialize(path, rfs = nil)
43
+ @path = path
44
+ if rfs === nil && /^https?:\/\//i.match(path)
45
+ raise ArgumentError,
46
+ 'http urls require a RemoteFilesystem instance to be passed'
47
+ end
48
+ @rfs = rfs
49
+ end
50
+
51
+ # Checks whether this json file exists.
52
+ #
53
+ # Returns:
54
+ # true if this json file exists; otherwise false.
55
+ def exist?
56
+ File.exist?(path)
57
+ end
58
+
59
+ # Reads the json file.
60
+ #
61
+ # Raises:
62
+ # RuntimeError
63
+ #
64
+ # Returns:
65
+ # mixed
66
+ def read
67
+ if @rfs
68
+ json = @rfs.get_contents(@path, @path, false)
69
+ else
70
+ json = File.open(@path, 'r') { |f| f.read }
71
+ end
72
+
73
+ parse_json(json, @path)
74
+
75
+ rescue Exception => e
76
+ raise e
77
+ end
78
+
79
+ def write(hash, options = 448)
80
+ dir = File.dirname(@path)
81
+
82
+ unless File.directory?(storage_path)
83
+ if File.exist?(dir)
84
+ raise UnexpectedValueError,
85
+ "#{dir} exists and is not a directory."
86
+ end
87
+ FileUtils.mkdir_p(dir, 0777)
88
+ end
89
+
90
+ retries = 3
91
+ while retries >= 0
92
+ begin
93
+ file_ending = options & JSON_PRETTY_PRINT ? "\n" : ''
94
+ File.open(path, 'w') do |f|
95
+ content = encode(hash, options) + file_ending
96
+ f.write(content)
97
+ end
98
+ break
99
+
100
+ rescue Exception => e
101
+ if retries
102
+ retries -= 1
103
+ sleep 0.5
104
+ else
105
+ raise e
106
+ end
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ # Validates the schema of the current json file according
113
+ # to composer-schema.json rules
114
+ #
115
+ # @param schema int a JsonFile::*_SCHEMA constant
116
+ # @return bool true if schema is valid; Otherwise false.
117
+ # @throw Composer::Json::JsonValidationError
118
+ def validate_schema(schema = STRICT_SCHEMA)
119
+ content = File.open(@path, 'r') { |f| f.read }
120
+ data = JSON.parse(content)
121
+
122
+ if data == nil && content != 'null'
123
+ self::validate_syntax(content, @path)
124
+ end
125
+
126
+ schema_file = File.join(
127
+ File.dirname(__FILE__),
128
+ '../../../resources/composer-schema.json'
129
+ )
130
+
131
+ schema_data = JSON.parse(
132
+ File.open(schema_file, 'r') { |f| f.read }
133
+ )
134
+
135
+ if schema === LAX_SCHEMA
136
+ schema_data['additionalProperties'] = true
137
+ schema_data['properties']['name']['required'] = false
138
+ schema_data['properties']['description']['required'] = false
139
+ end
140
+
141
+ errors = JSON::Validator.fully_validate(
142
+ schema_data,
143
+ data,
144
+ {:errors_as_objects => true}
145
+ )
146
+
147
+ unless errors.empty?
148
+ processed_errors = []
149
+ errors.each do |error|
150
+ prefix = error[:fragment] ? "#{error[:fragment]} : " : ''
151
+ processed_errors.push( prefix + error[:message])
152
+ end
153
+ raise Composer::Json::JsonValidationError.new(processed_errors),
154
+ "\"#{@path}\" does not match the expected JSON schema"
155
+ end
156
+
157
+ true
158
+ end
159
+
160
+ class << self
161
+
162
+ # Encodes an hash into (optionally pretty-printed) JSON
163
+ #
164
+ # @param data mixed Data to encode into a formatted JSON string
165
+ # @param options int json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
166
+ # @return string Encoded json
167
+ def encode(data, options = 448)
168
+
169
+ # if (version_compare(PHP_VERSION, '5.4', '>=')) {
170
+ # $json = json_encode(data, options);
171
+
172
+ # # compact brackets to follow recent php versions
173
+ # if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
174
+ # $json = preg_replace('/\[\s+\]/', '[]', $json);
175
+ # $json = preg_replace('/\{\s+\}/', '{}', $json);
176
+ # }
177
+
178
+ # return $json;
179
+ # }
180
+
181
+ # * *indent*: a string used to indent levels (default: ''),
182
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
183
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
184
+ # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
185
+ # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
186
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
187
+ # generated, otherwise an exception is thrown if these values are
188
+ # encountered. This options defaults to false.
189
+ # * *max_nesting*: The maximum depth of nesting allowed in the data
190
+ # structures from which JSON is to be generated. Disable depth checking
191
+ # with :max_nesting => false, it defaults to 100.
192
+
193
+ if data.nil?
194
+ return 'null'
195
+ elsif data.is_a?(TrueClass)
196
+ return 'true'
197
+ elsif data.is_a?(FalseClass)
198
+ return 'false'
199
+ elsif data.is_a?(Integer)
200
+ return Integer(data)
201
+ elsif data.is_a?(Float)
202
+ return Float(data)
203
+ else
204
+ begin
205
+ json = JSON.generate(data, { quirks_mode: false })
206
+ rescue JSON::GeneratorError => e
207
+ if e.message === 'only generation of JSON objects or arrays allowed'
208
+ #trick into parsing scalar values by wrapping them in an array
209
+ scalar = data.gsub("\\\\", "\\\\\\")
210
+ if json = JSON::generate([scalar])
211
+ json = json[1..(json.length - 2)]
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ return json unless options
218
+
219
+ result = Composer::Json::JsonFormatter::format(
220
+ json,
221
+ options
222
+ )
223
+
224
+ result
225
+ end
226
+
227
+ # Parses json string and returns hash.
228
+ #
229
+ # Params:
230
+ # +json+ string The json string to parse
231
+ # +file+ string The json file
232
+ #
233
+ # Returns:
234
+ # mixed
235
+ def parse_json(json, file = nil)
236
+ last_error = JSON_ERROR_NONE
237
+
238
+ begin
239
+ data = JSON.parse(json)
240
+ rescue Exception => e
241
+ last_error = e
242
+ end
243
+
244
+ if data.nil? && last_error != JSON_ERROR_NONE
245
+ validate_syntax(json, file)
246
+ raise JSON::ParserError,
247
+ "\"#{file}\" does not contain valid JSON\n
248
+ #{last_error.message}"
249
+ end
250
+
251
+ data
252
+ end
253
+
254
+ def validate_syntax(json, file)
255
+ # JSON::
256
+ # parser = Composer::Json::JsonParser.new
257
+ # if (result = parser.lint(json))
258
+ # raise ParsingError,
259
+ # "\"#{file}\" does not contain valid JSON\n
260
+ # #{result.message}"
261
+ # end
262
+ # if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) {
263
+ # throw new \UnexpectedValueException('"'.$file.'" is not UTF-8, could not parse as JSON');
264
+ # }
265
+ true
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,159 @@
1
+ #
2
+ # This file was ported to ruby from Composer php source code file.
3
+ # Original Source: Composer\Json\JsonFormatter.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
+ # JSON_HEX_TAG => 1
13
+ # JSON_HEX_AMP => 2
14
+ # JSON_HEX_APOS => 4
15
+ # JSON_HEX_QUOT => 8
16
+ # JSON_FORCE_OBJECT => 16
17
+ # JSON_NUMERIC_CHECK => 32
18
+ # JSON_UNESCAPED_SLASHES => 64
19
+ # JSON_PRETTY_PRINT => 128
20
+ # JSON_UNESCAPED_UNICODE => 256
21
+
22
+ module Composer
23
+ module Json
24
+ # * Formats json strings used for php < 5.4 because the json_encode doesn't
25
+ # * supports the flags JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
26
+ # * in these versions
27
+ #
28
+ # PHP Authors:
29
+ # Konstantin Kudryashiv <ever.zet@gmail.com>
30
+ # Jordi Boggiano <j.boggiano@seld.be>
31
+ #
32
+ # Ruby Authors:
33
+ # Ioannis Kappas <ikappas@devworks.gr>
34
+ class JsonFormatter
35
+
36
+ JSON_HEX_TAG = 1
37
+ JSON_HEX_AMP = 2
38
+ JSON_HEX_APOS = 4
39
+ JSON_HEX_QUOT = 8
40
+ JSON_FORCE_OBJECT = 16
41
+ JSON_NUMERIC_CHECK = 32
42
+ JSON_UNESCAPED_SLASHES = 64
43
+ JSON_PRETTY_PRINT = 128
44
+ JSON_UNESCAPED_UNICODE = 256
45
+
46
+ class << self
47
+ # This code is based on the function found at:
48
+ # http://recursive-design.com/blog/2008/03/11/format-json-with-php/
49
+ #
50
+ # Originally licensed under MIT by Dave Perrett <mail@recursive-design.com>
51
+ #
52
+ # @param json string
53
+ # @param unescape_unicode bool Un escape unicode
54
+ # @param unescape_slashes bool Un escape slashes
55
+ # @return string
56
+ def format(json, options)
57
+
58
+ result = ''
59
+ pos = 0
60
+ str_len = json.length
61
+ indent_str = ' '
62
+ new_line = "\n"
63
+ out_of_quotes = true
64
+ buffer = ''
65
+ no_escape = true
66
+
67
+ for i in 0..(str_len - 1)
68
+
69
+ # Grab the next character in the string
70
+ char = json[i]
71
+
72
+ # Are we inside a quoted string?
73
+ if '"' === char && no_escape
74
+ out_of_quotes = !out_of_quotes
75
+ end
76
+
77
+ if !out_of_quotes
78
+ buffer << char
79
+ no_escape = '\\' === char ? !no_escape : true
80
+ next
81
+ elsif buffer != ''
82
+ if options & JSON_HEX_TAG === JSON_HEX_TAG
83
+ buffer.gsub!('<', '\\u003C')
84
+ buffer.gsub!('>', '\\u003E')
85
+ end
86
+ if options & JSON_HEX_AMP === JSON_HEX_AMP
87
+ buffer.gsub!('&', '\\u0026')
88
+ end
89
+ if options & JSON_HEX_APOS === JSON_HEX_APOS
90
+ buffer.gsub!('\'', '\\u0027')
91
+ end
92
+ if options & JSON_HEX_QUOT === JSON_HEX_QUOT
93
+ buffer.gsub!('\"', '\\u0022')
94
+ end
95
+ if options & JSON_UNESCAPED_SLASHES === JSON_UNESCAPED_SLASHES
96
+ buffer.gsub!('\\/', '/')
97
+ end
98
+ if options & JSON_UNESCAPED_UNICODE === JSON_UNESCAPED_UNICODE
99
+ buffer.gsub!(/\\u([\da-fA-F]{4})/) {|m| [$1].pack('H*').unpack('n*').pack('U*')}
100
+ end
101
+
102
+ result << buffer + char
103
+ buffer = ''
104
+ next
105
+ end
106
+
107
+ if options & JSON_PRETTY_PRINT === JSON_PRETTY_PRINT
108
+ if char === ':'
109
+ # Add a space after the : character
110
+ char << ' '
111
+ elsif char === '}' || char === ']'
112
+ pos -= 1
113
+ prev_char = json[i - 1] #substr(json, i - 1, 1)
114
+
115
+ if prev_char != '{' && prev_char != '['
116
+ # If this character is the end of an element,
117
+ # output a new line and indent the next line
118
+ result << new_line
119
+
120
+ for j in 0..(pos - 1)
121
+ result << indent_str
122
+ end
123
+ else
124
+ # Collapse empty {} and []
125
+ result.rstrip!
126
+ end
127
+ end
128
+ end
129
+
130
+ result << char
131
+
132
+ if options & JSON_PRETTY_PRINT === JSON_PRETTY_PRINT
133
+ # If the last character was the beginning of an element,
134
+ # output a new line and indent the next line
135
+ if char === ',' || char === '{' || char === '['
136
+ result << new_line
137
+ pos += 1 if char === '{' || char === '['
138
+ for j in 0..(pos - 1)
139
+ result << indent_str
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ result
146
+ end
147
+
148
+ def unescape_slashes(s)
149
+ s.gsub('\\/', '/')
150
+ end
151
+
152
+ def unescape_unicode(s)
153
+ s.gsub(/\\u([\da-fA-F]{4})/) {|m| [$1].pack('H*').unpack('n*').pack('U*')}
154
+ end
155
+
156
+ end
157
+ end
158
+ end
159
+ end