cape 1.6.2 → 1.7.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 (72) hide show
  1. data/Gemfile +7 -6
  2. data/Guardfile +29 -10
  3. data/History.markdown +4 -0
  4. data/README.markdown +38 -9
  5. data/Rakefile +35 -8
  6. data/features/dsl/each_rake_task/{without_arguments.feature → unqualified.feature} +16 -37
  7. data/features/dsl/each_rake_task/{with_defined_namespace_argument.feature → with_defined_namespace.feature} +2 -13
  8. data/features/dsl/each_rake_task/{with_defined_task_argument.feature → with_defined_task.feature} +2 -6
  9. data/features/dsl/each_rake_task/with_undefined_task_or_namespace.feature +24 -0
  10. data/features/dsl/mirror_rake_tasks/inside_capistrano_namespace.feature +2 -2
  11. data/features/dsl/mirror_rake_tasks/{without_arguments.feature → unqualified.feature} +15 -11
  12. data/features/dsl/mirror_rake_tasks/with_cd.feature +63 -0
  13. data/features/dsl/mirror_rake_tasks/with_cd_and_environment_variables.feature +27 -0
  14. data/features/dsl/mirror_rake_tasks/{with_defined_namespace_argument.feature → with_defined_namespace.feature} +6 -8
  15. data/features/dsl/mirror_rake_tasks/{with_defined_task_argument.feature → with_defined_task.feature} +4 -4
  16. data/features/dsl/mirror_rake_tasks/{with_defined_task_argument_and_environment_variables.feature → with_defined_task_and_cd.feature} +8 -8
  17. data/features/dsl/mirror_rake_tasks/with_defined_task_and_cd_and_environment_variables.feature +46 -0
  18. data/features/dsl/mirror_rake_tasks/with_defined_task_and_environment_variables.feature +92 -0
  19. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename.feature +47 -0
  20. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_cd.feature +49 -0
  21. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_cd_and_environment_variables.feature +52 -0
  22. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_environment_variables.feature +50 -0
  23. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_valid_options.feature +49 -0
  24. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_valid_options_and_cd.feature +51 -0
  25. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_valid_options_and_cd_and_environment_variables.feature +54 -0
  26. data/features/dsl/mirror_rake_tasks/with_defined_task_and_rename_and_valid_options_and_environment_variables.feature +52 -0
  27. data/features/dsl/mirror_rake_tasks/with_defined_task_and_valid_options.feature +53 -6
  28. data/features/dsl/mirror_rake_tasks/{with_defined_task_and_valid_options_arguments_and_environment_variables.feature → with_defined_task_and_valid_options_and_cd.feature} +10 -8
  29. data/features/dsl/mirror_rake_tasks/with_defined_task_and_valid_options_and_cd_and_environment_variables.feature +48 -0
  30. data/features/dsl/mirror_rake_tasks/with_defined_task_and_valid_options_and_environment_variables.feature +98 -0
  31. data/features/dsl/mirror_rake_tasks/with_environment_variables.feature +61 -4
  32. data/features/dsl/mirror_rake_tasks/with_rename.feature +27 -0
  33. data/features/dsl/mirror_rake_tasks/with_rename_and_cd.feature +28 -0
  34. data/features/dsl/mirror_rake_tasks/with_rename_and_cd_and_environment_variables.feature +30 -0
  35. data/features/dsl/mirror_rake_tasks/with_rename_and_environment_variables.feature +29 -0
  36. data/features/dsl/mirror_rake_tasks/with_rename_and_valid_options.feature +28 -0
  37. data/features/dsl/mirror_rake_tasks/with_rename_and_valid_options_and_cd.feature +29 -0
  38. data/features/dsl/mirror_rake_tasks/with_rename_and_valid_options_and_cd_and_environment_variables.feature +31 -0
  39. data/features/dsl/mirror_rake_tasks/with_rename_and_valid_options_and_environment_variables.feature +30 -0
  40. data/features/dsl/mirror_rake_tasks/{with_undefined_argument.feature → with_undefined_task_or_namespace.feature} +3 -4
  41. data/features/dsl/mirror_rake_tasks/with_valid_options.feature +46 -0
  42. data/features/dsl/mirror_rake_tasks/{with_valid_options_argument.feature → with_valid_options_and_cd.feature} +7 -5
  43. data/features/dsl/mirror_rake_tasks/with_valid_options_and_cd_and_environment_variables.feature +28 -0
  44. data/features/dsl/mirror_rake_tasks/with_valid_options_and_environment_variables.feature +51 -0
  45. data/features/dsl/rake_executable.feature +2 -2
  46. data/features/step_definitions.rb +40 -0
  47. data/lib/cape.rb +2 -0
  48. data/lib/cape/capistrano.rb +59 -32
  49. data/lib/cape/capistrano_deprecated.rb +165 -0
  50. data/lib/cape/core_ext.rb +2 -0
  51. data/lib/cape/deprecation.rb +12 -0
  52. data/lib/cape/deprecation/base.rb +59 -0
  53. data/lib/cape/deprecation/capistrano_deprecated_define_rake_wrapper.rb +168 -0
  54. data/lib/cape/deprecation/dsl_deprecated_mirror_rake_tasks.rb +145 -0
  55. data/lib/cape/dsl.rb +49 -60
  56. data/lib/cape/dsl_deprecated.rb +157 -0
  57. data/lib/cape/hash_list.rb +2 -0
  58. data/lib/cape/recipe_definition.rb +103 -0
  59. data/lib/cape/recipe_definition_deprecated.rb +41 -0
  60. data/lib/cape/util.rb +2 -0
  61. data/lib/cape/version.rb +1 -1
  62. data/lib/cape/xterm.rb +326 -0
  63. data/spec/cape/deprecation/base_sharedspec.rb +18 -0
  64. data/spec/cape/deprecation/capistrano_deprecated_define_rake_wrapper_spec.rb +157 -0
  65. data/spec/cape/deprecation/dsl_deprecated_mirror_rake_tasks_spec.rb +153 -0
  66. data/spec/cape/dsl_deprecated_spec.rb +307 -0
  67. data/spec/cape/dsl_spec.rb +10 -43
  68. data/spec/cape/recipe_definition_spec.rb +53 -0
  69. data/spec/cape/xterm_spec.rb +72 -0
  70. metadata +97 -28
  71. data/features/dsl/each_rake_task/with_undefined_argument.feature +0 -53
  72. data/features/dsl/mirror_rake_tasks/with_valid_options_arguments_and_environment_variables.feature +0 -26
