batchfetch 1.2.6__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.6 → batchfetch-1.2.7}/PKG-INFO +72 -26
- batchfetch-1.2.7/README.md +156 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch/batchfetch_cli.py +81 -16
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch/batchfetch_git.py +21 -45
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch/helpers.py +1 -1
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch.egg-info/PKG-INFO +72 -26
- {batchfetch-1.2.6 → batchfetch-1.2.7}/setup.py +1 -1
- batchfetch-1.2.6/README.md +0 -110
- {batchfetch-1.2.6 → batchfetch-1.2.7}/LICENSE +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch/__init__.py +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch/batchfetch_base.py +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch.egg-info/SOURCES.txt +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch.egg-info/dependency_links.txt +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch.egg-info/entry_points.txt +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch.egg-info/requires.txt +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/batchfetch.egg-info/top_level.txt +0 -0
- {batchfetch-1.2.6 → batchfetch-1.2.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: batchfetch
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: Efficiently clone and pull multiple Git repositories.
|
|
5
5
|
Home-page: https://github.com/jamescherti/batchfetch
|
|
6
6
|
Author: James Cherti
|
|
@@ -22,27 +22,24 @@ License-File: LICENSE
|
|
|
22
22
|
|
|
23
23
|
## Introduction
|
|
24
24
|
|
|
25
|
-
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously.
|
|
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
26
|
|
|
27
|
-
|
|
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
28
|
|
|
29
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
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
31
|
## Installation
|
|
38
32
|
|
|
33
|
+
Here is how to install *batchfetch* using [pip](https://pypi.org/project/pip/):
|
|
39
34
|
```
|
|
40
35
|
pip install --user batchfetch
|
|
41
36
|
```
|
|
42
37
|
|
|
43
|
-
The pip command above
|
|
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
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
### Example of a `batchfetch.yaml` file
|
|
46
43
|
|
|
47
44
|
Here is an example of a `batchfetch.yaml` file:
|
|
48
45
|
|
|
@@ -52,43 +49,55 @@ Here is an example of a `batchfetch.yaml` file:
|
|
|
52
49
|
tasks:
|
|
53
50
|
# Clone the default branch of the general.el repository to the
|
|
54
51
|
# './general.el' directory
|
|
55
|
-
- git: https://github.com/
|
|
52
|
+
- git: https://github.com/jamescherti/compile-angel.el
|
|
56
53
|
|
|
57
54
|
# Clone the tag 1.5 of the consult repository to the './consult'
|
|
58
55
|
# directory
|
|
59
|
-
- git: https://github.com/
|
|
60
|
-
revision: "1.
|
|
56
|
+
- git: https://github.com/jamescherti/outline-indent.el
|
|
57
|
+
revision: "1.1.0"
|
|
61
58
|
|
|
62
59
|
# Clone the s.el repository to the './another-name.el' directory
|
|
63
|
-
- git: https://github.com/
|
|
64
|
-
path:
|
|
65
|
-
revision:
|
|
60
|
+
- git: https://github.com/jamescherti/easysession.el
|
|
61
|
+
path: easysession
|
|
62
|
+
revision: b9c6d9b6134b4981760893254f804a371ffbc899
|
|
66
63
|
|
|
67
|
-
# Delete
|
|
68
|
-
- git: https://github.com/
|
|
64
|
+
# Delete the local copy of the following repository
|
|
65
|
+
- git: https://github.com/jamescherti/dir-config.el
|
|
69
66
|
delete: true
|
|
70
67
|
```
|
|
71
68
|
|
|
72
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.
|
|
73
70
|
|
|
74
|
-
##
|
|
71
|
+
## Command-line options
|
|
75
72
|
|
|
76
73
|
Here are the various options that `batchfetch` provides, along with descriptions of their usage:
|
|
77
74
|
|
|
78
75
|
```
|
|
79
|
-
usage: batchfetch [--option]
|
|
76
|
+
usage: batchfetch [--option]
|
|
80
77
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
positional arguments:
|
|
84
|
-
N Specify the batchfetch YAML file(s) (default: './batchfetch.yaml').
|
|
78
|
+
Efficiently clone/pull multiple Git repositories in parallel.
|
|
85
79
|
|
|
86
80
|
options:
|
|
87
81
|
-h, --help show this help message and exit
|
|
88
|
-
-
|
|
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.
|
|
89
91
|
-v, --verbose Enable verbose mode.
|
|
90
92
|
```
|
|
91
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
|
+
|
|
92
101
|
## Frequently Asked Questions
|
|
93
102
|
|
|
94
103
|
### What are untracked files?
|
|
@@ -114,6 +123,43 @@ tasks:
|
|
|
114
123
|
|
|
115
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.
|
|
116
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
|
+
|
|
117
163
|
## License
|
|
118
164
|
|
|
119
165
|
Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
|
|
@@ -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/)
|
|
@@ -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,9 +40,10 @@ 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.check_untracked = check_untracked
|
|
46
47
|
self.tracked_paths: Dict[Path, Set[str]] = {}
|
|
47
48
|
self.ignore_untracked_paths: Set[Path] = set()
|
|
48
49
|
self.verbose = verbose
|
|
@@ -101,7 +102,8 @@ class BatchFetchCli:
|
|
|
101
102
|
self.ignore_untracked_paths.add(Path(path).absolute())
|
|
102
103
|
self.ignore_untracked_paths.add(Path(path).resolve())
|
|
103
104
|
untracked_paths = None
|
|
104
|
-
if "options" in yaml_dict
|
|
105
|
+
if "options" in yaml_dict and \
|
|
106
|
+
"ignore_untracked_paths" in yaml_dict["options"]:
|
|
105
107
|
untracked_paths = \
|
|
106
108
|
yaml_dict["options"]["ignore_untracked_paths"]
|
|
107
109
|
|
|
@@ -155,10 +157,12 @@ class BatchFetchCli:
|
|
|
155
157
|
print(f"Schema error: {err}.", file=sys.stderr)
|
|
156
158
|
sys.exit(1)
|
|
157
159
|
|
|
158
|
-
dest_path = Path(batchfetch_instance["path"]).
|
|
159
|
-
|
|
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:
|
|
160
164
|
err_str = ("More than one task have the " +
|
|
161
|
-
f"destination path
|
|
165
|
+
f"destination path (" +
|
|
162
166
|
str(task[keyword]) + " and " +
|
|
163
167
|
str(dict_local_dir[(str(dest_path))]) +
|
|
164
168
|
")")
|
|
@@ -232,7 +236,8 @@ class BatchFetchCli:
|
|
|
232
236
|
|
|
233
237
|
return False
|
|
234
238
|
else:
|
|
235
|
-
self.
|
|
239
|
+
if self.check_untracked:
|
|
240
|
+
self._find_untracked_paths()
|
|
236
241
|
|
|
237
242
|
if num_success == 0:
|
|
238
243
|
print("Nothing to do.")
|
|
@@ -269,7 +274,24 @@ class BatchFetchCli:
|
|
|
269
274
|
|
|
270
275
|
def parse_args():
|
|
271
276
|
"""Parse the command line arguments."""
|
|
272
|
-
|
|
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."
|
|
273
295
|
usage = "%(prog)s [--option]"
|
|
274
296
|
parser = argparse.ArgumentParser(description=desc, usage=usage)
|
|
275
297
|
|
|
@@ -281,15 +303,40 @@ def parse_args():
|
|
|
281
303
|
"(default: './batchfetch.yaml')."))
|
|
282
304
|
|
|
283
305
|
parser.add_argument(
|
|
284
|
-
"-
|
|
285
|
-
|
|
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.")
|
|
286
313
|
)
|
|
287
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
|
+
|
|
288
325
|
parser.add_argument(
|
|
289
326
|
"-v", "--verbose", action="store_true", default=False,
|
|
290
327
|
help="Enable verbose mode.",
|
|
291
328
|
)
|
|
292
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
|
+
|
|
293
340
|
args = parser.parse_args()
|
|
294
341
|
|
|
295
342
|
if not args.file:
|
|
@@ -303,11 +350,16 @@ def parse_args():
|
|
|
303
350
|
return args
|
|
304
351
|
|
|
305
352
|
|
|
306
|
-
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:
|
|
307
358
|
errno = 0
|
|
308
|
-
batchfetch_cli = BatchFetchCli(verbose=
|
|
309
|
-
max_workers=int(
|
|
310
|
-
|
|
359
|
+
batchfetch_cli = BatchFetchCli(verbose=verbose,
|
|
360
|
+
max_workers=int(jobs),
|
|
361
|
+
check_untracked=check_untracked)
|
|
362
|
+
os.chdir(directory)
|
|
311
363
|
batchfetch_cli.load(file)
|
|
312
364
|
|
|
313
365
|
try:
|
|
@@ -337,14 +389,27 @@ def command_line_interface():
|
|
|
337
389
|
args = parse_args()
|
|
338
390
|
done = []
|
|
339
391
|
file = Path(args.file)
|
|
340
|
-
file_resolved = file.
|
|
392
|
+
file_resolved = file.absolute()
|
|
341
393
|
if not file_resolved:
|
|
342
394
|
print(f"Error: cannot resolve the path {file}",
|
|
343
395
|
file=sys.stderr)
|
|
344
396
|
sys.exit(1)
|
|
345
397
|
|
|
346
398
|
done.append(file_resolved)
|
|
347
|
-
|
|
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)
|
|
348
413
|
|
|
349
414
|
sys.exit(errno)
|
|
350
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
|
|
@@ -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)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: batchfetch
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: Efficiently clone and pull multiple Git repositories.
|
|
5
5
|
Home-page: https://github.com/jamescherti/batchfetch
|
|
6
6
|
Author: James Cherti
|
|
@@ -22,27 +22,24 @@ License-File: LICENSE
|
|
|
22
22
|
|
|
23
23
|
## Introduction
|
|
24
24
|
|
|
25
|
-
Batchfetch is a command-line tool designed to clone, fetch, and merge multiple Git repositories simultaneously.
|
|
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
26
|
|
|
27
|
-
|
|
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
28
|
|
|
29
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
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
31
|
## Installation
|
|
38
32
|
|
|
33
|
+
Here is how to install *batchfetch* using [pip](https://pypi.org/project/pip/):
|
|
39
34
|
```
|
|
40
35
|
pip install --user batchfetch
|
|
41
36
|
```
|
|
42
37
|
|
|
43
|
-
The pip command above
|
|
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
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
### Example of a `batchfetch.yaml` file
|
|
46
43
|
|
|
47
44
|
Here is an example of a `batchfetch.yaml` file:
|
|
48
45
|
|
|
@@ -52,43 +49,55 @@ Here is an example of a `batchfetch.yaml` file:
|
|
|
52
49
|
tasks:
|
|
53
50
|
# Clone the default branch of the general.el repository to the
|
|
54
51
|
# './general.el' directory
|
|
55
|
-
- git: https://github.com/
|
|
52
|
+
- git: https://github.com/jamescherti/compile-angel.el
|
|
56
53
|
|
|
57
54
|
# Clone the tag 1.5 of the consult repository to the './consult'
|
|
58
55
|
# directory
|
|
59
|
-
- git: https://github.com/
|
|
60
|
-
revision: "1.
|
|
56
|
+
- git: https://github.com/jamescherti/outline-indent.el
|
|
57
|
+
revision: "1.1.0"
|
|
61
58
|
|
|
62
59
|
# Clone the s.el repository to the './another-name.el' directory
|
|
63
|
-
- git: https://github.com/
|
|
64
|
-
path:
|
|
65
|
-
revision:
|
|
60
|
+
- git: https://github.com/jamescherti/easysession.el
|
|
61
|
+
path: easysession
|
|
62
|
+
revision: b9c6d9b6134b4981760893254f804a371ffbc899
|
|
66
63
|
|
|
67
|
-
# Delete
|
|
68
|
-
- git: https://github.com/
|
|
64
|
+
# Delete the local copy of the following repository
|
|
65
|
+
- git: https://github.com/jamescherti/dir-config.el
|
|
69
66
|
delete: true
|
|
70
67
|
```
|
|
71
68
|
|
|
72
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.
|
|
73
70
|
|
|
74
|
-
##
|
|
71
|
+
## Command-line options
|
|
75
72
|
|
|
76
73
|
Here are the various options that `batchfetch` provides, along with descriptions of their usage:
|
|
77
74
|
|
|
78
75
|
```
|
|
79
|
-
usage: batchfetch [--option]
|
|
76
|
+
usage: batchfetch [--option]
|
|
80
77
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
positional arguments:
|
|
84
|
-
N Specify the batchfetch YAML file(s) (default: './batchfetch.yaml').
|
|
78
|
+
Efficiently clone/pull multiple Git repositories in parallel.
|
|
85
79
|
|
|
86
80
|
options:
|
|
87
81
|
-h, --help show this help message and exit
|
|
88
|
-
-
|
|
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.
|
|
89
91
|
-v, --verbose Enable verbose mode.
|
|
90
92
|
```
|
|
91
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
|
+
|
|
92
101
|
## Frequently Asked Questions
|
|
93
102
|
|
|
94
103
|
### What are untracked files?
|
|
@@ -114,6 +123,43 @@ tasks:
|
|
|
114
123
|
|
|
115
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.
|
|
116
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
|
+
|
|
117
163
|
## License
|
|
118
164
|
|
|
119
165
|
Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
|
batchfetch-1.2.6/README.md
DELETED
|
@@ -1,110 +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
|
-
## Frequently Asked Questions
|
|
73
|
-
|
|
74
|
-
### What are untracked files?
|
|
75
|
-
|
|
76
|
-
The parent directory of the "path:" value defines the managed directory, where the directory of each path is considered as the managed directory.
|
|
77
|
-
|
|
78
|
-
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.
|
|
79
|
-
|
|
80
|
-
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.
|
|
81
|
-
|
|
82
|
-
Here is an example of a *batchfetch.yaml* file that enables *batchfetch* to accept a list of untracked files:
|
|
83
|
-
|
|
84
|
-
``` yaml
|
|
85
|
-
options:
|
|
86
|
-
ignore_untracked_paths:
|
|
87
|
-
- ./test
|
|
88
|
-
- /absolute/path
|
|
89
|
-
- ../relative/path
|
|
90
|
-
|
|
91
|
-
tasks:
|
|
92
|
-
- git: https://github.com/user/project
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
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.
|
|
96
|
-
|
|
97
|
-
## License
|
|
98
|
-
|
|
99
|
-
Copyright (C) 2024 [James Cherti](https://www.jamescherti.com)
|
|
100
|
-
|
|
101
|
-
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.
|
|
102
|
-
|
|
103
|
-
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.
|
|
104
|
-
|
|
105
|
-
You should have received a copy of the GNU General Public License along with this program.
|
|
106
|
-
|
|
107
|
-
## Links
|
|
108
|
-
|
|
109
|
-
- [batchfetch @GitHub](https://github.com/jamescherti/batchfetch)
|
|
110
|
-
- [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
|
|
File without changes
|