capistrano-git-copy 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +5 -0
- data/.gitmodules +1 -1
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +4 -0
- data/README.md +0 -7
- data/capistrano-git-copy.gemspec +5 -6
- data/lib/capistrano/git_copy/scm.rb +12 -82
- data/lib/capistrano/git_copy/scm_helpers.rb +93 -0
- data/lib/capistrano/git_copy/version.rb +1 -1
- data/vendor/git-archive-all/git_archive_all.py +64 -170
- metadata +12 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0193555dcc7eefb6ad1c129cc92d99314fd5631a386f8daf39e4ef53a5ab9d7d'
|
4
|
+
data.tar.gz: 60b392776e795ee02a8cf2af8c4952c8d33eceb9277a2fd7c782e67b01189da3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e125d7493ca8d54242e211604105b5d138e5c1944a165efdd888fde77599204a40ca47dcd9b5ea4ba16d765b6c2af9fdcc2f8cc5bd93435fb3c8158f5f827282
|
7
|
+
data.tar.gz: d5627c293b8a6cf4b614dae2b86779468eb0fd48baa43ea9ad43ff745bc5437a994785f02575221549c1e9b6627ccad340c7abf65c38b875ff5d084973b19c9d
|
data/.gitlab-ci.yml
ADDED
data/.gitmodules
CHANGED
data/.rubocop.yml
ADDED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
[![Gem Version](https://img.shields.io/gem/v/capistrano-git-copy.svg)](https://rubygems.org/gems/capistrano-git-copy)
|
2
|
-
[![Dependencies](https://img.shields.io/gemnasium/ydkn/capistrano-git-copy.svg)](https://gemnasium.com/ydkn/capistrano-git-copy)
|
3
|
-
[![Code Climate](https://img.shields.io/codeclimate/github/ydkn/capistrano-git-copy.svg)](https://codeclimate.com/github/ydkn/capistrano-git-copy)
|
4
|
-
|
5
|
-
[![Join the chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ydkn/capistrano-git-copy)
|
6
|
-
|
7
|
-
|
8
1
|
# Capistrano::GitCopy
|
9
2
|
|
10
3
|
Creates a tar archive locally from the git repository and uploads it to the remote server.
|
data/capistrano-git-copy.gemspec
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'capistrano/git_copy/version'
|
5
4
|
|
@@ -10,17 +9,17 @@ Gem::Specification.new do |spec|
|
|
10
9
|
spec.email = ['me@ydkn.de']
|
11
10
|
spec.description = 'Copy local git repository deploy strategy for capistrano.'
|
12
11
|
spec.summary = 'Copy local git repository deploy strategy for capistrano.'
|
13
|
-
spec.homepage = 'https://
|
12
|
+
spec.homepage = 'https://gitlab.com/ydkn/capistrano-git-copy'
|
14
13
|
spec.license = 'MIT'
|
15
14
|
|
16
|
-
spec.files = `git ls-files`.split(
|
15
|
+
spec.files = `git ls-files`.split("\n") + %w[vendor/git-archive-all/git_archive_all.py]
|
17
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
18
|
spec.require_paths = ['lib']
|
20
19
|
|
21
20
|
spec.add_dependency 'capistrano', '>= 3.7.0', '< 4.0.0'
|
22
21
|
|
23
|
-
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'bundler'
|
24
23
|
spec.add_development_dependency 'rake'
|
25
|
-
spec.add_development_dependency '
|
24
|
+
spec.add_development_dependency 'rubocop'
|
26
25
|
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'tmpdir'
|
2
2
|
require 'capistrano/scm/plugin'
|
3
|
+
require 'capistrano/git_copy/scm_helpers'
|
3
4
|
|
4
5
|
module Capistrano
|
5
6
|
module GitCopy
|
6
7
|
# SCM plugin for capistrano
|
7
8
|
# uses a local clone and uploads a tar archive to the server
|
8
9
|
class SCM < ::Capistrano::SCM::Plugin
|
10
|
+
include Capistrano::GitCopy::SCMHelpers
|
11
|
+
|
9
12
|
# set default values
|
10
13
|
def set_defaults
|
11
14
|
set_if_empty :with_clean, true
|
@@ -16,7 +19,7 @@ module Capistrano
|
|
16
19
|
|
17
20
|
# define plugin tasks
|
18
21
|
def define_tasks
|
19
|
-
eval_rakefile File.expand_path('
|
22
|
+
eval_rakefile File.expand_path('tasks/git_copy.rake', __dir__)
|
20
23
|
end
|
21
24
|
|
22
25
|
# register capistrano hooks
|
@@ -38,15 +41,7 @@ module Capistrano
|
|
38
41
|
# @return [Boolean] indicates if repo cache exists
|
39
42
|
def test
|
40
43
|
if backend.test("[ -d #{repo_cache_path} ]")
|
41
|
-
|
42
|
-
if backend.test(:git, :status, '>/dev/null 2>/dev/null')
|
43
|
-
true
|
44
|
-
else
|
45
|
-
backend.execute(:rm, '-rf', repo_cache_path)
|
46
|
-
|
47
|
-
false
|
48
|
-
end
|
49
|
-
end
|
44
|
+
check_repo_cache_path
|
50
45
|
else
|
51
46
|
false
|
52
47
|
end
|
@@ -76,26 +71,16 @@ module Capistrano
|
|
76
71
|
end
|
77
72
|
|
78
73
|
# cleanup
|
79
|
-
if fetch(:with_clean)
|
80
|
-
git(:clean, '-d', '-f')
|
81
|
-
end
|
74
|
+
git(:clean, '-d', '-f') if fetch(:with_clean)
|
82
75
|
|
83
|
-
if fetch(:with_submodules)
|
84
|
-
git(:submodule, :foreach, '--recursive', :git, :clean, '-d', '-f')
|
85
|
-
end
|
76
|
+
git(:submodule, :foreach, '--recursive', :git, :clean, '-d', '-f') if fetch(:with_submodules)
|
86
77
|
end
|
87
78
|
|
88
79
|
# Create tar archive
|
89
80
|
#
|
90
81
|
# @return void
|
91
82
|
def prepare_release
|
92
|
-
|
93
|
-
backend.execute(:tar, '-czf', archive_path, '-C', fetch(:upload_path), '.')
|
94
|
-
elsif fetch(:with_submodules)
|
95
|
-
backend.execute(git_archive_all_bin, "--prefix=''", archive_path)
|
96
|
-
else
|
97
|
-
git(:archive, '--format=tar', 'HEAD', '|', 'gzip', "> #{archive_path}")
|
98
|
-
end
|
83
|
+
package_release_archive
|
99
84
|
|
100
85
|
exclude_files_from_archive if fetch(:git_excludes, []).count > 0
|
101
86
|
end
|
@@ -110,9 +95,7 @@ module Capistrano
|
|
110
95
|
|
111
96
|
backend.upload!(archive_path, remote_archive_path)
|
112
97
|
|
113
|
-
|
114
|
-
backend.execute(:tar, '-f', remote_archive_path, '-x', '-C', release_path)
|
115
|
-
backend.execute(:rm, '-f', remote_archive_path)
|
98
|
+
extract_archive_on_remote(remote_archive_path)
|
116
99
|
end
|
117
100
|
|
118
101
|
# Set deployed revision
|
@@ -135,74 +118,21 @@ module Capistrano
|
|
135
118
|
#
|
136
119
|
# @return [String]
|
137
120
|
def tmp_path
|
138
|
-
@
|
121
|
+
@tmp_path ||= File.join(Dir.tmpdir, deploy_id)
|
139
122
|
end
|
140
123
|
|
141
124
|
# Path to repository cache
|
142
125
|
#
|
143
126
|
# @return [String]
|
144
127
|
def repo_cache_path
|
145
|
-
@
|
128
|
+
@repo_cache_path ||= fetch(:git_repo_cach_path, File.join(tmp_path, 'repo'))
|
146
129
|
end
|
147
130
|
|
148
131
|
# Path to archive
|
149
132
|
#
|
150
133
|
# @return [String]
|
151
134
|
def archive_path
|
152
|
-
@
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
def deploy_id
|
158
|
-
[
|
159
|
-
fetch(:application),
|
160
|
-
fetch(:stage),
|
161
|
-
Digest::MD5.hexdigest(fetch(:repo_url))[0..7],
|
162
|
-
Digest::MD5.hexdigest(Dir.getwd)[0..7]
|
163
|
-
].compact.join('_').gsub(/[^\w]/, '')
|
164
|
-
end
|
165
|
-
|
166
|
-
def commit_hash
|
167
|
-
return @_commit_hash if @_commit_hash
|
168
|
-
|
169
|
-
branch = fetch(:branch, 'master').to_s.strip
|
170
|
-
|
171
|
-
if backend.test(:git, 'rev-parse', "origin/#{branch}", '>/dev/null 2>/dev/null')
|
172
|
-
@_commit_hash = backend.capture(:git, 'rev-parse', "origin/#{branch}").strip
|
173
|
-
else
|
174
|
-
@_commit_hash = backend.capture(:git, 'rev-parse', branch).strip
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def git_archive_all_bin
|
179
|
-
File.expand_path('../../../../vendor/git-archive-all/git_archive_all.py', __FILE__)
|
180
|
-
end
|
181
|
-
|
182
|
-
def git(*args)
|
183
|
-
backend.execute(:git, *args)
|
184
|
-
end
|
185
|
-
|
186
|
-
def exclude_files_from_archive
|
187
|
-
archive_dir = File.join(tmp_path, 'archive')
|
188
|
-
|
189
|
-
backend.execute(:rm, '-rf', archive_dir)
|
190
|
-
backend.execute(:mkdir, '-p', archive_dir)
|
191
|
-
backend.execute(:tar, '-xzf', archive_path, '-C', archive_dir)
|
192
|
-
|
193
|
-
fetch(:git_excludes, []).each do |f|
|
194
|
-
file_path = File.join(archive_dir, f.gsub(/\A\//, ''))
|
195
|
-
|
196
|
-
unless File.exists?(file_path)
|
197
|
-
backend.warn("#{f} does not exists!")
|
198
|
-
|
199
|
-
next
|
200
|
-
end
|
201
|
-
|
202
|
-
FileUtils.rm_rf(file_path)
|
203
|
-
end
|
204
|
-
|
205
|
-
backend.execute(:tar, '-czf', archive_path, '-C', archive_dir, '.')
|
135
|
+
@archive_path ||= File.join(tmp_path, 'archive.tar.gz')
|
206
136
|
end
|
207
137
|
end
|
208
138
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module GitCopy
|
5
|
+
# Helper methods for capistrano SCM plugin
|
6
|
+
module SCMHelpers
|
7
|
+
private
|
8
|
+
|
9
|
+
def deploy_id
|
10
|
+
[
|
11
|
+
fetch(:application),
|
12
|
+
fetch(:stage),
|
13
|
+
Digest::MD5.hexdigest(fetch(:repo_url))[0..7],
|
14
|
+
Digest::MD5.hexdigest(Dir.getwd)[0..7]
|
15
|
+
].compact.join('_').gsub(/[^\w]/, '')
|
16
|
+
end
|
17
|
+
|
18
|
+
def commit_hash
|
19
|
+
return @commit_hash if @commit_hash
|
20
|
+
|
21
|
+
branch = fetch(:branch, 'master').to_s.strip
|
22
|
+
|
23
|
+
@commit_hash = if backend.test(:git, 'rev-parse', "origin/#{branch}", '>/dev/null 2>/dev/null')
|
24
|
+
backend.capture(:git, 'rev-parse', "origin/#{branch}").strip
|
25
|
+
else
|
26
|
+
backend.capture(:git, 'rev-parse', branch).strip
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def git_archive_all_bin
|
31
|
+
File.expand_path('../../../vendor/git-archive-all/git_archive_all.py', __dir__)
|
32
|
+
end
|
33
|
+
|
34
|
+
def git(*args)
|
35
|
+
backend.execute(:git, *args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def check_repo_cache_path
|
39
|
+
backend.within(repo_cache_path) do
|
40
|
+
if backend.test(:git, :status, '>/dev/null 2>/dev/null')
|
41
|
+
true
|
42
|
+
else
|
43
|
+
backend.execute(:rm, '-rf', repo_cache_path)
|
44
|
+
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def package_release_archive
|
51
|
+
if fetch(:upload_path) != '.'
|
52
|
+
backend.execute(:tar, '-czf', archive_path, '-C', fetch(:upload_path), '.')
|
53
|
+
elsif fetch(:with_submodules)
|
54
|
+
backend.execute(git_archive_all_bin, "--prefix=''", archive_path)
|
55
|
+
else
|
56
|
+
git(:archive, '--format=tar', 'HEAD', '|', 'gzip', "> #{archive_path}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def exclude_files_from_archive
|
61
|
+
archive_dir = File.join(tmp_path, 'archive')
|
62
|
+
|
63
|
+
backend.execute(:rm, '-rf', archive_dir)
|
64
|
+
backend.execute(:mkdir, '-p', archive_dir)
|
65
|
+
backend.execute(:tar, '-xzf', archive_path, '-C', archive_dir)
|
66
|
+
|
67
|
+
remove_file_from_archive_dir(archive_dir)
|
68
|
+
|
69
|
+
backend.execute(:tar, '-czf', archive_path, '-C', archive_dir, '.')
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove_file_from_archive_dir(archive_dir)
|
73
|
+
fetch(:git_excludes, []).each do |f|
|
74
|
+
file_path = File.join(archive_dir, f.gsub(%r{\A/}, ''))
|
75
|
+
|
76
|
+
unless File.exist?(file_path)
|
77
|
+
backend.warn("#{f} does not exists!")
|
78
|
+
|
79
|
+
next
|
80
|
+
end
|
81
|
+
|
82
|
+
FileUtils.rm_rf(file_path)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def extract_archive_on_remote(remote_archive_path)
|
87
|
+
backend.execute(:mkdir, '-p', release_path)
|
88
|
+
backend.execute(:tar, '-f', remote_archive_path, '-x', '-C', release_path)
|
89
|
+
backend.execute(:rm, '-f', remote_archive_path)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -27,14 +27,29 @@ from __future__ import print_function
|
|
27
27
|
from __future__ import unicode_literals
|
28
28
|
|
29
29
|
import logging
|
30
|
-
from os import extsep, path, readlink
|
30
|
+
from os import extsep, path, readlink
|
31
31
|
from subprocess import CalledProcessError, Popen, PIPE
|
32
32
|
import sys
|
33
|
-
import tarfile
|
34
|
-
from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED
|
35
33
|
import re
|
36
34
|
|
37
|
-
__version__ = "1.
|
35
|
+
__version__ = "1.18.2"
|
36
|
+
|
37
|
+
|
38
|
+
try:
|
39
|
+
# Python 3.3+
|
40
|
+
from shlex import quote
|
41
|
+
except ImportError:
|
42
|
+
_find_unsafe = re.compile(r'[^a-zA-Z0-9_@%+=:,./-]').search
|
43
|
+
|
44
|
+
def quote(s):
|
45
|
+
"""Return a shell-escaped version of the string *s*."""
|
46
|
+
if not s:
|
47
|
+
return "''"
|
48
|
+
|
49
|
+
if _find_unsafe(s) is None:
|
50
|
+
return s
|
51
|
+
|
52
|
+
return "'" + s.replace("'", "'\"'\"'") + "'"
|
38
53
|
|
39
54
|
|
40
55
|
class GitArchiver(object):
|
@@ -48,6 +63,17 @@ class GitArchiver(object):
|
|
48
63
|
>>> archiver = GitArchiver(main_repo_abspath='my/repo/path')
|
49
64
|
>>> archiver.create('output.zip')
|
50
65
|
"""
|
66
|
+
TARFILE_FORMATS = {
|
67
|
+
'tar': 'w',
|
68
|
+
'tbz2': 'w:bz2',
|
69
|
+
'tgz': 'w:gz',
|
70
|
+
'txz': 'w:xz',
|
71
|
+
'bz2': 'w:bz2',
|
72
|
+
'gz': 'w:gz',
|
73
|
+
'xz': 'w:xz'
|
74
|
+
}
|
75
|
+
ZIPFILE_FORMATS = ('.zip',)
|
76
|
+
|
51
77
|
LOG = logging.getLogger('GitArchiver')
|
52
78
|
|
53
79
|
def __init__(self, prefix='', exclude=True, force_sub=False, extra=None, main_repo_abspath=None):
|
@@ -118,7 +144,9 @@ class GitArchiver(object):
|
|
118
144
|
self.LOG.debug("Output format is not explicitly set, determined format is {0}.".format(output_format))
|
119
145
|
|
120
146
|
if not dry_run:
|
121
|
-
if output_format
|
147
|
+
if output_format in self.ZIPFILE_FORMATS:
|
148
|
+
from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED
|
149
|
+
|
122
150
|
archive = ZipFile(path.abspath(output_path), 'w')
|
123
151
|
|
124
152
|
def add_file(file_path, arcname):
|
@@ -129,25 +157,19 @@ class GitArchiver(object):
|
|
129
157
|
i.create_system = 3
|
130
158
|
i.external_attr = 0xA1ED0000
|
131
159
|
archive.writestr(i, readlink(file_path))
|
132
|
-
elif output_format in
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
elif output_format == 'txz':
|
138
|
-
t_mode = 'w:xz'
|
139
|
-
else:
|
140
|
-
t_mode = 'w:{0}'.format(output_format)
|
141
|
-
|
142
|
-
archive = tarfile.open(path.abspath(output_path), t_mode)
|
160
|
+
elif output_format in self.TARFILE_FORMATS:
|
161
|
+
import tarfile
|
162
|
+
|
163
|
+
mode = self.TARFILE_FORMATS[output_format]
|
164
|
+
archive = tarfile.open(path.abspath(output_path), mode)
|
143
165
|
|
144
166
|
def add_file(file_path, arcname):
|
145
167
|
archive.add(file_path, arcname)
|
146
168
|
else:
|
147
|
-
raise
|
169
|
+
raise ValueError("unknown format: {0}".format(output_format))
|
148
170
|
|
149
171
|
def archiver(file_path, arcname):
|
150
|
-
self.LOG.debug("
|
172
|
+
self.LOG.debug("{0} => {1}".format(file_path, arcname))
|
151
173
|
add_file(file_path, arcname)
|
152
174
|
else:
|
153
175
|
archive = None
|
@@ -160,105 +182,28 @@ class GitArchiver(object):
|
|
160
182
|
if archive is not None:
|
161
183
|
archive.close()
|
162
184
|
|
163
|
-
def
|
164
|
-
"""
|
165
|
-
Returns exclude patterns for a given repo. It looks for .gitattributes files in repo_file_paths.
|
166
|
-
|
167
|
-
Resulting dictionary will contain exclude patterns per path (relative to the repo_abspath).
|
168
|
-
E.g. {('.', 'Catalyst', 'Editions', 'Base'): ['Foo*', '*Bar']}
|
169
|
-
|
170
|
-
@param repo_abspath: Absolute path to the git repository.
|
171
|
-
@type repo_abspath: str
|
172
|
-
|
173
|
-
@param repo_file_paths: List of paths relative to the repo_abspath that are under git control.
|
174
|
-
@type repo_file_paths: list
|
175
|
-
|
176
|
-
@return: Dictionary representing exclude patterns.
|
177
|
-
Keys are tuples of strings. Values are lists of strings.
|
178
|
-
Returns None if self.exclude is not set.
|
179
|
-
@rtype: dict or None
|
180
|
-
"""
|
181
|
-
if not self.exclude:
|
182
|
-
return None
|
183
|
-
|
184
|
-
def read_attributes(attributes_abspath):
|
185
|
-
patterns = []
|
186
|
-
if path.isfile(attributes_abspath):
|
187
|
-
attributes = open(attributes_abspath, 'r').readlines()
|
188
|
-
patterns = []
|
189
|
-
for line in attributes:
|
190
|
-
tokens = line.strip().split()
|
191
|
-
if "export-ignore" in tokens[1:]:
|
192
|
-
patterns.append(tokens[0])
|
193
|
-
return patterns
|
194
|
-
|
195
|
-
exclude_patterns = {(): []}
|
196
|
-
|
197
|
-
# There may be no gitattributes.
|
198
|
-
try:
|
199
|
-
global_attributes_abspath = self.run_git_shell("git config --get core.attributesfile", repo_abspath).rstrip()
|
200
|
-
exclude_patterns[()] = read_attributes(global_attributes_abspath)
|
201
|
-
except:
|
202
|
-
# And it's valid to not have them.
|
203
|
-
pass
|
204
|
-
|
205
|
-
for attributes_abspath in [path.join(repo_abspath, f) for f in repo_file_paths if f.endswith(".gitattributes")]:
|
206
|
-
# Each .gitattributes affects only files within its directory.
|
207
|
-
key = tuple(self.get_path_components(repo_abspath, path.dirname(attributes_abspath)))
|
208
|
-
exclude_patterns[key] = read_attributes(attributes_abspath)
|
209
|
-
|
210
|
-
local_attributes_abspath = path.join(repo_abspath, ".git", "info", "attributes")
|
211
|
-
key = tuple(self.get_path_components(repo_abspath, repo_abspath))
|
212
|
-
|
213
|
-
if key in exclude_patterns:
|
214
|
-
exclude_patterns[key].extend(read_attributes(local_attributes_abspath))
|
215
|
-
else:
|
216
|
-
exclude_patterns[key] = read_attributes(local_attributes_abspath)
|
217
|
-
|
218
|
-
return exclude_patterns
|
219
|
-
|
220
|
-
def is_file_excluded(self, repo_abspath, repo_file_path, exclude_patterns):
|
185
|
+
def is_file_excluded(self, repo_abspath, repo_file_path):
|
221
186
|
"""
|
222
187
|
Checks whether file at a given path is excluded.
|
223
188
|
|
224
189
|
@param repo_abspath: Absolute path to the git repository.
|
225
190
|
@type repo_abspath: str
|
226
191
|
|
227
|
-
@param repo_file_path: Path to a file
|
192
|
+
@param repo_file_path: Path to a file relative to repo_abspath.
|
228
193
|
@type repo_file_path: str
|
229
194
|
|
230
|
-
@param exclude_patterns: Exclude patterns with format specified for get_exclude_patterns.
|
231
|
-
@type exclude_patterns: dict
|
232
|
-
|
233
195
|
@return: True if file should be excluded. Otherwise False.
|
234
196
|
@rtype: bool
|
235
197
|
"""
|
236
|
-
|
237
|
-
|
198
|
+
out = self.run_git_shell(
|
199
|
+
'git check-attr -z export-ignore -- %s' % quote(repo_file_path),
|
200
|
+
cwd=repo_abspath
|
201
|
+
).split('\0')
|
238
202
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
is_excluded = False
|
245
|
-
# We should check all patterns specified in intermediate directories to the given file.
|
246
|
-
# At the end we should also check for the global patterns (key '()' or empty tuple).
|
247
|
-
while not is_excluded:
|
248
|
-
key = tuple(components)
|
249
|
-
if key in exclude_patterns:
|
250
|
-
patterns = exclude_patterns[key]
|
251
|
-
for p in patterns:
|
252
|
-
if fnmatch(file_name, p) or fnmatch(repo_file_path, p):
|
253
|
-
self.LOG.debug("Exclude pattern matched {0}: {1}".format(p, repo_file_path))
|
254
|
-
is_excluded = True
|
255
|
-
|
256
|
-
if not len(components):
|
257
|
-
break
|
258
|
-
|
259
|
-
components.pop()
|
260
|
-
|
261
|
-
return is_excluded
|
203
|
+
try:
|
204
|
+
return out[2] == 'set'
|
205
|
+
except IndexError:
|
206
|
+
return False
|
262
207
|
|
263
208
|
def archive_all_files(self, archiver):
|
264
209
|
"""
|
@@ -291,14 +236,11 @@ class GitArchiver(object):
|
|
291
236
|
"""
|
292
237
|
repo_abspath = path.join(self.main_repo_abspath, repo_path)
|
293
238
|
repo_file_paths = self.run_git_shell(
|
294
|
-
|
239
|
+
'git ls-files -z --cached --full-name --no-empty-directory',
|
295
240
|
repo_abspath
|
296
|
-
).
|
297
|
-
exclude_patterns = self.get_exclude_patterns(repo_abspath, repo_file_paths)
|
241
|
+
).split('\0')[:-1]
|
298
242
|
|
299
243
|
for repo_file_path in repo_file_paths:
|
300
|
-
# Git puts path in quotes if file path has unicode characters.
|
301
|
-
repo_file_path = repo_file_path.strip('"') # file path relative to current repo
|
302
244
|
repo_file_abspath = path.join(repo_abspath, repo_file_path) # absolute file path
|
303
245
|
main_repo_file_path = path.join(repo_path, repo_file_path) # file path relative to the main repo
|
304
246
|
|
@@ -306,14 +248,14 @@ class GitArchiver(object):
|
|
306
248
|
if not path.islink(repo_file_abspath) and path.isdir(repo_file_abspath):
|
307
249
|
continue
|
308
250
|
|
309
|
-
if self.is_file_excluded(repo_abspath, repo_file_path
|
251
|
+
if self.is_file_excluded(repo_abspath, repo_file_path):
|
310
252
|
continue
|
311
253
|
|
312
254
|
yield main_repo_file_path
|
313
255
|
|
314
256
|
if self.force_sub:
|
315
|
-
self.run_git_shell(
|
316
|
-
self.run_git_shell(
|
257
|
+
self.run_git_shell('git submodule init', repo_abspath)
|
258
|
+
self.run_git_shell('git submodule update', repo_abspath)
|
317
259
|
|
318
260
|
try:
|
319
261
|
repo_gitmodules_abspath = path.join(repo_abspath, ".gitmodules")
|
@@ -322,70 +264,24 @@ class GitArchiver(object):
|
|
322
264
|
lines = f.readlines()
|
323
265
|
|
324
266
|
for l in lines:
|
325
|
-
m = re.match("
|
267
|
+
m = re.match("^\\s*path\\s*=\\s*(.*)\\s*$", l)
|
326
268
|
|
327
269
|
if m:
|
328
|
-
|
329
|
-
|
270
|
+
repo_submodule_path = m.group(1) # relative to repo_path
|
271
|
+
main_repo_submodule_path = path.join(repo_path, repo_submodule_path) # relative to main_repo_abspath
|
330
272
|
|
331
|
-
if self.is_file_excluded(repo_abspath,
|
273
|
+
if self.is_file_excluded(repo_abspath, repo_submodule_path):
|
332
274
|
continue
|
333
275
|
|
334
|
-
for
|
335
|
-
|
276
|
+
for main_repo_submodule_file_path in self.walk_git_files(main_repo_submodule_path):
|
277
|
+
repo_submodule_file_path = main_repo_submodule_file_path.replace(repo_path, "", 1).strip("/")
|
278
|
+
if self.is_file_excluded(repo_abspath, repo_submodule_file_path):
|
336
279
|
continue
|
337
280
|
|
338
|
-
yield
|
281
|
+
yield main_repo_submodule_file_path
|
339
282
|
except IOError:
|
340
283
|
pass
|
341
284
|
|
342
|
-
@staticmethod
|
343
|
-
def get_path_components(repo_abspath, abspath):
|
344
|
-
"""
|
345
|
-
Split given abspath into components relative to repo_abspath.
|
346
|
-
These components are primarily used as unique keys of files and folders within a repository.
|
347
|
-
|
348
|
-
E.g. if repo_abspath is '/Documents/Hobby/ParaView/' and abspath is
|
349
|
-
'/Documents/Hobby/ParaView/Catalyst/Editions/Base/', function will return:
|
350
|
-
['.', 'Catalyst', 'Editions', 'Base']
|
351
|
-
|
352
|
-
First element is always os.curdir (concrete symbol depends on OS).
|
353
|
-
|
354
|
-
@param repo_abspath: Absolute path to the git repository. Normalized via os.path.normpath.
|
355
|
-
@type repo_abspath: str
|
356
|
-
|
357
|
-
@param abspath: Absolute path to a file within repo_abspath. Normalized via os.path.normpath.
|
358
|
-
@type abspath: str
|
359
|
-
|
360
|
-
@return: List of path components.
|
361
|
-
@rtype: list
|
362
|
-
"""
|
363
|
-
repo_abspath = path.normpath(repo_abspath)
|
364
|
-
abspath = path.normpath(abspath)
|
365
|
-
|
366
|
-
if not path.isabs(repo_abspath):
|
367
|
-
raise ValueError("repo_abspath MUST be absolute path.")
|
368
|
-
|
369
|
-
if not path.isabs(abspath):
|
370
|
-
raise ValueError("abspath MUST be absoulte path.")
|
371
|
-
|
372
|
-
if not path.commonprefix([repo_abspath, abspath]):
|
373
|
-
raise ValueError(
|
374
|
-
"abspath (\"{0}\") MUST have common prefix with repo_abspath (\"{1}\")"
|
375
|
-
.format(abspath, repo_abspath)
|
376
|
-
)
|
377
|
-
|
378
|
-
components = []
|
379
|
-
|
380
|
-
while not abspath == repo_abspath:
|
381
|
-
abspath, tail = path.split(abspath)
|
382
|
-
|
383
|
-
if tail:
|
384
|
-
components.insert(0, tail)
|
385
|
-
|
386
|
-
components.insert(0, curdir)
|
387
|
-
return components
|
388
|
-
|
389
285
|
@staticmethod
|
390
286
|
def run_git_shell(cmd, cwd=None):
|
391
287
|
"""
|
@@ -473,11 +369,9 @@ def main():
|
|
473
369
|
if options.prefix is not None:
|
474
370
|
options.prefix = path.join(options.prefix, '')
|
475
371
|
else:
|
476
|
-
import re
|
477
|
-
|
478
372
|
output_name = path.basename(output_file_path)
|
479
373
|
output_name = re.sub(
|
480
|
-
'(
|
374
|
+
'(\\.zip|\\.tar|\\.tbz2|\\.tgz|\\.txz|\\.bz2|\\.gz|\\.xz|\\.tar\\.bz2|\\.tar\\.gz|\\.tar\\.xz)$',
|
481
375
|
'',
|
482
376
|
output_name
|
483
377
|
) or "Archive"
|
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.5.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Schwab
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capistrano
|
@@ -34,16 +34,16 @@ dependencies:
|
|
34
34
|
name: bundler
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - "
|
37
|
+
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '0'
|
40
40
|
type: :development
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - "
|
44
|
+
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
46
|
+
version: '0'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,7 +59,7 @@ dependencies:
|
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
62
|
+
name: rubocop
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - ">="
|
@@ -80,7 +80,9 @@ extensions: []
|
|
80
80
|
extra_rdoc_files: []
|
81
81
|
files:
|
82
82
|
- ".gitignore"
|
83
|
+
- ".gitlab-ci.yml"
|
83
84
|
- ".gitmodules"
|
85
|
+
- ".rubocop.yml"
|
84
86
|
- CHANGELOG.md
|
85
87
|
- Gemfile
|
86
88
|
- LICENSE.txt
|
@@ -89,10 +91,11 @@ files:
|
|
89
91
|
- capistrano-git-copy.gemspec
|
90
92
|
- lib/capistrano/git_copy.rb
|
91
93
|
- lib/capistrano/git_copy/scm.rb
|
94
|
+
- lib/capistrano/git_copy/scm_helpers.rb
|
92
95
|
- lib/capistrano/git_copy/tasks/git_copy.rake
|
93
96
|
- lib/capistrano/git_copy/version.rb
|
94
97
|
- vendor/git-archive-all/git_archive_all.py
|
95
|
-
homepage: https://
|
98
|
+
homepage: https://gitlab.com/ydkn/capistrano-git-copy
|
96
99
|
licenses:
|
97
100
|
- MIT
|
98
101
|
metadata: {}
|
@@ -112,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
115
|
version: '0'
|
113
116
|
requirements: []
|
114
117
|
rubyforge_project:
|
115
|
-
rubygems_version: 2.7.
|
118
|
+
rubygems_version: 2.7.7
|
116
119
|
signing_key:
|
117
120
|
specification_version: 4
|
118
121
|
summary: Copy local git repository deploy strategy for capistrano.
|