capistrano 2.15.11 → 3.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +17 -8
  3. data/Gemfile +1 -12
  4. data/LICENSE.txt +18 -0
  5. data/README.md +65 -68
  6. data/Rakefile +4 -10
  7. data/bin/cap +2 -3
  8. data/bin/capify +7 -91
  9. data/capistrano.gemspec +20 -34
  10. data/lib/Capfile +2 -0
  11. data/lib/capistrano/application.rb +28 -0
  12. data/lib/capistrano/bundler.rb +1 -0
  13. data/lib/capistrano/configuration/question.rb +42 -0
  14. data/lib/capistrano/configuration/server.rb +24 -0
  15. data/lib/capistrano/configuration/servers.rb +43 -95
  16. data/lib/capistrano/configuration.rb +81 -44
  17. data/lib/capistrano/console.rb +1 -0
  18. data/lib/capistrano/defaults.rb +11 -0
  19. data/lib/capistrano/deploy.rb +3 -0
  20. data/lib/capistrano/dotfile.rb +3 -0
  21. data/lib/capistrano/dsl/env.rb +57 -0
  22. data/lib/capistrano/dsl/paths.rb +74 -0
  23. data/lib/capistrano/dsl/stages.rb +15 -0
  24. data/lib/capistrano/dsl/task_enhancements.rb +15 -0
  25. data/lib/capistrano/dsl.rb +38 -0
  26. data/lib/capistrano/git.rb +1 -0
  27. data/lib/capistrano/i18n.rb +33 -0
  28. data/lib/capistrano/install.rb +1 -0
  29. data/lib/capistrano/setup.rb +17 -0
  30. data/lib/capistrano/tasks/bundler.rake +13 -0
  31. data/lib/capistrano/tasks/console.rake +21 -0
  32. data/lib/capistrano/tasks/deploy.rake +153 -0
  33. data/lib/capistrano/tasks/framework.rake +45 -0
  34. data/lib/capistrano/tasks/git.rake +65 -0
  35. data/lib/capistrano/tasks/install.rake +39 -0
  36. data/lib/capistrano/templates/Capfile +43 -0
  37. data/lib/capistrano/templates/deploy.rb.erb +17 -0
  38. data/lib/capistrano/templates/stage.rb.erb +20 -0
  39. data/lib/capistrano/version.rb +1 -11
  40. data/lib/capistrano.rb +9 -3
  41. data/spec/lib/capistrano/configuration/question_spec.rb +54 -0
  42. data/spec/lib/capistrano/configuration/server_spec.rb +48 -0
  43. data/spec/lib/capistrano/configuration/servers_spec.rb +79 -0
  44. data/spec/lib/capistrano/configuration_spec.rb +80 -0
  45. data/spec/lib/capistrano/dsl/env_spec.rb +83 -0
  46. data/spec/lib/capistrano/dsl/paths_spec.rb +69 -0
  47. data/spec/lib/capistrano/dsl_spec.rb +51 -0
  48. data/spec/lib/capistrano_spec.rb +8 -0
  49. data/spec/spec_helper.rb +14 -0
  50. metadata +89 -215
  51. data/.travis.yml +0 -9
  52. data/CHANGELOG +0 -1203
  53. data/lib/capistrano/callback.rb +0 -45
  54. data/lib/capistrano/cli/execute.rb +0 -85
  55. data/lib/capistrano/cli/help.rb +0 -125
  56. data/lib/capistrano/cli/help.txt +0 -81
  57. data/lib/capistrano/cli/options.rb +0 -243
  58. data/lib/capistrano/cli/ui.rb +0 -40
  59. data/lib/capistrano/cli.rb +0 -47
  60. data/lib/capistrano/command.rb +0 -303
  61. data/lib/capistrano/configuration/actions/file_transfer.rb +0 -50
  62. data/lib/capistrano/configuration/actions/inspect.rb +0 -46
  63. data/lib/capistrano/configuration/actions/invocation.rb +0 -329
  64. data/lib/capistrano/configuration/alias_task.rb +0 -26
  65. data/lib/capistrano/configuration/callbacks.rb +0 -147
  66. data/lib/capistrano/configuration/connections.rb +0 -237
  67. data/lib/capistrano/configuration/execution.rb +0 -142
  68. data/lib/capistrano/configuration/loading.rb +0 -205
  69. data/lib/capistrano/configuration/log_formatters.rb +0 -75
  70. data/lib/capistrano/configuration/namespaces.rb +0 -223
  71. data/lib/capistrano/configuration/roles.rb +0 -83
  72. data/lib/capistrano/configuration/variables.rb +0 -127
  73. data/lib/capistrano/errors.rb +0 -19
  74. data/lib/capistrano/ext/multistage.rb +0 -67
  75. data/lib/capistrano/ext/string.rb +0 -5
  76. data/lib/capistrano/extensions.rb +0 -57
  77. data/lib/capistrano/fix_rake_deprecated_dsl.rb +0 -8
  78. data/lib/capistrano/logger.rb +0 -166
  79. data/lib/capistrano/processable.rb +0 -55
  80. data/lib/capistrano/recipes/compat.rb +0 -32
  81. data/lib/capistrano/recipes/deploy/assets.rb +0 -202
  82. data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
  83. data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -54
  84. data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -117
  85. data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
  86. data/lib/capistrano/recipes/deploy/scm/base.rb +0 -200
  87. data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
  88. data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -153
  89. data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -96
  90. data/lib/capistrano/recipes/deploy/scm/git.rb +0 -299
  91. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -137
  92. data/lib/capistrano/recipes/deploy/scm/none.rb +0 -55
  93. data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -152
  94. data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -121
  95. data/lib/capistrano/recipes/deploy/scm.rb +0 -19
  96. data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -92
  97. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
  98. data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -338
  99. data/lib/capistrano/recipes/deploy/strategy/export.rb +0 -20
  100. data/lib/capistrano/recipes/deploy/strategy/remote.rb +0 -52
  101. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +0 -57
  102. data/lib/capistrano/recipes/deploy/strategy/unshared_remote_cache.rb +0 -21
  103. data/lib/capistrano/recipes/deploy/strategy.rb +0 -20
  104. data/lib/capistrano/recipes/deploy.rb +0 -625
  105. data/lib/capistrano/recipes/standard.rb +0 -37
  106. data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
  107. data/lib/capistrano/role.rb +0 -102
  108. data/lib/capistrano/server_definition.rb +0 -56
  109. data/lib/capistrano/shell.rb +0 -265
  110. data/lib/capistrano/ssh.rb +0 -95
  111. data/lib/capistrano/task_definition.rb +0 -77
  112. data/lib/capistrano/transfer.rb +0 -218
  113. data/test/cli/execute_test.rb +0 -132
  114. data/test/cli/help_test.rb +0 -165
  115. data/test/cli/options_test.rb +0 -329
  116. data/test/cli/ui_test.rb +0 -28
  117. data/test/cli_test.rb +0 -17
  118. data/test/command_test.rb +0 -322
  119. data/test/configuration/actions/file_transfer_test.rb +0 -61
  120. data/test/configuration/actions/inspect_test.rb +0 -76
  121. data/test/configuration/actions/invocation_test.rb +0 -306
  122. data/test/configuration/alias_task_test.rb +0 -118
  123. data/test/configuration/callbacks_test.rb +0 -201
  124. data/test/configuration/connections_test.rb +0 -439
  125. data/test/configuration/execution_test.rb +0 -175
  126. data/test/configuration/loading_test.rb +0 -148
  127. data/test/configuration/namespace_dsl_test.rb +0 -332
  128. data/test/configuration/roles_test.rb +0 -157
  129. data/test/configuration/servers_test.rb +0 -183
  130. data/test/configuration/variables_test.rb +0 -190
  131. data/test/configuration_test.rb +0 -77
  132. data/test/deploy/local_dependency_test.rb +0 -76
  133. data/test/deploy/remote_dependency_test.rb +0 -146
  134. data/test/deploy/scm/accurev_test.rb +0 -23
  135. data/test/deploy/scm/base_test.rb +0 -55
  136. data/test/deploy/scm/bzr_test.rb +0 -51
  137. data/test/deploy/scm/darcs_test.rb +0 -37
  138. data/test/deploy/scm/git_test.rb +0 -274
  139. data/test/deploy/scm/mercurial_test.rb +0 -134
  140. data/test/deploy/scm/none_test.rb +0 -35
  141. data/test/deploy/scm/perforce_test.rb +0 -23
  142. data/test/deploy/scm/subversion_test.rb +0 -68
  143. data/test/deploy/strategy/copy_test.rb +0 -360
  144. data/test/extensions_test.rb +0 -69
  145. data/test/fixtures/cli_integration.rb +0 -5
  146. data/test/fixtures/config.rb +0 -5
  147. data/test/fixtures/custom.rb +0 -3
  148. data/test/logger_formatting_test.rb +0 -149
  149. data/test/logger_test.rb +0 -134
  150. data/test/recipes_test.rb +0 -25
  151. data/test/role_test.rb +0 -11
  152. data/test/server_definition_test.rb +0 -121
  153. data/test/shell_test.rb +0 -96
  154. data/test/ssh_test.rb +0 -113
  155. data/test/task_definition_test.rb +0 -117
  156. data/test/transfer_test.rb +0 -168
  157. data/test/utils.rb +0 -37
  158. data/test/version_test.rb +0 -11
