batchfetch 1.1.2__tar.gz → 1.1.4__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.1.2/batchfetch.egg-info → batchfetch-1.1.4}/PKG-INFO +2 -2
- {batchfetch-1.1.2 → batchfetch-1.1.4}/README.md +1 -1
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch/__init__.py +1 -1
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch/batchfetch_base.py +2 -2
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch/batchfetch_cli.py +27 -23
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch/batchfetch_git.py +200 -85
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch/helpers.py +1 -1
- {batchfetch-1.1.2 → batchfetch-1.1.4/batchfetch.egg-info}/PKG-INFO +2 -2
- {batchfetch-1.1.2 → batchfetch-1.1.4}/run_tests.sh +1 -1
- {batchfetch-1.1.2 → batchfetch-1.1.4}/setup.py +2 -2
- {batchfetch-1.1.2 → batchfetch-1.1.4}/tests/test_helpers.py +1 -1
- {batchfetch-1.1.2 → batchfetch-1.1.4}/.gitignore +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/LICENSE +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch.egg-info/SOURCES.txt +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch.egg-info/dependency_links.txt +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch.egg-info/entry_points.txt +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch.egg-info/requires.txt +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/batchfetch.egg-info/top_level.txt +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/setup.cfg +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/tests/data/test-md5sum.txt +0 -0
- {batchfetch-1.1.2 → batchfetch-1.1.4}/tests/data/test-run_simple.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: batchfetch
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: Efficiently clone and pull multiple Git repositories.
|
|
5
5
|
Home-page: https://github.com/jamescherti/batchfetch
|
|
6
6
|
Author: James Cherti
|
|
@@ -95,7 +95,7 @@ options:
|
|
|
95
95
|
|
|
96
96
|
## License
|
|
97
97
|
|
|
98
|
-
Copyright (
|
|
98
|
+
Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
|
|
99
99
|
|
|
100
100
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
101
101
|
|
|
@@ -71,7 +71,7 @@ options:
|
|
|
71
71
|
|
|
72
72
|
## License
|
|
73
73
|
|
|
74
|
-
Copyright (
|
|
74
|
+
Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
|
|
75
75
|
|
|
76
76
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
77
77
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
#
|
|
3
|
-
# Copyright (
|
|
3
|
+
# Copyright (C) 2024 James Cherti
|
|
4
4
|
# URL: https://github.com/jamescherti/batchfetch
|
|
5
5
|
#
|
|
6
6
|
# This program is free software: you can redistribute it and/or modify it under
|
|
@@ -94,7 +94,7 @@ class TaskBase:
|
|
|
94
94
|
raise KeyError(f"The item '{key}' was not found in '{self.values}")
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
class
|
|
97
|
+
class TaskBatchFetch(TaskBase):
|
|
98
98
|
"""Plugin downloader base class."""
|
|
99
99
|
|
|
100
100
|
def __init__(self, data: Dict[str, Any], options: Dict[str, Any]):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
#
|
|
3
|
-
# Copyright (
|
|
3
|
+
# Copyright (C) 2024 James Cherti
|
|
4
4
|
# URL: https://github.com/jamescherti/batchfetch
|
|
5
5
|
#
|
|
6
6
|
# This program is free software: you can redistribute it and/or modify it under
|
|
@@ -33,7 +33,7 @@ from colorama import Fore
|
|
|
33
33
|
from schema import Optional, Or, Schema, SchemaError
|
|
34
34
|
from setproctitle import setproctitle
|
|
35
35
|
|
|
36
|
-
from .batchfetch_base import
|
|
36
|
+
from .batchfetch_base import BatchFetchError, TaskBatchFetch
|
|
37
37
|
from .batchfetch_git import BatchFetchGit
|
|
38
38
|
|
|
39
39
|
|
|
@@ -51,7 +51,7 @@ class BatchFetchCli:
|
|
|
51
51
|
|
|
52
52
|
# Plugin
|
|
53
53
|
self.batchfetch_schemas: Dict[Any, Any] = {}
|
|
54
|
-
self.batchfetch_classes: Dict[str,
|
|
54
|
+
self.batchfetch_classes: Dict[str, TaskBatchFetch] = {}
|
|
55
55
|
self.cfg_schema: Dict[Any, Any] = {}
|
|
56
56
|
self._plugin_add("git", BatchFetchGit)
|
|
57
57
|
|
|
@@ -216,8 +216,11 @@ def parse_args():
|
|
|
216
216
|
usage = "%(prog)s [--option] [args]"
|
|
217
217
|
parser = argparse.ArgumentParser(description=desc, usage=usage)
|
|
218
218
|
|
|
219
|
-
parser.add_argument("
|
|
220
|
-
|
|
219
|
+
parser.add_argument("-f",
|
|
220
|
+
"--file",
|
|
221
|
+
default=None,
|
|
222
|
+
required=False,
|
|
223
|
+
help=("Specify the batchfetch YAML file "
|
|
221
224
|
"(default: './batchfetch.yaml')."))
|
|
222
225
|
|
|
223
226
|
parser.add_argument(
|
|
@@ -231,24 +234,24 @@ def parse_args():
|
|
|
231
234
|
)
|
|
232
235
|
|
|
233
236
|
args = parser.parse_args()
|
|
234
|
-
if not args.batchfetch_files:
|
|
235
|
-
args.batchfetch_files = ["./batchfetch.yaml"]
|
|
236
237
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
if not args.file:
|
|
239
|
+
args.file = "./batchfetch.yaml"
|
|
240
|
+
|
|
241
|
+
if not Path(args.file).is_file():
|
|
242
|
+
print(f"Error: File not found: {args.file}",
|
|
243
|
+
file=sys.stderr)
|
|
244
|
+
sys.exit(1)
|
|
242
245
|
|
|
243
246
|
return args
|
|
244
247
|
|
|
245
248
|
|
|
246
|
-
def run_batchfetch_procedure(
|
|
249
|
+
def run_batchfetch_procedure(file: Path, args) -> int:
|
|
247
250
|
errno = 0
|
|
248
251
|
batchfetch_cli = BatchFetchCli(verbose=args.verbose,
|
|
249
252
|
max_workers=int(args.jobs))
|
|
250
|
-
batchfetch_cli.load(
|
|
251
|
-
os.chdir(
|
|
253
|
+
batchfetch_cli.load(file)
|
|
254
|
+
os.chdir(file.parent)
|
|
252
255
|
|
|
253
256
|
try:
|
|
254
257
|
if not batchfetch_cli.run_tasks():
|
|
@@ -276,14 +279,15 @@ def command_line_interface():
|
|
|
276
279
|
|
|
277
280
|
args = parse_args()
|
|
278
281
|
done = []
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
282
|
+
file = Path(args.file)
|
|
283
|
+
file_resolved = file.resolve()
|
|
284
|
+
if not file_resolved:
|
|
285
|
+
print(f"Error: cannot resolve the path {file}",
|
|
286
|
+
file=sys.stderr)
|
|
287
|
+
sys.exit(1)
|
|
288
|
+
|
|
289
|
+
done.append(file_resolved)
|
|
290
|
+
errno |= run_batchfetch_procedure(file, args)
|
|
287
291
|
|
|
288
292
|
sys.exit(errno)
|
|
289
293
|
except BrokenPipeError:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
#
|
|
3
|
-
# Copyright (
|
|
3
|
+
# Copyright (C) 2024 James Cherti
|
|
4
4
|
# URL: https://github.com/jamescherti/batchfetch
|
|
5
5
|
#
|
|
6
6
|
# This program is free software: you can redistribute it and/or modify it under
|
|
@@ -28,18 +28,27 @@ from typing import List, Union
|
|
|
28
28
|
|
|
29
29
|
from schema import Optional
|
|
30
30
|
|
|
31
|
-
from .batchfetch_base import
|
|
31
|
+
from .batchfetch_base import BatchFetchError, TaskBatchFetch
|
|
32
32
|
from .helpers import run_simple
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class GitReferenceDoesNotExist(Exception):
|
|
36
|
-
"""
|
|
36
|
+
"""The Git reference does not exist."""
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
class
|
|
39
|
+
class GitRemoteError(Exception):
|
|
40
|
+
"""The git remote does not exist."""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class BatchFetchGit(TaskBatchFetch):
|
|
40
44
|
"""Clone or update a Git repository."""
|
|
41
45
|
|
|
42
46
|
def __init__(self, *args, **kwargs):
|
|
47
|
+
self._git_fetch_origin_done = False
|
|
48
|
+
|
|
49
|
+
self.branch_commit_ref = None
|
|
50
|
+
self.is_branch = False
|
|
51
|
+
|
|
43
52
|
super().__init__(*args, **kwargs)
|
|
44
53
|
self.env["GIT_TERMINAL_PROMPT"] = "0"
|
|
45
54
|
self.env["GIT_PAGER"] = ""
|
|
@@ -87,25 +96,11 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
87
96
|
posixpath.basename(
|
|
88
97
|
self.values[self.main_key]) # type: ignore
|
|
89
98
|
|
|
90
|
-
def _git_ref(self, cwd: Union[None, Path] = None) -> str:
|
|
91
|
-
"""Get the commit reference of HEAD.
|
|
92
|
-
|
|
93
|
-
The command will fail if the branch is detached.
|
|
94
|
-
"""
|
|
95
|
-
cmd = ["git", "show-ref", "--head", "--verify", "HEAD"]
|
|
96
|
-
try:
|
|
97
|
-
stdout, _ = run_simple(cmd, cwd=cwd, env=self.env)
|
|
98
|
-
output = stdout[0].split(" ")[0]
|
|
99
|
-
except IndexError:
|
|
100
|
-
return ""
|
|
101
|
-
return output
|
|
102
|
-
|
|
103
99
|
def update(self):
|
|
104
100
|
"""Clone or update a Git repository."""
|
|
105
101
|
super().update()
|
|
106
102
|
|
|
107
103
|
is_clone = False
|
|
108
|
-
|
|
109
104
|
if not self.git_local_dir.exists():
|
|
110
105
|
is_clone = True
|
|
111
106
|
|
|
@@ -117,16 +112,15 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
117
112
|
else:
|
|
118
113
|
update_type = "UPDATE"
|
|
119
114
|
|
|
120
|
-
self.add_output(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if self["reference"] else "") + "\n"
|
|
124
|
-
)
|
|
115
|
+
self.add_output(f"[GIT {update_type}] {self[self.main_key]}" +
|
|
116
|
+
(f" (Ref: {self['reference']})"
|
|
117
|
+
if self["reference"] else "") + "\n")
|
|
125
118
|
|
|
126
119
|
try:
|
|
127
120
|
# Delete
|
|
128
121
|
if self["delete"]:
|
|
129
122
|
self._repo_delete()
|
|
123
|
+
|
|
130
124
|
# Clone
|
|
131
125
|
elif is_clone:
|
|
132
126
|
self._repo_clone()
|
|
@@ -134,14 +128,17 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
134
128
|
# Update
|
|
135
129
|
if self.git_local_dir.is_dir():
|
|
136
130
|
# Pre exec
|
|
131
|
+
self._update_current_branch()
|
|
132
|
+
self._repo_fix_remote_origin()
|
|
137
133
|
self._run_pre_exec(cwd=self.git_local_dir)
|
|
138
134
|
|
|
139
|
-
self._repo_check_remote_origin()
|
|
140
|
-
self._update_current_branch()
|
|
141
135
|
self._repo_reset()
|
|
142
136
|
|
|
143
137
|
git_merge_done = self._repo_pull()
|
|
144
|
-
git_branch_changed =
|
|
138
|
+
git_branch_changed = False
|
|
139
|
+
if self.is_branch:
|
|
140
|
+
git_branch_changed = self._repo_fix_branch()
|
|
141
|
+
|
|
145
142
|
if git_merge_done or git_branch_changed:
|
|
146
143
|
self._repo_update_submodules()
|
|
147
144
|
|
|
@@ -163,17 +160,44 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
163
160
|
|
|
164
161
|
return self.values
|
|
165
162
|
|
|
163
|
+
def _git_ref(self, cwd: Union[None, Path] = None) -> str:
|
|
164
|
+
"""Get the commit reference of HEAD.
|
|
165
|
+
|
|
166
|
+
The command will fail if the branch is detached.
|
|
167
|
+
"""
|
|
168
|
+
cmd = ["git", "show-ref", "--head", "--verify", "HEAD"]
|
|
169
|
+
try:
|
|
170
|
+
stdout, _ = run_simple(cmd, cwd=cwd, env=self.env)
|
|
171
|
+
output = stdout[0].split(" ")[0]
|
|
172
|
+
except IndexError:
|
|
173
|
+
return ""
|
|
174
|
+
return output
|
|
175
|
+
|
|
166
176
|
def _update_current_branch(self):
|
|
167
177
|
try:
|
|
168
|
-
|
|
178
|
+
stdout, _ = run_simple(
|
|
169
179
|
["git", "symbolic-ref", "--short", "HEAD"],
|
|
170
180
|
env=self.env,
|
|
171
181
|
cwd=self.git_local_dir,
|
|
172
182
|
)
|
|
173
|
-
|
|
183
|
+
self.current_branch = stdout[0]
|
|
184
|
+
except (IndexError, subprocess.CalledProcessError):
|
|
174
185
|
# Not a symbolic ref
|
|
175
186
|
self.current_branch = None
|
|
176
187
|
|
|
188
|
+
if self.current_branch:
|
|
189
|
+
try:
|
|
190
|
+
# If the tag is annotated, it points to a tag object, not
|
|
191
|
+
# directly to a commit. You need to resolve it to the
|
|
192
|
+
# commit it points to. Using `git rev-parse
|
|
193
|
+
# <tagname>^{commit}` allows getting the right reference.
|
|
194
|
+
commit_ref = self._git_tags("origin/" + self["reference"] +
|
|
195
|
+
"^{commit}")[0]
|
|
196
|
+
self.branch_commit_ref = commit_ref.strip().lower()
|
|
197
|
+
self.is_branch = True
|
|
198
|
+
except GitReferenceDoesNotExist:
|
|
199
|
+
pass
|
|
200
|
+
|
|
177
201
|
def _repo_delete(self):
|
|
178
202
|
if not self.git_local_dir.exists():
|
|
179
203
|
self.add_output(self.indent_spaces + "[INFO] Already deleted\n")
|
|
@@ -209,64 +233,84 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
209
233
|
|
|
210
234
|
# Merge
|
|
211
235
|
do_git_pull = self["git_pull"]
|
|
212
|
-
if self["reference"]:
|
|
236
|
+
if not self["reference"]:
|
|
237
|
+
self.add_output(
|
|
238
|
+
self.indent_spaces +
|
|
239
|
+
"[INFO] Git fetch origin reason: " +
|
|
240
|
+
f"No 'reference:' specified." +
|
|
241
|
+
"\n")
|
|
242
|
+
else:
|
|
213
243
|
do_git_pull = False
|
|
214
244
|
commit_ref = None
|
|
215
245
|
|
|
216
246
|
try:
|
|
217
|
-
#
|
|
218
|
-
#
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
# points to. Using `git rev-parse <tagname>^{commit}` allows
|
|
222
|
-
# getting the right reference.
|
|
223
|
-
commit_ref = self._git_tags(self["reference"] + "^{commit}")[0]
|
|
247
|
+
# Check if the reference such as
|
|
248
|
+
# 0560fe21d1173b2221fd8c600fab818f7eecbad4 exist
|
|
249
|
+
commit_ref = self._git_tags(self["reference"])[0]
|
|
250
|
+
commit_ref = commit_ref.strip().lower()
|
|
224
251
|
except GitReferenceDoesNotExist:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
do_git_pull = True
|
|
234
|
-
except subprocess.CalledProcessError:
|
|
235
|
-
pass
|
|
252
|
+
pass
|
|
253
|
+
|
|
254
|
+
if not commit_ref and not self.is_branch:
|
|
255
|
+
self.add_output(
|
|
256
|
+
self.indent_spaces +
|
|
257
|
+
"[INFO] Git fetch origin reason:" +
|
|
258
|
+
f"The reference does not exist: {self['reference']}" +
|
|
259
|
+
"\n")
|
|
236
260
|
|
|
237
261
|
if not do_git_pull:
|
|
238
262
|
try:
|
|
239
|
-
#
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
# The wanted commit reference does not exist
|
|
250
|
-
# Or the commit ref of HEAD hasn't changed
|
|
251
|
-
if commit_ref and commit_ref_head == commit_ref:
|
|
252
|
-
do_git_pull = False
|
|
253
|
-
else:
|
|
263
|
+
# Check if the branch is a tag or a branch
|
|
264
|
+
cmd = ["git", "show-ref", "--verify", "--quiet",
|
|
265
|
+
f"refs/heads/{self['reference']}"]
|
|
266
|
+
run_simple(cmd, env=self.env, cwd=self.git_local_dir)
|
|
267
|
+
self.add_output(
|
|
268
|
+
self.indent_spaces +
|
|
269
|
+
"[INFO] Git fetch origin reason:" +
|
|
270
|
+
f"{self['reference']} is a branch, not a tag" +
|
|
271
|
+
"\n")
|
|
254
272
|
do_git_pull = True
|
|
273
|
+
except subprocess.CalledProcessError:
|
|
274
|
+
pass
|
|
275
|
+
|
|
276
|
+
# if not do_git_pull:
|
|
277
|
+
# try:
|
|
278
|
+
# # If the tag is annotated, it points to a tag object,
|
|
279
|
+
# # not directly to a commit. You need to resolve it to
|
|
280
|
+
# # the commit it points to. Using `git rev-parse
|
|
281
|
+
# # <tagname>^{commit}` allows getting the right
|
|
282
|
+
# # reference.
|
|
283
|
+
# commit_ref_head = self._git_tags("HEAD^{commit}")[0]
|
|
284
|
+
# commit_ref_head = commit_ref_head.strip().lower()
|
|
285
|
+
# except GitReferenceDoesNotExist:
|
|
286
|
+
# # HEAD is detached
|
|
287
|
+
# commit_ref_head = None
|
|
288
|
+
#
|
|
289
|
+
# # The wanted commit reference does not exist
|
|
290
|
+
# # Or the commit ref of HEAD hasn't changed
|
|
291
|
+
# if not commit_ref_head or commit_ref_head != commit_ref:
|
|
292
|
+
# self.add_output(
|
|
293
|
+
# self.indent_spaces +
|
|
294
|
+
# "[INFO] Git fetch origin reason: "
|
|
295
|
+
# f"Commit ref head '{commit_ref_head}' != "
|
|
296
|
+
# f"commit ref '{commit_ref_head}'"
|
|
297
|
+
# "\n")
|
|
298
|
+
# do_git_pull = True
|
|
255
299
|
|
|
256
300
|
if not do_git_pull:
|
|
257
301
|
self.add_output(self.indent_spaces + "[INFO] git pull ignored\n")
|
|
258
302
|
return git_merge
|
|
259
303
|
|
|
260
304
|
# Fetch
|
|
261
|
-
|
|
262
|
-
self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
|
|
305
|
+
self._git_fetch_origin()
|
|
263
306
|
|
|
264
307
|
# Merge
|
|
265
308
|
real_branch = self._git_is_local_branch("HEAD")
|
|
266
|
-
if real_branch:
|
|
309
|
+
if real_branch and self.current_branch:
|
|
267
310
|
# TODO: only merge when difference from upstream
|
|
268
311
|
commit_ref_head = self._git_ref(cwd=self.git_local_dir)
|
|
269
|
-
self._run(["git", "merge", "--ff-only"
|
|
312
|
+
self._run(["git", "merge", "--ff-only",
|
|
313
|
+
f"origin/{self.current_branch}"],
|
|
270
314
|
cwd=str(self.git_local_dir), env=self.env)
|
|
271
315
|
git_ref_after_merge = self._git_ref(cwd=self.git_local_dir)
|
|
272
316
|
if commit_ref_head != git_ref_after_merge:
|
|
@@ -281,6 +325,43 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
281
325
|
|
|
282
326
|
return git_merge
|
|
283
327
|
|
|
328
|
+
def _git_get_remote_url(self, remote_name: str = "origin") -> str:
|
|
329
|
+
origin_url = ""
|
|
330
|
+
try:
|
|
331
|
+
stdout, _ = run_simple(["git", "config",
|
|
332
|
+
f"remote.{remote_name}.url"],
|
|
333
|
+
env=self.env,
|
|
334
|
+
cwd=self.git_local_dir)
|
|
335
|
+
origin_url = stdout[0]
|
|
336
|
+
except (subprocess.CalledProcessError, IndexError) as err:
|
|
337
|
+
raise GitRemoteError(
|
|
338
|
+
f"Failed to get the Git remote url: {remote_name}") from err
|
|
339
|
+
|
|
340
|
+
return origin_url
|
|
341
|
+
|
|
342
|
+
def _git_set_remote_url(self, url: str,
|
|
343
|
+
remote_name: str = "origin") -> str:
|
|
344
|
+
origin_url = ""
|
|
345
|
+
try:
|
|
346
|
+
run_simple(["git", "remote", "remove", remote_name],
|
|
347
|
+
env=self.env, cwd=self.git_local_dir)
|
|
348
|
+
except subprocess.CalledProcessError:
|
|
349
|
+
# Ignore when it cannot be removed when it does not exist
|
|
350
|
+
pass
|
|
351
|
+
|
|
352
|
+
try:
|
|
353
|
+
stdout, _ = run_simple(
|
|
354
|
+
["git", "remote", "add", remote_name, url],
|
|
355
|
+
env=self.env,
|
|
356
|
+
cwd=self.git_local_dir,
|
|
357
|
+
)
|
|
358
|
+
origin_url = stdout[0]
|
|
359
|
+
except (subprocess.CalledProcessError, IndexError) as err:
|
|
360
|
+
raise GitRemoteError(
|
|
361
|
+
f"Failed to modify the Git remote url: {remote_name}") from err
|
|
362
|
+
|
|
363
|
+
return origin_url
|
|
364
|
+
|
|
284
365
|
def _git_is_local_branch(self, branch: str) -> bool:
|
|
285
366
|
try:
|
|
286
367
|
stdout, _ = run_simple(["git", "rev-parse", "--symbolic-full-name",
|
|
@@ -300,13 +381,19 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
300
381
|
|
|
301
382
|
def _git_tags(self, branch: str) -> List[str]:
|
|
302
383
|
stdout: List[str] = []
|
|
384
|
+
error = False
|
|
303
385
|
try:
|
|
304
386
|
stdout, _ = run_simple(["git", "rev-parse", "--verify", branch],
|
|
305
387
|
env=self.env,
|
|
306
388
|
cwd=self.git_local_dir)
|
|
307
|
-
|
|
389
|
+
if not stdout:
|
|
390
|
+
error = True
|
|
391
|
+
except subprocess.CalledProcessError:
|
|
392
|
+
error = True
|
|
393
|
+
|
|
394
|
+
if error:
|
|
308
395
|
raise GitReferenceDoesNotExist(
|
|
309
|
-
f"The reference '{branch}' does not exist.")
|
|
396
|
+
f"The reference '{branch}' does not exist.")
|
|
310
397
|
|
|
311
398
|
return stdout
|
|
312
399
|
|
|
@@ -325,7 +412,8 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
325
412
|
# Also check the commit reference in case
|
|
326
413
|
# branch is a commit reference instead of a tag
|
|
327
414
|
try:
|
|
328
|
-
git_ref_branch = self._git_tags(
|
|
415
|
+
git_ref_branch = self._git_tags("origin/" +
|
|
416
|
+
self["reference"] +
|
|
329
417
|
"^{commit}")[0]
|
|
330
418
|
except GitReferenceDoesNotExist as err:
|
|
331
419
|
raise BatchFetchError(f"The branch '{self['reference']}' "
|
|
@@ -347,6 +435,13 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
347
435
|
|
|
348
436
|
return branch_changed
|
|
349
437
|
|
|
438
|
+
def _git_fetch_origin(self):
|
|
439
|
+
# Fetch
|
|
440
|
+
if not self._git_fetch_origin_done:
|
|
441
|
+
cmd = ["git", "fetch", "origin"]
|
|
442
|
+
self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
|
|
443
|
+
self._git_fetch_origin_done = True
|
|
444
|
+
|
|
350
445
|
def _repo_update_submodules(self):
|
|
351
446
|
# This parameter instructs Git to initiate the update
|
|
352
447
|
# process for submodules:
|
|
@@ -364,21 +459,41 @@ class BatchFetchGit(BatchFetchBase):
|
|
|
364
459
|
cmd = ["git", "submodule", "update", "--recursive"]
|
|
365
460
|
self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
|
|
366
461
|
|
|
367
|
-
def
|
|
368
|
-
|
|
462
|
+
def _repo_fix_remote_origin(self):
|
|
463
|
+
correct_origin_url = self[self.main_key]
|
|
464
|
+
update_remote_origin = False
|
|
465
|
+
|
|
369
466
|
try:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
467
|
+
origin_url = self._git_get_remote_url()
|
|
468
|
+
if origin_url != correct_origin_url:
|
|
469
|
+
update_remote_origin = True
|
|
470
|
+
except GitRemoteError:
|
|
471
|
+
update_remote_origin = True
|
|
472
|
+
|
|
473
|
+
if update_remote_origin:
|
|
474
|
+
# Update remote
|
|
475
|
+
try:
|
|
476
|
+
self._git_set_remote_url(correct_origin_url)
|
|
477
|
+
except GitRemoteError:
|
|
478
|
+
# TODO handle errors
|
|
479
|
+
return
|
|
376
480
|
|
|
377
|
-
|
|
378
|
-
self.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
481
|
+
# Get the current branch
|
|
482
|
+
if self.current_branch:
|
|
483
|
+
try:
|
|
484
|
+
self.add_output(
|
|
485
|
+
self.indent_spaces +
|
|
486
|
+
"[INFO] Git fetch origin reason: "
|
|
487
|
+
f"we need to set the upstream "
|
|
488
|
+
f"origin to {self.current_branch}"
|
|
489
|
+
"\n"
|
|
490
|
+
)
|
|
491
|
+
self._git_fetch_origin()
|
|
492
|
+
|
|
493
|
+
cmd = ["git", "branch",
|
|
494
|
+
f"--set-upstream-to=origin/{self.current_branch}"]
|
|
495
|
+
_, _ = run_simple(cmd, env=self.env,
|
|
496
|
+
cwd=self.git_local_dir)
|
|
497
|
+
# TODO: handle errors
|
|
498
|
+
except subprocess.CalledProcessError as err:
|
|
499
|
+
raise BatchFetchError(str(err)) from err
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: batchfetch
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: Efficiently clone and pull multiple Git repositories.
|
|
5
5
|
Home-page: https://github.com/jamescherti/batchfetch
|
|
6
6
|
Author: James Cherti
|
|
@@ -95,7 +95,7 @@ options:
|
|
|
95
95
|
|
|
96
96
|
## License
|
|
97
97
|
|
|
98
|
-
Copyright (
|
|
98
|
+
Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
|
|
99
99
|
|
|
100
100
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
101
101
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
#
|
|
3
|
-
# Copyright (
|
|
3
|
+
# Copyright (C) 2024 James Cherti
|
|
4
4
|
# URL: https://github.com/jamescherti/batchfetch
|
|
5
5
|
#
|
|
6
6
|
# This program is free software: you can redistribute it and/or modify it under
|
|
@@ -22,7 +22,7 @@ from setuptools import find_packages, setup
|
|
|
22
22
|
|
|
23
23
|
setup(
|
|
24
24
|
name="batchfetch",
|
|
25
|
-
version="1.1.
|
|
25
|
+
version="1.1.4",
|
|
26
26
|
packages=find_packages(),
|
|
27
27
|
description="Efficiently clone and pull multiple Git repositories.",
|
|
28
28
|
license="GPLv3",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|