batchfetch 1.3.3__tar.gz → 1.3.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: batchfetch
3
- Version: 1.3.3
3
+ Version: 1.3.5
4
4
  Summary: Efficiently clone and pull multiple Git repositories.
5
5
  Home-page: https://github.com/jamescherti/batchfetch
6
6
  Author: James Cherti
@@ -213,7 +213,7 @@ batchfetch
213
213
 
214
214
  ## License
215
215
 
216
- Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
216
+ Copyright (C) 2024-2025 [James Cherti](https://www.jamescherti.com)
217
217
 
218
218
  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.
219
219
 
@@ -193,7 +193,7 @@ batchfetch
193
193
 
194
194
  ## License
195
195
 
196
- Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
196
+ Copyright (C) 2024-2025 [James Cherti](https://www.jamescherti.com)
197
197
 
198
198
  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.
199
199
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  #
3
- # Copyright (C) 2024 James Cherti
3
+ # Copyright (C) 2024-2025 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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  #
3
- # Copyright (C) 2024 James Cherti
3
+ # Copyright (C) 2024-2025 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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  #
3
- # Copyright (C) 2024 James Cherti
3
+ # Copyright (C) 2024-2025 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
@@ -35,6 +35,7 @@ from setproctitle import setproctitle
35
35
 
36
36
  from .batchfetch_base import BatchFetchError, TaskBatchFetch
37
37
  from .batchfetch_git import BatchFetchGit
38
+ from .helpers import collect_parent_dirs
38
39
 
39
40
 
40
41
  class BatchFetchCli:
@@ -100,10 +101,17 @@ class BatchFetchCli:
100
101
  file=sys.stderr)
101
102
  sys.exit(1)
102
103
 
103
- self.ignore_untracked.add(Path(path).absolute())
104
- self.ignore_untracked.add(Path(path).resolve())
104
+ # The Batchfetch file shouldn't be tracked
105
+ absolute_batchfetch = Path(path).absolute()
106
+ self.ignore_untracked.add(absolute_batchfetch)
107
+
108
+ resolved_batchfetch = absolute_batchfetch.resolve()
109
+ self.ignore_untracked.add(resolved_batchfetch)
110
+
111
+ # Paths specified in the batchfetch.yaml file
105
112
  untracked_paths = None
106
113
  if "options" in yaml_dict and \
114
+ isinstance(yaml_dict["options"], dict) and \
107
115
  "ignore_untracked" in yaml_dict["options"]:
108
116
  untracked_paths = \
109
117
  yaml_dict["options"]["ignore_untracked"]
@@ -113,9 +121,14 @@ class BatchFetchCli:
113
121
 
114
122
  if untracked_paths:
115
123
  for ignore_untracked_path in untracked_paths:
116
- self.ignore_untracked.add(
124
+ # Absolute
125
+ ignore_untracked_path = \
117
126
  Path(ignore_untracked_path).absolute()
118
- )
127
+ self.ignore_untracked.add(ignore_untracked_path)
128
+
129
+ # Resolve
130
+ ignore_untracked_path = ignore_untracked_path.resolve()
131
+ self.ignore_untracked.add(ignore_untracked_path)
119
132
 
120
133
  self._loads(dict(yaml_dict))
121
134
  except OSError as err:
@@ -273,10 +286,22 @@ class BatchFetchCli:
273
286
  def _find_untracked_paths(self):
274
287
  "Find the files that are untracked and should be deleted."
275
288
  untracked_paths = set()
289
+ cwd = Path.cwd()
290
+ local_ignore_untracked = set()
291
+
292
+ for tracked_dir, tracked_filenames in self.tracked_paths.items():
293
+ actual_filenames = {file.name for file in tracked_dir.iterdir()}
294
+ self.ignore_untracked |= {tracked_dir}
295
+ parents = collect_parent_dirs(cwd, tracked_dir)
296
+ local_ignore_untracked |= parents
297
+
276
298
  for tracked_dir, tracked_filenames in self.tracked_paths.items():
277
299
  actual_filenames = {file.name for file in tracked_dir.iterdir()}
278
300
  for filename in actual_filenames - tracked_filenames:
279
301
  full_path = tracked_dir / filename
302
+ if full_path in local_ignore_untracked:
303
+ continue
304
+
280
305
  if full_path in self.ignore_untracked:
281
306
  continue
282
307
 
@@ -422,19 +447,21 @@ def command_line_interface():
422
447
  print()
423
448
 
424
449
  os.chdir(args.directory)
425
- batchfetch_cli = BatchFetchCli(verbose=args.verbose,
426
- max_workers=args.jobs,
427
- check_untracked=args.check_untracked,
428
- targets=args.targets)
429
- batchfetch_cli.load(file)
430
-
431
450
  try:
451
+ batchfetch_cli = BatchFetchCli(
452
+ verbose=args.verbose,
453
+ max_workers=args.jobs,
454
+ check_untracked=args.check_untracked,
455
+ targets=args.targets,
456
+ )
457
+
458
+ batchfetch_cli.load(file)
432
459
  if not batchfetch_cli.run_tasks():
433
460
  errno = 1
434
461
  except KeyboardInterrupt:
435
462
  print("Interrupted.", file=sys.stderr)
436
463
  errno = 1
437
- except BatchFetchError as err:
464
+ except (yaml.parser.MarkedYAMLError, BatchFetchError) as err:
438
465
  print(f"Error: {err}.", file=sys.stderr)
439
466
  errno = 1
440
467
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  #
3
- # Copyright (C) 2024 James Cherti
3
+ # Copyright (C) 2024-2025 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
@@ -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
- if self["revision"] else "") + "\n")
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
- self._update_current_branch_name()
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 refs/remotes/origin/HEAD"
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
- f"[INFO] Update revision to: '" +
151
+ "[INFO] Update revision to: '" +
149
152
  self["revision"] + "'\n")
