batchfetch 1.2.5__tar.gz → 1.2.7__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.
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.1
2
+ Name: batchfetch
3
+ Version: 1.2.7
4
+ Summary: Efficiently clone and pull multiple Git repositories.
5
+ Home-page: https://github.com/jamescherti/batchfetch
6
+ Author: James Cherti
7
+ License: GPLv3
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: License :: OSI Approved :: GNU General Public License (GPL)
10
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
+ Classifier: Environment :: Console
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Operating System :: POSIX :: Other
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Version Control :: Git
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.6, <4
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+
21
+ # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
22
+
23
+ ## Introduction
24
+
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, freeing you up to focus on what truly matters: your workflow.
26
+
27
+ 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
+
29
+ Batchfetch is ideal for quickly cloning or pulling multiple Git repositories. It is also useful for cloning various addons, such as Vim plugins, Emacs packages, Ansible roles, Ansible collections, and other addons available on websites like GitHub, Codeberg, and GitLab.
30
+
31
+ ## Installation
32
+
33
+ Here is how to install *batchfetch* using [pip](https://pypi.org/project/pip/):
34
+ ```
35
+ pip install --user batchfetch
36
+ ```
37
+
38
+ The pip command above installs the *batchfetch* executable in the `~/.local/bin/` directory. Omitting the `--user` flag will install it system-wide.
39
+
40
+ ## Usage
41
+
42
+ ### Example of a `batchfetch.yaml` file
43
+
44
+ Here is an example of a `batchfetch.yaml` file:
45
+
46
+ ```yaml
47
+ ---
48
+
49
+ tasks:
50
+ # Clone the default branch of the general.el repository to the
51
+ # './general.el' directory
52
+ - git: https://github.com/jamescherti/compile-angel.el
53
+
54
+ # Clone the tag 1.5 of the consult repository to the './consult'
55
+ # directory
56
+ - git: https://github.com/jamescherti/outline-indent.el
57
+ revision: "1.1.0"
58
+
59
+ # Clone the s.el repository to the './another-name.el' directory
60
+ - git: https://github.com/jamescherti/easysession.el
61
+ path: easysession
62
+ revision: b9c6d9b6134b4981760893254f804a371ffbc899
63
+
64
+ # Delete the local copy of the following repository
65
+ - git: https://github.com/jamescherti/dir-config.el
66
+ delete: true
67
+ ```
68
+
69
+ Execute the `batchfetch` command from the same directory as `batchfetch.yml` to make it clone or update the local copies of the repositories above.
70
+
71
+ ## Command-line options
72
+
73
+ Here are the various options that `batchfetch` provides, along with descriptions of their usage:
74
+
75
+ ```
76
+ usage: batchfetch [--option]
77
+
78
+ Efficiently clone/pull multiple Git repositories in parallel.
79
+
80
+ options:
81
+ -h, --help show this help message and exit
82
+ -f FILE, --file FILE Specify the batchfetch YAML file (default:
83
+ './batchfetch.yaml').
84
+ -C DIRECTORY, --directory DIRECTORY
85
+ Change the working directory before reading the
86
+ batchfetch.yaml file. If not specified, the directory is
87
+ set to the parent directory of the batchfetch.yaml file.
88
+ -j JOBS, --jobs JOBS Run up to N parallel processes (default: 5).
89
+ Alternatively, the BATCHFETCH_JOBS environment variable
90
+ can be used to configure the number of jobs.
91
+ -v, --verbose Enable verbose mode.
92
+ ```
93
+
94
+ ## Features
95
+ - Git Clone and Fetch/Merge: Clones the repositories and their submodules, ensuring that all the repositories are always up-to-date by fetching and merging changes.
96
+ - Parallel Operations: Utilizes threads to simultaneously Git clone or pull multiple repositories, dramatically reducing wait times.
97
+ - User-Friendly Interface: Provides simple and straightforward command-line options that make it easy to get started and effectively manage your repositories.
98
+ - Custom Configuration: Allows the use of a YAML configuration file to specify and manage the repositories you interact with, enabling repeatable setups and consistent environments.
99
+ - Detect files that should not be present in directories managed by batchfetch, known as untracked files.
100
+
101
+ ## Frequently Asked Questions
102
+
103
+ ### What are untracked files?
104
+
105
+ The parent directory of the "path:" value defines the managed directory, where the directory of each path is considered as the managed directory.
106
+
107
+ For example, if the "path:" value is `file/my-project`, the managed directory will be `file/`. Any file within `file/` that is not managed by batchfetch will be considered an untracked file.
108
+
109
+ When *batchfetch* encounters an untracked file, it displays an error message to inform users about paths that are not managed by the system. The message provides clear instructions on how to handle these paths by adding them to the `options.ignore_untracked_paths` list, enabling users to manage untracked files effectively.
110
+
111
+ Here is an example of a *batchfetch.yaml* file that enables *batchfetch* to accept a list of untracked files:
112
+
113
+ ``` yaml
114
+ options:
115
+ ignore_untracked_paths:
116
+ - ./test
117
+ - /absolute/path
118
+ - ../relative/path
119
+
120
+ tasks:
121
+ - git: https://github.com/user/project
122
+ ```
123
+
124
+ By default, *batchfetch.yaml* is the only untracked file that is ignored. The user does not need to add it to the *ignore_untracked_paths* option.
125
+
126
+ ### How is the Git local paths handled?
127
+
128
+ When "path:" is specified, that's the path that is used.
129
+
130
+ When "path:" is not specified, Batchfetch attempts to determine the path name by extracting the repository name from the URI (e.g., `https://domain.com/repo` becomes `repo`). If the URL ends with a `.git` extension, it removes the extension (e.g., `https://domain.com/repo.git` becomes `repo`).
131
+
132
+ ### How does Batchfetch detect when a git fetch is necessary?
133
+
134
+ Batchfetch is fast, not only because it runs Git commands in parallel, but also because it intelligently detects whether a `git fetch` is needed, further speeding up the process of downloading data from repositories.
135
+
136
+ When the user has specifies a revision (branch or commit reference), Batchfetch only performs a `git fetch` if that revision does not exist locally. If the revision is already up to date, it simply proceeds to the next repository in the queue.
137
+
138
+ That's why it is highly recommended to always specify the revision to speed up Batchfetch, if speed is important to you. Here is an example of a `batchfetch.yaml` file where the branch (`1.1.0`) or commit reference (`b9c6d9b6134b4981760893254f804a371ffbc899`) is specified:
139
+ ``` yaml
140
+ tasks:
141
+ - git: https://github.com/jamescherti/outline-indent.el
142
+ revision: "1.1.0"
143
+
144
+ - git: https://github.com/jamescherti/easysession.el
145
+ path: easysession
146
+ revision: b9c6d9b6134b4981760893254f804a371ffbc899
147
+ ```
148
+
149
+ ### How to execute a command before and after a task?
150
+
151
+ To execute a command both before and after a specific task, you can define the `exec_before` and `exec_after` directives within the task configuration. These directives specify commands to be executed at the respective stages of the task lifecycle.
152
+
153
+ Here is an example:
154
+ ``` yaml
155
+ ---
156
+ tasks:
157
+ - git: https://github.com/jamescherti/easysession.el
158
+ path: easysession
159
+ exec_before: ["sh", "-c", "echo exec_before_task"]
160
+ exec_after: ["sh", "-c", "echo exec_after_task"]
161
+ ```
162
+
163
+ ## License
164
+
165
+ Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
166
+
167
+ 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.
168
+
169
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
170
+
171
+ You should have received a copy of the GNU General Public License along with this program.
172
+
173
+ ## Links
174
+
175
+ - [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
176
+ - [batchfetch @Pypi](https://pypi.org/project/batchfetch/)
@@ -0,0 +1,156 @@
1
+ # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
2
+
3
+ ## Introduction
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, freeing you up to focus on what truly matters: your workflow.
6
+
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
+
9
+ Batchfetch is ideal for quickly cloning or pulling multiple Git repositories. It is also useful for cloning various addons, such as Vim plugins, Emacs packages, Ansible roles, Ansible collections, and other addons available on websites like GitHub, Codeberg, and GitLab.
10
+
11
+ ## Installation
12
+
13
+ Here is how to install *batchfetch* using [pip](https://pypi.org/project/pip/):
14
+ ```
15
+ pip install --user batchfetch
16
+ ```
17
+
18
+ The pip command above installs the *batchfetch* executable in the `~/.local/bin/` directory. Omitting the `--user` flag will install it system-wide.
19
+
20
+ ## Usage
21
+
22
+ ### Example of a `batchfetch.yaml` file
23
+
24
+ Here is an example of a `batchfetch.yaml` file:
25
+
26
+ ```yaml
27
+ ---
28
+
29
+ tasks:
30
+ # Clone the default branch of the general.el repository to the
31
+ # './general.el' directory
32
+ - git: https://github.com/jamescherti/compile-angel.el
33
+
34
+ # Clone the tag 1.5 of the consult repository to the './consult'
35
+ # directory
36
+ - git: https://github.com/jamescherti/outline-indent.el
37
+ revision: "1.1.0"
38
+
39
+ # Clone the s.el repository to the './another-name.el' directory
40
+ - git: https://github.com/jamescherti/easysession.el
41
+ path: easysession
42
+ revision: b9c6d9b6134b4981760893254f804a371ffbc899
43
+
44
+ # Delete the local copy of the following repository
45
+ - git: https://github.com/jamescherti/dir-config.el
46
+ delete: true
47
+ ```
48
+
49
+ Execute the `batchfetch` command from the same directory as `batchfetch.yml` to make it clone or update the local copies of the repositories above.
50
+
51
+ ## Command-line options
52
+
53
+ Here are the various options that `batchfetch` provides, along with descriptions of their usage:
54
+
55
+ ```
56
+ usage: batchfetch [--option]
57
+
58
+ Efficiently clone/pull multiple Git repositories in parallel.
59
+
60
+ options:
61
+ -h, --help show this help message and exit
62
+ -f FILE, --file FILE Specify the batchfetch YAML file (default:
63
+ './batchfetch.yaml').
64
+ -C DIRECTORY, --directory DIRECTORY
65
+ Change the working directory before reading the
66
+ batchfetch.yaml file. If not specified, the directory is
67
+ set to the parent directory of the batchfetch.yaml file.
68
+ -j JOBS, --jobs JOBS Run up to N parallel processes (default: 5).
69
+ Alternatively, the BATCHFETCH_JOBS environment variable
70
+ can be used to configure the number of jobs.
71
+ -v, --verbose Enable verbose mode.
72
+ ```
73
+
74
+ ## Features
75
+ - Git Clone and Fetch/Merge: Clones the repositories and their submodules, ensuring that all the repositories are always up-to-date by fetching and merging changes.
76
+ - Parallel Operations: Utilizes threads to simultaneously Git clone or pull multiple repositories, dramatically reducing wait times.
77
+ - User-Friendly Interface: Provides simple and straightforward command-line options that make it easy to get started and effectively manage your repositories.
78
+ - Custom Configuration: Allows the use of a YAML configuration file to specify and manage the repositories you interact with, enabling repeatable setups and consistent environments.
79
+ - Detect files that should not be present in directories managed by batchfetch, known as untracked files.
80
+
81
+ ## Frequently Asked Questions
82
+
83
+ ### What are untracked files?
84
+
85
+ The parent directory of the "path:" value defines the managed directory, where the directory of each path is considered as the managed directory.
86
+
87
+ For example, if the "path:" value is `file/my-project`, the managed directory will be `file/`. Any file within `file/` that is not managed by batchfetch will be considered an untracked file.
88
+
89
+ When *batchfetch* encounters an untracked file, it displays an error message to inform users about paths that are not managed by the system. The message provides clear instructions on how to handle these paths by adding them to the `options.ignore_untracked_paths` list, enabling users to manage untracked files effectively.
90
+
91
+ Here is an example of a *batchfetch.yaml* file that enables *batchfetch* to accept a list of untracked files:
92
+
93
+ ``` yaml
94
+ options:
95
+ ignore_untracked_paths:
96
+ - ./test
97
+ - /absolute/path
98
+ - ../relative/path
99
+
100
+ tasks:
101
+ - git: https://github.com/user/project
102
+ ```
103
+
104
+ By default, *batchfetch.yaml* is the only untracked file that is ignored. The user does not need to add it to the *ignore_untracked_paths* option.
105
+
106
+ ### How is the Git local paths handled?
107
+
108
+ When "path:" is specified, that's the path that is used.
109
+
110
+ When "path:" is not specified, Batchfetch attempts to determine the path name by extracting the repository name from the URI (e.g., `https://domain.com/repo` becomes `repo`). If the URL ends with a `.git` extension, it removes the extension (e.g., `https://domain.com/repo.git` becomes `repo`).
111
+
112
+ ### How does Batchfetch detect when a git fetch is necessary?
113
+
114
+ Batchfetch is fast, not only because it runs Git commands in parallel, but also because it intelligently detects whether a `git fetch` is needed, further speeding up the process of downloading data from repositories.
115
+
116
+ When the user has specifies a revision (branch or commit reference), Batchfetch only performs a `git fetch` if that revision does not exist locally. If the revision is already up to date, it simply proceeds to the next repository in the queue.
117
+
118
+ That's why it is highly recommended to always specify the revision to speed up Batchfetch, if speed is important to you. Here is an example of a `batchfetch.yaml` file where the branch (`1.1.0`) or commit reference (`b9c6d9b6134b4981760893254f804a371ffbc899`) is specified:
119
+ ``` yaml
120
+ tasks:
121
+ - git: https://github.com/jamescherti/outline-indent.el
122
+ revision: "1.1.0"
123
+
124
+ - git: https://github.com/jamescherti/easysession.el
125
+ path: easysession
126
+ revision: b9c6d9b6134b4981760893254f804a371ffbc899
127
+ ```
128
+
129
+ ### How to execute a command before and after a task?
130
+
131
+ To execute a command both before and after a specific task, you can define the `exec_before` and `exec_after` directives within the task configuration. These directives specify commands to be executed at the respective stages of the task lifecycle.
132
+
133
+ Here is an example:
134
+ ``` yaml
135
+ ---
136
+ tasks:
137
+ - git: https://github.com/jamescherti/easysession.el
138
+ path: easysession
139
+ exec_before: ["sh", "-c", "echo exec_before_task"]
140
+ exec_after: ["sh", "-c", "echo exec_after_task"]
141
+ ```
142
+
143
+ ## License
144
+
145
+ Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
146
+
147
+ 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.
148
+
149
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
150
+
151
+ You should have received a copy of the GNU General Public License along with this program.
152
+
153
+ ## Links
154
+
155
+ - [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
156
+ - [batchfetch @Pypi](https://pypi.org/project/batchfetch/)
@@ -107,6 +107,7 @@ class TaskBatchFetch(TaskBase):
107
107
  self.global_options_schema: Dict[Any, Any] = {
108
108
  Optional("exec_before"): Or([str], str),
109
109
  Optional("exec_after"): Or([str], str),
110
+ Optional("ignore_untracked_paths"): Or([str], str),
110
111
  }
111
112
 
112
113
  self.task_schema: Dict[Any, Any] = {
@@ -120,6 +121,7 @@ class TaskBatchFetch(TaskBase):
120
121
  self.global_options_values: Dict[str, Any] = {
121
122
  "exec_before": [],
122
123
  "exec_after": [],
124
+ "ignore_untracked_paths": [],
123
125
  }
124
126
 
125
127
  self.task_default_values: Dict[str, Any] = {
@@ -25,7 +25,7 @@ import subprocess
25
25
  import sys
26
26
  from concurrent.futures import ThreadPoolExecutor, as_completed
27
27
  from pathlib import Path
28
- from typing import Any, Dict, Set
28
+ from typing import Any, Dict, Set, Union
29
29
 
30
30
  import colorama
31
31
  import yaml # type: ignore
@@ -40,10 +40,12 @@ from .batchfetch_git import BatchFetchGit
40
40
  class BatchFetchCli:
41
41
  """Command-line-interface that downloads."""
42
42
 
43
- def __init__(self, max_workers: int, verbose: bool = False):
43
+ def __init__(self, max_workers: int, verbose: bool, check_untracked: bool):
44
44
  self.cfg: dict = {}
45
45
  self.folder = Path(".")
46
- self.managed_paths: Set[Path] = set()
46
+ self.check_untracked = check_untracked
47
+ self.tracked_paths: Dict[Path, Set[str]] = {}
48
+ self.ignore_untracked_paths: Set[Path] = set()
47
49
  self.verbose = verbose
48
50
  self.max_workers = max_workers
49
51
  self._logger = logging.getLogger(self.__class__.__name__)
@@ -97,6 +99,23 @@ class BatchFetchCli:
97
99
  file=sys.stderr)
98
100
  sys.exit(1)
99
101
 
102
+ self.ignore_untracked_paths.add(Path(path).absolute())
103
+ self.ignore_untracked_paths.add(Path(path).resolve())
104
+ untracked_paths = None
105
+ if "options" in yaml_dict and \
106
+ "ignore_untracked_paths" in yaml_dict["options"]:
107
+ untracked_paths = \
108
+ yaml_dict["options"]["ignore_untracked_paths"]
109
+
110
+ if isinstance(untracked_paths, str):
111
+ untracked_paths = [untracked_paths]
112
+
113
+ if untracked_paths:
114
+ for ignore_untracked_path in untracked_paths:
115
+ self.ignore_untracked_paths.add(
116
+ Path(ignore_untracked_path).absolute()
117
+ )
118
+
100
119
  self._loads(dict(yaml_dict))
101
120
  except OSError as err:
102
121
  raise BatchFetchError(str(err)) from err
@@ -138,10 +157,12 @@ class BatchFetchCli:
138
157
  print(f"Schema error: {err}.", file=sys.stderr)
139
158
  sys.exit(1)
140
159
 
141
- dest_path = Path(batchfetch_instance["path"]).resolve()
142
- if str(dest_path) in dict_local_dir:
160
+ dest_path = Path(batchfetch_instance["path"]).absolute()
161
+ dest_path2 = Path(batchfetch_instance["path"]).resolve()
162
+ if str(dest_path) in dict_local_dir \
163
+ or str(dest_path2) in dict_local_dir:
143
164
  err_str = ("More than one task have the " +
144
- f"destination path '{dest_path}' (" +
165
+ f"destination path (" +
145
166
  str(task[keyword]) + " and " +
146
167
  str(dict_local_dir[(str(dest_path))]) +
147
168
  ")")
@@ -154,7 +175,7 @@ class BatchFetchCli:
154
175
  error = False
155
176
  threads = []
156
177
  num_success = 0
157
- self.managed_paths = set()
178
+ self.tracked_paths = {}
158
179
 
159
180
  executor_update = ThreadPoolExecutor(max_workers=self.max_workers)
160
181
 
@@ -165,7 +186,15 @@ class BatchFetchCli:
165
186
  for task in all_tasks:
166
187
  self.dirs_relative_to_batchfetch.add(str(task["path"]))
167
188
  if not task["delete"]:
168
- self.managed_paths.add(Path(task["path"]).absolute())
189
+ full_path = Path(task["path"]).absolute()
190
+ base_path = full_path.parent
191
+ try:
192
+ self.tracked_paths[base_path]
193
+ except KeyError:
194
+ self.tracked_paths[base_path] = set()
195
+
196
+ self.tracked_paths[base_path].add(full_path.name)
197
+
169
198
  threads.append(executor_update.submit(task.update))
170
199
 
171
200
  for future in as_completed(threads):
@@ -207,6 +236,9 @@ class BatchFetchCli:
207
236
 
208
237
  return False
209
238
  else:
239
+ if self.check_untracked:
240
+ self._find_untracked_paths()
241
+
210
242
  if num_success == 0:
211
243
  print("Nothing to do.")
212
244
  elif not self.verbose:
@@ -214,11 +246,53 @@ class BatchFetchCli:
214
246
 
215
247
  return True
216
248
 
249
+ def _find_untracked_paths(self):
250
+ "Find the files that are untracked and should be deleted."
251
+ untracked_paths = set()
252
+ for tracked_dir, tracked_filenames in self.tracked_paths.items():
253
+ actual_filenames = {file.name for file in tracked_dir.iterdir()}
254
+ for filename in actual_filenames - tracked_filenames:
255
+ full_path = tracked_dir / filename
256
+ if full_path in self.ignore_untracked_paths:
257
+ continue
258
+
259
+ untracked_paths.add(full_path)
260
+
261
+ if untracked_paths:
262
+ err_str = "The following files need to be deleted:\n"
263
+ for path in untracked_paths:
264
+ err_str += (" - " +
265
+ str(path) +
266
+ ("/" if path.is_dir() else "") +
267
+ "\n")
268
+ err_str += ("The paths above are not managed by batchfetch."
269
+ " To retain them, add them to the "
270
+ "options.ignore_untracked_paths list, using either "
271
+ "relative or absolute paths")
272
+ raise BatchFetchError(err_str)
273
+
217
274
 
218
275
  def parse_args():
219
276
  """Parse the command line arguments."""
220
- desc = __doc__
221
- usage = "%(prog)s [--option] [args]"
277
+ # Jobs
278
+ try:
279
+ jobs = os.environ["BATCHFETCH_JOBS"]
280
+ except KeyError:
281
+ jobs = 5
282
+ else:
283
+ if jobs:
284
+ jobs = int(jobs)
285
+
286
+ # Check untracked
287
+ try:
288
+ check_untracked = os.environ["BATCHFETCH_CHECK_UNTRACKED"]
289
+ except KeyError:
290
+ check_untracked = False
291
+ else:
292
+ check_untracked = bool(check_untracked)
293
+
294
+ desc = "Efficiently clone/pull multiple Git repositories in parallel."
295
+ usage = "%(prog)s [--option]"
222
296
  parser = argparse.ArgumentParser(description=desc, usage=usage)
223
297
 
224
298
  parser.add_argument("-f",
@@ -229,15 +303,40 @@ def parse_args():
229
303
  "(default: './batchfetch.yaml')."))
230
304
 
231
305
  parser.add_argument(
232
- "-j", "--jobs", default="5", required=False,
233
- help="Run up to N Number of parallel processes (Default: 5).",
306
+ "-C",
307
+ "--directory",
308
+ default=None,
309
+ required=False,
310
+ help=("Change the working directory before reading the "
311
+ "batchfetch.yaml file. If not specified, the directory is "
312
+ "set to the parent directory of the batchfetch.yaml file.")
234
313
  )
235
314
 
315
+ parser.add_argument(
316
+ "-j",
317
+ "--jobs",
318
+ default=jobs,
319
+ type=int,
320
+ required=False,
321
+ help=("Run up to N parallel processes (default: 5). "
322
+ "Alternatively, the BATCHFETCH_JOBS environment variable can be "
323
+ "used to configure the number of jobs."))
324
+
236
325
  parser.add_argument(
237
326
  "-v", "--verbose", action="store_true", default=False,
238
327
  help="Enable verbose mode.",
239
328
  )
240
329
 
330
+ parser.add_argument(
331
+ "-u",
332
+ "--check-untracked",
333
+ default=check_untracked,
334
+ action="store_true",
335
+ required=False,
336
+ help=("Abort if untracked files or directories exist. "
337
+ "Alternatively, set the BATCHFETCH_CHECK_UNTRACKED=1 "
338
+ "environment variable to enable this check."))
339
+
241
340
  args = parser.parse_args()
242
341
 
243
342
  if not args.file:
@@ -251,12 +350,17 @@ def parse_args():
251
350
  return args
252
351
 
253
352
 
254
- def run_batchfetch_procedure(file: Path, args) -> int:
353
+ def run_batchfetch_procedure(file: Path,
354
+ directory: Union[None, Path],
355
+ verbose: bool,
356
+ jobs: int,
357
+ check_untracked: bool) -> int:
255
358
  errno = 0
256
- batchfetch_cli = BatchFetchCli(verbose=args.verbose,
257
- max_workers=int(args.jobs))
359
+ batchfetch_cli = BatchFetchCli(verbose=verbose,
360
+ max_workers=int(jobs),
361
+ check_untracked=check_untracked)
362
+ os.chdir(directory)
258
363
  batchfetch_cli.load(file)
259
- os.chdir(file.parent)
260
364
 
261
365
  try:
262
366
  if not batchfetch_cli.run_tasks():
@@ -285,14 +389,27 @@ def command_line_interface():
285
389
  args = parse_args()
286
390
  done = []
287
391
  file = Path(args.file)
288
- file_resolved = file.resolve()
392
+ file_resolved = file.absolute()
289
393
  if not file_resolved:
290
394
  print(f"Error: cannot resolve the path {file}",
291
395
  file=sys.stderr)
292
396
  sys.exit(1)
293
397
 
294
398
  done.append(file_resolved)
295
- errno |= run_batchfetch_procedure(file, args)
399
+
400
+ args.directory = args.directory if args.directory else file.parent
401
+ if args.verbose and args.jobs:
402
+ print(f"[FILE] {file}")
403
+ print(f"[DIR] {args.directory}")
404
+ print(f"[JOBS] {args.jobs}")
405
+ print(f"[CHECK UNTRACKED] {args.check_untracked}")
406
+ print()
407
+
408
+ errno |= run_batchfetch_procedure(file=file,
409
+ directory=args.directory,
410
+ verbose=args.verbose,
411
+ jobs=args.jobs,
412
+ check_untracked=args.check_untracked)
296
413
 
297
414
  sys.exit(errno)
298
415
  except BrokenPipeError:
@@ -93,9 +93,12 @@ class BatchFetchGit(TaskBatchFetch):
93
93
  self.values[self.main_key].rstrip("/")
94
94
 
95
95
  if "path" not in self.values:
96
- self.values["path"] = \
97
- posixpath.basename(
98
- self.values[self.main_key]) # type: ignore
96
+ path = \
97
+ posixpath.basename(self.values[self.main_key]) # type: ignore
98
+ # Remove .git from the file name
99
+ if path.endswith(".git"):
100
+ path = path[:-4]
101
+ self.values["path"] = path
99
102
 
100
103
  def update(self):
101
104
  """Clone or update a Git repository."""
@@ -120,7 +123,7 @@ class BatchFetchGit(TaskBatchFetch):
120
123
 
121
124
  self.add_output(f"[GIT {update_type}] {self[self.main_key]}"
122
125
  + (f" (Ref: {self['revision']})"
123
- if self["revision"] else "") + "\n")
126
+ if self["revision"] else "") + "\n")
124
127
 
125
128
  try:
126
129
  # Delete
@@ -203,8 +206,8 @@ class BatchFetchGit(TaskBatchFetch):
203
206
  # directly to a commit. You need to resolve it to the
204
207
  # commit it points to. Using `git rev-parse
205
208
  # <tagname>^{commit}` allows getting the right revision.
206
- commit_ref = self._git_tags(self["revision"]
207
- + "^{commit}")[0]
209
+ commit_ref = self._git_rev_parse_verify(self["revision"]
210
+ + "^{commit}")[0]
208
211
  self.branch_commit_ref = commit_ref.strip()
209
212
  except GitRevisionDoesNotExist:
210
213
  pass
@@ -242,9 +245,7 @@ class BatchFetchGit(TaskBatchFetch):
242
245
  def _repo_fetch(self):
243
246
  # Merge
244
247
  do_git_fetch = self["git_pull"]
245
- if self.is_branch:
246
- do_git_fetch = True
247
- elif not self["revision"]:
248
+ if not self["revision"]:
248
249
  do_git_fetch = True
249
250
  self.add_output(self.indent_spaces
250
251
  + "[INFO] Git fetch origin reason: "
@@ -256,12 +257,9 @@ class BatchFetchGit(TaskBatchFetch):
256
257
  try:
257
258
  # Check if the revision such as
258
259
  # 0560fe21d1173b2221fd8c600fab818f7eecbad4 exist
259
- commit_ref = self._git_tags(self["revision"])[0]
260
+ commit_ref = self._git_rev_parse_verify(self["revision"])[0]
260
261
  commit_ref = commit_ref.strip()
261
262
  except GitRevisionDoesNotExist:
262
- pass
263
-
264
- if not commit_ref and not self.is_branch:
265
263
  do_git_fetch = True
266
264
  self.add_output(
267
265
  self.indent_spaces
@@ -269,6 +267,7 @@ class BatchFetchGit(TaskBatchFetch):
269
267
  + f"The revision does not exist: {self['revision']}"
270
268
  + "\n")
271
269
 
270
+ # The revision exists, but if it a branch, git pull anyway
272
271
  if not do_git_fetch:
273
272
  try:
274
273
  # Check if the branch is a tag or a branch
@@ -284,31 +283,6 @@ class BatchFetchGit(TaskBatchFetch):
284
283
  except subprocess.CalledProcessError:
285
284
  pass
286
285
 
287
- if not do_git_fetch and commit_ref:
288
- # This is to check if a tag has been changed
289
- try:
290
- # If the tag is annotated, it points to a tag object,
291
- # not directly to a commit. You need to resolve it to
292
- # the commit it points to. Using `git rev-parse
293
- # <tagname>^{commit}` allows getting the right
294
- # revision.
295
- commit_ref_head = self._git_tags("HEAD^{commit}")[0]
296
- commit_ref_head = commit_ref_head.strip()
297
- except GitRevisionDoesNotExist:
298
- # HEAD is detached
299
- commit_ref_head = None
300
-
301
- # The wanted commit revision does not exist
302
- # Or the commit ref of HEAD hasn't changed
303
- if not commit_ref_head or commit_ref_head != commit_ref:
304
- self.add_output(
305
- self.indent_spaces
306
- + "[INFO] Git fetch origin reason: "
307
- f"Commit ref head '{commit_ref_head}' != "
308
- f"commit ref '{commit_ref_head}'"
309
- "\n")
310
- do_git_fetch = True
311
-
312
286
  if not do_git_fetch:
313
287
  self.add_output(self.indent_spaces + "[INFO] git fetch ignored\n")
314
288
  return False
@@ -379,6 +353,7 @@ class BatchFetchGit(TaskBatchFetch):
379
353
  return origin_url
380
354
 
381
355
  def _git_is_local_branch(self, branch: str) -> bool:
356
+ "Return True if it is a local branch that exists."
382
357
  try:
383
358
  stdout, _ = run_simple(["git", "rev-parse", "--symbolic-full-name",
384
359
  branch], env=self.env,
@@ -395,11 +370,11 @@ class BatchFetchGit(TaskBatchFetch):
395
370
 
396
371
  return False
397
372
 
398
- def _git_tags(self, branch: str) -> List[str]:
373
+ def _git_rev_parse_verify(self, revision: str) -> List[str]:
399
374
  stdout: List[str] = []
400
375
  error = False
401
376
  try:
402
- stdout, _ = run_simple(["git", "rev-parse", "--verify", branch],
377
+ stdout, _ = run_simple(["git", "rev-parse", "--verify", revision],
403
378
  env=self.env,
404
379
  cwd=self.git_local_dir)
405
380
  if not stdout:
@@ -409,7 +384,7 @@ class BatchFetchGit(TaskBatchFetch):
409
384
 
410
385
  if error:
411
386
  raise GitRevisionDoesNotExist(
412
- f"The revision '{branch}' does not exist.")
387
+ f"The revision '{revision}' does not exist.")
413
388
 
414
389
  return stdout
415
390
 
@@ -429,13 +404,14 @@ class BatchFetchGit(TaskBatchFetch):
429
404
  # branch is a commit revision instead of a tag
430
405
  try:
431
406
  # Check if the branch exists
432
- git_ref_branch = self._git_tags("origin/"
433
- + self["revision"]
434
- + "^{commit}")[0]
407
+ git_ref_branch = self._git_rev_parse_verify("origin/"
408
+ + self["revision"]
409
+ + "^{commit}")[0]
435
410
  except GitRevisionDoesNotExist:
436
411
  # Check if the commit ref exists
437
412
  try:
438
- git_ref_branch = self._git_tags(self["revision"])[0]
413
+ git_ref_branch = self._git_rev_parse_verify(self["revision"])[
414
+ 0]
439
415
  except GitRevisionDoesNotExist as err:
440
416
  raise BatchFetchError(f"The branch '{self['revision']}' "
441
417
  "does not exist.") from err
@@ -463,22 +439,22 @@ class BatchFetchGit(TaskBatchFetch):
463
439
  self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
464
440
  self._git_fetch_origin_done = True
465
441
 
466
- def _repo_update_submodules(self):
467
- # This parameter instructs Git to initiate the update
468
- # process for submodules:
469
- # 1. Git fetches the commits specified in the parent
470
- # repository's configuration for each submodule.
471
- # 2. Updates are based solely on the commit pointers stored
472
- # within the parent repository's submodule configuration.
473
- # 3. It does not directly consult the upstream repositories
474
- # of the submodules.
475
- # 4. Submodules are updated to reflect the exact commits
476
- # revision in the parent repository's configuration,
477
- # potentially lagging behind the latest changes made in the
478
- # upstream repositories.
479
- if self.git_local_dir.joinpath(".gitmodules").is_file():
480
- cmd = ["git", "submodule", "update", "--recursive"]
481
- self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
442
+ # def _repo_update_submodules(self):
443
+ # # This parameter instructs Git to initiate the update
444
+ # # process for submodules:
445
+ # # 1. Git fetches the commits specified in the parent
446
+ # # repository's configuration for each submodule.
447
+ # # 2. Updates are based solely on the commit pointers stored
448
+ # # within the parent repository's submodule configuration.
449
+ # # 3. It does not directly consult the upstream repositories
450
+ # # of the submodules.
451
+ # # 4. Submodules are updated to reflect the exact commits
452
+ # # revision in the parent repository's configuration,
453
+ # # potentially lagging behind the latest changes made in the
454
+ # # upstream repositories.
455
+ # if self.git_local_dir.joinpath(".gitmodules").is_file():
456
+ # cmd = ["git", "submodule", "update", "--recursive"]
457
+ # self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
482
458
 
483
459
  def _repo_fix_remote_origin(self):
484
460
  correct_origin_url = self[self.main_key]
@@ -112,7 +112,7 @@ def run_indent(cmd: Union[List[str], str], spaces: int = 4,
112
112
  cmd = shlex.split(cmd) if isinstance(cmd, str) else cmd
113
113
  stdout, stderr = run_simple(cmd=cmd, **kwargs)
114
114
  stdout = indent_raw_output([f"[RUN] {list2cmdline(cmd)}"], spaces) + \
115
- indent_raw_output(stdout, spaces)
115
+ indent_raw_output(stdout, spaces + spaces)
116
116
  stderr = indent_raw_output(stderr, spaces)
117
117
 
118
118
  return (stdout, stderr)
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.1
2
+ Name: batchfetch
3
+ Version: 1.2.7
4
+ Summary: Efficiently clone and pull multiple Git repositories.
5
+ Home-page: https://github.com/jamescherti/batchfetch
6
+ Author: James Cherti
7
+ License: GPLv3
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: License :: OSI Approved :: GNU General Public License (GPL)
10
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
+ Classifier: Environment :: Console
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Operating System :: POSIX :: Other
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Version Control :: Git
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.6, <4
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+
21
+ # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
22
+
23
+ ## Introduction
24
+
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, freeing you up to focus on what truly matters: your workflow.
26
+
27
+ 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
+
29
+ Batchfetch is ideal for quickly cloning or pulling multiple Git repositories. It is also useful for cloning various addons, such as Vim plugins, Emacs packages, Ansible roles, Ansible collections, and other addons available on websites like GitHub, Codeberg, and GitLab.
30
+
31
+ ## Installation
32
+
33
+ Here is how to install *batchfetch* using [pip](https://pypi.org/project/pip/):
34
+ ```
35
+ pip install --user batchfetch
36
+ ```
37
+
38
+ The pip command above installs the *batchfetch* executable in the `~/.local/bin/` directory. Omitting the `--user` flag will install it system-wide.
39
+
40
+ ## Usage
41
+
42
+ ### Example of a `batchfetch.yaml` file
43
+
44
+ Here is an example of a `batchfetch.yaml` file:
45
+
46
+ ```yaml
47
+ ---
48
+
49
+ tasks:
50
+ # Clone the default branch of the general.el repository to the
51
+ # './general.el' directory
52
+ - git: https://github.com/jamescherti/compile-angel.el
53
+
54
+ # Clone the tag 1.5 of the consult repository to the './consult'
55
+ # directory
56
+ - git: https://github.com/jamescherti/outline-indent.el
57
+ revision: "1.1.0"
58
+
59
+ # Clone the s.el repository to the './another-name.el' directory
60
+ - git: https://github.com/jamescherti/easysession.el
61
+ path: easysession
62
+ revision: b9c6d9b6134b4981760893254f804a371ffbc899
63
+
64
+ # Delete the local copy of the following repository
65
+ - git: https://github.com/jamescherti/dir-config.el
66
+ delete: true
67
+ ```
68
+
69
+ Execute the `batchfetch` command from the same directory as `batchfetch.yml` to make it clone or update the local copies of the repositories above.
70
+
71
+ ## Command-line options
72
+
73
+ Here are the various options that `batchfetch` provides, along with descriptions of their usage:
74
+
75
+ ```
76
+ usage: batchfetch [--option]
77
+
78
+ Efficiently clone/pull multiple Git repositories in parallel.
79
+
80
+ options:
81
+ -h, --help show this help message and exit
82
+ -f FILE, --file FILE Specify the batchfetch YAML file (default:
83
+ './batchfetch.yaml').
84
+ -C DIRECTORY, --directory DIRECTORY
85
+ Change the working directory before reading the
86
+ batchfetch.yaml file. If not specified, the directory is
87
+ set to the parent directory of the batchfetch.yaml file.
88
+ -j JOBS, --jobs JOBS Run up to N parallel processes (default: 5).
89
+ Alternatively, the BATCHFETCH_JOBS environment variable
90
+ can be used to configure the number of jobs.
91
+ -v, --verbose Enable verbose mode.
92
+ ```
93
+
94
+ ## Features
95
+ - Git Clone and Fetch/Merge: Clones the repositories and their submodules, ensuring that all the repositories are always up-to-date by fetching and merging changes.
96
+ - Parallel Operations: Utilizes threads to simultaneously Git clone or pull multiple repositories, dramatically reducing wait times.
97
+ - User-Friendly Interface: Provides simple and straightforward command-line options that make it easy to get started and effectively manage your repositories.
98
+ - Custom Configuration: Allows the use of a YAML configuration file to specify and manage the repositories you interact with, enabling repeatable setups and consistent environments.
99
+ - Detect files that should not be present in directories managed by batchfetch, known as untracked files.
100
+
101
+ ## Frequently Asked Questions
102
+
103
+ ### What are untracked files?
104
+
105
+ The parent directory of the "path:" value defines the managed directory, where the directory of each path is considered as the managed directory.
106
+
107
+ For example, if the "path:" value is `file/my-project`, the managed directory will be `file/`. Any file within `file/` that is not managed by batchfetch will be considered an untracked file.
108
+
109
+ When *batchfetch* encounters an untracked file, it displays an error message to inform users about paths that are not managed by the system. The message provides clear instructions on how to handle these paths by adding them to the `options.ignore_untracked_paths` list, enabling users to manage untracked files effectively.
110
+
111
+ Here is an example of a *batchfetch.yaml* file that enables *batchfetch* to accept a list of untracked files:
112
+
113
+ ``` yaml
114
+ options:
115
+ ignore_untracked_paths:
116
+ - ./test
117
+ - /absolute/path
118
+ - ../relative/path
119
+
120
+ tasks:
121
+ - git: https://github.com/user/project
122
+ ```
123
+
124
+ By default, *batchfetch.yaml* is the only untracked file that is ignored. The user does not need to add it to the *ignore_untracked_paths* option.
125
+
126
+ ### How is the Git local paths handled?
127
+
128
+ When "path:" is specified, that's the path that is used.
129
+
130
+ When "path:" is not specified, Batchfetch attempts to determine the path name by extracting the repository name from the URI (e.g., `https://domain.com/repo` becomes `repo`). If the URL ends with a `.git` extension, it removes the extension (e.g., `https://domain.com/repo.git` becomes `repo`).
131
+
132
+ ### How does Batchfetch detect when a git fetch is necessary?
133
+
134
+ Batchfetch is fast, not only because it runs Git commands in parallel, but also because it intelligently detects whether a `git fetch` is needed, further speeding up the process of downloading data from repositories.
135
+
136
+ When the user has specifies a revision (branch or commit reference), Batchfetch only performs a `git fetch` if that revision does not exist locally. If the revision is already up to date, it simply proceeds to the next repository in the queue.
137
+
138
+ That's why it is highly recommended to always specify the revision to speed up Batchfetch, if speed is important to you. Here is an example of a `batchfetch.yaml` file where the branch (`1.1.0`) or commit reference (`b9c6d9b6134b4981760893254f804a371ffbc899`) is specified:
139
+ ``` yaml
140
+ tasks:
141
+ - git: https://github.com/jamescherti/outline-indent.el
142
+ revision: "1.1.0"
143
+
144
+ - git: https://github.com/jamescherti/easysession.el
145
+ path: easysession
146
+ revision: b9c6d9b6134b4981760893254f804a371ffbc899
147
+ ```
148
+
149
+ ### How to execute a command before and after a task?
150
+
151
+ To execute a command both before and after a specific task, you can define the `exec_before` and `exec_after` directives within the task configuration. These directives specify commands to be executed at the respective stages of the task lifecycle.
152
+
153
+ Here is an example:
154
+ ``` yaml
155
+ ---
156
+ tasks:
157
+ - git: https://github.com/jamescherti/easysession.el
158
+ path: easysession
159
+ exec_before: ["sh", "-c", "echo exec_before_task"]
160
+ exec_after: ["sh", "-c", "echo exec_after_task"]
161
+ ```
162
+
163
+ ## License
164
+
165
+ Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
166
+
167
+ 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.
168
+
169
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
170
+
171
+ You should have received a copy of the GNU General Public License along with this program.
172
+
173
+ ## Links
174
+
175
+ - [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
176
+ - [batchfetch @Pypi](https://pypi.org/project/batchfetch/)
@@ -22,7 +22,7 @@ from setuptools import find_packages, setup
22
22
 
23
23
  setup(
24
24
  name="batchfetch",
25
- version="1.2.5",
25
+ version="1.2.7",
26
26
  packages=find_packages(),
27
27
  description="Efficiently clone and pull multiple Git repositories.",
28
28
  license="GPLv3",
batchfetch-1.2.5/PKG-INFO DELETED
@@ -1,105 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: batchfetch
3
- Version: 1.2.5
4
- Summary: Efficiently clone and pull multiple Git repositories.
5
- Home-page: https://github.com/jamescherti/batchfetch
6
- Author: James Cherti
7
- License: GPLv3
8
- Classifier: Development Status :: 5 - Production/Stable
9
- Classifier: License :: OSI Approved :: GNU General Public License (GPL)
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
- Classifier: Environment :: Console
12
- Classifier: Operating System :: POSIX :: Linux
13
- Classifier: Operating System :: POSIX :: Other
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Topic :: Software Development :: Version Control :: Git
16
- Classifier: Topic :: Utilities
17
- Requires-Python: >=3.6, <4
18
- Description-Content-Type: text/markdown
19
- License-File: LICENSE
20
-
21
- # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
22
-
23
- ## Introduction
24
-
25
- Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously.
26
-
27
- With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management, freeing you up to focus on what truly matters: your workflow.
28
-
29
- Batchfetch is ideal for quickly cloning or pulling multiple Git repositories. It is also useful for cloning various addons, such as Vim plugins, Emacs packages, Ansible roles, Ansible collections, and other addons available on websites like GitHub, Codeberg, and GitLab.
30
-
31
- ## Features:
32
- - Git Clone and Fetch/Merge: Clones the repositories and their submodules, ensuring that all the repositories are always up-to-date by fetching and merging changes.
33
- - Parallel Operations: Utilizes threads to simultaneously Git clone or pull multiple repositories, dramatically reducing wait times.
34
- - User-Friendly Interface: Provides simple and straightforward command-line options that make it easy to get started and effectively manage your repositories.
35
- - Custom Configuration: Allows the use of a YAML configuration file to specify and manage the repositories you interact with, enabling repeatable setups and consistent environments.
36
-
37
- ## Installation
38
-
39
- ```
40
- pip install --user batchfetch
41
- ```
42
-
43
- The pip command above will install the `batchfetch` executable in the directory `~/.local/bin/`.
44
-
45
- ## Example
46
-
47
- Here is an example of a `batchfetch.yaml` file:
48
-
49
- ```yaml
50
- ---
51
-
52
- tasks:
53
- # Clone the default branch of the general.el repository to the
54
- # './general.el' directory
55
- - git: https://github.com/noctuid/general.el
56
-
57
- # Clone the tag 1.5 of the consult repository to the './consult'
58
- # directory
59
- - git: https://github.com/minad/consult
60
- revision: "1.5"
61
-
62
- # Clone the s.el repository to the './another-name.el' directory
63
- - git: https://github.com/magnars/s.el
64
- path: another-name.el
65
- revision: dda84d38fffdaf0c9b12837b504b402af910d01d
66
-
67
- # Delete './impatient-mode'
68
- - git: https://github.com/skeeto/impatient-mode
69
- delete: true
70
- ```
71
-
72
- Execute the `batchfetch` command from the same directory as `batchfetch.yml` to make it clone or update the local copies of the repositories above.
73
-
74
- ## Usage
75
-
76
- Here are the various options that `batchfetch` provides, along with descriptions of their usage:
77
-
78
- ```
79
- usage: batchfetch [--option] [args]
80
-
81
- Command line interface.
82
-
83
- positional arguments:
84
- N Specify the batchfetch YAML file(s) (default: './batchfetch.yaml').
85
-
86
- options:
87
- -h, --help show this help message and exit
88
- -j JOBS, --jobs JOBS Run up to N Number of parallel processes (Default: 5).
89
- -v, --verbose Enable verbose mode.
90
- ```
91
-
92
- ## License
93
-
94
- Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
95
-
96
- 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.
97
-
98
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
99
-
100
- You should have received a copy of the GNU General Public License along with this program.
101
-
102
- ## Links
103
-
104
- - [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
105
- - [batchfetch @Pypi](https://pypi.org/project/batchfetch/)
@@ -1,85 +0,0 @@
1
- # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
2
-
3
- ## Introduction
4
-
5
- Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously.
6
-
7
- With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management, freeing you up to focus on what truly matters: your workflow.
8
-
9
- Batchfetch is ideal for quickly cloning or pulling multiple Git repositories. It is also useful for cloning various addons, such as Vim plugins, Emacs packages, Ansible roles, Ansible collections, and other addons available on websites like GitHub, Codeberg, and GitLab.
10
-
11
- ## Features:
12
- - Git Clone and Fetch/Merge: Clones the repositories and their submodules, ensuring that all the repositories are always up-to-date by fetching and merging changes.
13
- - Parallel Operations: Utilizes threads to simultaneously Git clone or pull multiple repositories, dramatically reducing wait times.
14
- - User-Friendly Interface: Provides simple and straightforward command-line options that make it easy to get started and effectively manage your repositories.
15
- - Custom Configuration: Allows the use of a YAML configuration file to specify and manage the repositories you interact with, enabling repeatable setups and consistent environments.
16
-
17
- ## Installation
18
-
19
- ```
20
- pip install --user batchfetch
21
- ```
22
-
23
- The pip command above will install the `batchfetch` executable in the directory `~/.local/bin/`.
24
-
25
- ## Example
26
-
27
- Here is an example of a `batchfetch.yaml` file:
28
-
29
- ```yaml
30
- ---
31
-
32
- tasks:
33
- # Clone the default branch of the general.el repository to the
34
- # './general.el' directory
35
- - git: https://github.com/noctuid/general.el
36
-
37
- # Clone the tag 1.5 of the consult repository to the './consult'
38
- # directory
39
- - git: https://github.com/minad/consult
40
- revision: "1.5"
41
-
42
- # Clone the s.el repository to the './another-name.el' directory
43
- - git: https://github.com/magnars/s.el
44
- path: another-name.el
45
- revision: dda84d38fffdaf0c9b12837b504b402af910d01d
46
-
47
- # Delete './impatient-mode'
48
- - git: https://github.com/skeeto/impatient-mode
49
- delete: true
50
- ```
51
-
52
- Execute the `batchfetch` command from the same directory as `batchfetch.yml` to make it clone or update the local copies of the repositories above.
53
-
54
- ## Usage
55
-
56
- Here are the various options that `batchfetch` provides, along with descriptions of their usage:
57
-
58
- ```
59
- usage: batchfetch [--option] [args]
60
-
61
- Command line interface.
62
-
63
- positional arguments:
64
- N Specify the batchfetch YAML file(s) (default: './batchfetch.yaml').
65
-
66
- options:
67
- -h, --help show this help message and exit
68
- -j JOBS, --jobs JOBS Run up to N Number of parallel processes (Default: 5).
69
- -v, --verbose Enable verbose mode.
70
- ```
71
-
72
- ## License
73
-
74
- Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
75
-
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
-
78
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
79
-
80
- You should have received a copy of the GNU General Public License along with this program.
81
-
82
- ## Links
83
-
84
- - [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
85
- - [batchfetch @Pypi](https://pypi.org/project/batchfetch/)
@@ -1,105 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: batchfetch
3
- Version: 1.2.5
4
- Summary: Efficiently clone and pull multiple Git repositories.
5
- Home-page: https://github.com/jamescherti/batchfetch
6
- Author: James Cherti
7
- License: GPLv3
8
- Classifier: Development Status :: 5 - Production/Stable
9
- Classifier: License :: OSI Approved :: GNU General Public License (GPL)
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
- Classifier: Environment :: Console
12
- Classifier: Operating System :: POSIX :: Linux
13
- Classifier: Operating System :: POSIX :: Other
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Topic :: Software Development :: Version Control :: Git
16
- Classifier: Topic :: Utilities
17
- Requires-Python: >=3.6, <4
18
- Description-Content-Type: text/markdown
19
- License-File: LICENSE
20
-
21
- # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
22
-
23
- ## Introduction
24
-
25
- Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously.
26
-
27
- With Batchfetch, you no longer need to manually manage each repository one by one. It automates the tedious aspects of repository management, freeing you up to focus on what truly matters: your workflow.
28
-
29
- Batchfetch is ideal for quickly cloning or pulling multiple Git repositories. It is also useful for cloning various addons, such as Vim plugins, Emacs packages, Ansible roles, Ansible collections, and other addons available on websites like GitHub, Codeberg, and GitLab.
30
-
31
- ## Features:
32
- - Git Clone and Fetch/Merge: Clones the repositories and their submodules, ensuring that all the repositories are always up-to-date by fetching and merging changes.
33
- - Parallel Operations: Utilizes threads to simultaneously Git clone or pull multiple repositories, dramatically reducing wait times.
34
- - User-Friendly Interface: Provides simple and straightforward command-line options that make it easy to get started and effectively manage your repositories.
35
- - Custom Configuration: Allows the use of a YAML configuration file to specify and manage the repositories you interact with, enabling repeatable setups and consistent environments.
36
-
37
- ## Installation
38
-
39
- ```
40
- pip install --user batchfetch
41
- ```
42
-
43
- The pip command above will install the `batchfetch` executable in the directory `~/.local/bin/`.
44
-
45
- ## Example
46
-
47
- Here is an example of a `batchfetch.yaml` file:
48
-
49
- ```yaml
50
- ---
51
-
52
- tasks:
53
- # Clone the default branch of the general.el repository to the
54
- # './general.el' directory
55
- - git: https://github.com/noctuid/general.el
56
-
57
- # Clone the tag 1.5 of the consult repository to the './consult'
58
- # directory
59
- - git: https://github.com/minad/consult
60
- revision: "1.5"
61
-
62
- # Clone the s.el repository to the './another-name.el' directory
63
- - git: https://github.com/magnars/s.el
64
- path: another-name.el
65
- revision: dda84d38fffdaf0c9b12837b504b402af910d01d
66
-
67
- # Delete './impatient-mode'
68
- - git: https://github.com/skeeto/impatient-mode
69
- delete: true
70
- ```
71
-
72
- Execute the `batchfetch` command from the same directory as `batchfetch.yml` to make it clone or update the local copies of the repositories above.
73
-
74
- ## Usage
75
-
76
- Here are the various options that `batchfetch` provides, along with descriptions of their usage:
77
-
78
- ```
79
- usage: batchfetch [--option] [args]
80
-
81
- Command line interface.
82
-
83
- positional arguments:
84
- N Specify the batchfetch YAML file(s) (default: './batchfetch.yaml').
85
-
86
- options:
87
- -h, --help show this help message and exit
88
- -j JOBS, --jobs JOBS Run up to N Number of parallel processes (Default: 5).
89
- -v, --verbose Enable verbose mode.
90
- ```
91
-
92
- ## License
93
-
94
- Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
95
-
96
- 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.
97
-
98
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
99
-
100
- You should have received a copy of the GNU General Public License along with this program.
101
-
102
- ## Links
103
-
104
- - [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
105
- - [batchfetch @Pypi](https://pypi.org/project/batchfetch/)
File without changes
File without changes