pivotal-piston 1.9.4
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/.gitignore +8 -0
- data/History.txt +11 -0
- data/License.txt +20 -0
- data/Manifest.txt +85 -0
- data/README.txt +136 -0
- data/Rakefile +4 -0
- data/bin/piston +5 -0
- data/config/hoe.rb +79 -0
- data/config/requirements.rb +18 -0
- data/lib/piston.rb +18 -0
- data/lib/piston/cli.rb +315 -0
- data/lib/piston/commands.rb +4 -0
- data/lib/piston/commands/base.rb +44 -0
- data/lib/piston/commands/import.rb +42 -0
- data/lib/piston/commands/info.rb +14 -0
- data/lib/piston/commands/lock_unlock.rb +21 -0
- data/lib/piston/commands/update.rb +29 -0
- data/lib/piston/git.rb +12 -0
- data/lib/piston/git/client.rb +77 -0
- data/lib/piston/git/commit.rb +74 -0
- data/lib/piston/git/repository.rb +63 -0
- data/lib/piston/git/working_copy.rb +86 -0
- data/lib/piston/repository.rb +57 -0
- data/lib/piston/revision.rb +53 -0
- data/lib/piston/svn.rb +14 -0
- data/lib/piston/svn/client.rb +88 -0
- data/lib/piston/svn/repository.rb +67 -0
- data/lib/piston/svn/revision.rb +74 -0
- data/lib/piston/svn/working_copy.rb +108 -0
- data/lib/piston/version.rb +9 -0
- data/lib/piston/working_copy.rb +183 -0
- data/lib/subclass_responsibility_error.rb +2 -0
- data/log/.gitignore +0 -0
- data/samples/common.rb +19 -0
- data/samples/import_git_git.rb +39 -0
- data/samples/import_git_svn.rb +36 -0
- data/samples/import_svn_git.rb +29 -0
- data/samples/import_svn_svn.rb +24 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/samples.rake +6 -0
- data/tasks/test.rake +69 -0
- data/tasks/website.rake +17 -0
- data/test/integration/test_git_git.rb +99 -0
- data/test/integration/test_git_svn.rb +121 -0
- data/test/integration/test_import_svn_git.rb +47 -0
- data/test/integration/test_import_svn_svn.rb +38 -0
- data/test/integration_helpers.rb +33 -0
- data/test/test_helper.rb +83 -0
- data/test/unit/git/commit/test_checkout.rb +31 -0
- data/test/unit/git/commit/test_each.rb +30 -0
- data/test/unit/git/commit/test_rememberance.rb +21 -0
- data/test/unit/git/commit/test_validation.rb +34 -0
- data/test/unit/git/repository/test_at.rb +23 -0
- data/test/unit/git/repository/test_basename.rb +12 -0
- data/test/unit/git/repository/test_branchanme.rb +15 -0
- data/test/unit/git/repository/test_guessing.rb +32 -0
- data/test/unit/git/working_copy/test_copying.rb +25 -0
- data/test/unit/git/working_copy/test_creation.rb +22 -0
- data/test/unit/git/working_copy/test_existence.rb +18 -0
- data/test/unit/git/working_copy/test_finalization.rb +15 -0
- data/test/unit/git/working_copy/test_guessing.rb +35 -0
- data/test/unit/git/working_copy/test_rememberance.rb +21 -0
- data/test/unit/svn/repository/test_at.rb +19 -0
- data/test/unit/svn/repository/test_basename.rb +24 -0
- data/test/unit/svn/repository/test_guessing.rb +45 -0
- data/test/unit/svn/revision/test_checkout.rb +28 -0
- data/test/unit/svn/revision/test_each.rb +22 -0
- data/test/unit/svn/revision/test_rememberance.rb +38 -0
- data/test/unit/svn/revision/test_validation.rb +50 -0
- data/test/unit/svn/working_copy/test_copying.rb +26 -0
- data/test/unit/svn/working_copy/test_creation.rb +16 -0
- data/test/unit/svn/working_copy/test_existence.rb +23 -0
- data/test/unit/svn/working_copy/test_externals.rb +56 -0
- data/test/unit/svn/working_copy/test_finalization.rb +17 -0
- data/test/unit/svn/working_copy/test_guessing.rb +18 -0
- data/test/unit/svn/working_copy/test_merging.rb +47 -0
- data/test/unit/svn/working_copy/test_rememberance.rb +26 -0
- data/test/unit/test_info.rb +37 -0
- data/test/unit/test_lock_unlock.rb +47 -0
- data/test/unit/test_repository.rb +51 -0
- data/test/unit/test_revision.rb +31 -0
- data/test/unit/working_copy/test_guessing.rb +35 -0
- data/test/unit/working_copy/test_info.rb +14 -0
- data/test/unit/working_copy/test_rememberance.rb +42 -0
- data/test/unit/working_copy/test_validate.rb +63 -0
- data/website/index.html +11 -0
- data/website/index.txt +39 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +244 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require "piston/revision"
|
|
2
|
+
|
|
3
|
+
module Piston
|
|
4
|
+
class Repository
|
|
5
|
+
class UnhandledUrl < RuntimeError; end
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
def logger
|
|
9
|
+
@@logger ||= Log4r::Logger["handler"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def guess(url)
|
|
13
|
+
logger.info {"Guessing the repository type of #{url.inspect}"}
|
|
14
|
+
|
|
15
|
+
handler = handlers.detect do |handler|
|
|
16
|
+
logger.debug {"Asking #{handler}"}
|
|
17
|
+
handler.understands_url?(url)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
raise UnhandledUrl unless handler
|
|
21
|
+
|
|
22
|
+
handler.new(url)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@@handlers = Array.new
|
|
26
|
+
def add_handler(handler)
|
|
27
|
+
@@handlers << handler
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def handlers
|
|
31
|
+
@@handlers
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :url
|
|
36
|
+
|
|
37
|
+
def initialize(url)
|
|
38
|
+
@url = url
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def logger
|
|
42
|
+
self.class.logger
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def at(revision)
|
|
46
|
+
raise SubclassResponsibilityError, "Piston::Repository#at should be implemented by a subclass."
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_s
|
|
50
|
+
"Piston::Repository(#{@url})"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def ==(other)
|
|
54
|
+
url == other.url
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Piston
|
|
2
|
+
class Revision
|
|
3
|
+
include Enumerable
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
def logger
|
|
7
|
+
@@logger ||= Log4r::Logger["handler"]
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_reader :repository, :revision, :recalled_values, :dir
|
|
12
|
+
|
|
13
|
+
def initialize(repository, revision, recalled_values={})
|
|
14
|
+
@repository, @revision, @recalled_values = repository, revision, recalled_values
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def url
|
|
18
|
+
repository.url
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def name
|
|
22
|
+
@revision
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def logger
|
|
26
|
+
self.class.logger
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
"Piston::Revision(#{@repository.url}@#{@revision})"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Retrieve a copy of this repository into +dir+.
|
|
34
|
+
def checkout_to(dir)
|
|
35
|
+
logger.debug {"Checking out #{@repository}@#{@revision} into #{dir}"}
|
|
36
|
+
@dir = dir.kind_of?(Pathname) ? dir : Pathname.new(dir)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# What values does this revision want to remember for the future ?
|
|
40
|
+
def remember_values
|
|
41
|
+
logger.debug {"Generating remember values"}
|
|
42
|
+
{}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Yields each file of this revision in turn to our caller.
|
|
46
|
+
def each
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Copies +relpath+ (relative to ourselves) to +abspath+ (an absolute path).
|
|
50
|
+
def copy_to(relpath, abspath)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/piston/svn.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "piston/svn/client"
|
|
2
|
+
require "piston/svn/repository"
|
|
3
|
+
require "piston/svn/revision"
|
|
4
|
+
require "piston/svn/working_copy"
|
|
5
|
+
|
|
6
|
+
module Piston
|
|
7
|
+
module Svn
|
|
8
|
+
ROOT = "piston:root"
|
|
9
|
+
UUID = "piston:uuid"
|
|
10
|
+
REMOTE_REV = "piston:remote-revision"
|
|
11
|
+
LOCAL_REV = "piston:local-revision"
|
|
12
|
+
LOCKED = "piston:locked"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "singleton"
|
|
2
|
+
|
|
3
|
+
module Piston
|
|
4
|
+
module Svn
|
|
5
|
+
class Client
|
|
6
|
+
include Singleton
|
|
7
|
+
|
|
8
|
+
class CommandError < RuntimeError; end
|
|
9
|
+
class Failed < CommandError; end
|
|
10
|
+
class BadCommand < CommandError; end
|
|
11
|
+
|
|
12
|
+
def logger
|
|
13
|
+
@logger ||= Log4r::Logger["handler::client"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def out_logger
|
|
17
|
+
@out_logger ||= Log4r::Logger["handler::client::out"]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def svnadmin(*args)
|
|
21
|
+
run_cmd :svnadmin, *args
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def svn(*args)
|
|
25
|
+
run_cmd :svn, *args
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def svnlook(*args)
|
|
29
|
+
run_cmd :svnlook, *args
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def svnversion(*args)
|
|
33
|
+
run_cmd :svnversion, *args
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
def run_cmd(executable, *args)
|
|
38
|
+
args.collect! {|arg| arg =~ /\s|\*|\?|"|\n|\r/ ? %Q('#{arg}') : arg}
|
|
39
|
+
args.collect! {|arg| arg ? arg : '""'}
|
|
40
|
+
cmd = %Q|#{executable} #{args.join(' ')}|
|
|
41
|
+
logger.debug {"> " + cmd}
|
|
42
|
+
|
|
43
|
+
original_language = ENV["LANGUAGE"]
|
|
44
|
+
begin
|
|
45
|
+
ENV["LANGUAGE"] = "C"
|
|
46
|
+
value = run_real(cmd)
|
|
47
|
+
out_logger.info {"< " + value} unless (value || "").strip.empty?
|
|
48
|
+
return value
|
|
49
|
+
ensure
|
|
50
|
+
ENV["LANGUAGE"] = original_language
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
begin
|
|
55
|
+
raise LoadError, "Not implemented on Win32 machines" if RUBY_PLATFORM =~ /mswin32/
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
require "rubygems"
|
|
59
|
+
rescue LoadError
|
|
60
|
+
# NOP -- attempt to load without Rubygems
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
require "open4"
|
|
64
|
+
|
|
65
|
+
def run_real(cmd)
|
|
66
|
+
begin
|
|
67
|
+
pid, stdin, stdout, stderr = Open4::popen4(cmd)
|
|
68
|
+
_, cmdstatus = Process.waitpid2(pid)
|
|
69
|
+
raise CommandError, "#{cmd.inspect} exited with status: #{cmdstatus.exitstatus}\n#{stderr.read}" unless cmdstatus.success?
|
|
70
|
+
return stdout.read
|
|
71
|
+
rescue Errno::ENOENT
|
|
72
|
+
raise BadCommand, cmd.inspect
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
rescue LoadError
|
|
77
|
+
# On platforms where open4 is unavailable, we fallback to running using
|
|
78
|
+
# the backtick method of Kernel.
|
|
79
|
+
def run_real(cmd)
|
|
80
|
+
out = `#{cmd}`
|
|
81
|
+
raise BadCommand, cmd.inspect if $?.exitstatus == 127
|
|
82
|
+
raise Failed, "#{cmd.inspect} exited with status: #{$?.exitstatus}" unless $?.success?
|
|
83
|
+
out
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require "uri"
|
|
2
|
+
|
|
3
|
+
module Piston
|
|
4
|
+
module Svn
|
|
5
|
+
class Repository < Piston::Repository
|
|
6
|
+
# Register ourselves as a repository handler
|
|
7
|
+
Piston::Repository.add_handler self
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def understands_url?(url)
|
|
11
|
+
uri = URI.parse(url)
|
|
12
|
+
case uri.scheme
|
|
13
|
+
when "svn", /^svn\+/
|
|
14
|
+
true
|
|
15
|
+
when "http", "https", "file"
|
|
16
|
+
# Have to contact server to know
|
|
17
|
+
result = svn(:info, url) rescue :failed
|
|
18
|
+
result == :failed ? false : true
|
|
19
|
+
else
|
|
20
|
+
# Don't know how to handle this scheme.
|
|
21
|
+
# Let someone else handle it
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def client
|
|
26
|
+
@@client ||= Piston::Svn::Client.instance
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def svn(*args)
|
|
30
|
+
client.svn(*args)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def repository_type
|
|
34
|
+
'svn'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def svn(*args)
|
|
39
|
+
self.class.svn(*args)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def at(revision)
|
|
43
|
+
if revision.respond_to?(:keys) then
|
|
44
|
+
rev = revision[Piston::Svn::REMOTE_REV]
|
|
45
|
+
Piston::Svn::Revision.new(self, rev, revision)
|
|
46
|
+
else
|
|
47
|
+
case
|
|
48
|
+
when revision == :head
|
|
49
|
+
Piston::Svn::Revision.new(self, "HEAD")
|
|
50
|
+
when revision.to_i != 0
|
|
51
|
+
Piston::Svn::Revision.new(self, revision.to_i)
|
|
52
|
+
else
|
|
53
|
+
raise ArgumentError, "Invalid revision argument: #{revision.inspect}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def basename
|
|
59
|
+
if self.url =~ /trunk|branches|tags/ then
|
|
60
|
+
self.url.sub(%r{/(?:trunk|branches|tags).*$}, "").split("/").last
|
|
61
|
+
else
|
|
62
|
+
self.url.split("/").last
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require "piston/revision"
|
|
2
|
+
require "fileutils"
|
|
3
|
+
|
|
4
|
+
module Piston
|
|
5
|
+
module Svn
|
|
6
|
+
class Revision < Piston::Revision
|
|
7
|
+
class InvalidRevision < RuntimeError; end
|
|
8
|
+
class RepositoryMoved < InvalidRevision; end
|
|
9
|
+
class UuidChanged < InvalidRevision; end
|
|
10
|
+
|
|
11
|
+
def client
|
|
12
|
+
@client ||= Piston::Svn::Client.instance
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def svn(*args)
|
|
16
|
+
client.svn(*args)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def name
|
|
20
|
+
"r#{revision}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def checkout_to(dir)
|
|
24
|
+
super
|
|
25
|
+
answer = svn(:checkout, "--revision", revision, repository.url, dir)
|
|
26
|
+
if answer =~ /Checked out revision (\d+)[.]/ then
|
|
27
|
+
if revision == "HEAD" then
|
|
28
|
+
@revision = $1.to_i
|
|
29
|
+
elsif revision != $1.to_i then
|
|
30
|
+
raise Failed, "Did not get the revision I wanted to checkout. Subversion checked out #{$1}, I wanted #{revision}"
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
raise Failed, "Could not checkout revision #{revision} from #{repository.url} to #{dir}\n#{answer}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def remember_values
|
|
38
|
+
str = svn(:info, "--revision", revision, repository.url)
|
|
39
|
+
raise Failed, "Could not get 'svn info' from #{repository.url} at revision #{revision}" if str.nil? || str.chomp.strip.empty?
|
|
40
|
+
info = YAML.load(str)
|
|
41
|
+
{ Piston::Svn::UUID => info["Repository UUID"],
|
|
42
|
+
Piston::Svn::REMOTE_REV => info["Revision"]}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def each
|
|
46
|
+
raise ArgumentError, "Revision #{revision} of #{repository.url} was never checked out -- can't iterate over files" unless @dir
|
|
47
|
+
|
|
48
|
+
svn(:ls, "--recursive", @dir).each do |relpath|
|
|
49
|
+
next if relpath =~ %r{/$}
|
|
50
|
+
yield relpath.chomp
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def copy_to(relpath, abspath)
|
|
55
|
+
raise ArgumentError, "Revision #{revision} of #{repository.url} was never checked out -- can't iterate over files" unless @dir
|
|
56
|
+
|
|
57
|
+
Pathname.new(abspath).dirname.mkpath
|
|
58
|
+
FileUtils.cp(@dir + relpath, abspath)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def validate!
|
|
62
|
+
data = svn(:info, "--revision", revision, repository.url)
|
|
63
|
+
info = YAML.load(data)
|
|
64
|
+
actual_uuid = info["Repository UUID"]
|
|
65
|
+
raise RepositoryMoved, "Repository at #{repository.url} does not exist anymore:\n#{data}" if actual_uuid.blank?
|
|
66
|
+
raise UuidChanged, "Expected repository at #{repository.url} to have UUID #{recalled_uuid} but found #{actual_uuid}" if recalled_uuid != actual_uuid
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def recalled_uuid
|
|
70
|
+
recalled_values[Piston::Svn::UUID]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module Piston
|
|
4
|
+
module Svn
|
|
5
|
+
class WorkingCopy < Piston::WorkingCopy
|
|
6
|
+
# Register ourselves as a handler for working copies
|
|
7
|
+
Piston::WorkingCopy.add_handler self
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def understands_dir?(dir)
|
|
11
|
+
result = svn(:info, dir) rescue :failed
|
|
12
|
+
result == :failed ? false : true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def client
|
|
16
|
+
@@client ||= Piston::Svn::Client.instance
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def svn(*args)
|
|
20
|
+
client.svn(*args)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def svn(*args)
|
|
25
|
+
self.class.svn(*args)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def exist?
|
|
29
|
+
result = svn(:info, path) rescue :failed
|
|
30
|
+
logger.debug {"result: #{result.inspect}"}
|
|
31
|
+
return false if result == :failed
|
|
32
|
+
return false if result.nil? || result.chomp.strip.empty?
|
|
33
|
+
return true if YAML.load(result).has_key?("Path")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create
|
|
37
|
+
svn(:mkdir, path)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def after_remember(path)
|
|
41
|
+
begin
|
|
42
|
+
info = svn(:info, path)
|
|
43
|
+
rescue Piston::Svn::Client::CommandError
|
|
44
|
+
ensure
|
|
45
|
+
return unless info =~ /\(not a versioned resource\)/i || info =~ /\(is not under version control\)/i || info.blank?
|
|
46
|
+
svn(:add, path)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def finalize
|
|
51
|
+
targets = []
|
|
52
|
+
Dir[path + "*"].each do |item|
|
|
53
|
+
svn(:add, item)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns all defined externals (recursively) of this WC.
|
|
58
|
+
# Returns a Hash:
|
|
59
|
+
# {"vendor/rails" => {:revision => :head, :url => "http://dev.rubyonrails.org/svn/rails/trunk"},
|
|
60
|
+
# "vendor/plugins/will_paginate" => {:revision => 1234, :url => "http://will_paginate.org/svn/trunk"}}
|
|
61
|
+
def externals
|
|
62
|
+
externals = svn(:proplist, "--recursive", "--verbose")
|
|
63
|
+
return Hash.new if externals.blank?
|
|
64
|
+
returning(Hash.new) do |result|
|
|
65
|
+
YAML.load(externals).each_pair do |dir, props|
|
|
66
|
+
next if props["svn:externals"].blank?
|
|
67
|
+
next unless dir =~ /Properties on '([^']+)'/
|
|
68
|
+
basedir = self.path + $1
|
|
69
|
+
exts = props["svn:externals"]
|
|
70
|
+
exts.split("\n").each do |external|
|
|
71
|
+
data = external.match(/^([^\s]+)\s+(?:(?:-r|--revision)\s*(\d+)\s+)?(.+)$/)
|
|
72
|
+
case data.length
|
|
73
|
+
when 4
|
|
74
|
+
subdir, rev, url = data[1], data[2].nil? ? :head : data[2].to_i, data[3]
|
|
75
|
+
else
|
|
76
|
+
raise SyntaxError, "Could not parse svn:externals on #{basedir}: #{external}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
result[basedir + subdir] = {:revision => rev, :url => url}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def merge_changes(to)
|
|
86
|
+
data = svn(:info, yaml_path)
|
|
87
|
+
info = YAML.load(data)
|
|
88
|
+
initial_revision = info["Last Changed Rev"].to_i
|
|
89
|
+
logger.debug {"Going to merge #{initial_revision} to #{to.revision}"}
|
|
90
|
+
svn(:merge, "--revision", "#{initial_revision}:#{to.revision}", path, path)
|
|
91
|
+
logger.debug {"after merge"}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def remove_external_references(*targets)
|
|
95
|
+
svn(:propdel, "svn:externals", *targets)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
protected
|
|
99
|
+
def do_update(to, lock)
|
|
100
|
+
logger.info "Copying new changes in place"
|
|
101
|
+
copy_from(to)
|
|
102
|
+
logger.info "Merging local changes into working copy"
|
|
103
|
+
merge_changes(to)
|
|
104
|
+
remember(recall.merge(:lock => lock), to.remember_values)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|