sneakin-capistrano 2.5.5

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 (107) hide show
  1. data/CHANGELOG.rdoc +761 -0
  2. data/Manifest +104 -0
  3. data/README.rdoc +66 -0
  4. data/Rakefile +35 -0
  5. data/bin/cap +4 -0
  6. data/bin/capify +78 -0
  7. data/capistrano.gemspec +48 -0
  8. data/examples/sample.rb +14 -0
  9. data/lib/capistrano/callback.rb +45 -0
  10. data/lib/capistrano/cli/execute.rb +84 -0
  11. data/lib/capistrano/cli/help.rb +125 -0
  12. data/lib/capistrano/cli/help.txt +75 -0
  13. data/lib/capistrano/cli/options.rb +224 -0
  14. data/lib/capistrano/cli/ui.rb +40 -0
  15. data/lib/capistrano/cli.rb +47 -0
  16. data/lib/capistrano/command.rb +283 -0
  17. data/lib/capistrano/configuration/actions/file_transfer.rb +47 -0
  18. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  19. data/lib/capistrano/configuration/actions/invocation.rb +293 -0
  20. data/lib/capistrano/configuration/callbacks.rb +148 -0
  21. data/lib/capistrano/configuration/connections.rb +200 -0
  22. data/lib/capistrano/configuration/execution.rb +132 -0
  23. data/lib/capistrano/configuration/loading.rb +197 -0
  24. data/lib/capistrano/configuration/namespaces.rb +197 -0
  25. data/lib/capistrano/configuration/roles.rb +73 -0
  26. data/lib/capistrano/configuration/servers.rb +85 -0
  27. data/lib/capistrano/configuration/variables.rb +127 -0
  28. data/lib/capistrano/configuration.rb +43 -0
  29. data/lib/capistrano/errors.rb +15 -0
  30. data/lib/capistrano/extensions.rb +57 -0
  31. data/lib/capistrano/logger.rb +59 -0
  32. data/lib/capistrano/processable.rb +53 -0
  33. data/lib/capistrano/recipes/compat.rb +32 -0
  34. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  35. data/lib/capistrano/recipes/deploy/local_dependency.rb +54 -0
  36. data/lib/capistrano/recipes/deploy/remote_dependency.rb +105 -0
  37. data/lib/capistrano/recipes/deploy/scm/accurev.rb +169 -0
  38. data/lib/capistrano/recipes/deploy/scm/base.rb +196 -0
  39. data/lib/capistrano/recipes/deploy/scm/bzr.rb +83 -0
  40. data/lib/capistrano/recipes/deploy/scm/cvs.rb +152 -0
  41. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  42. data/lib/capistrano/recipes/deploy/scm/git.rb +274 -0
  43. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +137 -0
  44. data/lib/capistrano/recipes/deploy/scm/none.rb +44 -0
  45. data/lib/capistrano/recipes/deploy/scm/perforce.rb +133 -0
  46. data/lib/capistrano/recipes/deploy/scm/subversion.rb +121 -0
  47. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  48. data/lib/capistrano/recipes/deploy/strategy/base.rb +79 -0
  49. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  50. data/lib/capistrano/recipes/deploy/strategy/copy.rb +210 -0
  51. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  52. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  53. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +56 -0
  54. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  55. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  56. data/lib/capistrano/recipes/deploy.rb +562 -0
  57. data/lib/capistrano/recipes/standard.rb +37 -0
  58. data/lib/capistrano/recipes/templates/maintenance.rhtml +53 -0
  59. data/lib/capistrano/recipes/upgrade.rb +33 -0
  60. data/lib/capistrano/role.rb +102 -0
  61. data/lib/capistrano/server_definition.rb +56 -0
  62. data/lib/capistrano/shell.rb +260 -0
  63. data/lib/capistrano/ssh.rb +99 -0
  64. data/lib/capistrano/task_definition.rb +70 -0
  65. data/lib/capistrano/transfer.rb +216 -0
  66. data/lib/capistrano/version.rb +18 -0
  67. data/lib/capistrano.rb +2 -0
  68. data/setup.rb +1346 -0
  69. data/test/cli/execute_test.rb +132 -0
  70. data/test/cli/help_test.rb +165 -0
  71. data/test/cli/options_test.rb +317 -0
  72. data/test/cli/ui_test.rb +28 -0
  73. data/test/cli_test.rb +17 -0
  74. data/test/command_test.rb +286 -0
  75. data/test/configuration/actions/file_transfer_test.rb +61 -0
  76. data/test/configuration/actions/inspect_test.rb +65 -0
  77. data/test/configuration/actions/invocation_test.rb +224 -0
  78. data/test/configuration/callbacks_test.rb +220 -0
  79. data/test/configuration/connections_test.rb +349 -0
  80. data/test/configuration/execution_test.rb +175 -0
  81. data/test/configuration/loading_test.rb +132 -0
  82. data/test/configuration/namespace_dsl_test.rb +311 -0
  83. data/test/configuration/roles_test.rb +144 -0
  84. data/test/configuration/servers_test.rb +121 -0
  85. data/test/configuration/variables_test.rb +184 -0
  86. data/test/configuration_test.rb +88 -0
  87. data/test/deploy/local_dependency_test.rb +76 -0
  88. data/test/deploy/remote_dependency_test.rb +114 -0
  89. data/test/deploy/scm/accurev_test.rb +23 -0
  90. data/test/deploy/scm/base_test.rb +55 -0
  91. data/test/deploy/scm/git_test.rb +184 -0
  92. data/test/deploy/scm/mercurial_test.rb +129 -0
  93. data/test/deploy/scm/none_test.rb +35 -0
  94. data/test/deploy/strategy/copy_test.rb +258 -0
  95. data/test/extensions_test.rb +69 -0
  96. data/test/fixtures/cli_integration.rb +5 -0
  97. data/test/fixtures/config.rb +5 -0
  98. data/test/fixtures/custom.rb +3 -0
  99. data/test/logger_test.rb +123 -0
  100. data/test/role_test.rb +11 -0
  101. data/test/server_definition_test.rb +121 -0
  102. data/test/shell_test.rb +90 -0
  103. data/test/ssh_test.rb +104 -0
  104. data/test/task_definition_test.rb +101 -0
  105. data/test/transfer_test.rb +160 -0
  106. data/test/utils.rb +38 -0
  107. metadata +306 -0
