capistrano-git-copy 1.1.0 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d4ae3564eccef2c188c4176c2ad8f2276b1f7c88
4
- data.tar.gz: 993bfa2dc61a9c78376b5af0847f7c0fed5c6ae3
3
+ metadata.gz: e7784ccb4cb4af337de3e9023b46775da88e48e4
4
+ data.tar.gz: 7f9abc9ceefb06d7247ecdc7c6080bdb2dd6a751
5
5
  SHA512:
6
- metadata.gz: 4833479a333245dda86f3b10fe27b90fd5050be08b9ec10444d751c11745c75d586de4d6e67b5d25ea1d1869b888aeb22aa1e71f219579f268f839a76b98c7b5
7
- data.tar.gz: 31bd01e829bd93683883deb00a2ba0f960979d1f5badd3e77b4f7e6d855eb8b0a12b9607e05e98b676d2d87de7a22de1312c8989da00f3455abdee9e442a024e
6
+ metadata.gz: 8dd0c5ad1efaf9c7c8a9da570d2c4bd51c4ecc52f3c85c8d8edffdea818d03489d628e5de526e18f5f8049491ee2cac52735c1a86fb40ed9ac8cc6d51fb89073
7
+ data.tar.gz: 10200bb1f194a6489a2cfc77a8086d093a6bda24349f1a56c49b585c88cd8d6d5e596972363ed7d54e1a1a7f7dafbbba6ba32b5fe266d9c3f8893d1d9951ec3b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 1.2.0 (2016-01-25)
4
+ ### Changes
5
+ - Check if local repository mirror is working and reinitialize if necessary
6
+ - Added config option `git_excludes` to exclude files and directories
7
+ - updated _git-archive-all_ to v1.13
8
+
3
9
  ## 1.1.0 (2015-08-10)
4
10
  ### Changes
5
11
  - Deprecated: require 'capistrano/git/copy'
data/README.md CHANGED
@@ -29,12 +29,17 @@ Now use `git_copy` as your SCM type in your `config/deploy.rb`:
29
29
 
30
30
  set :scm, :git_copy
31
31
 
32
- By default, it includes all submodules into the deployment package. However,
33
- if they are not needed in a particular deployment, you can disable them with
32
+ By default, it includes all submodules into the deployment package. However,
33
+ if they are not needed in a particular deployment, you can disable them with
34
34
  a configuration option:
35
35
 
36
36
  set :with_submodules, false
37
37
 
38
+ Besides using `export-ignore` in `.gitattributes` it's possible exclude files and directories by
39
+ adding them to `git_excludes`:
40
+
41
+ set :git_excludes, %w(config/database.yml.example test rspec)
42
+
38
43
  ## Notes
39
44
 