@@ -1,4 +1,4 @@
1
- Feature: The #mirror_rake_tasks DSL method with an undefined argument
1
+ Feature: The #mirror_rake_tasks DSL method with an undefined task or namespace
2
2
 
3
3
  In order to include Rake tasks with descriptions in my Capistrano recipes,
4
4
  As a developer using Cape,
@@ -9,9 +9,8 @@ Feature: The #mirror_rake_tasks DSL method with an undefined argument
9
9
  And a Capfile with:
10
10
  """
11
11
  Cape do
12
- mirror_rake_tasks :this_does_not_exist
12
+ mirror_rake_tasks 'period'
13
13
  end
14
14
  """
15
15
  When I run `cap -vT`
16
- Then the output should not contain "cap this_does_not_exist"
17
- And the output should not contain "cap with_period"
16
+ Then the output should not contain "period"
@@ -0,0 +1,46 @@
1
+ Feature: The #mirror_rake_tasks DSL method with valid options
2
+
3
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
4
+ As a developer using Cape,
5
+ I want to use the Cape DSL.
6
+
7
+ @deprecated
8
+ Scenario: mirror a Rake task with its implementation (deprecated)
9
+ Given a full-featured Rakefile
10
+ And a Capfile with:
11
+ """
12
+ set :current_path, '/current/path'
13
+
14
+ Cape do
15
+ mirror_rake_tasks :roles => :app
16
+ end
17
+ """
18
+ When I run `cap with_period`
19
+ Then the output should contain:
20
+ """
21
+ *** DEPRECATED: `mirror_rake_tasks :roles => :app`. Use this instead: `mirror_rake_tasks { |recipes| recipes.options[:roles] = :app }`
22
+ * executing `with_period'
23
+ * executing "cd /current/path && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period"
24
+ `with_period' is only run for servers matching {:roles=>:app}, but no servers matched
25
+ """
26
+
27
+ Scenario: mirror a Rake task with its implementation
28
+ Given a full-featured Rakefile
29
+ And a Capfile with:
30
+ """
31
+ set :current_path, '/current/path'
32
+
33
+ Cape do
34
+ mirror_rake_tasks do |recipes|
35
+ recipes.options[:roles] = :app
36
+ end
37
+ end
38
+ """
39
+ When I run `cap with_period`
40
+ Then the output should contain:
41
+ """
42
+ * executing `with_period'
43
+ * executing "cd /current/path && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period"
44
+ `with_period' is only run for servers matching {:roles=>:app}, but no servers matched
45
+ """
46
+ And the output should not contain "DEPRECATED"
@@ -1,4 +1,4 @@
1
- Feature: The #mirror_rake_tasks DSL method with an argument of valid options
1
+ Feature: The #mirror_rake_tasks DSL method with valid options and a different directory
2
2
 