@@ -0,0 +1,197 @@
1
+ require 'capistrano/task_definition'
2
+
3
+ module Capistrano
4
+ class Configuration
5
+ module Namespaces
6
+ DEFAULT_TASK = :default
7
+
8
+ def self.included(base) #:nodoc:
9
+ base.send :alias_method, :initialize_without_namespaces, :initialize
10
+ base.send :alias_method, :initialize, :initialize_with_namespaces
11
+ end
12
+
13
+ # The name of this namespace. Defaults to +nil+ for the top-level
14
+ # namespace.
15
+ attr_reader :name
16
+
17
+ # The parent namespace of this namespace. Returns +nil+ for the top-level
18
+ # namespace.
19
+ attr_reader :parent
20
+
21
+ # The hash of tasks defined for this namespace.
22
+ attr_reader :tasks
23
+
24
+ # The hash of namespaces defined for this namespace.
25
+ attr_reader :namespaces
26
+
27
+ def initialize_with_namespaces(*args) #:nodoc:
28
+ @name = @parent = nil
29
+ initialize_without_namespaces(*args)
30
+ @tasks = {}
31
+ @namespaces = {}
32
+ end
33
+ private :initialize_with_namespaces
34
+
35
+ # Returns the top-level namespace (the one with no parent).
36
+ def top
37
+ return parent.top if parent
38
+ return self
39
+ end
40
+
41
+ # Returns the fully-qualified name of this namespace, or nil if the
42
+ # namespace is at the top-level.
43
+ def fully_qualified_name
44
+ return nil if name.nil?
45
+ [parent.fully_qualified_name, name].compact.join(":")
46
+ end
47
+
48
+ # Describe the next task to be defined. The given text will be attached to
49
+ # the next task that is defined and used as its description.
50
+ def desc(text)
51
+ @next_description = text
52
+ end
53
+
54
+ # Returns the value set by the last, pending "desc" call. If +reset+ is
55
+ # not false, the value will be reset immediately afterwards.
56
+ def next_description(reset=false)
57
+ @next_description
58
+ ensure
59
+ @next_description = nil if reset
60
+ end
61
+
62
+ # Open a namespace in which to define new tasks. If the namespace was
63
+ # defined previously, it will be reopened, otherwise a new namespace
64
+ # will be created for the given name.
65
+ def namespace(name, &block)
66
+ name = name.to_sym
67
+ raise ArgumentError, "expected a block" unless block_given?
68
+
69
+ namespace_already_defined = namespaces.key?(name)
70
+ if all_methods.any? { |m| m.to_sym == name } && !namespace_already_defined
71
+ thing = tasks.key?(name) ? "task" : "method"
72
+ raise ArgumentError, "defining a namespace named `#{name}' would shadow an existing #{thing} with that name"
73
+ end
74
+
75
+ namespaces[name] ||= Namespace.new(name, self)
76
+ namespaces[name].instance_eval(&block)
77
+
78
+ # make sure any open description gets terminated
79
+ namespaces[name].desc(nil)
80
+
81
+ if !namespace_already_defined
82
+ metaclass = class << self; self; end
83
+ metaclass.send(:define_method, name) { namespaces[name] }
84
+ end
85
+ end
86
+
87
+ # Describe a new task. If a description is active (see #desc), it is added
88
+ # to the options under the <tt>:desc</tt> key. The new task is added to
89
+ # the namespace.
90
+ def task(name, options={}, &block)
91
+ name = name.to_sym
92
+ raise ArgumentError, "expected a block" unless block_given?
93
+
94
+ task_already_defined = tasks.key?(name)
95
+ if all_methods.any? { |m| m.to_sym == name } && !task_already_defined
96
+ thing = namespaces.key?(name) ? "namespace" : "method"
97
+ raise ArgumentError, "defining a task named `#{name}' would shadow an existing #{thing} with that name"
98
+ end
99
+
100
+ tasks[name] = TaskDefinition.new(name, self, {:desc => next_description(:reset)}.merge(options), &block)
101
+
102
+ if !task_already_defined
103
+ metaclass = class << self; self; end
104
+ metaclass.send(:define_method, name) { execute_task(tasks[name]) }
105
+ end
106
+ end
107
+
108
+ # Find the task with the given name, where name is the fully-qualified
109
+ # name of the task. This will search into the namespaces and return
110
+ # the referenced task, or nil if no such task can be found. If the name
111
+ # refers to a namespace, the task in that namespace named "default"
112
+ # will be returned instead, if one exists.
113
+ def find_task(name)
114
+ parts = name.to_s.split(/:/)
115
+ tail = parts.pop.to_sym
116
+
117
+ ns = self
118
+ until parts.empty?
119
+ next_part = parts.shift
120
+ ns = next_part.empty? ? nil : ns.namespaces[next_part.to_sym]
121
+ return nil if ns.nil?
122
+ end
123
+
124
+ if ns.namespaces.key?(tail)
125
+ ns = ns.namespaces[tail]
126
+ tail = DEFAULT_TASK
127
+ end
128
+
129
+ ns.tasks[tail]
130
+ end
131
+
132
+ # Given a task name, this will search the current namespace, and all
133
+ # parent namespaces, looking for a task that matches the name, exactly.
134
+ # It returns the task, if found, or nil, if not.
135
+ def search_task(name)
136
+ name = name.to_sym
137
+ ns = self
138
+
139
+ until ns.nil?
140
+ return ns.tasks[name] if ns.tasks.key?(name)
141
+ ns = ns.parent
142
+ end
143
+
144
+ return nil
145
+ end
146
+
147
+ # Returns the default task for this namespace. This will be +nil+ if
148
+ # the namespace is at the top-level, and will otherwise return the
149
+ # task named "default". If no such task exists, +nil+ will be returned.
150
+ def default_task
151
+ return nil if parent.nil?
152
+ return tasks[DEFAULT_TASK]
153
+ end
154
+
155
+ # Returns the tasks in this namespace as an array of TaskDefinition
156
+ # objects. If a non-false parameter is given, all tasks in all
157
+ # namespaces under this namespace will be returned as well.
158
+ def task_list(all=false)
159
+ list = tasks.values
160
+ namespaces.each { |name,space| list.concat(space.task_list(:all)) } if all
161
+ list
162
+ end
163
+
164
+ private
165
+
166
+ def all_methods
167
+ public_methods.concat(protected_methods).concat(private_methods)
168
+ end
169
+
170
+ class Namespace
171
+ def initialize(name, parent)
172
+ @parent = parent
173
+ @name = name
174
+ end
175
+
176
+ def role(*args)
177
+ raise NotImplementedError, "roles cannot be defined in a namespace"
178
+ end
179
+
180
+ def respond_to?(sym, include_priv=false)
181
+ super || parent.respond_to?(sym, include_priv)
182
+ end
183
+
184
+ def method_missing(sym, *args, &block)
185
+ if parent.respond_to?(sym)
186
+ parent.send(sym, *args, &block)
187
+ else
188
+ super
189
+ end
190
+ end
191
+
192
+ include Capistrano::Configuration::Namespaces
193
+ undef :desc, :next_description
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,73 @@
1
+ require 'capistrano/server_definition'
2
+ require 'capistrano/role'
3
+
4
+ module Capistrano
5
+ class Configuration
6
+ module Roles
7
+ def self.included(base) #:nodoc:
8
+ base.send :alias_method, :initialize_without_roles, :initialize
9
+ base.send :alias_method, :initialize, :initialize_with_roles
10
+ end
11
+
12
+ # The hash of roles defined for this configuration. Each entry in the
13
+ # hash points to an array of server definitions that belong in that
14
+ # role.
15
+ attr_reader :roles
16
+
17
+ def initialize_with_roles(*args) #:nodoc:
18
+ initialize_without_roles(*args)
19
+ @roles = Hash.new { |h,k| h[k] = Role.new }
20
+ end
21
+
22
+ # Define a new role and its associated servers. You must specify at least
23
+ # one host for each role. Also, you can specify additional information
24
+ # (in the form of a Hash) which can be used to more uniquely specify the
25
+ # subset of servers specified by this specific role definition.
26
+ #
27
+ # Usage:
28
+ #
29
+ # role :db, "db1.example.com", "db2.example.com"
30
+ # role :db, "master.example.com", :primary => true
31
+ # role :app, "app1.example.com", "app2.example.com"
32
+ #
33
+ # You can also encode the username and port number for each host in the
34
+ # server string, if needed:
35
+ #
36
+ # role :web, "www@web1.example.com"
37
+ # role :file, "files.example.com:4144"
38
+ # role :db, "admin@db3.example.com:1234"
39
+ #
40
+ # Lastly, username and port number may be passed as options, if that is
41
+ # preferred; note that the options apply to all servers defined in
42
+ # that call to "role":
43
+ #
44
+ # role :web, "web2", "web3", :user => "www", :port => 2345
45
+ def role(which, *args, &block)
46
+ options = args.last.is_a?(Hash) ? args.pop : {}
47
+ which = which.to_sym
48
+
49
+ # The roles Hash is defined so that unrecognized keys always auto-initialize
50
+ # to a new Role instance (see the assignment in the initialize_with_roles method,
51
+ # above). However, we explicitly assign here so that role declarations will
52
+ # vivify the role object even if there are no server arguments. (Otherwise,
53
+ # role(:app) won't actually instantiate a Role object for :app.)
54
+ roles[which] ||= Role.new
55
+
56
+ roles[which].push(block, options) if block_given?
57
+ args.each { |host| roles[which] << ServerDefinition.new(host, options) }
58
+ end
59
+
60
+ # An alternative way to associate servers with roles. If you have a server
61
+ # that participates in multiple roles, this can be a DRYer way to describe
62
+ # the relationships. Pass the host definition as the first parameter, and
63
+ # the roles as the remaining parameters:
64
+ #
65
+ # server "master.example.com", :web, :app
66
+ def server(host, *roles)
67
+ options = roles.last.is_a?(Hash) ? roles.pop : {}
68
+ raise ArgumentError, "you must associate a server with at least one role" if roles.empty?
69
+ roles.each { |name| role(name, host, options) }
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,85 @@
1
+ module Capistrano
2
+ class Configuration
3
+ module Servers
4
+ # Identifies all servers that the given task should be executed on.
5
+ # The options hash accepts the same arguments as #find_servers, and any
6
+ # preexisting options there will take precedence over the options in
7
+ # the task.
8
+ def find_servers_for_task(task, options={})
9
+ find_servers(task.options.merge(options))
10
+ end
11
+
12
+ # Attempts to find all defined servers that match the given criteria.
13
+ # The options hash may include a :hosts option (which should specify
14
+ # an array of host names or ServerDefinition instances), a :roles
15
+ # option (specifying an array of roles), an :only option (specifying
16
+ # a hash of key/value pairs that any matching server must match), and
17
+ # an :exception option (like :only, but the inverse).
18
+ #
19
+ # Additionally, if the HOSTS environment variable is set, it will take
20
+ # precedence over any other options. Similarly, the ROLES environment
21
+ # variable will take precedence over other options. If both HOSTS and
22
+ # ROLES are given, HOSTS wins.
23
+ #
24
+ # Yet additionally, if the HOSTFILTER environment variable is set, it
25
+ # will limit the result to hosts found in that (comma-separated) list.
26
+ #
27
+ # Usage:
28
+ #
29
+ # # return all known servers
30
+ # servers = find_servers
31
+ #
32
+ # # find all servers in the app role that are not exempted from
33
+ # # deployment
34
+ # servers = find_servers :roles => :app,
35
+ # :except => { :no_release => true }
36
+ #
37
+ # # returns the given hosts, translated to ServerDefinition objects
38
+ # servers = find_servers :hosts => "jamis@example.host.com"
39
+ def find_servers(options={})
40
+ hosts = server_list_from(ENV['HOSTS'] || options[:hosts])
41
+
42
+ if hosts.any?
43
+ filter_server_list(hosts.uniq)
44
+ else
45
+ roles = role_list_from(ENV['ROLES'] || options[:roles] || self.roles.keys)
46
+ only = options[:only] || {}
47
+ except = options[:except] || {}
48
+
49
+ servers = roles.inject([]) { |list, role| list.concat(self.roles[role]) }
50
+ servers = servers.select { |server| only.all? { |key,value| server.options[key] == value } }
51
+ servers = servers.reject { |server| except.any? { |key,value| server.options[key] == value } }
52
+ filter_server_list(servers.uniq)
53
+ end
54
+ end
55
+
56
+ protected
57
+
58
+ def filter_server_list(servers)
59
+ return servers unless ENV['HOSTFILTER']
60
+ filters = ENV['HOSTFILTER'].split(/,/)
61
+ servers.select { |server| filters.include?(server.host) }
62
+ end
63
+
64
+ def server_list_from(hosts)
65
+ hosts = hosts.split(/,/) if String === hosts
66
+ hosts = build_list(hosts)
67
+ hosts.map { |s| String === s ? ServerDefinition.new(s.strip) : s }
68
+ end
69
+
70
+ def role_list_from(roles)
71
+ roles = roles.split(/,/) if String === roles
72
+ roles = build_list(roles)
73
+ roles.map do |role|
74
+ role = String === role ? role.strip.to_sym : role
75
+ raise ArgumentError, "unknown role `#{role}'" unless self.roles.key?(role)
76
+ role
77
+ end
78
+ end
79
+
80
+ def build_list(list)
81
+ Array(list).map { |item| item.respond_to?(:call) ? item.call : item }.flatten
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,127 @@
1
+ require 'thread'
2
+
3
+ module Capistrano
4
+ class Configuration
5
+ module Variables
6
+ def self.included(base) #:nodoc:
7
+ %w(initialize respond_to? method_missing).each do |m|
8
+ base_name = m[/^\w+/]
9
+ punct = m[/\W+$/]
10
+ base.send :alias_method, "#{base_name}_without_variables#{punct}", m
11
+ base.send :alias_method, m, "#{base_name}_with_variables#{punct}"
12
+ end
13
+ end
14
+
15
+ # The hash of variables that have been defined in this configuration
16
+ # instance.
17
+ attr_reader :variables
18
+
19
+ # Set a variable to the given value.
20
+ def set(variable, *args, &block)
21
+ if variable.to_s !~ /^[_a-z]/
22
+ raise ArgumentError, "invalid variable `#{variable}' (variables must begin with an underscore, or a lower-case letter)"
23
+ end
24
+
25
+ if !block_given? && args.empty? || block_given? && !args.empty?
26
+ raise ArgumentError, "you must specify exactly one of either a value or a block"
27
+ end
28
+
29
+ if args.length > 1
30
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 1)"
31
+ end
32
+
33
+ value = args.empty? ? block : args.first
34
+ sym = variable.to_sym
35
+ protect(sym) { @variables[sym] = value }
36
+ end
37
+
38
+ alias :[]= :set
39
+
40
+ # Removes any trace of the given variable.
41
+ def unset(variable)
42
+ sym = variable.to_sym
43
+ protect(sym) do
44
+ @original_procs.delete(sym)
45
+ @variables.delete(sym)
46
+ end
47
+ end
48
+
49
+ # Returns true if the variable has been defined, and false otherwise.
50
+ def exists?(variable)
51
+ @variables.key?(variable.to_sym)
52
+ end
53
+
54
+ # If the variable was originally a proc value, it will be reset to it's
55
+ # original proc value. Otherwise, this method does nothing. It returns
56
+ # true if the variable was actually reset.
57
+ def reset!(variable)
58
+ sym = variable.to_sym
59
+ protect(sym) do
60
+ if @original_procs.key?(sym)
61
+ @variables[sym] = @original_procs.delete(sym)
62
+ true
63
+ else
64
+ false
65
+ end
66
+ end
67
+ end
68
+
69
+ # Access a named variable. If the value of the variable responds_to? :call,
70
+ # #call will be invoked (without parameters) and the return value cached
71
+ # and returned.
72
+ def fetch(variable, *args)
73
+ if !args.empty? && block_given?
74
+ raise ArgumentError, "you must specify either a default value or a block, but not both"
75
+ end
76
+
77
+ sym = variable.to_sym
78
+ protect(sym) do
79
+ if !@variables.key?(sym)
80
+ return args.first unless args.empty?
81
+ return yield(variable) if block_given?
82
+ raise IndexError, "`#{variable}' not found"
83
+ end
84
+
85
+ if @variables[sym].respond_to?(:call)
86
+ @original_procs[sym] = @variables[sym]
87
+ @variables[sym] = @variables[sym].call
88
+ end
89
+ end
90
+
91
+ @variables[sym]
92
+ end
93
+
94
+ def [](variable)
95
+ fetch(variable, nil)
96
+ end
97
+
98
+ def initialize_with_variables(*args) #:nodoc:
99
+ initialize_without_variables(*args)
100
+ @variables = {}
101
+ @original_procs = {}
102
+ @variable_locks = Hash.new { |h,k| h[k] = Mutex.new }
103
+
104
+ set :ssh_options, {}
105
+ set :logger, logger
106
+ end
107
+ private :initialize_with_variables
108
+
109
+ def protect(variable)
110
+ @variable_locks[variable.to_sym].synchronize { yield }
111
+ end
112
+ private :protect
113
+
114
+ def respond_to_with_variables?(sym, include_priv=false) #:nodoc:
115
+ @variables.has_key?(sym) || respond_to_without_variables?(sym, include_priv)
116
+ end
117
+
118
+ def method_missing_with_variables(sym, *args, &block) #:nodoc:
119
+ if args.length == 0 && block.nil? && @variables.has_key?(sym)
120
+ self[sym]
121
+ else
122
+ method_missing_without_variables(sym, *args, &block)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,43 @@
1
+ require 'capistrano/logger'
2
+
3
+ require 'capistrano/configuration/callbacks'
4
+ require 'capistrano/configuration/connections'
5
+ require 'capistrano/configuration/execution'
6
+ require 'capistrano/configuration/loading'
7
+ require 'capistrano/configuration/namespaces'
8
+ require 'capistrano/configuration/roles'
9
+ require 'capistrano/configuration/servers'
10
+ require 'capistrano/configuration/variables'
11
+
12
+ require 'capistrano/configuration/actions/file_transfer'
13
+ require 'capistrano/configuration/actions/inspect'
14
+ require 'capistrano/configuration/actions/invocation'
15
+
16
+ module Capistrano
17
+ # Represents a specific Capistrano configuration. A Configuration instance
18
+ # may be used to load multiple recipe files, define and describe tasks,
19
+ # define roles, and set configuration variables.
20
+ class Configuration
21
+ # The logger instance defined for this configuration.
22
+ attr_accessor :debug, :logger, :dry_run
23
+
24
+ def initialize #:nodoc:
25
+ @debug = false
26
+ @dry_run = false
27
+ @logger = Logger.new
28
+ end
29
+
30
+ # make the DSL easier to read when using lazy evaluation via lambdas
31
+ alias defer lambda
32
+
33
+ # The includes must come at the bottom, since they may redefine methods
34
+ # defined in the base class.
35
+ include Connections, Execution, Loading, Namespaces, Roles, Servers, Variables
36
+
37
+ # Mix in the actions
38
+ include Actions::FileTransfer, Actions::Inspect, Actions::Invocation
39
+
40
+ # Must mix last, because it hooks into previously defined methods
41
+ include Callbacks
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ module Capistrano
2
+ class Error < RuntimeError; end
3
+
4
+ class CaptureError < Error; end
5
+ class NoSuchTaskError < Error; end
6
+ class NoMatchingServersError < Error; end
7
+
8
+ class RemoteError < Error
9
+ attr_accessor :hosts
10
+ end
11
+
12
+ class ConnectionError < RemoteError; end
13
+ class TransferError < RemoteError; end
14
+ class CommandError < RemoteError; end
15
+ end
@@ -0,0 +1,57 @@
1
+ module Capistrano
2
+ class ExtensionProxy #:nodoc:
3
+ def initialize(config, mod)
4
+ @config = config
5
+ extend(mod)
6
+ end
7
+
8
+ def method_missing(sym, *args, &block)
9
+ @config.send(sym, *args, &block)
10
+ end
11
+ end
12
+
13
+ # Holds the set of registered plugins, keyed by name (where the name is a
14
+ # symbol).
15
+ EXTENSIONS = {}
16
+
17
+ # Register the given module as a plugin with the given name. It will henceforth
18
+ # be available via a proxy object on Configuration instances, accessible by
19
+ # a method with the given name.
20
+ def self.plugin(name, mod)
21
+ name = name.to_sym
22
+ return false if EXTENSIONS.has_key?(name)
23
+
24
+ methods = Capistrano::Configuration.public_instance_methods +
25
+ Capistrano::Configuration.protected_instance_methods +
26
+ Capistrano::Configuration.private_instance_methods
27
+
28
+ if methods.any? { |m| m.to_sym == name }
29
+ raise Capistrano::Error, "registering a plugin named `#{name}' would shadow a method on Capistrano::Configuration with the same name"
30
+ end
31
+
32
+ Capistrano::Configuration.class_eval <<-STR, __FILE__, __LINE__+1
33
+ def #{name}
34
+ @__#{name}_proxy ||= Capistrano::ExtensionProxy.new(self, Capistrano::EXTENSIONS[#{name.inspect}])
35
+ end
36
+ STR
37
+
38
+ EXTENSIONS[name] = mod
39
+ return true
40
+ end
41
+
42
+ # Unregister the plugin with the given name.
43
+ def self.remove_plugin(name)
44
+ name = name.to_sym
45
+ if EXTENSIONS.delete(name)
46
+ Capistrano::Configuration.send(:remove_method, name)
47
+ return true
48
+ end
49
+
50
+ return false
51
+ end
52
+
53
+ def self.configuration(*args) #:nodoc:
54
+ warn "[DEPRECATION] Capistrano.configuration is deprecated. Use Capistrano::Configuration.instance instead"
55
+ Capistrano::Configuration.instance(*args)
56
+ end
57
+ end
@@ -0,0 +1,59 @@
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
+ (RUBY_VERSION >= "1.9" ? message.lines : 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