drupid 1.0.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.
- data/bin/drupid +270 -0
- data/lib/drupid/component.rb +236 -0
- data/lib/drupid/download_strategy.rb +585 -0
- data/lib/drupid/drush.rb +185 -0
- data/lib/drupid/extend/pathname.rb +114 -0
- data/lib/drupid/library.rb +52 -0
- data/lib/drupid/makefile.rb +423 -0
- data/lib/drupid/patch.rb +92 -0
- data/lib/drupid/platform.rb +234 -0
- data/lib/drupid/platform_project.rb +91 -0
- data/lib/drupid/project.rb +563 -0
- data/lib/drupid/updater.rb +683 -0
- data/lib/drupid/utils.rb +301 -0
- data/lib/drupid/version.rb +230 -0
- data/lib/drupid.rb +56 -0
- metadata +76 -0
data/lib/drupid/utils.rb
ADDED
@@ -0,0 +1,301 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# Copyright (c) 2012 Lifepillar
|
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 all
|
13
|
+
# 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 THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
# Portions Copyright 2009-2011 Max Howell and other contributors.
|
24
|
+
#
|
25
|
+
# Redistribution and use in source and binary forms, with or without
|
26
|
+
# modification, are permitted provided that the following conditions
|
27
|
+
# are met:
|
28
|
+
#
|
29
|
+
# 1. Redistributions of source code must retain the above copyright
|
30
|
+
# notice, this list of conditions and the following disclaimer.
|
31
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
32
|
+
# notice, this list of conditions and the following disclaimer in the
|
33
|
+
# documentation and/or other materials provided with the distribution.
|
34
|
+
#
|
35
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
36
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
37
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
38
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
39
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
40
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
41
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
42
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
43
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
44
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
45
|
+
|
46
|
+
require 'shellwords'
|
47
|
+
|
48
|
+
# Common methods, borrowed from Homebrew, which can be mixed-in by a class.
|
49
|
+
module Drupid
|
50
|
+
module Utils
|
51
|
+
|
52
|
+
class ErrorDuringExecution < RuntimeError
|
53
|
+
end
|
54
|
+
|
55
|
+
class NotAnArchiveError < RuntimeError
|
56
|
+
end
|
57
|
+
|
58
|
+
class Tty
|
59
|
+
class <<self
|
60
|
+
def blue; bold 34; end
|
61
|
+
def white; bold 39; end
|
62
|
+
def red; underline 31; end
|
63
|
+
def yellow; bold 33; end
|
64
|
+
def purple; bold 35; end
|
65
|
+
def reset; escape 0; end
|
66
|
+
def em; underline 39; end
|
67
|
+
def green; color 92; end
|
68
|
+
|
69
|
+
private
|
70
|
+
def color n
|
71
|
+
escape "0;#{n}"
|
72
|
+
end
|
73
|
+
def bold n
|
74
|
+
escape "1;#{n}"
|
75
|
+
end
|
76
|
+
def underline n
|
77
|
+
escape "4;#{n}"
|
78
|
+
end
|
79
|
+
def escape n
|
80
|
+
"\033[#{n}m" if $stdout.tty?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Prints a message.
|
86
|
+
def ohai title, *sput
|
87
|
+
puts "#{Tty.green}==>#{Tty.white} #{title}#{Tty.reset}"
|
88
|
+
puts sput unless sput.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
# Print a warning message.
|
92
|
+
def owarn warning
|
93
|
+
puts "#{Tty.red}Warning#{Tty.reset}: #{warning}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Prints an error message.
|
97
|
+
def ofail error, *info
|
98
|
+
puts "#{Tty.red}Error#{Tty.reset}: #{error}"
|
99
|
+
puts info unless info.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
# Prints an error message and exits.
|
103
|
+
def odie error
|
104
|
+
ofail error
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
# Prints debug information.
|
109
|
+
def debug title, *info
|
110
|
+
return unless $DEBUG
|
111
|
+
puts "#{Tty.purple}[DEBUG]#{Tty.white} #{title}#{Tty.reset}"
|
112
|
+
info.each do |chunk|
|
113
|
+
chunk.each_line do |l|
|
114
|
+
puts "#{Tty.purple}[DEBUG]#{Tty.reset} #{l.chomp!}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Prints a notice if in verbose mode.
|
120
|
+
def blah notice
|
121
|
+
return unless $VERBOSE
|
122
|
+
puts notice.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
# Executes a command. Returns the output of the command.
|
126
|
+
# Raises a Drupid::ErrorDuringExecution error if the command does not
|
127
|
+
# exit successfully.
|
128
|
+
#
|
129
|
+
# [command] A String or Pathname object
|
130
|
+
# [arguments] An optional Array of arguments
|
131
|
+
# [options] An optional Hash of options
|
132
|
+
#
|
133
|
+
# Options: out, err, redirect_stderr_to_stdout, dry
|
134
|
+
def runBabyRun command, arguments = [], options = {}
|
135
|
+
opts = { :dry => false }.merge!(options)
|
136
|
+
cmd = String.new(command.to_s)
|
137
|
+
raise "Not an array" unless arguments.is_a?(Array)
|
138
|
+
args = arguments.map { |arg| arg.to_s }
|
139
|
+
cmd << ' ' + args.shelljoin
|
140
|
+
cmd << ' >' + Shellwords.shellescape(opts[:out]) if opts[:out]
|
141
|
+
cmd << ' 2>' + Shellwords.shellescape(opts[:err]) if opts[:err]
|
142
|
+
cmd << ' 2>&1' if opts[:redirect_stderr_to_stdout]
|
143
|
+
debug cmd
|
144
|
+
return cmd if opts[:dry]
|
145
|
+
output = %x|#{cmd}| # Run baby run!
|
146
|
+
unless $?.success?
|
147
|
+
debug 'Command failed', output
|
148
|
+
raise ErrorDuringExecution, output
|
149
|
+
end
|
150
|
+
return output
|
151
|
+
end
|
152
|
+
|
153
|
+
def curl *args
|
154
|
+
curl = Pathname.new(which 'curl')
|
155
|
+
raise "curl not found" unless curl.exist?
|
156
|
+
raise "curl is not executable" unless curl.executable?
|
157
|
+
|
158
|
+
args = ['-qf#LA', DRUPID_USER_AGENT, *args]
|
159
|
+
args << "--insecure" #if MacOS.version < 10.6
|
160
|
+
args << "--silent" unless $VERBOSE
|
161
|
+
|
162
|
+
runBabyRun curl, args
|
163
|
+
end
|
164
|
+
|
165
|
+
def git *args
|
166
|
+
git = Pathname.new(which 'git')
|
167
|
+
raise "git not found" unless git.exist?
|
168
|
+
raise "git is not executable" unless git.executable?
|
169
|
+
runBabyRun git, args, :redirect_stderr_to_stdout => true
|
170
|
+
end
|
171
|
+
|
172
|
+
def svn *args
|
173
|
+
svn = Pathname.new(which 'svn')
|
174
|
+
raise "svn not found" unless svn.exist?
|
175
|
+
raise "svn is not executable" unless svn.executable?
|
176
|
+
runBabyRun svn, args, :redirect_stderr_to_stdout => true
|
177
|
+
end
|
178
|
+
|
179
|
+
def cvs *args
|
180
|
+
cvs = Pathname.new(which 'cvs')
|
181
|
+
raise "cvs not found" unless cvs.exist?
|
182
|
+
raise "cvs is not executable" unless cvs.executable?
|
183
|
+
runBabyRun cvs, args, :redirect_stderr_to_stdout => true
|
184
|
+
end
|
185
|
+
|
186
|
+
def hg *args
|
187
|
+
hg = Pathname.new(which 'hg')
|
188
|
+
raise "hg not found" unless hg.exist?
|
189
|
+
raise "hg is not executable" unless hg.executable?
|
190
|
+
runBabyRun hg, args, :redirect_stderr_to_stdout => true
|
191
|
+
end
|
192
|
+
|
193
|
+
def bzr *args
|
194
|
+
bzr = Pathname.new(which 'bzr')
|
195
|
+
raise "bzr not found" unless bzr.exist?
|
196
|
+
raise "bzr is not executable" unless bzr.executable?
|
197
|
+
runBabyRun bzr, args, :redirect_stderr_to_stdout => true
|
198
|
+
end
|
199
|
+
|
200
|
+
# Uncompresses an archive in the current directory.
|
201
|
+
# [archive] A Pathname object representing the full path to the archive.
|
202
|
+
# The the :type options is used, the archive is interpreted as the given
|
203
|
+
# type (:zip, :gzip, :bzip2, :compress, :tar, :xz, :rar), otherwise
|
204
|
+
# the type is guessed based on the file content.
|
205
|
+
#
|
206
|
+
# Options: type
|
207
|
+
def uncompress archive, options = {}
|
208
|
+
type = options[:type] ? options[:type] : archive.compression_type
|
209
|
+
case type
|
210
|
+
when :zip
|
211
|
+
runBabyRun 'unzip', ['-qq', archive]
|
212
|
+
when :gzip, :bzip2, :compress, :tar
|
213
|
+
# Assume these are also tarred
|
214
|
+
# TODO check if it's really a tar archive
|
215
|
+
runBabyRun 'tar', ['xf', archive]
|
216
|
+
when :xz
|
217
|
+
runBabyRun "xz -dc \"#{archive}\" | tar xf -"
|
218
|
+
when :rar
|
219
|
+
runBabyRun 'unrar', ['x', '-inul', archive]
|
220
|
+
else
|
221
|
+
raise NotAnArchiveError
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Creates a temporary directory then yield. When the block returns,
|
226
|
+
# recursively delete the temporary directory.
|
227
|
+
def tempdir
|
228
|
+
# I used /tmp rather than `mktemp -td` because that generates a directory
|
229
|
+
# name with exotic characters like + in it, and these break badly written
|
230
|
+
# scripts that don't escape strings before trying to regexp them :(
|
231
|
+
|
232
|
+
# If the user has FileVault enabled, then we can't mv symlinks from the
|
233
|
+
# /tmp volume to the other volume. So we let the user override the tmp
|
234
|
+
# prefix if they need to.
|
235
|
+
tmp_prefix = '/tmp'
|
236
|
+
tmp = Pathname.new `mktemp -d #{tmp_prefix}/temp_item-XXXXXX`.strip
|
237
|
+
raise "Couldn't create temporary directory" if not tmp.directory? or $? != 0
|
238
|
+
begin
|
239
|
+
wd = Dir.pwd
|
240
|
+
FileUtils.chdir tmp
|
241
|
+
yield
|
242
|
+
ensure
|
243
|
+
FileUtils.chdir wd
|
244
|
+
tmp.rmtree
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Compares the content of two directories using rsync.
|
249
|
+
# Changes in timestamps only are ignored.
|
250
|
+
# Returns a possibly empty list of differences.
|
251
|
+
def compare_paths src, tgt, additional_rsync_options = []
|
252
|
+
p1 = Pathname.new(src).realpath.to_s + '/'
|
253
|
+
p2 = Pathname.new(tgt).realpath.to_s + '/'
|
254
|
+
args = Array.new
|
255
|
+
args << '-rlD'
|
256
|
+
args << '--dry-run'
|
257
|
+
args << '--delete'
|
258
|
+
args << '--itemize-changes'
|
259
|
+
args += additional_rsync_options
|
260
|
+
args << p1
|
261
|
+
args << p2
|
262
|
+
output = runBabyRun 'rsync', args, :verbose => false
|
263
|
+
changes = Array.new
|
264
|
+
output.each_line do |l|
|
265
|
+
next if l =~ /[fdLDS]\.\.[tT]\.\.\.\./ # Skip changes in timestamps only
|
266
|
+
changes << l.strip
|
267
|
+
end
|
268
|
+
return changes
|
269
|
+
end
|
270
|
+
|
271
|
+
def which cmd
|
272
|
+
path = `which #{cmd} 2>/dev/null`.chomp
|
273
|
+
path.empty? ? nil : Pathname.new(path)
|
274
|
+
end
|
275
|
+
|
276
|
+
def ignore_interrupts
|
277
|
+
std_trap = trap("INT") {}
|
278
|
+
yield
|
279
|
+
ensure
|
280
|
+
trap("INT", std_trap)
|
281
|
+
end
|
282
|
+
|
283
|
+
def interactive_shell
|
284
|
+
fork {exec ENV['SHELL'] }
|
285
|
+
Process.wait
|
286
|
+
unless $?.success?
|
287
|
+
owarn "Non-zero exit status: #{$?}"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Creates the specified file with the given content.
|
292
|
+
# The file is overwritten if it exists.
|
293
|
+
def writeFile path, content
|
294
|
+
p = Pathname.new(path)
|
295
|
+
blah "Writing #{p}"
|
296
|
+
p.open("w") { |f| f.write(content) }
|
297
|
+
end
|
298
|
+
|
299
|
+
end # Utils
|
300
|
+
end # Drupid
|
301
|
+
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# Copyright (c) 2012 Lifepillar
|
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 all
|
13
|
+
# 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 THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
module Drupid
|
24
|
+
|
25
|
+
class NotDrupalVersionError < RuntimeError
|
26
|
+
end
|
27
|
+
|
28
|
+
# Represents the core attribute of a version object (e.g., '7.x').
|
29
|
+
# A VersionCore object can be initialized from a number, a string,
|
30
|
+
# a Drupid::VersionCore object or a Drupid::Version object.
|
31
|
+
#
|
32
|
+
# Examples:
|
33
|
+
# core = Drupid::VersionCore.new '8.x'
|
34
|
+
# core = Drupid::VersionCore.new '8'
|
35
|
+
# core = Drupid::VersionCore.new '8.x-1.0'
|
36
|
+
# core = Drupid::VersionCore.new 8
|
37
|
+
# core = Drupid::VersionCore.new(Drupid::Version.new(8, '1.0'))
|
38
|
+
class VersionCore
|
39
|
+
include Comparable
|
40
|
+
|
41
|
+
attr :core
|
42
|
+
|
43
|
+
def initialize spec
|
44
|
+
if spec.is_a?(String)
|
45
|
+
spec.strip.match(/^(\d+)(\.x)?($|-)/)
|
46
|
+
raise NotDrupalVersionError, "Wrong core specification: #{core}" unless $1
|
47
|
+
@core = $1.to_i
|
48
|
+
elsif spec.is_a?(Version)
|
49
|
+
@core = spec.core.to_i
|
50
|
+
elsif spec.is_a?(VersionCore)
|
51
|
+
@core = spec.to_i
|
52
|
+
elsif spec.is_a?(Numeric)
|
53
|
+
@core = spec.to_i # to_i truncates a Float object (so that 7.9 correctly becomes 7)
|
54
|
+
else
|
55
|
+
raise NotDrupalVersionError, "Wrong core specification: #{core}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the core number as a string, e.g., '8.x'.
|
60
|
+
def to_s
|
61
|
+
@core.to_s + '.x'
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the core number as a Fixnum object.
|
65
|
+
def to_i
|
66
|
+
@core
|
67
|
+
end
|
68
|
+
|
69
|
+
def <=>(other)
|
70
|
+
@core <=> other.core
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Represents a project's version. A version has the form:
|
75
|
+
# <core>.x-<major>.<patch level>[-<extra>]
|
76
|
+
# Examples of versions include: '7.x-1.0', '7.x-1.2-beta2', '8.x-1.x-dev'.
|
77
|
+
#
|
78
|
+
# See also: http://drupal.org/node/467026
|
79
|
+
class Version
|
80
|
+
include Comparable
|
81
|
+
# The core number, e.g., in 7.x-3.2.beta1, it is 7.
|
82
|
+
attr :core
|
83
|
+
# The major version number, e.g., in 7.x-3.2-beta1, it is 3 (Fixnum).
|
84
|
+
attr :major
|
85
|
+
# The patch level, e.g., in 7.x-3.2-beta1, it is 2 (Fixnum).
|
86
|
+
attr :patchlevel
|
87
|
+
# The project's type, which is one of the constants UNSTABLE,
|
88
|
+
# ALPHA, BETA, RC, DEVELOPMENT, EMPTY or UNKNOWN.
|
89
|
+
# For example, for 7.x-3.2-beta1, it is BETA.
|
90
|
+
attr :extra_type
|
91
|
+
# The numeric part of the extra description, e.g., 7.x-3.2-beta1, it is 1 (Fixnum).
|
92
|
+
attr :extra_num
|
93
|
+
|
94
|
+
UNKNOWN = -1
|
95
|
+
DEVELOPMENT = 1
|
96
|
+
UNSTABLE = 2
|
97
|
+
ALPHA = 4
|
98
|
+
BETA = 8
|
99
|
+
RC = 16
|
100
|
+
EMPTY = 32
|
101
|
+
|
102
|
+
def initialize(core_num, v)
|
103
|
+
raise 'Drupal version is not a string.' unless v.is_a?(String)
|
104
|
+
@core = Drupid::VersionCore.new(core_num)
|
105
|
+
@major = v.match(/^(\d+)/)[1].to_i
|
106
|
+
@patchlevel = $~.post_match.match(/\.(\d+|x)/)[1]
|
107
|
+
@patchlevel = @patchlevel.to_i if 'x' != @patchlevel
|
108
|
+
@extra_string = ''
|
109
|
+
encode_extra($~.post_match) # Initialize @extra_type and @extra_num
|
110
|
+
end
|
111
|
+
|
112
|
+
# Builds a Drupid::Version object from a string, e.g., '8.x-2.0rc1'.
|
113
|
+
def self.from_s v
|
114
|
+
if v.match(/^(\d+)\.x-(\d+.+)$/)
|
115
|
+
Version.new($1.to_i, $2)
|
116
|
+
else
|
117
|
+
raise NotDrupalVersionError, "Cannot build a version from this string: #{v}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns true if this version represents a development snapshot;
|
122
|
+
# returns false otherwise.
|
123
|
+
def development_snapshot?
|
124
|
+
'x' == @patchlevel
|
125
|
+
end
|
126
|
+
|
127
|
+
# A synonym for self.short.
|
128
|
+
def to_s
|
129
|
+
short
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns a short textual representation of this version, e.g., '3.2'.
|
133
|
+
def short
|
134
|
+
xtr = extra()
|
135
|
+
xtr = '-' + xtr if '' != xtr
|
136
|
+
@major.to_s + '.' + @patchlevel.to_s + xtr
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns the full textual representation of this version, e.g., '7.x-3.2'.
|
140
|
+
def long
|
141
|
+
xtr = extra()
|
142
|
+
xtr = '-' + xtr if '' != xtr
|
143
|
+
@core.to_s + '-' + @major.to_s + '.' + @patchlevel.to_s + xtr
|
144
|
+
end
|
145
|
+
|
146
|
+
# In Ruby 1.8.7, some equality tests fail with the following message:
|
147
|
+
# No visible difference.
|
148
|
+
# You should look at your implementation of ==.
|
149
|
+
# if only <=> is defined. This is why we define == explicitly.
|
150
|
+
def ==(other)
|
151
|
+
@core == other.core and
|
152
|
+
@major == other.major and
|
153
|
+
@patchlevel == other.patchlevel and
|
154
|
+
@extra_type == other.extra_type and
|
155
|
+
@extra_num == other.extra_num
|
156
|
+
end
|
157
|
+
|
158
|
+
def <=>(w)
|
159
|
+
c = @core <=> w.core
|
160
|
+
if 0 == c
|
161
|
+
c = @major <=> w.major
|
162
|
+
if 0 == c
|
163
|
+
c = @patchlevel <=> w.patchlevel
|
164
|
+
case c
|
165
|
+
when nil # e.g., 1 vs 'x'
|
166
|
+
c = ('x' == @patchlevel) ? -1 : 1
|
167
|
+
when 0
|
168
|
+
c = @extra_type <=> w.extra_type
|
169
|
+
if 0 == c
|
170
|
+
c = @extra_num <=> w.extra_num
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
c
|
176
|
+
end
|
177
|
+
|
178
|
+
def extra
|
179
|
+
case @extra_type
|
180
|
+
when EMPTY then t = ''
|
181
|
+
when UNSTABLE then t = 'unstable'
|
182
|
+
when ALPHA then t = 'alpha'
|
183
|
+
when BETA then t = 'beta'
|
184
|
+
when RC then t = 'rc'
|
185
|
+
when DEVELOPMENT then t = 'dev'
|
186
|
+
else # unknown
|
187
|
+
t = @extra_string
|
188
|
+
end
|
189
|
+
if UNKNOWN == @extra_num
|
190
|
+
t
|
191
|
+
else
|
192
|
+
t + @extra_num.to_s
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def encode_extra(e)
|
199
|
+
@extra_string = e.start_with?('-') ? e.sub(/-/, '') : e
|
200
|
+
if e.match(/dev(\d*)$/)
|
201
|
+
@patchlevel = 'x'
|
202
|
+
@extra_type = DEVELOPMENT
|
203
|
+
@extra_num = ($~[1] == '') ? UNKNOWN : $~[1].to_i
|
204
|
+
return
|
205
|
+
end
|
206
|
+
e.match(/^-{0,1}([A-z]*)(\d*)$/)
|
207
|
+
if nil != $~
|
208
|
+
t = $~[1]
|
209
|
+
n = $~[2]
|
210
|
+
case t
|
211
|
+
when /^$/ then @extra_type = EMPTY
|
212
|
+
when /dev/ then @extra_type = DEVELOPMENT
|
213
|
+
when /unstable/ then @extra_type = UNSTABLE
|
214
|
+
when /alpha/ then @extra_type = ALPHA
|
215
|
+
when /beta/ then @extra_type = BETA
|
216
|
+
when /rc/ then @extra_type = RC
|
217
|
+
else
|
218
|
+
@extra_type = UNKNOWN
|
219
|
+
end
|
220
|
+
@extra_num = ('' != n) ? n.to_i : UNKNOWN
|
221
|
+
else
|
222
|
+
@extra_type = UNKNOWN
|
223
|
+
@extra_num = UNKNOWN
|
224
|
+
end
|
225
|
+
return
|
226
|
+
end
|
227
|
+
|
228
|
+
end # class Version
|
229
|
+
|
230
|
+
end # Drupid
|
data/lib/drupid.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# Copyright (c) 2012 Lifepillar
|
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 all
|
13
|
+
# 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 THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require 'fileutils'
|
24
|
+
require 'drupid/extend/pathname'
|
25
|
+
|
26
|
+
# To silence (most) warnings from a required file
|
27
|
+
module Kernel
|
28
|
+
def silence_warnings
|
29
|
+
with_warnings(nil) { yield }
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_warnings(flag)
|
33
|
+
old_verbose, $VERBOSE = $VERBOSE, flag
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
$VERBOSE = old_verbose
|
37
|
+
end
|
38
|
+
end unless Kernel.respond_to? :silence_warnings
|
39
|
+
|
40
|
+
module Drupid
|
41
|
+
DRUPID_VERSION = '1.0.0'
|
42
|
+
DRUPID_USER_AGENT = "Drupid #{DRUPID_VERSION} (Ruby #{RUBY_VERSION}-#{RUBY_PATCHLEVEL}; #{RUBY_PLATFORM})"
|
43
|
+
end
|
44
|
+
|
45
|
+
require 'drupid/utils'
|
46
|
+
require 'drupid/download_strategy'
|
47
|
+
require 'drupid/drush'
|
48
|
+
require 'drupid/patch'
|
49
|
+
require 'drupid/version'
|
50
|
+
require 'drupid/component'
|
51
|
+
require 'drupid/project'
|
52
|
+
require 'drupid/library'
|
53
|
+
require 'drupid/makefile'
|
54
|
+
require 'drupid/platform'
|
55
|
+
require 'drupid/platform_project'
|
56
|
+
require 'drupid/updater'
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: drupid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lifepillar
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rgl
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.4.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.4.0
|
30
|
+
description: Drupid keeps a Drush makefile in sync with a Drupal distribution.
|
31
|
+
email: lifepillar@lifepillar.com
|
32
|
+
executables:
|
33
|
+
- drupid
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- lib/drupid/component.rb
|
38
|
+
- lib/drupid/download_strategy.rb
|
39
|
+
- lib/drupid/drush.rb
|
40
|
+
- lib/drupid/extend/pathname.rb
|
41
|
+
- lib/drupid/library.rb
|
42
|
+
- lib/drupid/makefile.rb
|
43
|
+
- lib/drupid/patch.rb
|
44
|
+
- lib/drupid/platform.rb
|
45
|
+
- lib/drupid/platform_project.rb
|
46
|
+
- lib/drupid/project.rb
|
47
|
+
- lib/drupid/updater.rb
|
48
|
+
- lib/drupid/utils.rb
|
49
|
+
- lib/drupid/version.rb
|
50
|
+
- lib/drupid.rb
|
51
|
+
- bin/drupid
|
52
|
+
homepage: http://lifepillar.com
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.8.21
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: The not-so-smart Drupal bundler!
|
76
|
+
test_files: []
|