@@ -1,237 +0,0 @@
1
- require 'enumerator'
2
- require 'net/ssh/gateway'
3
- require 'capistrano/ssh'
4
- require 'capistrano/errors'
5
-
6
- module Capistrano
7
- class Configuration
8
- module Connections
9
- def self.included(base) #:nodoc:
10
- base.send :alias_method, :initialize_without_connections, :initialize
11
- base.send :alias_method, :initialize, :initialize_with_connections
12
- end
13
-
14
- class DefaultConnectionFactory #:nodoc:
15
- def initialize(options)
16
- @options = options
17
- end
18
-
19
- def connect_to(server)
20
- SSH.connect(server, @options)
21
- end
22
- end
23
-
24
- class GatewayConnectionFactory #:nodoc:
25
- def initialize(gateway, options)
26
- @options = options
27
- Thread.abort_on_exception = true
28
- @gateways = {}
29
- if gateway.is_a?(Hash)
30
- @options[:logger].debug "Creating multiple gateways using #{gateway.inspect}" if @options[:logger]
31
- gateway.each do |gw, hosts|
32
- gateway_connection = add_gateway(gw)
33
- [*hosts].each do |host|
34
- @gateways[:default] ||= gateway_connection
35
- @gateways[host] = gateway_connection
36
- end
37
- end
38
- else
39
- @options[:logger].debug "Creating gateway using #{[*gateway].join(', ')}" if @options[:logger]
40
- @gateways[:default] = add_gateway(gateway)
41
- end
42
- end
43
-
44
- def add_gateway(gateway)
45
- gateways = [*gateway].collect { |g| ServerDefinition.new(g) }
46
- tunnel = SSH.connection_strategy(gateways[0], @options) do |host, user, connect_options|
47
- Net::SSH::Gateway.new(host, user, connect_options)
48
- end
49
- (gateways[1..-1]).inject(tunnel) do |tunnel, destination|
50
- @options[:logger].debug "Creating tunnel to #{destination}" if @options[:logger]
51
- local_host = ServerDefinition.new("127.0.0.1", :user => destination.user, :port => tunnel.open(destination.host, (destination.port || 22)))
52
- SSH.connection_strategy(local_host, @options) do |host, user, connect_options|
53
- Net::SSH::Gateway.new(host, user, connect_options)
54
- end
55
- end
56
- end
57
-
58
- def connect_to(server)
59
- @options[:logger].debug "establishing connection to `#{server}' via gateway" if @options[:logger]
60
- local_host = ServerDefinition.new("127.0.0.1", :user => server.user, :port => gateway_for(server).open(server.host, server.port || 22))
61
- session = SSH.connect(local_host, @options)
62
- session.xserver = server
63
- session
64
- end
65
-
66
- def gateway_for(server)
67
- @gateways[server.host] || @gateways[:default]
68
- end
69
- end
70
-
71
- # A hash of the SSH sessions that are currently open and available.
72
- # Because sessions are constructed lazily, this will only contain
73
- # connections to those servers that have been the targets of one or more
74
- # executed tasks. Stored on a per-thread basis to improve thread-safety.
75
- def sessions
76
- Thread.current[:sessions] ||= {}
77
- end
78
-
79
- def initialize_with_connections(*args) #:nodoc:
80
- initialize_without_connections(*args)
81
- Thread.current[:sessions] = {}
82
- Thread.current[:failed_sessions] = []
83
- end
84
-
85
- # Indicate that the given server could not be connected to.
86
- def failed!(server)
87
- Thread.current[:failed_sessions] << server
88
- end
89
-
90
- # Query whether previous connection attempts to the given server have
91
- # failed.
92
- def has_failed?(server)
93
- Thread.current[:failed_sessions].include?(server)
94
- end
95
-
96
- # Used to force connections to be made to the current task's servers.
97
- # Connections are normally made lazily in Capistrano--you can use this
98
- # to force them open before performing some operation that might be
99
- # time-sensitive.
100
- def connect!(options={})
101
- execute_on_servers(options) { }
102
- end
103
-
104
- # Returns the object responsible for establishing new SSH connections.
105
- # The factory will respond to #connect_to, which can be used to
106
- # establish connections to servers defined via ServerDefinition objects.
107
- def connection_factory
108
- @connection_factory ||= begin
109
- if exists?(:gateway) && !fetch(:gateway).nil? && !fetch(:gateway).empty?
110
- logger.debug "establishing connection to gateway `#{fetch(:gateway).inspect}'"
111
- GatewayConnectionFactory.new(fetch(:gateway), self)
112
- else
113
- DefaultConnectionFactory.new(self)
114
- end
115
- end
116
- end
117
-
118
- # Ensures that there are active sessions for each server in the list.
119
- def establish_connections_to(servers)
120
- failed_servers = []
121
-
122
- # force the connection factory to be instantiated synchronously,
123
- # otherwise we wind up with multiple gateway instances, because
124
- # each connection is done in parallel.
125
- connection_factory
126
-
127
- threads = Array(servers).map { |server| establish_connection_to(server, failed_servers) }
128
- threads.each { |t| t.join }
129
-
130
- if failed_servers.any?
131
- errors = failed_servers.map { |h| "#{h[:server]} (#{h[:error].class}: #{h[:error].message})" }
132
- error = ConnectionError.new("connection failed for: #{errors.join(', ')}")
133
- error.hosts = failed_servers.map { |h| h[:server] }
134
- raise error
135
- end
136
- end
137
-
138
- # Destroys sessions for each server in the list.
139
- def teardown_connections_to(servers)
140
- servers.each do |server|
141
- begin
142
- session = sessions.delete(server)
143
- session.close if session
144
- rescue IOError, Net::SSH::Disconnect
145
- # the TCP connection is already dead
146
- end
147
- end
148
- end
149
-
150
- # Determines the set of servers within the current task's scope
151
- def filter_servers(options={})
152
- if task = current_task
153
- servers = find_servers_for_task(task, options)
154
-
155
- if servers.empty?
156
- if ENV['HOSTFILTER'] || ENV['HOSTROLEFILTER'] || task.options.merge(options)[:on_no_matching_servers] == :continue
157
- logger.info "skipping `#{task.fully_qualified_name}' because no servers matched"
158
- else
159
- unless dry_run
160
- raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
161
- end
162
- end
163
- end
164
-
165
- if task.continue_on_error?
166
- servers.delete_if { |s| has_failed?(s) }
167
- end
168
- else
169
- servers = find_servers(options)
170
- if servers.empty? && !dry_run
171
- raise Capistrano::NoMatchingServersError, "no servers found to match #{options.inspect}" if options[:on_no_matching_servers] != :continue
172
- end
173
- end
174
-
175
- servers = [servers.first] if options[:once]
176
- [task, servers.compact]
177
- end
178
-
179
- # Determines the set of servers within the current task's scope and
180
- # establishes connections to them, and then yields that list of
181
- # servers.
182
- def execute_on_servers(options={})
183
- raise ArgumentError, "expected a block" unless block_given?
184
-
185
- task, servers = filter_servers(options)
186
- return if servers.empty?
187
- logger.trace "servers: #{servers.map { |s| s.host }.inspect}"
188
-
189
- max_hosts = (options[:max_hosts] || (task && task.max_hosts) || servers.size).to_i
190
- is_subset = max_hosts < servers.size
191
-
192
- # establish connections to those servers in groups of max_hosts, as necessary
193
- servers.each_slice(max_hosts) do |servers_slice|
194
- begin
195
- establish_connections_to(servers_slice)
196
- rescue ConnectionError => error
197
- raise error unless task && task.continue_on_error?
198
- error.hosts.each do |h|
199
- servers_slice.delete(h)
200
- failed!(h)
201
- end
202
- end
203
-
204
- begin
205
- yield servers_slice
206
- rescue RemoteError => error
207
- raise error unless task && task.continue_on_error?
208
- error.hosts.each { |h| failed!(h) }
209
- end
210
-
211
- # if dealing with a subset (e.g., :max_hosts is less than the
212
- # number of servers available) teardown the subset of connections
213
- # that were just made, so that we can make room for the next subset.
214
- teardown_connections_to(servers_slice) if is_subset
215
- end
216
- end
217
-
218
- private
219
-
220
- # We establish the connection by creating a thread in a new method--this
221
- # prevents problems with the thread's scope seeing the wrong 'server'
222
- # variable if the thread just happens to take too long to start up.
223
- def establish_connection_to(server, failures=nil)
224
- current_thread = Thread.current
225
- Thread.new { safely_establish_connection_to(server, current_thread, failures) }
226
- end
227
-
228
- def safely_establish_connection_to(server, thread, failures=nil)
229
- thread[:sessions] ||= {}
230
- thread[:sessions][server] ||= connection_factory.connect_to(server)
231
- rescue Exception => err
232
- raise unless failures
233
- failures << { :server => server, :error => err }
234
- end
235
- end
236
- end
237
- end
@@ -1,142 +0,0 @@
1
- require 'capistrano/errors'
2
-
3
- module Capistrano
4
- class Configuration
5
- module Execution
6
- def self.included(base) #:nodoc:
7
- base.send :alias_method, :initialize_without_execution, :initialize
8
- base.send :alias_method, :initialize, :initialize_with_execution
9
- end
10
-
11
- # A struct for representing a single instance of an invoked task.
12
- TaskCallFrame = Struct.new(:task, :rollback)
13
-
14
- def initialize_with_execution(*args) #:nodoc:
15
- initialize_without_execution(*args)
16
- end
17
- private :initialize_with_execution
18
-
19
- # Returns true if there is a transaction currently active.
20
- def transaction?
21
- !rollback_requests.nil?
22
- end
23
-
24
- # The call stack of the tasks. The currently executing task may inspect
25
- # this to see who its caller was. The current task is always the last
26
- # element of this stack.
27
- def task_call_frames
28
- Thread.current[:task_call_frames] ||= []
29
- end
30
-
31
-
32
- # The stack of tasks that have registered rollback handlers within the
33
- # current transaction. If this is nil, then there is no transaction
34
- # that is currently active.
35
- def rollback_requests
36
- Thread.current[:rollback_requests]
37
- end
38
-
39
- def rollback_requests=(rollback_requests)
40
- Thread.current[:rollback_requests] = rollback_requests
41
- end
42
-
43
- # Invoke a set of tasks in a transaction. If any task fails (raises an
44
- # exception), all tasks executed within the transaction are inspected to
45
- # see if they have an associated on_rollback hook, and if so, that hook
46
- # is called.
47
- def transaction
48
- raise ArgumentError, "expected a block" unless block_given?
49
- raise ScriptError, "transaction must be called from within a task" if task_call_frames.empty?
50
-
51
- return yield if transaction?
52
-
53
- logger.info "transaction: start"
54
- begin
55
- self.rollback_requests = []
56
- yield
57
- logger.info "transaction: commit"
58
- rescue Object => e
59
- rollback!
60
- raise
61
- ensure
62
- self.rollback_requests = nil
63
- end
64
- end
65
-
66
- # Specifies an on_rollback hook for the currently executing task. If this
67
- # or any subsequent task then fails, and a transaction is active, this
68
- # hook will be executed.
69
- def on_rollback(&block)
70
- if transaction?
71
- # don't note a new rollback request if one has already been set
72
- rollback_requests << task_call_frames.last unless task_call_frames.last.rollback
73
- task_call_frames.last.rollback = block
74
- end
75
- end
76
-
77
- # Returns the TaskDefinition object for the currently executing task.
78
- # It returns nil if there is no task being executed.
79
- def current_task
80
- return nil if task_call_frames.empty?
81
- task_call_frames.last.task
82
- end
83
-
84
- # Executes the task with the given name, without invoking any associated
85
- # callbacks.
86
- def execute_task(task)
87
- logger.debug "executing `#{task.fully_qualified_name}'"
88
- push_task_call_frame(task)
89
- invoke_task_directly(task)
90
- ensure
91
- pop_task_call_frame
92
- end
93
-
94
- # Attempts to locate the task at the given fully-qualified path, and
95
- # execute it. If no such task exists, a Capistrano::NoSuchTaskError will
96
- # be raised.
97
- def find_and_execute_task(path, hooks={})
98
- task = find_task(path) or raise NoSuchTaskError, "the task `#{path}' does not exist"
99
-
100
- trigger(hooks[:before], task) if hooks[:before]
101
- result = execute_task(task)
102
- trigger(hooks[:after], task) if hooks[:after]
103
-
104
- result
105
- end
106
-
107
- protected
108
-
109
- def rollback!
110
- return if Thread.current[:rollback_requests].nil?
111
-
112
- # throw the task back on the stack so that roles are properly
113
- # interpreted in the scope of the task in question.
114
- rollback_requests.reverse.each do |frame|
115
- begin
116
- push_task_call_frame(frame.task)
117
- logger.important "rolling back", frame.task.fully_qualified_name
118
- frame.rollback.call
119
- rescue Object => e
120
- logger.info "exception while rolling back: #{e.class}, #{e.message}", frame.task.fully_qualified_name
121
- ensure
122
- pop_task_call_frame
123
- end
124
- end
125
- end
126
-
127
- def push_task_call_frame(task)
128
- frame = TaskCallFrame.new(task)
129
- task_call_frames.push frame
130
- end
131
-
132
- def pop_task_call_frame
133
- task_call_frames.pop
134
- end
135
-
136
- # Invokes the task's body directly, without setting up the call frame.
137
- def invoke_task_directly(task)
138
- task.namespace.instance_eval(&task.body)
139
- end
140
- end
141
- end
142
- end
@@ -1,205 +0,0 @@
1
- module Capistrano
2
- class Configuration
3
- module Loading
4
- def self.included(base) #:nodoc:
5
- base.send :alias_method, :initialize_without_loading, :initialize
6
- base.send :alias_method, :initialize, :initialize_with_loading
7
- base.extend ClassMethods
8
- end
9
-
10
- module ClassMethods
11
- # Used by third-party task bundles to identify the capistrano
12
- # configuration that is loading them. Its return value is not reliable
13
- # in other contexts. If +require_config+ is not false, an exception
14
- # will be raised if the current configuration is not set.
15
- def instance(require_config=false)
16
- config = Thread.current[:capistrano_configuration]
17
- if require_config && config.nil?
18
- raise LoadError, "Please require this file from within a Capistrano recipe"
19
- end
20
- config
21
- end
22
-
23
- # Used internally by Capistrano to specify the current configuration
24
- # before loading a third-party task bundle.
25
- def instance=(config)
26
- Thread.current[:capistrano_configuration] = config
27
- end
28
-
29
- # Used internally by Capistrano to track which recipes have been loaded
30
- # via require, so that they may be successfully reloaded when require
31
- # is called again.
32
- def recipes_per_feature
33
- @recipes_per_feature ||= {}
34
- end
35
-
36
- # Used internally to determine what the current "feature" being
37
- # required is. This is used to track which files load which recipes
38
- # via require.
39
- def current_feature
40
- Thread.current[:capistrano_current_feature]
41
- end
42
-
43
- # Used internally to specify the current file being required, so that
44
- # any recipes loaded by that file can be remembered. This allows
45
- # recipes loaded via require to be correctly reloaded in different
46
- # Configuration instances in the same Ruby instance.
47
- def current_feature=(feature)
48
- Thread.current[:capistrano_current_feature] = feature
49
- end
50
- end
51
-
52
- # The load paths used for locating recipe files.
53
- attr_reader :load_paths
54
-
55
- def initialize_with_loading(*args) #:nodoc:
56
- initialize_without_loading(*args)
57
- @load_paths = [".", File.expand_path(File.join(File.dirname(__FILE__), "../recipes"))]
58
- @loaded_features = []
59
- end
60
- private :initialize_with_loading
61
-
62
- # Load a configuration file or string into this configuration.
63
- #
64
- # Usage:
65
- #
66
- # load("recipe"):
67
- # Look for and load the contents of 'recipe.rb' into this
68
- # configuration.
69
- #
70
- # load(:file => "recipe"):
71
- # same as above
72
- #
73
- # load(:string => "set :scm, :subversion"):
74
- # Load the given string as a configuration specification.
75
- #
76
- # load { ... }
77
- # Load the block in the context of the configuration.
78
- def load(*args, &block)
79
- options = args.last.is_a?(Hash) ? args.pop : {}
80
-
81
- if block
82
- raise ArgumentError, "loading a block requires 0 arguments" unless options.empty? && args.empty?
83
- load(:proc => block)
84
-
85
- elsif args.any?
86
- args.each { |arg| load options.merge(:file => arg) }
87
-
88
- elsif options[:file]
89
- load_from_file(options[:file], options[:name])
90
-
91
- elsif options[:string]
92
- remember_load(options) unless options[:reloading]
93
- instance_eval(options[:string], options[:name] || "<eval>")
94
-
95
- elsif options[:proc]
96
- remember_load(options) unless options[:reloading]
97
- instance_eval(&options[:proc])
98
-
99
- else
100
- raise ArgumentError, "don't know how to load #{options.inspect}"
101
- end
102
- end
103
-
104
- # Require another file. This is identical to the standard require method,
105
- # with the exception that it sets the receiver as the "current" configuration
106
- # so that third-party task bundles can include themselves relative to
107
- # that configuration.
108
- #
109
- # This is a bit more complicated than an initial review would seem to
110
- # necessitate, but the use case that complicates things is this: An
111
- # advanced user wants to embed capistrano, and needs to instantiate
112
- # more than one capistrano configuration at a time. They also want each
113
- # configuration to require a third-party capistrano extension. Using a
114
- # naive require implementation, this would allow the first configuration
115
- # to successfully load the third-party extension, but the require would
116
- # fail for the second configuration because the extension has already
117
- # been loaded.
118
- #
119
- # To work around this, we do a few things:
120
- #
121
- # 1. Each time a 'require' is invoked inside of a capistrano recipe,
122
- # we remember the arguments (see "current_feature").
123
- # 2. Each time a 'load' is invoked inside of a capistrano recipe, and
124
- # "current_feature" is not nil (meaning we are inside of a pending
125
- # require) we remember the options (see "remember_load" and
126
- # "recipes_per_feature").
127
- # 3. Each time a 'require' is invoked inside of a capistrano recipe,
128
- # we check to see if this particular configuration has ever seen these
129
- # arguments to require (see @loaded_features), and if not, we proceed
130
- # as if the file had never been required. If the superclass' require
131
- # returns false (meaning, potentially, that the file has already been
132
- # required), then we look in the recipes_per_feature collection and
133
- # load any remembered recipes from there.
134
- #
135
- # It's kind of a bear, but it works, and works transparently. Note that
136
- # a simpler implementation would just muck with $", allowing files to be
137
- # required multiple times, but that will cause warnings (and possibly
138
- # errors) if the file to be required contains constant definitions and
139
- # such, alongside (or instead of) capistrano recipe definitions.
140
- def require(*args) #:nodoc:
141
- # look to see if this specific configuration instance has ever seen
142
- # these arguments to require before
143
- if @loaded_features.include?(args)
144
- return false
145
- end
146
-
147
- @loaded_features << args
148
- begin
149
- original_instance, self.class.instance = self.class.instance, self
150
- original_feature, self.class.current_feature = self.class.current_feature, args
151
-
152
- result = super
153
- if !result # file has been required previously, load up the remembered recipes
154
- list = self.class.recipes_per_feature[args] || []
155
- list.each { |options| load(options.merge(:reloading => true)) }
156
- end
157
-
158
- return result
159
- ensure
160
- # restore the original, so that require's can be nested
161
- self.class.instance = original_instance
162
- self.class.current_feature = original_feature
163
- end
164
- end
165
-
166
- def file_in_load_path?(file)
167
- begin
168
- !!find_file_in_load_path(file)
169
- rescue LoadError
170
- false
171
- end
172
- end
173
-
174
- private
175
-
176
- # Load a recipe from the named file. If +name+ is given, the file will
177
- # be reported using that name.
178
- def load_from_file(file, name=nil)
179
- file = find_file_in_load_path(file) unless File.file?(file)
180
- load :string => File.read(file), :name => name || file
181
- end
182
-
183
- def find_file_in_load_path(file)
184
- load_paths.each do |path|
185
- ["", ".rb"].each do |ext|
186
- name = File.join(path, "#{file}#{ext}")
187
- return name if File.file?(name)
188
- end
189
- end
190
-
191
- raise LoadError, "no such file to load -- #{file}"
192
- end
193
-
194
- # If a file is being required, the options associated with loading a
195
- # recipe are remembered in the recipes_per_feature archive under the
196
- # name of the file currently being required.
197
- def remember_load(options)
198
- if self.class.current_feature
199
- list = (self.class.recipes_per_feature[self.class.current_feature] ||= [])
200
- list << options
201
- end
202
- end
203
- end
204
- end
205
- end
@@ -1,75 +0,0 @@
1
- # Add custom log formatters
2
- #
3
- # Passing a hash or a array of hashes with custom log formatters.
4
- #
5
- # Add the following to your deploy.rb or in your ~/.caprc
6
- #
7
- # == Example:
8
- #
9
- # capistrano_log_formatters = [
10
- # { :match => /command finished/, :color => :hide, :priority => 10, :prepend => "$$$" },
11
- # { :match => /executing command/, :color => :blue, :priority => 10, :style => :underscore, :timestamp => true },
12
- # { :match => /^transaction: commit$/, :color => :magenta, :priority => 10, :style => :blink },
13
- # { :match => /git/, :color => :white, :priority => 20, :style => :reverse }
14
- # ]
15
- #
16
- # log_formatter capistrano_log_formatters
17
- #
18
- # You can call log_formatter multiple times, with either a hash or an array of hashes.
19
- #
20
- # == Colors:
21
- #
22
- # :color can have the following values:
23
- #
24
- # * :hide (hides the row completely)
25
- # * :none
26
- # * :black
27
- # * :red
28
- # * :green
29
- # * :yellow
30
- # * :blue
31
- # * :magenta
32
- # * :cyan
33
- # * :white
34
- #
35
- # == Styles:
36
- #
37
- # :style can have the following values:
38
- #
39
- # * :bright
40
- # * :dim
41
- # * :underscore
42
- # * :blink
43
- # * :reverse
44
- # * :hidden
45
- #
46
- #
47
- # == Text alterations
48
- #
49
- # :prepend gives static text to be prepended to the output
50
- # :replace replaces the matched text in the output
51
- # :timestamp adds the current time before the output
52
-
53
- module Capistrano
54
- class Configuration
55
- module LogFormatters
56
- def log_formatter(options)
57
- if options.class == Array
58
- options.each do |option|
59
- Capistrano::Logger.add_formatter(option)
60
- end
61
- else
62
- Capistrano::Logger.add_formatter(options)
63
- end
64
- end
65
-
66
- def default_log_formatters(formatters)
67
- default_formatters = [*formatters]
68
- end
69
-
70
- def disable_log_formatters
71
- @logger.disable_formatters = true
72
- end
73
- end
74
- end
75
- end