capistrano-distribution 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51e2dcb1ba15f838b76d6eaf72e6f451c793f32b
4
+ data.tar.gz: 1cb882b4e420dc6c2292e897657f681b831d5515
5
+ SHA512:
6
+ metadata.gz: 8f0275b355b9ee5311373aff3b70640ddb381fecd3dd3b6b57b9eab3817e17217a2c25667b53047dc69aa8fc3065050203fe7d828026c2f4bcfa1dc63ac2788c
7
+ data.tar.gz: 20a82ec2110fe7bfebd8ae1dfcd149e249f75332b1cde1d1fbeb4ac86afa6df2dff926958b2473b26c19882627f13414a02bc954540bc4cda5d87a2b5b70b78d
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --protected --private abstract lib/**/*.rb - README.md NEWS.md LICENSE
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2014 Spiceworks, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/NEWS.md ADDED
@@ -0,0 +1,35 @@
1
+ # News and Notifications by Version
2
+
3
+ This file lists noteworthy changes which may affect users of this project. More
4
+ detailed information is available in the rest of the documentation.
5
+
6
+ **NOTE:** Date stamps in the following entries are in YYYY/MM/DD format.
7
+
8
+
9
+ ## v0.2.0 (2016/02/29)
10
+
11
+ * Provide a setting (`:distribution_runner_opts`) to configure runner options.
12
+ * Must be a hash of options acceptable by the `on` method of sshkit.
13
+ * Git distributables can now change the repo URL without manual intervention.
14
+ * Pruning of dead Git branches now happens during repository update.
15
+ * Avoids too many dead branches causing updates to run forever.
16
+
17
+ ## v0.1.0 (2016/02/09)
18
+
19
+ * Incompatible changes
20
+ * The `distribution` setting is now a stack of distributor definitions to be
21
+ applied in order as a series of overlays in the release area.
22
+ * Provides the `distribution:set_current_revision` task used by newer
23
+ Capistrano releases.
24
+ * A `release_id` setting is required to provide a reasonable value.
25
+
26
+ ## v0.0.2 (2014/03/17)
27
+
28
+ * Ensure that the internal_path attribute of AbstractArchiver is a Pathname
29
+ * Fixes extraction of ZIP archives.
30
+ * Silence curl and unzip in the CurlZip distributor
31
+ * Silence unzip in the Zip distributor
32
+
33
+ ## v0.0.1 (2014/02/27)
34
+
35
+ * Birthday
data/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Capistrano Distribution: More Than Just Git Deployments
2
+
3
+ Flexible distribution for Capistrano 3.x.
4
+
5
+ ## LINKS
6
+
7
+ * Homepage :: http://github.com/spiceworks/capistrano-distribution
8
+ * Documentation :: http://rdoc.info/gems/capistrano-distribution/frames
9
+ * Source :: http://github.com/spiceworks/capistrano-distribution
10
+
11
+ ## DESCRIPTION
12
+
13
+ This gem hooks into the SCM functionality of Capistrano 3.x in order to provide
14
+ a more generic distribution strategy. Not only is it possible to deploy from a
15
+ simple Git repository, but deployment of contents from Tar and ZIP files is also
16
+ possible. It is even easy to create deployments based on multiple sources.
17
+
18
+ With the exception of the Git push method, all distribution operations pull
19
+ content from providers on each target host. For Git-based distributions
20
+ whether using the push or pull method, this is very efficient after the first
21
+ deployment because a mirror git repository is saved on each host such that only
22
+ differentials are needed for future deployments. All other types perform a
23
+ full download of the source artifact, so these could be expensive and/or slow.
24
+
25
+ ## Features
26
+
27
+ * Distribute from Git repositories and Tar/Zip archives.
28
+ * Use remote and local sources, anything supported by Git and Curl.
29
+ * Create homogenous deployments from multiple sources.
30
+
31
+ ## Known Bugs/Limitations
32
+
33
+ * None so far...
34
+
35
+ ## SYNOPSIS
36
+
37
+ Simple Git-based distribution (master branch of the current repository):
38
+
39
+ ```ruby
40
+ # config/deploy.rb
41
+ ...
42
+ set :scm, :distribution
43
+ set :release_id, ->{ `git rev-parse HEAD`.chomp }
44
+ set :distribution, ->{
45
+ [[
46
+ 'http://example.com/repositories/example.git',
47
+ fetch(:release_id)
48
+ ]]
49
+ }
50
+ ...
51
+ ```
52
+
53
+ Simple Tar-based distribution (everything in the `example.tar.gz` archive is
54
+ within an `example` subdirectory):
55
+
56
+ ```ruby
57
+ # config/deploy.rb
58
+ ...
59
+ set :scm, :distribution
60
+ set :release_id, ->{ "example-#{fetch(:release_timestamp)}" }
61
+ set :distribution, 'http://example.com/tarballs/example.tar.gz'
62
+ ...
63
+ ```
64
+
65
+ Heterogenous distribution (a Redmine deployment with plugins):
66
+
67
+ ```ruby
68
+ # config/deploy.rb
69
+ ...
70
+ set :scm, :distribution
71
+ set :release_id, ->{ "2.3.4-#{fetch(:release_timestamp)}" }
72
+ set :distribution,
73
+ [
74
+ 'http://www.redmine.org/releases/redmine-2.3.4.tar.gz'
75
+ ],
76
+ [
77
+ 'https://bitbucket.org/akiko_pusu/redmine_issue_templates/get/0.0.4.tar.gz',
78
+ {
79
+ subtree: 'akiko_pusu-redmine_issue_templates-b885dfe8263d',
80
+ target: 'plugins/redmine_issue_templates'
81
+ }
82
+ ],
83
+ [
84
+ 'https://bitbucket.org/haru_iida/redmine_code_review/get/0.6.2.tar.gz',
85
+ {
86
+ subtree: 'haru_iida-redmine_code_review-e79f98b8a77f',
87
+ target: 'plugins/redmine_code_review'
88
+ }
89
+ ],
90
+ [
91
+ 'https://github.com/Undev/notify_custom_users/archive/0.0.5.tar.gz',
92
+ {
93
+ subtree: 'notify_custom_users-0.0.5',
94
+ target: 'plugins/notify_custom_users'
95
+ }
96
+ ],
97
+ [
98
+ 'https://github.com/thorin/redmine_ldap_sync/archive/2.0.3.tar.gz',
99
+ {
100
+ subtree: 'redmine_ldap_sync-2.0.3',
101
+ target: 'plugins/redmine_ldap_sync'
102
+ }
103
+ ]
104
+ ...
105
+ ```
106
+
107
+ ## REQUIREMENTS
108
+
109
+ * Git binary (for Git repositories)
110
+ * Curl binary (for remote archives)
111
+ * Unzip binary (for ZIP archives)
112
+ * Tar binary (for Tar archives)
113
+
114
+ ## DEVELOPERS
115
+
116
+ After checking out the source, run:
117
+
118
+ $ bundle install
119
+ $ bundle exec rake test yard
120
+
121
+ This will install all dependencies, run the tests/specs, and generate the
122
+ documentation.
123
+
124
+ ## AUTHORS
125
+
126
+ Thanks to all contributors. Without your help this project would not exist.
127
+
128
+ * Jeremy Bopp :: jeremyb@spiceworks.com
129
+
130
+ ## Contributing
131
+
132
+ Contributions for bug fixes, documentation, extensions, tests, etc. are
133
+ encouraged.
134
+
135
+ 1. Clone the repository.
136
+ 2. Fix a bug or add a feature.
137
+ 3. Add tests for the fix or feature.
138
+ 4. Make a pull request.
139
+
140
+ ## LICENSE
141
+
142
+ ```
143
+ (The MIT License)
144
+
145
+ Copyright (c) 2014 Spiceworks, Inc.
146
+
147
+ Permission is hereby granted, free of charge, to any person obtaining
148
+ a copy of this software and associated documentation files (the
149
+ 'Software'), to deal in the Software without restriction, including
150
+ without limitation the rights to use, copy, modify, merge, publish,
151
+ distribute, sublicense, and/or sell copies of the Software, and to
152
+ permit persons to whom the Software is furnished to do so, subject to
153
+ the following conditions:
154
+
155
+ The above copyright notice and this permission notice shall be
156
+ included in all copies or substantial portions of the Software.
157
+
158
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
159
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
160
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
161
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
162
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
163
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
164
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
165
+ ```
data/Rakefile ADDED
@@ -0,0 +1,243 @@
1
+ # encoding: UTF-8
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+
6
+ require 'erb'
7
+ require 'rake/testtask'
8
+ require 'rubygems/package_task'
9
+ require 'rake/clean'
10
+ require 'yard'
11
+
12
+ # Load the gemspec file for this project.
13
+ GEMSPEC = Dir['*.gemspec'].first
14
+ SPEC = eval(File.read(GEMSPEC), nil, GEMSPEC)
15
+
16
+ # The path to the version.rb file and a string to eval to find the version.
17
+ VERSION_RB = "lib/#{SPEC.name.gsub('-', '/')}/version.rb"
18
+ VERSION_REF =
19
+ "#{SPEC.name.split('-').map { |p| p.split('_').map(&:capitalize).join }.join('::')}::VERSION"
20
+
21
+ # A dynamically generated list of files that should match the manifest (the
22
+ # combined contents of SPEC.files and SPEC.test_files). The idea is for this
23
+ # list to contain all project files except for those that have been explicitly
24
+ # excluded. This list will be compared with the manifest from the SPEC in order
25
+ # to help catch the addition or removal of files to or from the project that
26
+ # have not been accounted for either by an exclusion here or an inclusion in the
27
+ # SPEC manifest.
28
+ #
29
+ # NOTE:
30
+ # It is critical that the manifest is *not* automatically generated via globbing
31
+ # and the like; otherwise, this will yield a simple comparison between
32
+ # redundantly generated lists of files that probably will not protect the
33
+ # project from the unintentional inclusion or exclusion of files in the
34
+ # distribution.
35
+ PKG_FILES = FileList.new(Dir.glob('**/*', File::FNM_DOTMATCH)) do |files|
36
+ # Exclude anything that doesn't exist as well as directories.
37
+ files.exclude {|file| ! File.exist?(file) || File.directory?(file)}
38
+ # Exclude Git administrative files.
39
+ files.exclude(%r{(^|[/\\])\.git(ignore|modules|keep)?([/\\]|$)})
40
+ # Exclude editor swap/temporary files.
41
+ files.exclude('**/.*.sw?')
42
+ # Exclude the gemspec file.
43
+ files.exclude(GEMSPEC)
44
+ # Exclude the README template file.
45
+ files.exclude('README.md.erb')
46
+ # Exclude resources for bundler.
47
+ files.exclude('Gemfile', 'Gemfile.lock')
48
+ files.exclude(%r{^.bundle([/\\]|$)})
49
+ files.exclude(%r{^vendor/bundle([/\\]|$)})
50
+ # Exclude generated content, except for the README file.
51
+ files.exclude(%r{^(pkg|doc|.yardoc)([/\\]|$)})
52
+ # Exclude Rubinius compiled Ruby files.
53
+ files.exclude('**/*.rbc')
54
+ end
55
+
56
+ # Make sure that :clean and :clobber will not whack the repository files.
57
+ CLEAN.exclude('.git/**')
58
+ # Vim swap files are fair game for clean up.
59
+ CLEAN.include('**/.*.sw?')
60
+
61
+ # Returns the value of the VERSION environment variable as a Gem::Version object
62
+ # assuming it is set and a valid Gem version string. Otherwise, raises an
63
+ # exception.
64
+ def get_version_argument
65
+ version = ENV['VERSION']
66
+ if version.to_s.empty?
67
+ raise "No version specified: Add VERSION=X.Y.Z to the command line"
68
+ end
69
+ begin
70
+ Gem::Version.create(version.dup)
71
+ rescue ArgumentError
72
+ raise "Invalid version specified in `VERSION=#{version}'"
73
+ end
74
+ end
75
+
76
+ # Performs an in place, per line edit of the file indicated by _path_ by calling
77
+ # the sub method on each line and passing _pattern_, _replacement_, and _b_ as
78
+ # arguments.
79
+ def file_sub(path, pattern, replacement = nil, &b)
80
+ tmp_path = "#{path}.tmp"
81
+ File.open(path) do |infile|
82
+ File.open(tmp_path, 'w') do |outfile|
83
+ infile.each do |line|
84
+ outfile.write(line.sub(pattern, replacement, &b))
85
+ end
86
+ end
87
+ end
88
+ File.rename(tmp_path, path)
89
+ end
90
+
91
+ # Updates the version string in the gemspec file and a version.rb file it to the
92
+ # string in _version_.
93
+ def set_version(version)
94
+ file_sub(GEMSPEC, /(\.version\s*=\s*).*/, "\\1'#{version}'")
95
+ file_sub(VERSION_RB, /^(\s*VERSION\s*=\s*).*/, "\\1'#{version}'")
96
+ end
97
+
98
+ # Returns a string that is line wrapped at word boundaries, where each line is
99
+ # no longer than _line_width_ characters.
100
+ #
101
+ # This is mostly lifted directly from ActionView::Helpers::TextHelper.
102
+ def word_wrap(text, line_width = 80)
103
+ text.split("\n").collect do |line|
104
+ line.length > line_width ?
105
+ line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip :
106
+ line
107
+ end * "\n"
108
+ end
109
+
110
+ desc 'Alias for build:gem'
111
+ task :build => 'build:gem'
112
+
113
+ # Build related tasks.
114
+ namespace :build do
115
+ # Create the gem and package tasks.
116
+ Gem::PackageTask.new(SPEC).define
117
+
118
+ # Ensure that the that the manifest is consulted when building the gem. Any
119
+ # generated/compiled files should be available at that time.
120
+ task :gem => :check_manifest
121
+
122
+ desc 'Verify the manifest'
123
+ task :check_manifest do
124
+ manifest_files = (SPEC.files + SPEC.test_files).sort.uniq
125
+ pkg_files = PKG_FILES.sort.uniq
126
+ if manifest_files != pkg_files then
127
+ common_files = manifest_files & pkg_files
128
+ manifest_files -= common_files
129
+ pkg_files -= common_files
130
+ message = ["The manifest does not match the automatic file list."]
131
+ unless manifest_files.empty? then
132
+ message << " Extraneous files:\n " + manifest_files.join("\n ")
133
+ end
134
+ unless pkg_files.empty?
135
+ message << " Missing files:\n " + pkg_files.join("\n ")
136
+ end
137
+ raise message.join("\n")
138
+ end
139
+ end
140
+
141
+ # Creates the README.md file from a template and the gemspec contents.
142
+ file 'README.md' => ['README.md.erb', GEMSPEC] do
143
+ spec = SPEC
144
+ File.open('README.md', 'w') do |readme|
145
+ readme.write(
146
+ ERB.new(File.read('README.md.erb'), nil, '-').result(binding)
147
+ )
148
+ end
149
+ end
150
+ end
151
+
152
+ # Ensure that the clobber task also clobbers package files.
153
+ task :clobber => 'build:clobber_package'
154
+
155
+ # Create the documentation task.
156
+ YARD::Rake::YardocTask.new
157
+ # Ensure that the README file is (re)generated first.
158
+ task :yard => 'README.md'
159
+
160
+ # Gem related tasks.
161
+ namespace :gem do
162
+ desc 'Alias for build:gem'
163
+ task :build => 'build:gem'
164
+
165
+ desc 'Publish the gemfile'
166
+ task :publish => ['version:check', :test, 'repo:tag', :build] do
167
+ sh "gem push pkg/#{SPEC.name}-#{SPEC.version}*.gem"
168
+ end
169
+ end
170
+
171
+ Rake::TestTask.new do |t|
172
+ t.pattern = 'spec/**/*_spec.rb'
173
+ end
174
+
175
+ # Version string management tasks.
176
+ namespace :version do
177
+ desc 'Set the version for the project to a specified version'
178
+ task :set do
179
+ set_version(get_version_argument)
180
+ end
181
+
182
+ desc 'Set the version for the project back to 0.0.0'
183
+ task :reset do
184
+ set_version('0.0.0')
185
+ end
186
+
187
+ desc 'Check that all version strings are correctly set'
188
+ task :check => ['version:check:spec', 'version:check:version_rb', 'version:check:news']
189
+
190
+ namespace :check do
191
+ desc 'Check that the version in the gemspec is correctly set'
192
+ task :spec do
193
+ version = get_version_argument
194
+ if version != SPEC.version
195
+ raise "The given version `#{version}' does not match the gemspec version `#{SPEC.version}'"
196
+ end
197
+ end
198
+
199
+ desc 'Check that the version in the version.rb file is correctly set'
200
+ task :version_rb do
201
+ version = get_version_argument
202
+ begin
203
+ load VERSION_RB
204
+ internal_version = Gem::Version.create(eval(VERSION_REF))
205
+ if version != internal_version
206
+ raise "The given version `#{version}' does not match the version.rb version `#{internal_version}'"
207
+ end
208
+ rescue ArgumentError
209
+ raise "Invalid version specified in `#{VERSION_RB}'"
210
+ end
211
+ end
212
+
213
+ desc 'Check that the NEWS.md file mentions the version'
214
+ task :news do
215
+ version = get_version_argument
216
+ begin
217
+ File.open('NEWS.md') do |news|
218
+ unless news.each_line.any? {|l| l =~ /^## v#{Regexp.escape(version.to_s)} /}
219
+ raise "The NEWS.md file does not mention version `#{version}'"
220
+ end
221
+ end
222
+ rescue Errno::ENOENT
223
+ raise 'No NEWS.md file found'
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ # Repository and workspace management tasks.
230
+ namespace :repo do
231
+ desc 'Tag the current HEAD with the version string'
232
+ task :tag => :check_workspace do
233
+ version = get_version_argument
234
+ sh "git tag -s -m 'Release v#{version}' v#{version}"
235
+ end
236
+
237
+ desc 'Ensure the workspace is fully committed and clean'
238
+ task :check_workspace => ['README.md'] do
239
+ unless `git status --untracked-files=all --porcelain`.empty?
240
+ raise 'Workspace has been modified. Commit pending changes and try again.'
241
+ end
242
+ end
243
+ end
@@ -0,0 +1,85 @@
1
+ module Capistrano
2
+ class Distribution
3
+ module Distributor
4
+
5
+ ##
6
+ # @abstract Subclass and override {#check} and {#distribute} to create a
7
+ # distributor.
8
+ #
9
+ # An abstract distributor upon which all distributors should ultimately be
10
+ # based.
11
+ #
12
+ # See the existing concrete distributor definitions for examples.
13
+ class Abstract
14
+ ##
15
+ # @param context [(#test, #execute)] a Capistrano context used to run
16
+ # commands.
17
+ # @param url [URI, String] a URL to be used for fetching the artifact to be
18
+ # distributed
19
+ # @param opts [Hash] options to override default settings
20
+ # @option opts [String] :target ('') a path within the release area to be the
21
+ # root of the distribution.
22
+ def initialize(context, url, opts = {})
23
+ @context = context
24
+ @url = URI === url ? url : URI.parse(url)
25
+ @target = opts.fetch(:target, '')
26
+
27
+ @repo_id = Digest::SHA1.hexdigest(url.to_s)
28
+ end
29
+
30
+ ##
31
+ # @abstract Override to provide a meaningful check for prerequisites during
32
+ # deployment.
33
+ #
34
+ # @return [Boolean] +true+ when prerequisites are met and +false+
35
+ # otherwise.
36
+ def check
37
+ false
38
+ end
39
+
40
+ ##
41
+ # @abstract Override to provide meaningful distribution logic during
42
+ # deployment.
43
+ #
44
+ # @return [nil]
45
+ #
46
+ # @raise [exception] when distribution fails.
47
+ def distribute
48
+ end
49
+
50
+ private
51
+
52
+ ##
53
+ # The source URL for the artifact to be distributed.
54
+ attr_reader :url
55
+
56
+ ##
57
+ # The Capistrano context in which the distributor will operate.
58
+ attr_reader :context
59
+
60
+ ##
61
+ # A unique identifier for the distributor for use under {#repo_path}.
62
+ attr_reader :repo_id
63
+
64
+ ##
65
+ # A path relative to the release location in which to distribute the artifact.
66
+ attr_reader :target
67
+
68
+ ##
69
+ # @return [Pathname] a path to the release location in which to distribute the
70
+ # artifact based on {#target}
71
+ def release_path
72
+ context.release_path.join(target)
73
+ end
74
+
75
+ ##
76
+ # @return [Pathname] a path under the repo location to a unique workspace for
77
+ # the distributor
78
+ def repo_path
79
+ context.repo_path.join(repo_id)
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,60 @@
1
+ require 'pathname'
2
+
3
+ require 'capistrano/distribution/distributor/abstract'
4
+
5
+ module Capistrano
6
+ class Distribution
7
+ module Distributor
8
+
9
+ ##
10
+ # @abstract Subclass and override {#distribute} to create a distributor that
11
+ # extracts archives found on the local filesystem.
12
+ #
13
+ # A convenience class for distributors that extract an archive file.
14
+ class AbstractArchiver < Abstract
15
+ ##
16
+ # A regexp that matches file extentions typically found on archives used to
17
+ # distribute program binaries and source releases.
18
+ EXT_MATCHER = %r{(\.[^\d.]+[^.]*)+$}
19
+
20
+ ##
21
+ # @param context [{#test, #execute}] a Capistrano context used to run
22
+ # commands.
23
+ # @param url [URI, String] a URL to be used for fetching the artifact to be
24
+ # distributed
25
+ # @param opts [Hash] options to override default settings
26
+ # @option opts [String] :subtree a path within the archive to extract as if
27
+ # its contents were at the root of the archive
28
+ def initialize(context, url, opts = {})
29
+ super(context, url, opts)
30
+ @subtree = Pathname.new(
31
+ opts.fetch(:subtree, File.basename(url).sub(ext_matcher, ''))
32
+ )
33
+ end
34
+
35
+ ##
36
+ # Tests whether or not the archive indicated by {#url} is locally available.
37
+ #
38
+ # @return [Boolean] +true+ if the archive is available; otherwise, +false+.
39
+ #
40
+ # @see Abstract#check
41
+ def check
42
+ context.test '[', '-f', url.path, ']'
43
+ end
44
+
45
+ private
46
+
47
+ ##
48
+ # The path within the archive to extract. May be an empty string.
49
+ attr_reader :subtree
50
+
51
+ ##
52
+ # @return [Regexp] a regexp that matches file extentions.
53
+ def ext_matcher
54
+ EXT_MATCHER
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,28 @@
1
+ require 'capistrano/distribution/distributor/abstract_archiver'
2
+
3
+ module Capistrano
4
+ class Distribution
5
+ module Distributor
6
+
7
+ ##
8
+ # @abstract Subclass and override {#distribute} to create a distributor that
9
+ # extracts archives reachable via +curl+ command.
10
+ #
11
+ # A convenience class for distributors that extract an archive downloaded using
12
+ # the +curl+ command.
13
+ class AbstractCurl < AbstractArchiver
14
+ ##
15
+ # Tests whether or not the archive indicated by {#url} is available via the
16
+ # +curl+ command.
17
+ #
18
+ # @return [Boolean] +true+ if the archive is available; otherwise, +false+.
19
+ #
20
+ # @see Abstract#check
21
+ def check
22
+ context.test 'curl', '--fail', '--location', '--silent', '--head', '--request', 'GET', url
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end