3
3
  In order to include Rake tasks with descriptions in my Capistrano recipes,
4
4
  As a developer using Cape,
@@ -8,17 +8,19 @@ Feature: The #mirror_rake_tasks DSL method with an argument of valid options
8
8
  Given a full-featured Rakefile
9
9
  And a Capfile with:
10
10
  """
11
- set :current_path, '/path/to/current/deployed/application'
12
- set :rails_env, 'production'
11
+ set :release_path, '/release/path'
13
12
 
14
13
  Cape do
15
- mirror_rake_tasks :roles => :app
14
+ mirror_rake_tasks do |recipes|
15
+ recipes.options[:roles] = :app
16
+ recipes.cd { release_path }
17
+ end
16
18
  end
17
19
  """
18
20
  When I run `cap with_period`
19
21
  Then the output should contain:
20
22
  """
21
23
  * executing `with_period'
22
- * executing "cd /path/to/current/deployed/application && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period"
24
+ * executing "cd /release/path && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period"
23
25
  `with_period' is only run for servers matching {:roles=>:app}, but no servers matched
24
26
  """
@@ -0,0 +1,28 @@
1
+ Feature: The #mirror_rake_tasks DSL method with valid options, a different directory, and environment variables
2
+
3
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
4
+ As a developer using Cape,
5
+ I want to use the Cape DSL.
6
+
7
+ Scenario: mirror the matching Rake task with its implementation
8
+ Given a full-featured Rakefile
9
+ And a Capfile with:
10
+ """
11
+ set :release_path, '/release/path'
12
+ set :rails_env, 'rails-env'
13
+
14
+ Cape do
15
+ mirror_rake_tasks do |recipes|
16
+ recipes.options[:roles] = :app
17
+ recipes.cd { release_path }
18
+ recipes.env['RAILS_ENV'] = lambda { rails_env }
19
+ end
20
+ end
21
+ """
22
+ When I run `cap with_period`
23
+ Then the output should contain:
24
+ """
25
+ * executing `with_period'
26
+ * executing "cd /release/path && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period RAILS_ENV=\"rails-env\""
27
+ `with_period' is only run for servers matching {:roles=>:app}, but no servers matched
28
+ """
@@ -0,0 +1,51 @@
1
+ Feature: The #mirror_rake_tasks DSL method with valid options and environment variables
2
+
3
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
4
+ As a developer using Cape,
5
+ I want to use the Cape DSL.
6
+
7
+ @deprecated
8
+ Scenario: mirror the matching Rake task with its implementation (deprecated)
9
+ Given a full-featured Rakefile
10
+ And a Capfile with:
11
+ """
12
+ set :current_path, '/current/path'
13
+ set :rails_env, 'rails-env'
14
+
15
+ Cape do
16
+ mirror_rake_tasks :roles => :app do |env|
17
+ env['RAILS_ENV'] = rails_env
18
+ end
19
+ end
20
+ """
21
+ When I run `cap with_period`
22
+ Then the output should contain:
23
+ """
24
+ *** DEPRECATED: `mirror_rake_tasks(:roles => :app) { |env| env["RAILS_ENV"] = "rails-env" }`. Use this instead: `mirror_rake_tasks { |recipes| recipes.options[:roles] = :app; recipes.env["RAILS_ENV"] = "rails-env" }`
25
+ * executing `with_period'
26
+ * executing "cd /current/path && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period RAILS_ENV=\"rails-env\""
27
+ `with_period' is only run for servers matching {:roles=>:app}, but no servers matched
28
+ """
29
+
30
+ Scenario: mirror the matching Rake task with its implementation
31
+ Given a full-featured Rakefile
32
+ And a Capfile with:
33
+ """
34
+ set :current_path, '/current/path'
35
+ set :rails_env, 'rails-env'
36
+
37
+ Cape do
38
+ mirror_rake_tasks do |recipes|
39
+ recipes.options[:roles] = :app
40
+ recipes.env['RAILS_ENV'] = lambda { rails_env }
41
+ end
42
+ end
43
+ """
44
+ When I run `cap with_period`
45
+ Then the output should contain:
46
+ """
47
+ * executing `with_period'
48
+ * executing "cd /current/path && /usr/bin/env `/usr/bin/env bundle check >/dev/null 2>&1; case $? in 0|1 ) echo bundle exec ;; esac` rake with_period RAILS_ENV=\"rails-env\""
49
+ `with_period' is only run for servers matching {:roles=>:app}, but no servers matched
50
+ """
51
+ And the output should not contain "DEPRECATED"
@@ -44,7 +44,7 @@ Feature: The #local_rake_executable and #remote_rake_executable DSL attributes
44
44
  Given a full-featured Rakefile