40
45
  * Uses [git-archive-all](https://github.com/Kentzo/git-archive-all) for bundling repositories.
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = 'https://github.com/ydkn/capistrano-git-copy'
14
14
  spec.license = 'MIT'
15
15
 
16
- spec.files = `git ls-files`.split($/) + %w( vendor/git-archive-all/git-archive-all )
16
+ spec.files = `git ls-files`.split($/) + %w( vendor/git-archive-all/git_archive_all.py )
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
@@ -1 +1 @@
1
- STDERR.puts("[DEPRECATION] Please change \"require 'capistrano/git/copy'\" to \"require 'capistrano/git_copy'\" in your Capfile.")
1
+ STDERR.puts("[DEPRECATION] Please change \"require 'capistrano/git/copy'\" to \"require 'capistrano/git_copy'\" in your Capfile, and make sure to disable the default require in your Gemfile with 'gem \"capistrano-git-copy\", require: false\"' to make this warning disappear.")
@@ -1,6 +1,7 @@
1
1
  namespace :load do
2
2
  task :defaults do
3
- set :with_submodules, true
3
+ set :with_submodules, fetch(:with_submodules, true)
4
+ set :git_excludes, fetch(:git_excludes, [])
4
5
  end
5
6
  end
6
7
 
@@ -6,53 +6,66 @@ module Capistrano
6
6
  # Utility stuff to avoid cluttering of deploy.cap
7
7
  class Utility
8
8
  attr_reader :with_submodules
9
+ attr_reader :git_excludes
9
10
 
10
11
  def initialize(context)
11
- @context = context
12
+ @context = context
12
13
  @with_submodules = fetch(:with_submodules, true)
14
+ @git_excludes = fetch(:git_excludes, [])
13
15
  end
14
16
 
15
- # Check if repo cache exists
17
+ # Check if repo cache exists and is valid
16
18
  #
17
19
  # @return [Boolean] indicates if repo cache exists
18
20
  def test
19
- test! " [ -d #{repo_path} ] "
21
+ if test!("[ -d #{repo_path} ]")
22
+ @context.within(repo_path) do
23
+ if test!(:git, :status, '>/dev/null 2>/dev/null')
24
+ true
25
+ else
26
+ execute(:rm, '-rf', repo_path)
27
+ false
28
+ end
29
+ end
30
+ else
31
+ false
32
+ end
20
33
  end
21
34
 
22
35
  # Check if repo is accessible
23
36
  #
24
37
  # @return void
25
38
  def check
26
- git :'ls-remote --heads', repo_url
39
+ git(:'ls-remote --heads', repo_url)
27
40
  end
28
41
 
29
42
  # Clone repo to cache
30
43
  #
31
44
  # @return void
32
45
  def clone
33
- execute :mkdir, '-p', tmp_path
46
+ execute(:mkdir, '-p', tmp_path)
34
47
 
35
- git :clone, fetch(:repo_url), repo_path
48
+ git(:clone, fetch(:repo_url), repo_path)
36
49
  end
37
50
 
38
51
  # Update repo and submodules to branch
39
52
  #
40
53
  # @return void
41
54
  def update
42
- git :remote, :update
43
- git :reset, '--hard', commit_hash
55
+ git(:remote, :update)
56
+ git(:reset, '--hard', commit_hash)
44
57
 
45
58
  # submodules
46
59
  if with_submodules
47
- git :submodule, :init
48
- git :submodule, :update
49
- git :submodule, :foreach, '--recursive', :git, :submodule, :update, '--init'
60
+ git(:submodule, :init)
61
+ git(:submodule, :update)
62
+ git(:submodule, :foreach, '--recursive', :git, :submodule, :update, '--init')
50
63
  end
51
64
 
52
65
  # cleanup
53
- git :clean, '-d', '-f'
66
+ git(:clean, '-d', '-f')
54
67
  if with_submodules
55
- git :submodule, :foreach, '--recursive', :git, :clean, '-d', '-f'
68
+ git(:submodule, :foreach, '--recursive', :git, :clean, '-d', '-f')
56
69
  end
57
70
  end
58
71
 
@@ -61,9 +74,30 @@ module Capistrano
61
74
  # @return void
62
75
  def prepare_release
63
76
  if with_submodules
64
- execute git_archive_all_bin, "--prefix=''", archive_path
77
+ execute(git_archive_all_bin, "--prefix=''", archive_path)
65
78
  else
66
- git "archive --format=tar HEAD | gzip > #{archive_path}"
79
+ git(:archive, '--format=tar', 'HEAD', '|', 'gzip', "> #{archive_path}")
80
+ end
81
+
82
+ if git_excludes.count > 0
83
+ archive_dir = File.join(tmp_path, 'archive')
84
+
85
+ execute :rm, '-rf', archive_dir
86
+ execute :mkdir, '-p', archive_dir
87
+ execute :tar, '-xzf', archive_path, '-C', archive_dir
88
+
89
+ git_excludes.each do |f|
90
+ file_path = File.join(archive_dir, f.gsub(/\A\//, ''))
91
+
92
+ unless File.exists?(file_path)
93
+ warn("#{f} does not exists!")
94
+ next
95
+ end
96
+
97
+ FileUtils.rm_rf(file_path)
98
+ end
99
+
100
+ execute :tar, '-czf', archive_path, '-C', archive_dir, '.'
67
101
  end
68
102
  end
69
103
 
@@ -73,11 +107,11 @@ module Capistrano
73
107
  def release
74
108
  remote_archive_path = File.join(fetch(:deploy_to), File.basename(archive_path))
75
109
 
76
- upload! archive_path, remote_archive_path
110
+ upload!(archive_path, remote_archive_path)
77
111
 
78
- execute :mkdir, '-p', release_path
79
- execute :tar, '-f', remote_archive_path, '-x', '-C', release_path
80
- execute :rm, '-f', remote_archive_path
112
+ execute(:mkdir, '-p', release_path)
113
+ execute(:tar, '-f', remote_archive_path, '-x', '-C', release_path)
114
+ execute(:rm, '-f', remote_archive_path)
81
115
  end
82
116
 
83
117
  # Set deployed revision
@@ -91,9 +125,9 @@ module Capistrano
91
125
  #
92
126
  # @return void
93
127
  def cleanup
94
- execute :rm, '-rf', tmp_path
128
+ execute(:rm, '-rf', tmp_path)
95
129
 
96
- info 'Local repo cache was removed'
130
+ info('Local repo cache was removed')
97
131
  end
98
132
 
99
133
  # Temporary path for all git-copy operations
@@ -143,12 +177,16 @@ module Capistrano
143
177
  @context.info(*args)
144
178
  end
145
179
 
180
+ def warn(*args)
181
+ @context.warn(*args)
182
+ end
183
+
146
184
  def git(*args)
147
185
  execute(:git, *args)
148
186
  end
149
187
 
150
188
  def git_archive_all_bin
151
- File.expand_path('../../../../vendor/git-archive-all/git-archive-all', __FILE__)
189
+ File.expand_path('../../../../vendor/git-archive-all/git_archive_all.py', __FILE__)
152
190
  end
153
191
 
154
192
  def deploy_id
@@ -165,7 +203,7 @@ module Capistrano
165
203
 
166
204
  branch = fetch(:branch, 'master').to_s.strip
167
205
 
168
- if test! :git, 'rev-parse', "origin/#{branch}", '>/dev/null 2>/dev/null'
206
+ if test!(:git, 'rev-parse', "origin/#{branch}", '>/dev/null 2>/dev/null')
169
207
  @_commit_hash = capture(:git, 'rev-parse', "origin/#{branch}").strip
170
208
  else
171
209
  @_commit_hash = capture(:git, 'rev-parse', branch).strip
@@ -3,6 +3,6 @@ module Capistrano
3
3
  # GitCopy
4
4
  module GitCopy
5
5
  # gem version
6
- VERSION = '1.1.0'
6
+ VERSION = '1.2.0'
7
7
  end
8
8
  end
@@ -1,11 +1,31 @@
1
1
  #! /usr/bin/env python
2
2
  # coding=utf-8
3
3
 
4
+ # The MIT License (MIT)
5
+ #
6
+ # Copyright (c) 2010 Ilya Kulakov
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ # of this software and associated documentation files (the "Software"), to deal
10
+ # in the Software without restriction, including without limitation the rights
11
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ # copies of the Software, and to permit persons to whom the Software is
13
+ # furnished to do so, subject to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be included in
16
+ # all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ # THE SOFTWARE.
25
+
4
26
  from __future__ import print_function
5
27
  from __future__ import unicode_literals
6
28
 
7
- __version__ = "1.9"
8
-
9
29
  import logging
10
30
  from os import extsep, path, readlink, curdir
11
31
  from subprocess import CalledProcessError, Popen, PIPE
@@ -13,6 +33,8 @@ import sys
13
33
  import tarfile
14
34
  from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED
15
35
 
36
+ __version__ = "1.13"
37
+
16
38
 
17
39
  class GitArchiver(object):
18
40
  """
@@ -64,9 +86,12 @@ class GitArchiver(object):
64
86
  try:
65
87
  self.run_shell("[ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1", main_repo_abspath)
66
88
  except Exception as e:
67
- raise ValueError("Not a git repository (or any of the parent directories).")
89
+ raise ValueError("{0} not a git repository (or any of the parent directories).".format(main_repo_abspath))
68
90
 
69
- main_repo_abspath = path.abspath(self.read_git_shell('git rev-parse --show-toplevel', main_repo_abspath).rstrip())
91
+ main_repo_abspath = path.abspath(
92
+ self.read_git_shell('git rev-parse --show-toplevel', main_repo_abspath)
93
+ .rstrip()
94
+ )
70
95
 
71
96
  self.prefix = prefix
72
97
  self.exclude = exclude
@@ -94,7 +119,7 @@ class GitArchiver(object):
94
119
  if output_format is None:
95
120
  file_name, file_ext = path.splitext(output_path)
96
121
  output_format = file_ext[len(extsep):].lower()
97
- self.LOG.debug("Output format is not explicitly set, determined format is {}.".format(output_format))
122
+ self.LOG.debug("Output format is not explicitly set, determined format is {0}.".format(output_format))
98
123
 
99
124
  if not dry_run:
100
125
  if output_format == 'zip':
@@ -116,21 +141,25 @@ class GitArchiver(object):
116
141
  elif output_format == 'txz':
117
142
  t_mode = 'w:xz'
118
143
  else:
119
- t_mode = 'w:{}'.format(output_format)
144
+ t_mode = 'w:{0}'.format(output_format)
120
145
 
121
146
  archive = tarfile.open(path.abspath(output_path), t_mode)
122
- add_file = lambda file_path, arcname: archive.add(file_path, arcname)
147
+
148
+ def add_file(file_path, arcname):
149
+ archive.add(file_path, arcname)
123
150
  else:
124
- raise RuntimeError("Unknown format: {}".format(output_format))
151
+ raise RuntimeError("Unknown format: {0}".format(output_format))
125
152
 
126
153
  def archiver(file_path, arcname):
127
- self.LOG.debug("Compressing {} => {}...".format(file_path, arcname))
154
+ self.LOG.debug("Compressing {0} => {1}...".format(file_path, arcname))
128
155
  add_file(file_path, arcname)
129
156
  else:
130
157
  archive = None
131
- archiver = lambda file_path, arcname: self.LOG.info("{} => {}".format(file_path, arcname))
132
158
 
133
- self.archive_all_files(archiver)
159
+ def archiver(file_path, arcname):
160
+ self.LOG.info("{0} => {1}".format(file_path, arcname))
161
+
162
+ self.archive_all_files(archiver) # this will take care of submodule init and update
134
163
 
135
164
  if archive is not None:
136
165
  archive.close()
@@ -225,7 +254,7 @@ class GitArchiver(object):
225
254
  patterns = exclude_patterns[key]
226
255
  for p in patterns:
227
256
  if fnmatch(file_name, p) or fnmatch(repo_file_path, p):
228
- self.LOG.debug("Exclude pattern matched {}: {}".format(p, repo_file_path))
257
+ self.LOG.debug("Exclude pattern matched {0}: {1}".format(p, repo_file_path))
229
258
  is_excluded = True
230
259
 
231
260
  if not len(components):
@@ -239,7 +268,8 @@ class GitArchiver(object):
239
268
  """
240
269
  Archive all files using archiver.
241
270
 
242
- @param archiver: Function that accepts 2 arguments: abspath to file on the system and relative path within archive.
271
+ @param archiver: Callable that accepts 2 arguments:
272
+ abspath to file on the system and relative path within archive.
243
273
  """
244
274
  for file_path in self.extra:
245
275
  archiver(path.abspath(file_path), path.join(self.prefix, file_path))
@@ -263,7 +293,10 @@ class GitArchiver(object):
263
293
  @return: Iterator to traverse files under git control relative to main_repo_abspath.
264
294
  """
265
295
  repo_abspath = path.join(self.main_repo_abspath, repo_path)
266
- repo_file_paths = self.read_git_shell("git ls-files --cached --full-name --no-empty-directory", repo_abspath).splitlines()
296
+ repo_file_paths = self.read_git_shell(
297
+ "git ls-files --cached --full-name --no-empty-directory",
298
+ repo_abspath
299
+ ).splitlines()
267
300
  exclude_patterns = self.get_exclude_patterns(repo_abspath, repo_file_paths)
268
301
 
269
302
  for repo_file_path in repo_file_paths:
@@ -273,7 +306,9 @@ class GitArchiver(object):
273
306
  main_repo_file_path = path.join(repo_path, repo_file_path) # file path relative to the main repo
274
307
 
275
308
  # Only list symlinks and files that don't start with git.
276
- if file_name.startswith(".git") or (not path.islink(main_repo_file_path) and path.isdir(main_repo_file_path)):
309
+ if file_name.startswith(".git") or (
310
+ not path.islink(main_repo_file_path) and path.isdir(main_repo_file_path)
311
+ ):
277
312
  continue
278
313
 
279
314
  if self.is_file_excluded(repo_abspath, repo_file_path, exclude_patterns):
@@ -322,7 +357,10 @@ class GitArchiver(object):
322
357
  raise ValueError("abspath MUST be absoulte path.")
323
358
 
324
359
  if not path.commonprefix([repo_abspath, abspath]):
325
- raise ValueError("abspath (\"{}\") MUST have common prefix with repo_abspath (\"{}\")".format(abspath, repo_abspath))
360
+ raise ValueError(
361
+ "abspath (\"{0}\") MUST have common prefix with repo_abspath (\"{1}\")"
362
+ .format(abspath, repo_abspath)
363
+ )
326
364
 
327
365
  components = []
328
366
 
@@ -383,7 +421,7 @@ class GitArchiver(object):
383
421
  output = output.decode(encoding)
384
422
 
385
423
  if p.returncode:
386
- if sys.version_info > (2,6):
424
+ if sys.version_info > (2, 6):
387
425
  raise CalledProcessError(returncode=p.returncode, cmd=cmd, output=output)
388
426
  else:
389
427
  raise CalledProcessError(returncode=p.returncode, cmd=cmd)
@@ -411,7 +449,7 @@ class GitArchiver(object):
411
449
  output = output.decode('unicode_escape').encode('raw_unicode_escape').decode('utf-8')
412
450
 
413
451
  if p.returncode:
414
- if sys.version_info > (2,6):
452
+ if sys.version_info > (2, 6):
415
453
  raise CalledProcessError(returncode=p.returncode, cmd=cmd, output=output)
416
454
  else:
417
455
  raise CalledProcessError(returncode=p.returncode, cmd=cmd)
@@ -419,17 +457,22 @@ class GitArchiver(object):
419
457
  return output
420
458
 
421
459
 
422
- if __name__ == '__main__':
460
+ def main():
423
461
  from optparse import OptionParser
424
462
 
425
- parser = OptionParser(usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] [--force-submodules] [--extra EXTRA1 [EXTRA2]] [--dry-run] OUTPUT_FILE",
426
- version="%prog {}".format(__version__))
463
+ parser = OptionParser(
464
+ usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] [--force-submodules]"
465
+ " [--extra EXTRA1 [EXTRA2]] [--dry-run] OUTPUT_FILE",
466
+ version="%prog {0}".format(__version__)
467
+ )
427
468
 
428
469
  parser.add_option('--prefix',
429
470
  type='string',
430
471
  dest='prefix',
431
472
  default=None,
432
- help="prepend PREFIX to each filename in the archive. OUTPUT_FILE name is used by default to avoid tarbomb. You can set it to '' in order to explicitly request tarbomb")
473
+ help="""prepend PREFIX to each filename in the archive.
474
+ OUTPUT_FILE name is used by default to avoid tarbomb.
475
+ You can set it to '' in order to explicitly request tarbomb""")
433
476
 
