batchfetch 1.3.4__tar.gz → 1.3.6__tar.gz
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.
- {batchfetch-1.3.4 → batchfetch-1.3.6}/PKG-INFO +17 -3
- {batchfetch-1.3.4 → batchfetch-1.3.6}/README.md +1 -1
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch/batchfetch_cli.py +11 -18
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch/batchfetch_git.py +15 -12
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch.egg-info/PKG-INFO +17 -3
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch.egg-info/SOURCES.txt +2 -1
- {batchfetch-1.3.4 → batchfetch-1.3.6}/setup.py +1 -1
- batchfetch-1.3.6/tests/test_helpers.py +56 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/LICENSE +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch/__init__.py +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch/batchfetch_base.py +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch/helpers.py +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch.egg-info/dependency_links.txt +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch.egg-info/entry_points.txt +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch.egg-info/requires.txt +1 -1
- {batchfetch-1.3.4 → batchfetch-1.3.6}/batchfetch.egg-info/top_level.txt +0 -0
- {batchfetch-1.3.4 → batchfetch-1.3.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: batchfetch
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: Efficiently clone and pull multiple Git repositories.
|
|
5
5
|
Home-page: https://github.com/jamescherti/batchfetch
|
|
6
6
|
Author: James Cherti
|
|
@@ -17,12 +17,26 @@ Classifier: Topic :: Utilities
|
|
|
17
17
|
Requires-Python: >=3.6, <4
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
+
Requires-Dist: colorama
|
|
21
|
+
Requires-Dist: schema
|
|
22
|
+
Requires-Dist: setproctitle
|
|
23
|
+
Requires-Dist: PyYAML
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
20
34
|
|
|
21
35
|
# Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
|
|
22
36
|
|
|
23
37
|
## Introduction
|
|
24
38
|
|
|
25
|
-
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously. With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management
|
|
39
|
+
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously. With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management.
|
|
26
40
|
|
|
27
41
|
But why use Batchfetch? Because it is extremely fast, cloning repositories quickly by running Git operations in parallel. It intelligently detects whether a `git fetch` is needed, further speeding up the process of downloading data from repositories. Additionally, it allows specifying the revision (for Git), ensuring that the cloned repository matches the exact version you require.
|
|
28
42
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously. With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management
|
|
5
|
+
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously. With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management.
|
|
6
6
|
|
|
7
7
|
But why use Batchfetch? Because it is extremely fast, cloning repositories quickly by running Git operations in parallel. It intelligently detects whether a `git fetch` is needed, further speeding up the process of downloading data from repositories. Additionally, it allows specifying the revision (for Git), ensuring that the cloned repository matches the exact version you require.
|
|
8
8
|
|
|
@@ -42,7 +42,9 @@ class BatchFetchCli:
|
|
|
42
42
|
"""Command-line-interface that downloads."""
|
|
43
43
|
|
|
44
44
|
def __init__(self, max_workers: int, verbose: bool, check_untracked: bool,
|
|
45
|
-
targets: List[str]):
|
|
45
|
+
targets: List[str], cwd: os.PathLike):
|
|
46
|
+
os.chdir(cwd)
|
|
47
|
+
self._cwd = cwd
|
|
46
48
|
self._logger = logging.getLogger(self.__class__.__name__)
|
|
47
49
|
self.targets = {Path(item).absolute() for item in targets}
|
|
48
50
|
self.cfg: dict = {}
|
|
@@ -111,6 +113,7 @@ class BatchFetchCli:
|
|
|
111
113
|
# Paths specified in the batchfetch.yaml file
|
|
112
114
|
untracked_paths = None
|
|
113
115
|
if "options" in yaml_dict and \
|
|
116
|
+
isinstance(yaml_dict["options"], dict) and \
|
|
114
117
|
"ignore_untracked" in yaml_dict["options"]:
|
|
115
118
|
untracked_paths = \
|
|
116
119
|
yaml_dict["options"]["ignore_untracked"]
|
|
@@ -175,10 +178,7 @@ class BatchFetchCli:
|
|
|
175
178
|
if str(dest_path) in dict_local_dir \
|
|
176
179
|
or str(dest_path2) in dict_local_dir:
|
|
177
180
|
err_str = ("More than one task have the " +
|
|
178
|
-
f"destination path
|
|
179
|
-
str(task[keyword]) + " and " +
|
|
180
|
-
str(dict_local_dir[(str(dest_path))]) +
|
|
181
|
-
")")
|
|
181
|
+
f"destination path: {dest_path2}")
|
|
182
182
|
raise BatchFetchError(err_str)
|
|
183
183
|
|
|
184
184
|
dict_local_dir[str(dest_path)] = batchfetch_instance[keyword]
|
|
@@ -310,8 +310,8 @@ class BatchFetchCli:
|
|
|
310
310
|
err_str = "The following files need to be deleted:\n"
|
|
311
311
|
for path in untracked_paths:
|
|
312
312
|
err_str += (" - " +
|
|
313
|
-
str(path) +
|
|
314
|
-
(
|
|
313
|
+
str(path.relative_to(self._cwd)) +
|
|
314
|
+
(os.sep if path.is_dir() else "") +
|
|
315
315
|
"\n")
|
|
316
316
|
err_str += ("The paths above are not managed by batchfetch."
|
|
317
317
|
" To retain them, add them to the "
|
|
@@ -427,17 +427,10 @@ def command_line_interface():
|
|
|
427
427
|
sys.argv[1:]))
|
|
428
428
|
|
|
429
429
|
args = parse_args()
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
file_resolved = file.absolute()
|
|
433
|
-
if not file_resolved:
|
|
434
|
-
print(f"Error: cannot resolve the path {file}",
|
|
435
|
-
file=sys.stderr)
|
|
436
|
-
sys.exit(1)
|
|
437
|
-
|
|
438
|
-
done.append(file_resolved)
|
|
430
|
+
file = Path(args.file)
|
|
431
|
+
file_abs = file.absolute()
|
|
439
432
|
|
|
440
|
-
args.directory = args.directory if args.directory else
|
|
433
|
+
args.directory = args.directory if args.directory else file_abs.parent
|
|
441
434
|
if args.verbose and args.jobs:
|
|
442
435
|
print(f"[FILE] {file}")
|
|
443
436
|
print(f"[DIR] {args.directory}")
|
|
@@ -445,13 +438,13 @@ def command_line_interface():
|
|
|
445
438
|
print(f"[CHECK UNTRACKED] {args.check_untracked}")
|
|
446
439
|
print()
|
|
447
440
|
|
|
448
|
-
os.chdir(args.directory)
|
|
449
441
|
try:
|
|
450
442
|
batchfetch_cli = BatchFetchCli(
|
|
451
443
|
verbose=args.verbose,
|
|
452
444
|
max_workers=args.jobs,
|
|
453
445
|
check_untracked=args.check_untracked,
|
|
454
446
|
targets=args.targets,
|
|
447
|
+
cwd=args.directory,
|
|
455
448
|
)
|
|
456
449
|
|
|
457
450
|
batchfetch_cli.load(file)
|
|
@@ -117,7 +117,7 @@ class BatchFetchGit(TaskBatchFetch):
|
|
|
117
117
|
|
|
118
118
|
self.add_output(f"[GIT {update_type}] {self[self.main_key]}"
|
|
119
119
|
+ (f" (Ref: {self['revision']})"
|
|
120
|
-
|
|
120
|
+
if self["revision"] else "") + "\n")
|
|
121
121
|
|
|
122
122
|
try:
|
|
123
123
|
# Delete
|
|
@@ -130,32 +130,34 @@ class BatchFetchGit(TaskBatchFetch):
|
|
|
130
130
|
|
|
131
131
|
# Update
|
|
132
132
|
if self.git_local_dir.is_dir():
|
|
133
|
+
do_git_fetch = self["git_pull"]
|
|
134
|
+
|
|
133
135
|
# Pre exec
|
|
134
|
-
|
|
136
|
+
if do_git_fetch:
|
|
137
|
+
self._update_current_branch_name()
|
|
138
|
+
|
|
135
139
|
self._repo_fix_remote_origin()
|
|
136
140
|
self._exec_before(cwd=self.git_local_dir)
|
|
137
141
|
|
|
138
142
|
if not self["revision"]:
|
|
139
143
|
self.values["revision"] = self._run_get_firstline(
|
|
140
|
-
"git symbolic-ref
|
|
141
|
-
).split("/")[-1]
|
|
144
|
+
"git symbolic-ref --short HEAD")
|
|
142
145
|
if not self["revision"]:
|
|
143
146
|
raise BatchFetchError(
|
|
144
147
|
"Unable to determine the default origin branch"
|
|
145
148
|
)
|
|
146
149
|
|
|
147
150
|
self.add_output(self.indent_spaces +
|
|
148
|
-
|
|
151
|
+
"[INFO] Update revision to: '" +
|
|
149
152
|
self["revision"] + "'\n")
|
|
150
153
|
|
|
151
|
-
|
|
154
|
+
if do_git_fetch:
|
|
155
|
+
git_fetch_done = self._repo_fetch()
|
|
152
156
|
|
|
153
|
-
|
|
154
|
-
git_branch_changed = self._repo_fix_branch()
|
|
157
|
+
self._repo_fix_branch()
|
|
155
158
|
|
|
156
|
-
git_merge_done = False
|
|
157
159
|
if git_fetch_done:
|
|
158
|
-
|
|
160
|
+
self._git_merge()
|
|
159
161
|
|
|
160
162
|
if self.get_changed():
|
|
161
163
|
self._exec_after(cwd=self.git_local_dir)
|
|
@@ -192,6 +194,8 @@ class BatchFetchGit(TaskBatchFetch):
|
|
|
192
194
|
|
|
193
195
|
:param cmd: Command to be executed. Can be a list or a string.
|
|
194
196
|
:param kwargs: Additional keyword arguments for Popen.
|
|
197
|
+
:cwd: Current working directory.
|
|
198
|
+
:env: Environment variables.
|
|
195
199
|
:return: Tuple containing two lists: stdout lines and stderr lines.
|
|
196
200
|
"""
|
|
197
201
|
if not cwd:
|
|
@@ -264,11 +268,10 @@ class BatchFetchGit(TaskBatchFetch):
|
|
|
264
268
|
# Merge
|
|
265
269
|
do_git_fetch = self["git_pull"]
|
|
266
270
|
do_git_fetch = False
|
|
267
|
-
commit_ref = None
|
|
268
271
|
|
|
269
272
|
try:
|
|
270
273
|
# Check if the revision such as
|
|
271
|
-
|
|
274
|
+
_, _ = self._run(["git", "cat-file", "-e", self["revision"]])
|
|
272
275
|
except subprocess.CalledProcessError:
|
|
273
276
|
do_git_fetch = True
|
|
274
277
|
self.add_output(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: batchfetch
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: Efficiently clone and pull multiple Git repositories.
|
|
5
5
|
Home-page: https://github.com/jamescherti/batchfetch
|
|
6
6
|
Author: James Cherti
|
|
@@ -17,12 +17,26 @@ Classifier: Topic :: Utilities
|
|
|
17
17
|
Requires-Python: >=3.6, <4
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
+
Requires-Dist: colorama
|
|
21
|
+
Requires-Dist: schema
|
|
22
|
+
Requires-Dist: setproctitle
|
|
23
|
+
Requires-Dist: PyYAML
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
20
34
|
|
|
21
35
|
# Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
|
|
22
36
|
|
|
23
37
|
## Introduction
|
|
24
38
|
|
|
25
|
-
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously. With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management
|
|
39
|
+
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously. With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management.
|
|
26
40
|
|
|
27
41
|
But why use Batchfetch? Because it is extremely fast, cloning repositories quickly by running Git operations in parallel. It intelligently detects whether a `git fetch` is needed, further speeding up the process of downloading data from repositories. Additionally, it allows specifying the revision (for Git), ensuring that the cloned repository matches the exact version you require.
|
|
28
42
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2024-2025 James Cherti
|
|
4
|
+
# URL: https://github.com/jamescherti/batchfetch
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify it under
|
|
7
|
+
# the terms of the GNU General Public License as published by the Free Software
|
|
8
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
|
9
|
+
# version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
13
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License along with
|
|
16
|
+
# this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
#
|
|
18
|
+
"""Unit tests."""
|
|
19
|
+
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from batchfetch import helpers
|
|
23
|
+
|
|
24
|
+
DATA_PATH = Path(".").joinpath("tests", "data").absolute()
|
|
25
|
+
SCRIPT_RUN_SIMPLE = DATA_PATH / "test-run_simple.sh"
|
|
26
|
+
TEST_MD5SUM_FILE = DATA_PATH / "test-md5sum.txt"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_md5sum():
|
|
30
|
+
md5sum = helpers.md5sum(TEST_MD5SUM_FILE)
|
|
31
|
+
assert md5sum == "f31e127edc87a6aa2eb01b7d94d2ec58"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_run_simple():
|
|
35
|
+
# Stdout
|
|
36
|
+
stdout_lines, stderr_lines = helpers.run_simple(str(SCRIPT_RUN_SIMPLE))
|
|
37
|
+
assert stdout_lines == ['Test 1.',
|
|
38
|
+
'Test 2.',
|
|
39
|
+
'Test 3.']
|
|
40
|
+
assert stderr_lines == ['Test 3.']
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_indent_raw_output():
|
|
44
|
+
list_str = \
|
|
45
|
+
helpers.indent_raw_output(["Test 1.", "Test 2."])
|
|
46
|
+
|
|
47
|
+
assert list_str == [" Test 1.", " Test 2."]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_run_indent():
|
|
51
|
+
stdout_lines, stderr_lines = helpers.run_indent(str(SCRIPT_RUN_SIMPLE))
|
|
52
|
+
assert stdout_lines == [f' [RUN] {str(SCRIPT_RUN_SIMPLE)}',
|
|
53
|
+
' Test 1.',
|
|
54
|
+
' Test 2.',
|
|
55
|
+
' Test 3.']
|
|
56
|
+
assert stderr_lines == [' Test 3.']
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|