45
45
  And a Capfile with:
46
46
  """
47
- set :current_path, '/path/to/current/deployed/application'
47
+ set :current_path, '/current/path'
48
48
 
49
49
  Cape.remote_rake_executable = 'echo "This comes from overridden Rake" #'
50
50
 
@@ -66,5 +66,5 @@ Feature: The #local_rake_executable and #remote_rake_executable DSL attributes
66
66
  And the output should contain:
67
67
  """
68
68
  * executing `with_period'
69
- * executing "cd /path/to/current/deployed/application && echo \"This comes from overridden Rake\" # with_period"
69
+ * executing "cd /current/path && echo \"This comes from overridden Rake\" # with_period"
70
70
  """
@@ -43,3 +43,43 @@ Given 'a full-featured Rakefile' do
43
43
  task :hidden_task
44
44
  end_step
45
45
  end
46
+
47
+ Given 'a full-featured Rakefile defining a Ruby-method-shadowing task' do
48
+ step 'a file named "Rakefile" with:', <<-end_step
49
+ desc 'A task that shadows a Ruby method'
50
+ task :load
51
+
52
+ desc 'Ends with period.'
53
+ task :with_period
54
+
55
+ desc 'Ends without period'
56
+ task :without_period
57
+
58
+ desc 'My long task -- it has a very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very long description'
59
+ task :long
60
+
61
+ desc 'My task with one argument'
62
+ task :with_one_arg, [:the_arg]
63
+
64
+ desc 'A task that shadows a namespace'
65
+ task :my_namespace
66
+
67
+ namespace :my_namespace do
68
+ desc 'My task in a namespace'
69
+ task :in_a_namespace
70
+
71
+ namespace :my_nested_namespace do
72
+ desc 'My task in a nested namespace'
73
+ task :in_a_nested_namespace
74
+ end
75
+ end
76
+
77
+ desc 'My task with two arguments'
78
+ task :with_two_args, [:my_arg1, :my_arg2]
79
+
80
+ desc 'My task with three arguments'
81
+ task :with_three_args, [:an_arg1, :an_arg2, :an_arg3]
82
+
83
+ task :hidden_task
84
+ end_step
85
+ end
@@ -6,12 +6,14 @@ end
6
6
  module Cape
7
7
 
8
8
  extend DSL
9
+ extend DSLDeprecated
9
10
 
10
11
  end
11
12
 
12
13
  # The method used to group Cape statements.
13
14
  #
14
15
  # @param [Proc] block Cape and Capistrano statements
16
+ #
15
17
  # @return [Cape] the Cape module
16
18
  #
17
19
  # @yield [cape] a block containing Cape statements
@@ -1,5 +1,5 @@
1
- require 'cape/hash_list'
2
1
  require 'cape/rake'
2
+ require 'cape/recipe_definition'
3
3
  require 'cape/util'
4
4
 
5
5
  module Cape
@@ -17,14 +17,13 @@ module Cape
17
17
  attributes.each do |name, value|
18
18
  send "#{name}=", value
19
19
  end
20
- self.rake ||= Rake.new
20
+ self.rake ||= new_rake
21
21
  end
22
22
 
23
23
  # Defines a wrapper in Capistrano around the specified Rake _task_.
24
24
  #
25
25
  # @param [Hash] task metadata for a Rake task
26
- # @param [Hash] named_arguments named arguments, including options to pass to
27
- # the Capistrano +task+ method
26
+ # @param [Hash] named_arguments
28
27
  #
29
28
  # @option task [String] :name the name of the Rake task
30
29
  # @option task [Array of String, nil] :parameters the names of the Rake
@@ -32,33 +31,28 @@ module Cape
32
31
  # @option task [String] :description documentation for the Rake
33
32
  # task
34
33
  #
35
- # @option named_arguments [Binding] :binding the Binding of your
36
- # Capistrano recipes
37
- # file
34
+ # @option named_arguments [Binding] :binding the Binding of your Capistrano
35
+ # recipes file
38
36
  #
39
- # @yield [env] a block that defines environment variables for the Rake task;
40
- # optional
41
- # @yieldparam [Hash] env the environment variables to set before executing
42
- # the Rake task
37
+ # @yield [recipes] a block that customizes the Capistrano recipe(s)
38
+ # generated for the Rake task(s); optional
39
+ # @yieldparam [RecipeDefinition] recipes an interface for customizing the
40
+ # Capistrano recipe(s) generated for
41
+ # the Rake task(s)
43
42
  #
44
43
  # @return [Capistrano] the object
45
44
  #
46
45
  # @raise [ArgumentError] +named_arguments[:binding]+ is missing
47
46
  #
48
47
  # @note Any parameters that the Rake task has are integrated via environment variables, since Capistrano does not support recipe parameters per se.
49
- #
50
- # @see http://github.com/capistrano/capistrano/blob/master/lib/capistrano/configuration/actions/invocation.rb#L99-L144 Valid Capistrano ‘task’ method options
51
48
  def define_rake_wrapper(task, named_arguments, &block)
52
49
  unless (binding = named_arguments[:binding])
53
50
  raise ::ArgumentError, ':binding named argument is required'
54
51
  end
55
52
 
56
53
  capistrano_context = binding.eval('self', __FILE__, __LINE__)
57
- options = named_arguments.reject do |key, value|
58
- key == :binding
59
- end
60
54
  describe task, capistrano_context
61
- implement(task, capistrano_context, options, &block)
55
+ implement(task, capistrano_context, &block)
62
56
  end
63
57
 
64
58
  private
@@ -88,6 +82,11 @@ Set environment #{noun} #{parameters_list} if you want to pass #{noun_phrase}.
88
82
  description.join
89
83
  end
90
84
 
85
+ def capture_recipe_definition(recipe_definition, &recipe_definition_block)
86
+ recipe_definition_block.call(recipe_definition) if recipe_definition_block
87
+ true
88
+ end
89
+
91
90
  def describe(task, capistrano_context)
92
91
  if (description = build_capistrano_description(task))
93
92
  capistrano_context.desc description
@@ -95,13 +94,18 @@ Set environment #{noun} #{parameters_list} if you want to pass #{noun_phrase}.
95
94
  self
96
95
  end
97
96
 
98
- def implement(task, capistrano_context, options, &env_block)
99
- name_tokens = task[:name].split(':')
100
- name_tokens << 'default' if task[:default]
97
+ def implement(task, capistrano_context, &recipe_definition_block)
98
+ name_tokens = tokenize_name(task)
99
+ recipe_definition = new_recipe_definition
100
+ capture_recipe_definition(recipe_definition, &recipe_definition_block)
101
+ env = nil
101
102
  rake = self.rake
102
- # Define the recipe.
103
103
  block = lambda { |context|
104
- context.task name_tokens.last, options do
104
+ recipe_name = name_tokens.last
105
+ if recipe_definition.rename
106
+ recipe_name = recipe_definition.rename.call(name_tokens.last)
107
+ end
108
+ context.task recipe_name, recipe_definition.options do
105
109
  arguments = Array(task[:parameters]).collect do |a|
106
110
  if (value = ENV[a.upcase])
107
111
  value = value.inspect
@@ -113,17 +117,26 @@ Set environment #{noun} #{parameters_list} if you want to pass #{noun_phrase}.
113
117
  else
114
118
  arguments = "[#{arguments.join ','}]"
115
119
  end
116
- env_hash = HashList.new
117
- env_block.call(env_hash) if env_block
118
- env_hash.reject! do |var_name, var_value|
119
- var_name.nil? || var_value.nil?
120
- end
121
- env_strings = env_hash.collect do |var_name, var_value|
122
- "#{var_name}=#{var_value.inspect}"
120
+
121
+ unless env
122
+ env_strings = recipe_definition.env.collect do |var_name, var_value|
123
+ if var_name.nil? || var_value.nil?
124
+ nil
125
+ else
126
+ if var_value.is_a?(Proc)
127
+ var_value = context.instance_eval do
128
+ var_value.call
129
+ end
130
+ end
131
+ "#{var_name}=#{var_value.inspect}"
132
+ end
133
+ end.compact
134
+ env = env_strings.empty? ? nil : (' ' + env_strings.join(' '))
123
135
  end
124
- env = env_strings.empty? ? nil : (' ' + env_strings.join(' '))
125
- command = "cd #{context.current_path} && " +
126
- "#{rake.remote_executable} " +
136
+
137
+ path = recipe_definition.cd || context.current_path
138
+ path = path.call if path.respond_to?(:call)
139
+ command = "cd #{path} && #{rake.remote_executable} " +
127
140
  "#{task[:name]}#{arguments}#{env}"
128
141
  context.run command
129
142
  end
@@ -139,6 +152,20 @@ Set environment #{noun} #{parameters_list} if you want to pass #{noun_phrase}.
139
152
  self
140
153
  end
141
154
 
155
+ def new_rake(*arguments)
156
+ Rake.new(*arguments)
157
+ end
158
+
159
+ def new_recipe_definition(*arguments)
160
+ RecipeDefinition.new(*arguments)
161
+ end
162
+
163
+ def tokenize_name(task)
164
+ task[:name].split(':').tap do |result|
165
+ result << 'default' if task[:default]
166
+ end
167
+ end
168
+
142
169
  end
143
170
 
144
171
  end
@@ -0,0 +1,165 @@
1
+ require 'cape/capistrano'
2
+ require 'cape/deprecation/capistrano_deprecated_define_rake_wrapper'
3
+ require 'cape/recipe_definition_deprecated'
4
+ require 'cape/xterm'
5
+
6
+ module Cape
7
+
8
+ # Implements {Capistrano} with deprecated methods.
9
+ #
10
+ # @api private
11
+ class CapistranoDeprecated < Capistrano
12
+
13
+ # Defines a wrapper in Capistrano around the specified Rake _task_.
14
+ #
15
+ # @deprecated Use {Capistrano#define_rake_wrapper} instead.
16
+ #
17
+ # @param [Hash] task metadata for a Rake task
18
+ # @param [Hash] named_arguments named arguments, including options to pass to
19
+ # the Capistrano +task+ method
20
+ #
21
+ # @option task [String] :name the name of the Rake task
22
+ # @option task [Array of String, nil] :parameters the names of the Rake
23
+ # task's parameters, if any
24
+ # @option task [String] :description documentation for the Rake
25
+ # task
26
+ #
27
+ # @option named_arguments [Binding] :binding the Binding of your
28
+ # Capistrano recipes
29
+ # file
30
+ #
31
+ # @yield [env] a block that defines environment variables for the Rake task;
32
+ # optional
33
+ # @yieldparam [Hash] env the environment variables to set before executing
34
+ # the Rake task
35
+ #
36
+ # @return [CapistranoDeprecated] the object
37
+ #
38
+ # @raise [ArgumentError] +named_arguments[:binding]+ is missing
39
+ #
40
+ # @note Any parameters that the Rake task has are integrated via environment variables, since Capistrano does not support recipe parameters per se.
41
+ #
42
+ # @see http://github.com/capistrano/capistrano/blob/master/lib/capistrano/configuration/actions/invocation.rb#L99-L144 Valid Capistrano 'task' method options
43
+ #
44
+ # @api public
45
+ def define_rake_wrapper(task, named_arguments, &block)
46
+ unless (binding = named_arguments[:binding])
47
+ raise ::ArgumentError, ':binding named argument is required'
48
+ end
49
+
50
+ deprecation.task = task
51
+ deprecation.named_arguments = named_arguments
52
+
53
+ capistrano_context = binding.eval('self', __FILE__, __LINE__)
54
+ options = named_arguments.reject do |key, value|
55
+ key == :binding
56
+ end
57
+ describe task, capistrano_context
58
+ implement(task, capistrano_context, options, &block)
59
+ end
60
+
61
+ # The object in which deprecated API usage is recorded.
62
+ #
63
+ # @return [Deprecation::Base]
64
+ def deprecation
65
+ @deprecation ||= Deprecation::CapistranoDeprecatedDefineRakeWrapper.new
66
+ end
67
+
68
+ private
69
+
70
+ def capture_recipe_definition(recipe_definition, &recipe_definition_block)
71
+ begin
72
+ super
73
+ rescue NoMethodError
74
+ unless @warned
75
+ deprecation.stream.puts XTerm.bold_and_foreground_red('*** DEPRECATED:') +
76
+ ' ' +
77
+ XTerm.bold('Referencing Capistrano variables ' +
78
+ 'from Cape without wrapping them in ' +
79
+ 'a block, a lambda, or another ' +
80
+ 'callable object')
81
+ @warned = true
82
+ end
83
+ return false
84
+ end
85
+ true
86
+ end
87
+
88
+ def implement(task, capistrano_context, options, &env_block)
89
+ return super(task, capistrano_context, &env_block) if options.empty?
90
+
91
+ name_tokens = tokenize_name(task)
92
+ recipe_definition = new_recipe_definition(deprecation)
93
+ env = nil
94
+ if capture_recipe_definition(recipe_definition, &env_block)
95
+ env_strings = recipe_definition.env.collect do |var_name, var_value|
96
+ if var_name.nil? || var_value.nil?
97
+ nil
98
+ else
99
+ var_value = var_value.call if var_value.is_a?(Proc)
100
+ "#{var_name}=#{var_value.inspect}"
101
+ end
102
+ end.compact
103
+ env = env_strings.empty? ? nil : (' ' + env_strings.join(' '))
104
+ end
105
+ this = env ? nil : self
106
+ rake = self.rake
107
+ block = lambda { |context|
108
+ recipe_name = name_tokens.last
109
+ if recipe_definition.rename
110
+ recipe_name = recipe_definition.rename.call(name_tokens.last)
111
+ end
112
+ context.task recipe_name, options do
113
+ arguments = Array(task[:parameters]).collect do |a|
114
+ if (value = ENV[a.upcase])
115
+ value = value.inspect
116
+ end
117
+ value
118
+ end
119
+ if arguments.empty?
120
+ arguments = nil
121
+ else
122
+ arguments = "[#{arguments.join ','}]"
123
+ end
124
+
125
+ unless env
126
+ if this.instance_eval { capture_recipe_definition(recipe_definition, &env_block) }
127
+ env_strings = recipe_definition.env.collect do |var_name, var_value|
128
+ if var_name.nil? || var_value.nil?
129
+ nil
130
+ else
131
+ var_value = var_value.call if var_value.is_a?(Proc)
132
+ "#{var_name}=#{var_value.inspect}"
133
+ end
134
+ end.compact
135
+ env = env_strings.empty? ? nil : (' ' + env_strings.join(' '))
136
+ this = nil
137
+ end
138
+ end
139
+
140
+ path = recipe_definition.cd || context.current_path
141
+ path = path.call if path.respond_to?(:call)
142
+ command = "cd #{path} && #{rake.remote_executable} " +
143
+ "#{task[:name]}#{arguments}#{env}"
144
+ context.run command
145
+ end
146
+ }
147
+ # Nest the recipe inside its containing namespaces.
148
+ name_tokens[0...-1].reverse.each do |namespace_token|
149
+ inner_block = block
150
+ block = lambda { |context|
151
+ context.namespace(namespace_token, &inner_block)
152
+ }
153
+ end
154
+ block.call capistrano_context
155
+ self
156
+ end
157
+
158
+ def new_recipe_definition(*arguments)
159
+ arguments << deprecation if arguments.empty?
160
+ RecipeDefinitionDeprecated.new(*arguments)
161
+ end
162
+
163
+ end
164
+
165
+ end