434
477
  parser.add_option('-v', '--verbose',
435
478
  action='store_true',
@@ -445,7 +488,7 @@ if __name__ == '__main__':
445
488
  parser.add_option('--force-submodules',
446
489
  action='store_true',
447
490
  dest='force_sub',
448
- help="force a git submodule init && git submodule update at each level before iterating submodules")
491
+ help='force a git submodule init && git submodule update at each level before iterating submodules')
449
492
 
450
493
  parser.add_option('--extra',
451
494
  action='append',
@@ -475,7 +518,11 @@ if __name__ == '__main__':
475
518
  import re
476
519
 
477
520
  output_name = path.basename(output_file_path)
478
- output_name = re.sub('(\.zip|\.tar|\.tgz|\.txz|\.gz|\.bz2|\.xz|\.tar\.gz|\.tar\.bz2|\.tar\.xz)$', '', output_name) or "Archive"
521
+ output_name = re.sub(
522
+ '(\.zip|\.tar|\.tgz|\.txz|\.gz|\.bz2|\.xz|\.tar\.gz|\.tar\.bz2|\.tar\.xz)$',
523
+ '',
524
+ output_name
525
+ ) or "Archive"
479
526
  options.prefix = path.join(output_name, '')
480
527
 
481
528
  try:
@@ -489,6 +536,10 @@ if __name__ == '__main__':
489
536
  options.extra)
490
537
  archiver.create(output_file_path, options.dry_run)
491
538
  except Exception as e:
492
- parser.exit(2, "{}\n".format(e))
539
+ parser.exit(2, "{0}\n".format(e))
493
540
 
494
541
  sys.exit(0)
542
+
543
+
544
+ if __name__ == '__main__':
545
+ main()
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-git-copy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Schwab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-10 00:00:00.000000000 Z
11
+ date: 2016-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capistrano
@@ -93,7 +93,7 @@ files:
93
93
  - lib/capistrano/git_copy/tasks/deploy.cap
94
94
  - lib/capistrano/git_copy/utility.rb
95
95
  - lib/capistrano/git_copy/version.rb
96
- - vendor/git-archive-all/git-archive-all
96
+ - vendor/git-archive-all/git_archive_all.py
97
97
  homepage: https://github.com/ydkn/capistrano-git-copy
98
98
  licenses:
99
99
  - MIT
@@ -114,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
114
  version: '0'
115
115
  requirements: []
116
116
  rubyforge_project:
117
- rubygems_version: 2.4.8
117
+ rubygems_version: 2.5.1
118
118
  signing_key:
119
119
  specification_version: 4
120
120
  summary: Copy local git repository deploy strategy for capistrano