capistrano 2.1.0 → 3.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.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +89 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +226 -0
  8. data/Rakefile +5 -0
  9. data/bin/cap +2 -3
  10. data/bin/capify +7 -77
  11. data/capistrano-public_cert.pem +22 -0
  12. data/capistrano.gemspec +35 -0
  13. data/features/deploy.feature +52 -0
  14. data/features/installation.feature +16 -0
  15. data/features/remote_file_task.feature +14 -0
  16. data/features/step_definitions/assertions.rb +90 -0
  17. data/features/step_definitions/cap_commands.rb +8 -0
  18. data/features/step_definitions/setup.rb +25 -0
  19. data/features/support/env.rb +12 -0
  20. data/features/support/remote_command_helpers.rb +20 -0
  21. data/lib/Capfile +3 -0
  22. data/lib/capistrano/all.rb +16 -0
  23. data/lib/capistrano/application.rb +60 -0
  24. data/lib/capistrano/configuration/question.rb +42 -0
  25. data/lib/capistrano/configuration/server.rb +133 -0
  26. data/lib/capistrano/configuration/servers/role_filter.rb +86 -0
  27. data/lib/capistrano/configuration/servers.rb +53 -58
  28. data/lib/capistrano/configuration.rb +84 -30
  29. data/lib/capistrano/console.rb +1 -0
  30. data/lib/capistrano/defaults.rb +13 -0
  31. data/lib/capistrano/deploy.rb +3 -0
  32. data/lib/capistrano/dotfile.rb +3 -0
  33. data/lib/capistrano/dsl/env.rb +64 -0
  34. data/lib/capistrano/dsl/paths.rb +94 -0
  35. data/lib/capistrano/dsl/stages.rb +15 -0
  36. data/lib/capistrano/dsl/task_enhancements.rb +53 -0
  37. data/lib/capistrano/dsl.rb +48 -0
  38. data/lib/capistrano/git.rb +1 -0
  39. data/lib/capistrano/hg.rb +1 -0
  40. data/lib/capistrano/i18n.rb +34 -0
  41. data/lib/capistrano/install.rb +1 -0
  42. data/lib/capistrano/setup.rb +21 -0
  43. data/lib/capistrano/tasks/console.rake +21 -0
  44. data/lib/capistrano/tasks/deploy.rake +204 -0
  45. data/lib/capistrano/tasks/framework.rake +67 -0
  46. data/lib/capistrano/tasks/git.rake +62 -0
  47. data/lib/capistrano/tasks/hg.rake +39 -0
  48. data/lib/capistrano/tasks/install.rake +39 -0
  49. data/lib/capistrano/templates/Capfile +26 -0
  50. data/lib/capistrano/templates/deploy.rb.erb +40 -0
  51. data/lib/capistrano/templates/stage.rb.erb +42 -0
  52. data/lib/capistrano/version.rb +1 -20
  53. data/lib/capistrano/version_validator.rb +37 -0
  54. data/lib/capistrano.rb +0 -2
  55. data/spec/integration/dsl_spec.rb +344 -0
  56. data/spec/integration_spec_helper.rb +7 -0
  57. data/spec/lib/capistrano/application_spec.rb +61 -0
  58. data/spec/lib/capistrano/configuration/question_spec.rb +54 -0
  59. data/spec/lib/capistrano/configuration/server_spec.rb +249 -0
  60. data/spec/lib/capistrano/configuration/servers/role_filter_spec.rb +140 -0
  61. data/spec/lib/capistrano/configuration/servers_spec.rb +184 -0
  62. data/spec/lib/capistrano/configuration_spec.rb +101 -0
  63. data/spec/lib/capistrano/dsl/env_spec.rb +10 -0
  64. data/spec/lib/capistrano/dsl/paths_spec.rb +69 -0
  65. data/spec/lib/capistrano/dsl_spec.rb +63 -0
  66. data/spec/lib/capistrano/version_validator_spec.rb +103 -0
  67. data/spec/lib/capistrano_spec.rb +8 -0
  68. data/spec/spec_helper.rb +15 -0
  69. data/spec/support/.gitignore +1 -0
  70. data/spec/support/Vagrantfile +13 -0
  71. data/spec/support/matchers.rb +5 -0
  72. data/spec/support/tasks/database.cap +11 -0
  73. data/spec/support/test_app.rb +138 -0
  74. metadata +251 -179
  75. data/CHANGELOG +0 -512
  76. data/MIT-LICENSE +0 -20
  77. data/README +0 -43
  78. data/examples/sample.rb +0 -14
  79. data/lib/capistrano/callback.rb +0 -45
  80. data/lib/capistrano/cli/execute.rb +0 -82
  81. data/lib/capistrano/cli/help.rb +0 -102
  82. data/lib/capistrano/cli/help.txt +0 -53
  83. data/lib/capistrano/cli/options.rb +0 -183
  84. data/lib/capistrano/cli/ui.rb +0 -28
  85. data/lib/capistrano/cli.rb +0 -47
  86. data/lib/capistrano/command.rb +0 -161
  87. data/lib/capistrano/configuration/actions/file_transfer.rb +0 -35
  88. data/lib/capistrano/configuration/actions/inspect.rb +0 -46
  89. data/lib/capistrano/configuration/actions/invocation.rb +0 -134
  90. data/lib/capistrano/configuration/callbacks.rb +0 -148
  91. data/lib/capistrano/configuration/connections.rb +0 -159
  92. data/lib/capistrano/configuration/execution.rb +0 -126
  93. data/lib/capistrano/configuration/loading.rb +0 -198
  94. data/lib/capistrano/configuration/namespaces.rb +0 -196
  95. data/lib/capistrano/configuration/roles.rb +0 -51
  96. data/lib/capistrano/configuration/variables.rb +0 -127
  97. data/lib/capistrano/errors.rb +0 -15
  98. data/lib/capistrano/extensions.rb +0 -57
  99. data/lib/capistrano/gateway.rb +0 -131
  100. data/lib/capistrano/logger.rb +0 -59
  101. data/lib/capistrano/recipes/compat.rb +0 -32
  102. data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
  103. data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -46
  104. data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -96
  105. data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
  106. data/lib/capistrano/recipes/deploy/scm/base.rb +0 -192
  107. data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
  108. data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -151
  109. data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -85
  110. data/lib/capistrano/recipes/deploy/scm/git.rb +0 -191
  111. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -129
  112. data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -126
  113. data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -114
  114. data/lib/capistrano/recipes/deploy/scm.rb +0 -19
  115. data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -64
  116. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
  117. data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -144
  118. data/lib/capistrano/recipes/deploy/strategy/export.rb +0 -20
  119. data/lib/capistrano/recipes/deploy/strategy/remote.rb +0 -52
  120. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +0 -47
  121. data/lib/capistrano/recipes/deploy/strategy.rb +0 -19
  122. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
  123. data/lib/capistrano/recipes/deploy.rb +0 -494
  124. data/lib/capistrano/recipes/standard.rb +0 -37
  125. data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
  126. data/lib/capistrano/recipes/upgrade.rb +0 -33
  127. data/lib/capistrano/server_definition.rb +0 -51
  128. data/lib/capistrano/shell.rb +0 -256
  129. data/lib/capistrano/ssh.rb +0 -109
  130. data/lib/capistrano/task_definition.rb +0 -69
  131. data/lib/capistrano/upload.rb +0 -146
  132. data/test/cli/execute_test.rb +0 -132
  133. data/test/cli/help_test.rb +0 -139
  134. data/test/cli/options_test.rb +0 -226
  135. data/test/cli/ui_test.rb +0 -28
  136. data/test/cli_test.rb +0 -17
  137. data/test/command_test.rb +0 -309
  138. data/test/configuration/actions/file_transfer_test.rb +0 -40
  139. data/test/configuration/actions/inspect_test.rb +0 -62
  140. data/test/configuration/actions/invocation_test.rb +0 -202
  141. data/test/configuration/callbacks_test.rb +0 -206
  142. data/test/configuration/connections_test.rb +0 -288
  143. data/test/configuration/execution_test.rb +0 -159
  144. data/test/configuration/loading_test.rb +0 -127
  145. data/test/configuration/namespace_dsl_test.rb +0 -297
  146. data/test/configuration/roles_test.rb +0 -47
  147. data/test/configuration/servers_test.rb +0 -90
  148. data/test/configuration/variables_test.rb +0 -180
  149. data/test/configuration_test.rb +0 -81
  150. data/test/deploy/scm/accurev_test.rb +0 -23
  151. data/test/deploy/scm/base_test.rb +0 -55
  152. data/test/deploy/scm/git_test.rb +0 -112
  153. data/test/deploy/strategy/copy_test.rb +0 -147
  154. data/test/extensions_test.rb +0 -69
  155. data/test/fixtures/cli_integration.rb +0 -5
  156. data/test/fixtures/config.rb +0 -5
  157. data/test/fixtures/custom.rb +0 -3
  158. data/test/gateway_test.rb +0 -167
  159. data/test/logger_test.rb +0 -123
  160. data/test/server_definition_test.rb +0 -108
  161. data/test/shell_test.rb +0 -64
  162. data/test/ssh_test.rb +0 -97
  163. data/test/task_definition_test.rb +0 -101
  164. data/test/upload_test.rb +0 -131
  165. data/test/utils.rb +0 -42
  166. data/test/version_test.rb +0 -24