150
153
 
151
- git_fetch_done = self._repo_fetch()
154
+ if do_git_fetch:
155
+ git_fetch_done = self._repo_fetch()
152
156
 
153
- git_branch_changed = False
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
- git_merge_done = self._git_merge()
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
- stdout, _ = self._run(["git", "cat-file", "-e", self["revision"]])
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
1
  #!/usr/bin/env python
2
2
  #
3
- # Copyright (C) 2024 James Cherti
3
+ # Copyright (C) 2024-2025 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
@@ -21,8 +21,9 @@
21
21
  import hashlib
22
22
  import os
23
23
  import shlex
24
+ from pathlib import Path
24
25
  from subprocess import PIPE, CalledProcessError, Popen, list2cmdline
25
- from typing import List, Tuple, Union
26
+ from typing import List, Set, Tuple, Union
26
27
 
27
28
 
28
29
  def md5sum(filename: os.PathLike):
@@ -116,3 +117,25 @@ def run_indent(cmd: Union[List[str], str], spaces: int = 4,
116
117
  stderr = indent_raw_output(stderr, spaces)
117
118
 
118
119
  return (stdout, stderr)
120
+
121
+
122
+ def collect_parent_dirs(base_dir: Path, dir: Path) -> Set[Path]:
123
+ """Collect all parent directories of 'dir' until 'base_dir' is reached.
124
+
125
+ If 'dir' is not inside 'base_dir', return None.
126
+ """
127
+ parents: Set[Path] = set()
128
+
129
+ for dir_path, base_path in [(dir.resolve(), base_dir.resolve()),
130
+ (dir.absolute(), base_dir.absolute())]:
131
+ try:
132
+ # Check if dir is inside base_dir
133
+ dir_path.relative_to(base_path)
134
+ except ValueError:
135
+ continue
136
+
137
+ while dir_path != base_path:
138
+ parents.add(dir_path)
139
+ dir_path = dir_path.parent
140
+
141
+ return parents
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: batchfetch
3
- Version: 1.3.3
3
+ Version: 1.3.5
4
4
  Summary: Efficiently clone and pull multiple Git repositories.
5
5
  Home-page: https://github.com/jamescherti/batchfetch
6
6
  Author: James Cherti
@@ -213,7 +213,7 @@ batchfetch
213
213
 
214
214
  ## License
215
215
 
216
- Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
216
+ Copyright (C) 2024-2025 [James Cherti](https://www.jamescherti.com)
217
217
 
218
218
  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.
219
219
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  #
3
- # Copyright (C) 2024 James Cherti
3
+ # Copyright (C) 2024-2025 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.3.3",
25
+ version="1.3.5",
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