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.
- batchfetch-1.2.7/PKG-INFO +176 -0
- batchfetch-1.2.7/README.md +156 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch/batchfetch_base.py +2 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch/batchfetch_cli.py +135 -18
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch/batchfetch_git.py +37 -61
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch/helpers.py +1 -1
- batchfetch-1.2.7/batchfetch.egg-info/PKG-INFO +176 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/setup.py +1 -1
- batchfetch-1.2.5/PKG-INFO +0 -105
- batchfetch-1.2.5/README.md +0 -85
- batchfetch-1.2.5/batchfetch.egg-info/PKG-INFO +0 -105
- {batchfetch-1.2.5 → batchfetch-1.2.7}/LICENSE +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch/__init__.py +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch.egg-info/SOURCES.txt +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch.egg-info/dependency_links.txt +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch.egg-info/entry_points.txt +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch.egg-info/requires.txt +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/batchfetch.egg-info/top_level.txt +0 -0
- {batchfetch-1.2.5 → batchfetch-1.2.7}/setup.cfg +0 -0
|
@@ -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
|
|
43
|
+
def __init__(self, max_workers: int, verbose: bool, check_untracked: bool):
|
|
44
44
|
self.cfg: dict = {}
|
|
45
45
|
self.folder = Path(".")
|
|
46
|
-
self.
|
|
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"]).
|
|
142
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
221
|
-
|
|
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
|
-
"-
|
|
233
|
-
|
|
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,
|
|
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=
|
|
257
|
-
max_workers=int(
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
97
|
-
posixpath.basename(
|
|
98
|
-
|
|
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
|
-
|
|
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.
|
|
207
|
-
|
|
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
|
|
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.
|
|
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
|
|
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",
|
|
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 '{
|
|
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.
|
|
433
|
-
|
|
434
|
-
|
|
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.
|
|
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
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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/)
|
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/)
|
batchfetch-1.2.5/README.md
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|