@@ -1,131 +0,0 @@
1
- if RUBY_VERSION == "1.8.6"
2
- begin
3
- require 'fastthread'
4
- rescue LoadError
5
- warn "You are running Ruby 1.8.6, which has a bug in its threading implementation."
6
- warn "You are liable to encounter deadlocks running Capistrano, unless you install"
7
- warn "the fastthread library, which is available as a gem:"
8
- warn " gem install fastthread"
9
- end
10
- end
11
-
12
- require 'thread'
13
- require 'capistrano/errors'
14
- require 'capistrano/ssh'
15
- require 'capistrano/server_definition'
16
-
17
- Thread.abort_on_exception = true
18
-
19
- module Capistrano
20
-
21
- # Black magic. It uses threads and Net::SSH to set up a connection to a
22
- # gateway server, through which connections to other servers may be
23
- # tunnelled.
24
- #
25
- # It is used internally by Capistrano, but may be useful on its own, as well.
26
- #
27
- # Usage:
28
- #
29
- # gateway = Capistrano::Gateway.new(Capistrano::ServerDefinition.new('gateway.example.com'))
30
- #
31
- # sess1 = gateway.connect_to(Capistrano::ServerDefinition.new('hidden.example.com'))
32
- # sess2 = gateway.connect_to(Capistrano::ServerDefinition.new('other.example.com'))
33
- class Gateway
34
- # The Thread instance driving the gateway connection.
35
- attr_reader :thread
36
-
37
- # The Net::SSH session representing the gateway connection.
38
- attr_reader :session
39
-
40
- MAX_PORT = 65535
41
- MIN_PORT = 1024
42
-
43
- def initialize(server, options={}) #:nodoc:
44
- @options = options
45
- @next_port = MAX_PORT
46
- @terminate_thread = false
47
- @port_guard = Mutex.new
48
-
49
- mutex = Mutex.new
50
- waiter = ConditionVariable.new
51
-
52
- mutex.synchronize do
53
- @thread = Thread.new do
54
- logger.trace "starting connection to gateway `#{server}'" if logger
55
- SSH.connect(server, @options) do |@session|
56
- logger.trace "gateway connection established" if logger
57
- mutex.synchronize { waiter.signal }
58
- @session.loop do
59
- !@terminate_thread
60
- end
61
- end
62
- end
63
-
64
- waiter.wait(mutex)
65
- end
66
- end
67
-
68
- # Shuts down all forwarded connections and terminates the gateway.
69
- def shutdown!
70
- # cancel all active forward channels
71
- session.forward.active_locals.each do |lport, host, port|
72
- session.forward.cancel_local(lport)
73
- end
74
-
75
- # terminate the gateway thread
76
- @terminate_thread = true
77
-
78
- # wait for the gateway thread to stop
79
- thread.join
80
- end
81
-
82
- # Connects to the given server by opening a forwarded port from the local
83
- # host to the server, via the gateway, and then opens and returns a new
84
- # Net::SSH connection via that port.
85
- def connect_to(server)
86
- connection = nil
87
- logger.debug "establishing connection to `#{server}' via gateway" if logger
88
- local_port = next_port
89
-
90
- thread = Thread.new do
91
- begin
92
- local_host = ServerDefinition.new("127.0.0.1", :user => server.user, :port => local_port)
93
- session.forward.local(local_port, server.host, server.port || 22)
94
- connection = SSH.connect(local_host, @options)
95
- connection.xserver = server
96
- logger.trace "connected: `#{server}' (via gateway)" if logger
97
- rescue Errno::EADDRINUSE
98
- local_port = next_port
99
- retry
100
- rescue Exception => e
101
- warn "#{e.class}: #{e.message}"
102
- warn e.backtrace.join("\n")
103
- end
104
- end
105
-
106
- thread.join
107
- if connection.nil?
108
- error = ConnectionError.new("could not establish connection to `#{server}'")
109
- error.hosts = [server]
110
- raise error
111
- end
112
-
113
- connection
114
- end
115
-
116
- private
117
-
118
- def logger
119
- @options[:logger]
120
- end
121
-
122
- def next_port
123
- @port_guard.synchronize do
124
- port = @next_port
125
- @next_port -= 1
126
- @next_port = MAX_PORT if @next_port < MIN_PORT
127
- port
128
- end
129
- end
130
- end
131
- end
@@ -1,59 +0,0 @@
1
- module Capistrano
2
- class Logger #:nodoc:
3
- attr_accessor :level
4
- attr_reader :device
5
-
6
- IMPORTANT = 0
7
- INFO = 1
8
- DEBUG = 2
9
- TRACE = 3
10
-
11
- MAX_LEVEL = 3
12
-
13
- def initialize(options={})
14
- output = options[:output] || $stderr
15
- if output.respond_to?(:puts)
16
- @device = output
17
- else
18
- @device = File.open(output.to_str, "a")
19
- @needs_close = true
20
- end
21
-
22
- @options = options
23
- @level = 0
24
- end
25
-
26
- def close
27
- device.close if @needs_close
28
- end
29
-
30
- def log(level, message, line_prefix=nil)
31
- if level <= self.level
32
- indent = "%*s" % [MAX_LEVEL, "*" * (MAX_LEVEL - level)]
33
- message.each do |line|
34
- if line_prefix
35
- device.puts "#{indent} [#{line_prefix}] #{line.strip}\n"
36
- else
37
- device.puts "#{indent} #{line.strip}\n"
38
- end
39
- end
40
- end
41
- end
42
-
43
- def important(message, line_prefix=nil)
44
- log(IMPORTANT, message, line_prefix)
45
- end
46
-
47
- def info(message, line_prefix=nil)
48
- log(INFO, message, line_prefix)
49
- end
50
-
51
- def debug(message, line_prefix=nil)
52
- log(DEBUG, message, line_prefix)
53
- end
54
-
55
- def trace(message, line_prefix=nil)
56
- log(TRACE, message, line_prefix)
57
- end
58
- end
59
- end
@@ -1,32 +0,0 @@
1
- # A collection of compatibility scripts, to ease the transition between
2
- # Capistrano 1.x and Capistrano 2.x.
3
-
4
- # Depends on the deployment system
5
- load 'deploy'
6
-
7
- map = { "diff_from_last_deploy" => "deploy:pending:diff",
8
- "update" => "deploy:update",
9
- "update_code" => "deploy:update_code",
10
- "symlink" => "deploy:symlink",
11
- "restart" => "deploy:restart",
12
- "rollback" => "deploy:rollback",
13
- "cleanup" => "deploy:cleanup",
14
- "disable_web" => "deploy:web:disable",
15
- "enable_web" => "deploy:web:enable",
16
- "cold_deploy" => "deploy:cold",
17
- "deploy_with_migrations" => "deploy:migrations" }
18
-
19
- map.each do |old, new|
20
- desc "DEPRECATED: See #{new}."
21
- eval "task(#{old.inspect}) do
22
- warn \"[DEPRECATED] `#{old}' is deprecated. Use `#{new}' instead.\"
23
- find_and_execute_task(#{new.inspect})
24
- end"
25
- end
26
-
27
- desc "DEPRECATED: See deploy:start."
28
- task :spinner do
29
- warn "[DEPRECATED] `spinner' is deprecated. Use `deploy:start' instead."
30
- set :runner, fetch(:spinner_user, "app")
31
- deploy.start
32
- end
@@ -1,44 +0,0 @@
1
- require 'capistrano/recipes/deploy/local_dependency'
2
- require 'capistrano/recipes/deploy/remote_dependency'
3
-
4
- module Capistrano
5
- module Deploy
6
- class Dependencies
7
- include Enumerable
8
-
9
- attr_reader :configuration
10
-
11
- def initialize(configuration)
12
- @configuration = configuration
13
- @dependencies = []
14
- yield self if block_given?
15
- end
16
-
17
- def check
18
- yield self
19
- self
20
- end
21
-
22
- def remote
23
- dep = RemoteDependency.new(configuration)
24
- @dependencies << dep
25
- dep
26
- end
27
-
28
- def local
29
- dep = LocalDependency.new(configuration)
30
- @dependencies << dep
31
- dep
32
- end
33
-
34
- def each
35
- @dependencies.each { |d| yield d }
36
- self
37
- end
38
-
39
- def pass?
40
- all? { |d| d.pass? }
41
- end
42
- end
43
- end
44
- end
@@ -1,46 +0,0 @@
1
- module Capistrano
2
- module Deploy
3
- class LocalDependency
4
- attr_reader :configuration
5
- attr_reader :message
6
-
7
- def initialize(configuration)
8
- @configuration = configuration
9
- @success = true
10
- end
11
-
12
- def command(command)
13
- @message ||= "`#{command}' could not be found in the path on the local host"
14
- @success = find_in_path(command)
15
- self
16
- end
17
-
18
- def or(message)
19
- @message = message
20
- self
21
- end
22
-
23
- def pass?
24
- @success
25
- end
26
-
27
- private
28
-
29
- # Searches the path, looking for the given utility. If an executable
30
- # file is found that matches the parameter, this returns true.
31
- def find_in_path(utility)
32
- path = (ENV['PATH'] || "").split(File::PATH_SEPARATOR)
33
- suffixes = RUBY_PLATFORM =~ /mswin/ ? %w(.bat .exe .com .cmd) : [""]
34
-
35
- path.each do |dir|
36
- suffixes.each do |sfx|
37
- file = File.join(dir, utility + sfx)
38
- return true if File.executable?(file)
39
- end
40
- end
41
-
42
- false
43
- end
44
- end
45
- end
46
- end
@@ -1,96 +0,0 @@
1
- module Capistrano
2
- module Deploy
3
- class RemoteDependency
4
- attr_reader :configuration
5
- attr_reader :hosts
6
-
7
- def initialize(configuration)
8
- @configuration = configuration
9
- @success = true
10
- end
11
-
12
- def directory(path, options={})
13
- @message ||= "`#{path}' is not a directory"
14
- try("test -d #{path}", options)
15
- self
16
- end
17
-
18
- def writable(path, options={})
19
- @message ||= "`#{path}' is not writable"
20
- try("test -w #{path}", options)
21
- self
22
- end
23
-
24
- def command(command, options={})
25
- @message ||= "`#{command}' could not be found in the path"
26
- try("which #{command}", options)
27
- self
28
- end
29
-
30
- def gem(name, version, options={})
31
- @message ||= "gem `#{name}' #{version} could not be found"
32
- gem_cmd = configuration.fetch(:gem_command, "gem")
33
- try("#{gem_cmd} specification --version '#{version}' #{name} 2>&1 | awk 'BEGIN { s = 0 } /^name:/ { s = 1; exit }; END { if(s == 0) exit 1 }'", options)
34
- self
35
- end
36
-
37
- def match(command, expect, options={})
38
- expect = Regexp.new(Regexp.escape(expect.to_s)) unless expect.is_a?(Regexp)
39
-
40
- output_per_server = {}
41
- try("#{command} ", options) do |ch, stream, out|
42
- output_per_server[ch[:server]] ||= ''
43
- output_per_server[ch[:server]] += out
44
- end
45
-
46
- # It is possible for some of these commands to return a status != 0
47
- # (for example, rake --version exits with a 1). For this check we
48
- # just care if the output matches, so we reset the success flag.
49
- @success = true
50
-
51
- errored_hosts = []
52
- output_per_server.each_pair do |server, output|
53
- next if output =~ expect
54
- errored_hosts << server
55
- end
56
-
57
- if errored_hosts.any?
58
- @hosts = errored_hosts.join(', ')
59
- output = output_per_server[errored_hosts.first]
60
- @message = "the output #{output.inspect} from #{command.inspect} did not match #{expect.inspect}"
61
- @success = false
62
- end
63
-
64
- self
65
- end
66
-
67
- def or(message)
68
- @message = message
69
- self
70
- end
71
-
72
- def pass?
73
- @success
74
- end
75
-
76
- def message
77
- s = @message.dup
78
- s << " (#{@hosts})" if @hosts && @hosts.any?
79
- s
80
- end
81
-
82
- private
83
-
84
- def try(command, options)
85
- return unless @success # short-circuit evaluation
86
- configuration.run(command, options) do |ch,stream,out|
87
- warn "#{ch[:server]}: #{out}" if stream == :err
88
- yield ch, stream, out if block_given?
89
- end
90
- rescue Capistrano::CommandError => e
91
- @success = false
92
- @hosts = e.hosts.join(', ')
93
- end
94
- end
95
- end
96
- end
@@ -1,169 +0,0 @@
1
- require 'capistrano/recipes/deploy/scm/base'
2
- require 'rexml/xpath'
3
- require 'rexml/document'
4
-
5
- module Capistrano
6
- module Deploy
7
- module SCM
8
- # Accurev bridge for use by Capistrano. This implementation does not
9
- # implement all features of a Capistrano SCM module. The ones that are
10
- # left out are either exceedingly difficult to implement with Accurev
11
- # or are considered bad form.
12
- #
13
- # When using this module in a project, the following variables are used:
14
- # * :repository - This should match the depot that code lives in. If your code
15
- # exists in a subdirectory, you can append the path depot.
16
- # eg. foo-depot/bar_dir
17
- # * :stream - The stream in the depot that code should be pulled from. If
18
- # left blank, the depot stream will be used
19
- # * :revision - Should be in the form 'stream/transaction'.
20
- class Accurev < Base
21
- include REXML
22
- default_command 'accurev'
23
-
24
- # Defines pseudo-revision value for the most recent changes to be deployed.
25
- def head
26
- "#{stream}/highest"
27
- end
28
-
29
- # Given an Accurev revision identifier, this method returns an identifier that
30
- # can be used for later SCM calls. This returned identifier will not
31
- # change as a result of further SCM activity.
32
- def query_revision(revision)
33
- internal_revision = InternalRevision.parse(revision)
34
- return revision unless internal_revision.psuedo_revision?
35
-
36
- logger.debug("Querying for real revision for #{internal_revision}")
37
- rev_stream = internal_revision.stream
38
-
39
- logger.debug("Determining what type of stream #{rev_stream} is...")
40
- stream_xml = yield show_streams_for(rev_stream)
41
- stream_doc = Document.new(stream_xml)
42
- type = XPath.first(stream_doc, '//streams/stream/@type').value
43
-
44
- case type
45
- when 'snapshot'
46
- InternalRevision.new(rev_stream, 'highest').to_s
47
- else
48
- logger.debug("Getting latest transaction id in #{rev_stream}")
49
- # Doing another yield for a second Accurev call. Hopefully this is ok.
50
- hist_xml = yield scm(:hist, '-ftx', '-s', rev_stream, '-t', 'now.1')
51
- hist_doc = Document.new(hist_xml)
52
- transaction_id = XPath.first(hist_doc, '//AcResponse/transaction/@id').value
53
- InternalRevision.new(stream, transaction_id).to_s
54
- end
55
- end
56
-
57
- # Pops a copy of the code for the specified Accurev revision identifier.
58
- # The revision identifier is represented as a stream & transaction ID combo.
59
- # Accurev can only pop a particular transaction if a stream is created on the server
60
- # with a time basis of that transaction id. Therefore, we will create a stream with
61
- # the required criteria and pop that.
62
- def export(revision_id, destination)
63
- revision = InternalRevision.parse(revision_id)
64
- logger.debug("Exporting #{revision.stream}/#{revision.transaction_id} to #{destination}")
65
-
66
- commands = [
67
- change_or_create_stream("#{revision.stream}-capistrano-deploy", revision),
68
- "mkdir -p #{destination}",
69
- scm_quiet(:pop, "-Rv #{stream}", "-L #{destination}", "'/./#{subdir}'")
70
- ]
71
- if subdir
72
- commands.push(
73
- "mv #{destination}/#{subdir}/* #{destination}",
74
- "rm -rf #{File.join(destination, subdir)}"
75
- )
76
- end
77
- commands.join(' && ')
78
- end
79
-
80
- # Returns the command needed to show the changes that exist between the two revisions.
81
- def log(from, to=head)
82
- logger.info("Getting transactions between #{from} and #{to}")
83
- from_rev = InternalRevision.parse(from)
84
- to_rev = InternalRevision.parse(to)
85
-
86
- [
87
- scm(:hist, '-s', from_rev.stream, '-t', "#{to_rev.transaction_id}-#{from_rev.transaction_id}"),
88
- "sed -e '/transaction #{from_rev.transaction_id}/ { Q }'"
89
- ].join(' | ')
90
- end
91
-
92
- # Returns the command needed to show the diff between what is deployed and what is
93
- # pending. Because Accurev can not do this task without creating some streams,
94
- # two time basis streams will be created for the purposes of doing the diff.
95
- def diff(from, to=head)
96
- from = InternalRevision.parse(from)
97
- to = InternalRevision.parse(to)
98
-
99
- from_stream = "#{from.stream}-capistrano-diff-from"
100
- to_stream = "#{to.stream}-capistrano-diff-to"
101
-
102
- [
103
- change_or_create_stream(from_stream, from),
104
- change_or_create_stream(to_stream, to),
105
- scm(:diff, '-v', from_stream, '-V', to_stream, '-a')
106
- ].join(' && ')
107
- end
108
-
109
- private
110
- def depot
111
- repository.split('/')[0]
112
- end
113
-
114
- def stream
115
- variable(:stream) || depot
116
- end
117
-
118
- def subdir
119
- repository.split('/')[1..-1].join('/') unless repository.index('/').nil?
120
- end
121
-
122
- def change_or_create_stream(name, revision)
123
- [
124
- scm_quiet(:mkstream, '-b', revision.stream, '-s', name, '-t', revision.transaction_id),
125
- scm_quiet(:chstream, '-b', revision.stream, '-s', name, '-t', revision.transaction_id)
126
- ].join('; ')
127
- end
128
-
129
- def show_streams_for(stream)
130
- scm :show, '-fx', '-s', stream, :streams
131
- end
132
-
133
- def scm_quiet(*args)
134
- scm(*args) + (variable(:scm_verbose) ? '' : '&> /dev/null')
135
- end
136
-
137
- class InternalRevision
138
- attr_reader :stream, :transaction_id
139
-
140
- def self.parse(string)
141
- match = /([^\/]+)(\/(.+)){0,1}/.match(string)
142
- raise "Unrecognized revision identifier: #{string}" unless match
143
-
144
- stream = match[1]
145
- transaction_id = match[3] || 'highest'
146
- InternalRevision.new(stream, transaction_id)
147
- end
148
-
149
- def initialize(stream, transaction_id)
150
- @stream = stream
151
- @transaction_id = transaction_id
152
- end
153
-
154
- def psuedo_revision?
155
- @transaction_id == 'highest'
156
- end
157
-
158
- def to_s
159
- "#{stream}/#{transaction_id}"
160
- end
161
-
162
- def ==(other)
163
- (stream == other.stream) && (transaction_id == other.transaction_id)
164
- end
165
- end
166
- end
167
- end
168
- end
169
- end