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
@@ -0,0 +1,585 @@
|
|
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 'pathname'
|
47
|
+
require 'uri'
|
48
|
+
|
49
|
+
module Drupid
|
50
|
+
|
51
|
+
def self.makeDownloader uri, dest, name, download_specs = {}
|
52
|
+
case download_specs[:type]
|
53
|
+
when 'file'
|
54
|
+
DownloadStrategy::Curl.new uri, dest, name, download_specs
|
55
|
+
when 'git'
|
56
|
+
DownloadStrategy::Git.new uri, dest, name, download_specs
|
57
|
+
when 'svn'
|
58
|
+
DownloadStrategy::Subversion.new uri, dest, name, download_specs
|
59
|
+
when 'cvs'
|
60
|
+
DownloadStrategy::CVS.new uri, dest, name, download_specs
|
61
|
+
when 'bzr'
|
62
|
+
DownloadStrategy::Bazaar.new uri, dest, name, download_specs
|
63
|
+
else
|
64
|
+
(DownloadStrategy.detect uri).new uri, dest, name, download_specs
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module DownloadStrategy
|
69
|
+
|
70
|
+
def self.detect url
|
71
|
+
case url
|
72
|
+
when %r[^file://] then Curl
|
73
|
+
# We use a special URL pattern for cvs
|
74
|
+
when %r[^cvs://] then CVS
|
75
|
+
# Standard URLs
|
76
|
+
when %r[^bzr://] then Bazaar
|
77
|
+
when %r[^git://] then Git
|
78
|
+
when %r[^https?://.+\.git$] then Git
|
79
|
+
when %r[^hg://] then Mercurial
|
80
|
+
when %r[^svn://] then Subversion
|
81
|
+
when %r[^svn\+http://] then Subversion
|
82
|
+
when %r[^fossil://] then Fossil
|
83
|
+
# Some well-known source hosts
|
84
|
+
when %r[^https?://(.+?\.)?googlecode\.com/hg] then Mercurial
|
85
|
+
when %r[^https?://(.+?\.)?googlecode\.com/svn] then Subversion
|
86
|
+
when %r[^https?://(.+?\.)?sourceforge\.net/svnroot/] then Subversion
|
87
|
+
when %r[^http://svn.apache.org/repos/] then Subversion
|
88
|
+
when %r[^http://www.apache.org/dyn/closer.cgi] then CurlApacheMirror
|
89
|
+
# Common URL patterns
|
90
|
+
when %r[^https?://svn\.] then Subversion
|
91
|
+
when %r[\.git$] then Git
|
92
|
+
when %r[\/] then Curl
|
93
|
+
else Drush
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class CurlError < RuntimeError
|
98
|
+
end
|
99
|
+
|
100
|
+
# [url] The URL to download from
|
101
|
+
# [dest] The target directory for the download
|
102
|
+
# [name] The name (without extension) to assign to the downloaded entity
|
103
|
+
# [download_specs] A hash of optional download parameters.
|
104
|
+
class Base
|
105
|
+
include Drupid::Utils
|
106
|
+
|
107
|
+
attr :url
|
108
|
+
attr :dest
|
109
|
+
attr :name
|
110
|
+
attr :staged_path
|
111
|
+
|
112
|
+
def initialize url, dest, name, download_specs = {}
|
113
|
+
@url = url
|
114
|
+
@dest = Pathname.new(dest).expand_path
|
115
|
+
@name = name
|
116
|
+
@specs = download_specs
|
117
|
+
@staged_path = nil
|
118
|
+
debug "#{self.class.to_s.split(/::/).last} downloader created for url=#{@url}, dest=#{@dest}, name=#{@name}"
|
119
|
+
debug "Download specs: #{download_specs}" unless download_specs.empty?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
class Curl < Base
|
125
|
+
attr :tarball_path
|
126
|
+
|
127
|
+
def initialize url, dest, name = nil, download_specs = {}
|
128
|
+
super
|
129
|
+
if @name.to_s.empty?
|
130
|
+
@tarball_path = @dest + File.basename(@url)
|
131
|
+
else
|
132
|
+
# Do not add an extension if the provided name has an extension
|
133
|
+
n = @name.match(/\.\w+$/) ? @name : @name+ext
|
134
|
+
@tarball_path = @dest + n
|
135
|
+
end
|
136
|
+
if @specs.has_key?('file_type')
|
137
|
+
@tarball_path = @tarball_path.sub_ext('.' + @specs['file_type'])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
# Private method, can be overridden if needed.
|
144
|
+
def _fetch
|
145
|
+
if @specs.has_key?('post_data')
|
146
|
+
curl @url, '-d', @specs['post_data'], '-o', @tarball_path
|
147
|
+
else
|
148
|
+
curl @url, '-o', @tarball_path
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
public
|
153
|
+
|
154
|
+
# Retrieves a file from this object's URL.
|
155
|
+
def fetch
|
156
|
+
@tarball_path.rmtree if @tarball_path.exist?
|
157
|
+
begin
|
158
|
+
debug "Pathname.mkpath may raise harmless exceptions"
|
159
|
+
@dest.mkpath unless @dest.exist?
|
160
|
+
_fetch
|
161
|
+
rescue Exception => e
|
162
|
+
ignore_interrupts { @tarball_path.unlink if @tarball_path.exist? }
|
163
|
+
if e.kind_of? ErrorDuringExecution
|
164
|
+
raise CurlError, "Download failed: #{@url}"
|
165
|
+
else
|
166
|
+
raise
|
167
|
+
end
|
168
|
+
end
|
169
|
+
return @tarball_path
|
170
|
+
end
|
171
|
+
|
172
|
+
# Stages this download into the specified directory.
|
173
|
+
# Invokes #fetch to retrieve the file if needed.
|
174
|
+
def stage wd = @dest
|
175
|
+
fetch unless @tarball_path.exist?
|
176
|
+
debug "Pathname.mkpath may raise harmless exceptions"
|
177
|
+
wd.mkpath unless wd.exist?
|
178
|
+
target = wd + @tarball_path.basename
|
179
|
+
type = @tarball_path.compression_type
|
180
|
+
if type
|
181
|
+
tempdir do # uncompress inside a temporary directory
|
182
|
+
uncompress @tarball_path, :type => type
|
183
|
+
# Move extracted archive into the destination
|
184
|
+
content = Pathname.pwd.children
|
185
|
+
if 1 == content.size and content.first.directory?
|
186
|
+
src = content.first
|
187
|
+
target = wd + src.basename
|
188
|
+
FileUtils.mv src.to_s, wd.to_s, :force => true, :verbose => $DEBUG
|
189
|
+
else # the archive did not have a root folder or it expanded to a file instead of a folder
|
190
|
+
# We cannot move the temporary directory we are in, so we copy its content
|
191
|
+
src = Pathname.pwd
|
192
|
+
target = wd + src.basename
|
193
|
+
target.rmtree if target.exist? # Overwrite
|
194
|
+
target.mkpath
|
195
|
+
src.ditto target
|
196
|
+
end
|
197
|
+
debug "Temporary staging target: #{target}"
|
198
|
+
end
|
199
|
+
elsif wd != @dest
|
200
|
+
FileUtils.mv @tarball_path.to_s, wd.to_s, :force => true, :verbose => $DEBUG
|
201
|
+
end
|
202
|
+
if @name and @name != target.basename.to_s
|
203
|
+
new_path = target.dirname + @name
|
204
|
+
new_path.rmtree if new_path.exist? # Overwrite
|
205
|
+
File.rename target.to_s, new_path.to_s
|
206
|
+
target = target.dirname+@name
|
207
|
+
end
|
208
|
+
@staged_path = target
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def ext
|
214
|
+
# GitHub uses odd URLs for zip files, so check for those
|
215
|
+
rx=%r[https?://(www\.)?github\.com/.*/(zip|tar)ball/]
|
216
|
+
if rx.match @url
|
217
|
+
if $2 == 'zip'
|
218
|
+
'.zip'
|
219
|
+
else
|
220
|
+
'.tgz'
|
221
|
+
end
|
222
|
+
else
|
223
|
+
Pathname.new(@url).extname # uses extended extname that supports double extensions
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
end # Curl
|
228
|
+
|
229
|
+
|
230
|
+
class Drush < Curl
|
231
|
+
def initialize url, dest, name, download_specs = {}
|
232
|
+
super
|
233
|
+
@tarball_path = @dest + @name
|
234
|
+
end
|
235
|
+
|
236
|
+
def _fetch
|
237
|
+
output = Drupid::Drush.pm_download url, :destination => dest
|
238
|
+
p = Drupid::Drush.download_path(output)
|
239
|
+
if p
|
240
|
+
@tarball_path = Pathname.new(p).realpath
|
241
|
+
else
|
242
|
+
raise "Download failed for project #{name} (using Drush):\n#{output}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end # Drush
|
246
|
+
|
247
|
+
|
248
|
+
# Detect and download from Apache Mirror
|
249
|
+
class CurlApacheMirror < Curl
|
250
|
+
def _fetch
|
251
|
+
# Fetch mirror list site
|
252
|
+
require 'open-uri'
|
253
|
+
mirror_list = open(@url).read()
|
254
|
+
|
255
|
+
# Parse out suggested mirror
|
256
|
+
# Yep, this is ghetto, grep the first <strong></strong> element content
|
257
|
+
mirror_url = mirror_list[/<strong>([^<]+)/, 1]
|
258
|
+
|
259
|
+
raise "Couldn't determine mirror. Try again later." if mirror_url.nil?
|
260
|
+
|
261
|
+
blah "Best Mirror #{mirror_url}"
|
262
|
+
# Start download from that mirror
|
263
|
+
curl mirror_url, '-o', @tarball_path
|
264
|
+
end
|
265
|
+
end # CurlApacheMirror
|
266
|
+
|
267
|
+
|
268
|
+
class Git < Base
|
269
|
+
def initialize url, dest, name, download_specs = {}
|
270
|
+
super
|
271
|
+
@clone = @dest + @name
|
272
|
+
end
|
273
|
+
|
274
|
+
def support_depth?
|
275
|
+
!(@specs.has_key?('revision')) and host_supports_depth?
|
276
|
+
end
|
277
|
+
|
278
|
+
def host_supports_depth?
|
279
|
+
@url =~ %r(git://) or @url =~ %r(https://github.com/)
|
280
|
+
end
|
281
|
+
|
282
|
+
def fetch
|
283
|
+
raise "You must install Git." unless which "git"
|
284
|
+
|
285
|
+
blah "Cloning #{@url}"
|
286
|
+
|
287
|
+
if @clone.exist?
|
288
|
+
Dir.chdir(@clone) do
|
289
|
+
# Check for interrupted clone from a previous install
|
290
|
+
unless system 'git', 'status', '-s'
|
291
|
+
blah "Removing invalid .git repo from cache"
|
292
|
+
FileUtils.rm_rf @clone
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
unless @clone.exist?
|
298
|
+
clone_args = ['clone']
|
299
|
+
clone_args << '--depth' << '1' if support_depth?
|
300
|
+
|
301
|
+
if @specs.has_key?('branch')
|
302
|
+
clone_args << '--branch' << @specs['branch']
|
303
|
+
elsif @specs.has_key?('tag')
|
304
|
+
clone_args << '--branch' << @specs['tag']
|
305
|
+
end
|
306
|
+
|
307
|
+
clone_args << @url << @clone
|
308
|
+
git(*clone_args)
|
309
|
+
else
|
310
|
+
blah "Updating #{@clone}"
|
311
|
+
Dir.chdir(@clone) do
|
312
|
+
git 'config', 'remote.origin.url', @url
|
313
|
+
|
314
|
+
rof =
|
315
|
+
if @specs.has_key?('branch')
|
316
|
+
"+refs/heads/#{@specs['branch']}:refs/remotes/origin/#{@specs['branch']}"
|
317
|
+
elsif @specs.has_key?('tag')
|
318
|
+
"+refs/tags/#{@specs['tag']}:refs/tags/#{@specs['tag']}"
|
319
|
+
else
|
320
|
+
'+refs/heads/master:refs/remotes/origin/master'
|
321
|
+
end
|
322
|
+
git 'config', 'remote.origin.fetch', rof
|
323
|
+
|
324
|
+
git_args = %w[fetch origin]
|
325
|
+
git(*git_args)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# Stages this download into the specified directory.
|
331
|
+
# Invokes #fetch to retrieve the file if needed.
|
332
|
+
def stage wd = @dest
|
333
|
+
fetch unless @clone.exist?
|
334
|
+
debug "Pathname.mkpath may raise harmless exceptions"
|
335
|
+
wd.mkpath unless wd.exist?
|
336
|
+
target = wd + @clone.basename
|
337
|
+
Dir.chdir @clone do
|
338
|
+
if @specs.has_key?('branch')
|
339
|
+
git 'checkout', "origin/#{@specs['branch']}", '--'
|
340
|
+
elsif @specs.has_key?('tag')
|
341
|
+
git 'checkout', @specs['tag'], '--'
|
342
|
+
elsif @specs.has_key?('revision')
|
343
|
+
git 'checkout', @specs['revision'], '--'
|
344
|
+
else
|
345
|
+
# otherwise the checkout-index won't checkout HEAD
|
346
|
+
# https://github.com/mxcl/homebrew/issues/7124
|
347
|
+
# must specify origin/HEAD, otherwise it resets to the current local HEAD
|
348
|
+
git 'reset', '--hard', 'origin/HEAD'
|
349
|
+
end
|
350
|
+
# http://stackoverflow.com/questions/160608/how-to-do-a-git-export-like-svn-export
|
351
|
+
git 'checkout-index', '-a', '-f', "--prefix=#{target}/"
|
352
|
+
# check for submodules
|
353
|
+
if File.exist?('.gitmodules')
|
354
|
+
git 'submodule', 'init'
|
355
|
+
git 'submodule', 'update'
|
356
|
+
sub_cmd = "git checkout-index -a -f \"--prefix=#{target}/$path/\""
|
357
|
+
git 'submodule', '--quiet', 'foreach', '--recursive', sub_cmd
|
358
|
+
end
|
359
|
+
end
|
360
|
+
@staged_path = target
|
361
|
+
end
|
362
|
+
end # Git
|
363
|
+
|
364
|
+
|
365
|
+
class Subversion < Base
|
366
|
+
def initialize url, dest, name, download_specs = {}
|
367
|
+
super
|
368
|
+
@co = @dest + @name
|
369
|
+
end
|
370
|
+
|
371
|
+
def fetch
|
372
|
+
@url.sub!(/^svn\+/, '') if @url =~ %r[^svn\+http://]
|
373
|
+
blah "Checking out #{@url}"
|
374
|
+
if @specs.has_key?('revision')
|
375
|
+
fetch_repo @co, @url, @specs['revision']
|
376
|
+
# elsif @specs.has_key?('revisions')
|
377
|
+
# # nil is OK for main_revision, as fetch_repo will then get latest
|
378
|
+
# main_revision = @ref.delete :trunk
|
379
|
+
# fetch_repo @co, @url, main_revision, true
|
380
|
+
#
|
381
|
+
# get_externals do |external_name, external_url|
|
382
|
+
# fetch_repo @co+external_name, external_url, @ref[external_name], true
|
383
|
+
# end
|
384
|
+
else
|
385
|
+
fetch_repo @co, @url
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def stage wd = @dest
|
390
|
+
fetch unless @co.exist?
|
391
|
+
debug "Pathname.mkpath may raise harmless exceptions"
|
392
|
+
wd.mkpath unless wd.exist?
|
393
|
+
target = wd + @co.basename
|
394
|
+
svn 'export', '--force', @co, target
|
395
|
+
end
|
396
|
+
|
397
|
+
def get_externals
|
398
|
+
output = svn 'propget', 'svn:externals', @url
|
399
|
+
output.chomp.each_line do |line|
|
400
|
+
name, url = line.split(/\s+/)
|
401
|
+
yield name, url
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def fetch_repo target, url, revision=nil, ignore_externals=false
|
406
|
+
# Use "svn up" when the repository already exists locally.
|
407
|
+
# This saves on bandwidth and will have a similar effect to verifying the
|
408
|
+
# cache as it will make any changes to get the right revision.
|
409
|
+
svncommand = target.exist? ? 'up' : 'checkout'
|
410
|
+
args = [svncommand]
|
411
|
+
args << '--non-interactive' unless @specs.has_key?('interactive') and 'true' == @specs.has_key?('interactive')
|
412
|
+
args << '--trust-server-cert'
|
413
|
+
# SVN shipped with XCode 3.1.4 can't force a checkout.
|
414
|
+
#args << '--force' unless MacOS.leopard? and svn == '/usr/bin/svn'
|
415
|
+
args << url if !target.exist?
|
416
|
+
args << target
|
417
|
+
args << '-r' << revision if revision
|
418
|
+
args << '--ignore-externals' if ignore_externals
|
419
|
+
svn(*args)
|
420
|
+
end
|
421
|
+
end # Subversion
|
422
|
+
|
423
|
+
|
424
|
+
class CVS < Base
|
425
|
+
def initialize url, dest, name, download_specs = {}
|
426
|
+
super
|
427
|
+
@co = @dest + @name
|
428
|
+
end
|
429
|
+
|
430
|
+
def fetch
|
431
|
+
blah "Checking out #{@url}"
|
432
|
+
|
433
|
+
# URL of cvs cvs://:pserver:anoncvs@www.gccxml.org:/cvsroot/GCC_XML:gccxml
|
434
|
+
# will become:
|
435
|
+
# cvs -d :pserver:anoncvs@www.gccxml.org:/cvsroot/GCC_XML login
|
436
|
+
# cvs -d :pserver:anoncvs@www.gccxml.org:/cvsroot/GCC_XML co gccxml
|
437
|
+
mod, url = split_url(@url)
|
438
|
+
|
439
|
+
unless @co.exist?
|
440
|
+
Dir.chdir @dest do
|
441
|
+
cvs '-d', url, 'login'
|
442
|
+
cvs '-d', url, 'checkout', '-d', @name, mod
|
443
|
+
end
|
444
|
+
else
|
445
|
+
blah "Updating #{@co}"
|
446
|
+
Dir.chdir(@co) { cvs 'up' }
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def stage wd = @dest
|
451
|
+
fetch unless @co.exist?
|
452
|
+
debug "Pathname.mkpath may raise harmless exceptions"
|
453
|
+
wd.mkpath unless wd.exist?
|
454
|
+
target = wd + @co.basename
|
455
|
+
FileUtils.cp_r Dir[@co+"{.}"], target
|
456
|
+
|
457
|
+
require 'find'
|
458
|
+
Find.find(Dir.pwd) do |path|
|
459
|
+
if FileTest.directory?(path) && File.basename(path) == "CVS"
|
460
|
+
Find.prune
|
461
|
+
FileUtil.rm_r path, :force => true
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
private
|
467
|
+
def split_url(in_url)
|
468
|
+
parts=in_url.sub(%r[^cvs://], '').split(/:/)
|
469
|
+
mod=parts.pop
|
470
|
+
url=parts.join(':')
|
471
|
+
[ mod, url ]
|
472
|
+
end
|
473
|
+
end # CVS
|
474
|
+
|
475
|
+
|
476
|
+
class Mercurial < Base
|
477
|
+
def initialize url, dest, name, download_specs = {}
|
478
|
+
super
|
479
|
+
@clone = @dest + @name
|
480
|
+
end
|
481
|
+
|
482
|
+
def fetch
|
483
|
+
blah "Cloning #{@url}"
|
484
|
+
|
485
|
+
unless @clone.exist?
|
486
|
+
url=@url.sub(%r[^hg://], '')
|
487
|
+
hg 'clone', url, @clone
|
488
|
+
else
|
489
|
+
blah "Updating #{@clone}"
|
490
|
+
Dir.chdir(@clone) do
|
491
|
+
hg 'pull'
|
492
|
+
hg 'update'
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
def stage wd = @dest
|
498
|
+
fetch unless @co.exist?
|
499
|
+
debug "Pathname.mkpath may raise harmless exceptions"
|
500
|
+
wd.mkpath unless wd.exist?
|
501
|
+
dst = wd + @co.basename
|
502
|
+
Dir.chdir @clone do
|
503
|
+
#if @spec and @ref
|
504
|
+
# blah "Checking out #{@spec} #{@ref}"
|
505
|
+
# Dir.chdir @clone do
|
506
|
+
# safe_system 'hg', 'archive', '-y', '-r', @ref, '-t', 'files', dst
|
507
|
+
# end
|
508
|
+
#else
|
509
|
+
hg 'archive', '-y', '-t', 'files', dst
|
510
|
+
#end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end # Mercurial
|
514
|
+
|
515
|
+
|
516
|
+
class Bazaar < Base
|
517
|
+
def initialize url, dest, name, download_specs = {}
|
518
|
+
super
|
519
|
+
@clone = @dest + @name
|
520
|
+
end
|
521
|
+
|
522
|
+
def fetch
|
523
|
+
blah "Cloning #{@url}"
|
524
|
+
unless @clone.exist?
|
525
|
+
url=@url.sub(%r[^bzr://], '')
|
526
|
+
# 'lightweight' means history-less
|
527
|
+
bzr 'checkout', '--lightweight', url, @clone
|
528
|
+
else
|
529
|
+
blah "Updating #{@clone}"
|
530
|
+
Dir.chdir(@clone) { bzr 'update' }
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def stage
|
535
|
+
# FIXME: The export command doesn't work on checkouts
|
536
|
+
# See https://bugs.launchpad.net/bzr/+bug/897511
|
537
|
+
FileUtils.cp_r Dir[@clone+"{.}"], Dir.pwd
|
538
|
+
FileUtils.rm_r Dir[Dir.pwd+"/.bzr"]
|
539
|
+
|
540
|
+
#dst=Dir.getwd
|
541
|
+
#Dir.chdir @clone do
|
542
|
+
# if @spec and @ref
|
543
|
+
# ohai "Checking out #{@spec} #{@ref}"
|
544
|
+
# Dir.chdir @clone do
|
545
|
+
# safe_system 'bzr', 'export', '-r', @ref, dst
|
546
|
+
# end
|
547
|
+
# else
|
548
|
+
# safe_system 'bzr', 'export', dst
|
549
|
+
# end
|
550
|
+
#end
|
551
|
+
end
|
552
|
+
end # Bazaar
|
553
|
+
|
554
|
+
|
555
|
+
class Fossil < Base
|
556
|
+
def initialize url, dest, name, download_specs = {}
|
557
|
+
super
|
558
|
+
@clone = @dest + @name
|
559
|
+
end
|
560
|
+
|
561
|
+
def fetch
|
562
|
+
raise "You must install fossil first" unless which "fossil"
|
563
|
+
|
564
|
+
blah "Cloning #{@url}"
|
565
|
+
unless @clone.exist?
|
566
|
+
url=@url.sub(%r[^fossil://], '')
|
567
|
+
runBabyRun 'fossil', ['clone', url, @clone]
|
568
|
+
else
|
569
|
+
blah "Updating #{@clone}"
|
570
|
+
runBabyRun 'fossil', ['pull', '-R', @clone]
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
def stage
|
575
|
+
# TODO: The 'open' and 'checkout' commands are very noisy and have no '-q' option.
|
576
|
+
runBabyRun 'fossil', ['open', @clone]
|
577
|
+
#if @spec and @ref
|
578
|
+
# ohai "Checking out #{@spec} #{@ref}"
|
579
|
+
# safe_system 'fossil', 'checkout', @ref
|
580
|
+
#end
|
581
|
+
end
|
582
|
+
end # Fossil
|
583
|
+
|
584
|
+
end # module DownloadStrategy
|
585
|
+
end # module Drupid
|