batchfetch 1.0.7__tar.gz → 1.0.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,138 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98
+ __pypackages__/
99
+
100
+ # Celery stuff
101
+ celerybeat-schedule
102
+ celerybeat.pid
103
+
104
+ # SageMath parsed files
105
+ *.sage.py
106
+
107
+ # Environments
108
+ .env
109
+ .venv
110
+ env/
111
+ venv/
112
+ ENV/
113
+ env.bak/
114
+ venv.bak/
115
+
116
+ # Spyder project settings
117
+ .spyderproject
118
+ .spyproject
119
+
120
+ # Rope project settings
121
+ .ropeproject
122
+
123
+ # mkdocs documentation
124
+ /site
125
+
126
+ # mypy
127
+ .mypy_cache/
128
+ .dmypy.json
129
+ dmypy.json
130
+
131
+ # Pyre type checker
132
+ .pyre/
133
+
134
+ # pytype static type analyzer
135
+ .pytype/
136
+
137
+ # Cython debug symbols
138
+ cython_debug/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: batchfetch
3
- Version: 1.0.7
3
+ Version: 1.0.9
4
4
  Summary: Efficiently clone and pull multiple Git repositories.
5
5
  Home-page: https://github.com/jamescherti/batchfetch
6
6
  Author: James Cherti
@@ -17,6 +17,10 @@ Classifier: Topic :: Utilities
17
17
  Requires-Python: >=3.6, <4
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: colorama
21
+ Requires-Dist: schema
22
+ Requires-Dist: setproctitle
23
+ Requires-Dist: PyYAML
20
24
 
21
25
  # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
22
26
 
@@ -43,7 +43,7 @@ class BatchFetchCli:
43
43
  def __init__(self, max_workers: int, verbose: bool = False):
44
44
  self.cfg: dict = {}
45
45
  self.folder = Path(".")
46
- self.managed_filenames: Set[str] = set()
46
+ self.managed_paths: Set[Path] = set()
47
47
  self.verbose = verbose
48
48
  self.max_workers = max_workers
49
49
  self._logger = logging.getLogger(self.__class__.__name__)
@@ -149,7 +149,7 @@ class BatchFetchCli:
149
149
  error = False
150
150
  threads = []
151
151
  num_success = 0
152
- self.managed_filenames = set()
152
+ self.managed_paths = set()
153
153
 
154
154
  executor_update = ThreadPoolExecutor(max_workers=self.max_workers)
155
155
 
@@ -160,26 +160,28 @@ class BatchFetchCli:
160
160
  for task in all_tasks:
161
161
  self.dirs_relative_to_batchfetch.add(str(task["path"]))
162
162
  if not task["delete"]:
163
- self.managed_filenames.add(task["path"])
163
+ self.managed_paths.add(Path(task["path"]).absolute())
164
164
  threads.append(executor_update.submit(task.update))
165
165
 
166
166
  for future in as_completed(threads):
167
167
  data = future.result()
168
168
  if data["result"]["error"]:
169
- print(Fore.RED, end="")
170
- elif data["result"]["changed"]:
171
- print(Fore.YELLOW, end="")
169
+ error = True
170
+ failed.append(data)
172
171
  else:
173
- if not self.verbose:
174
- continue
172
+ num_success += 1
175
173
 
176
- print(Fore.GREEN, end="")
174
+ if (not self.verbose and
175
+ not data["result"]["error"] and
176
+ not data["result"]["changed"]):
177
+ continue
177
178
 
178
179
  if data["result"]["error"]:
179
- error = True
180
- failed.append(data)
180
+ print(Fore.RED, end="")
181
+ elif data["result"]["changed"]:
182
+ print(Fore.YELLOW, end="")
181
183
  else:
182
- num_success += 1
184
+ print(Fore.GREEN, end="")
183
185
 
184
186
  if data["result"]["output"]:
185
187
  print(data["result"]["output"].rstrip("\n"))
@@ -92,7 +92,7 @@ class BatchFetchGit(BatchFetchBase):
92
92
 
93
93
  The command will fail if the branch is detached.
94
94
  """
95
- cmd = "git show-ref --head --verify HEAD"
95
+ cmd = ["git", "show-ref", "--head", "--verify", "HEAD"]
96
96
  try:
97
97
  stdout, _ = run_simple(cmd, cwd=cwd, env=self.env)
98
98
  output = stdout[0].split(" ")[0]
@@ -119,7 +119,7 @@ class BatchFetchGit(BatchFetchBase):
119
119
 
120
120
  self.add_output(
121
121
  f"[GIT {update_type}] {self[self.main_key]}" +
122
- (f" (Reference: {self['reference']})"
122
+ (f" (Ref: {self['reference']})"
123
123
  if self["reference"] else "") + "\n"
124
124
  )
125
125
 
@@ -208,38 +208,37 @@ class BatchFetchGit(BatchFetchBase):
208
208
  git_merge = False
209
209
 
210
210
  # Merge
211
- ignore_git_pull = False
212
- if not self["git_pull"]:
213
- ignore_git_pull = True
214
-
211
+ do_git_pull = self["git_pull"]
212
+ disable_merge = False
215
213
  if self["reference"]:
216
- ignore_git_pull = False
217
- # Check if the new branch exists
214
+ commit_ref = None
218
215
  try:
219
- self._git_tags(self["reference"])
216
+ # Returns the commit ref of the branch or commit
217
+ commit_ref = self._git_tags(self["reference"])[0]
220
218
  except GitReferenceDoesNotExist:
221
- pass
222
- else:
223
- # The branch exists:
224
- # 1. Ignore Git pull when the git reference is the same
225
- # as the "branch:" key
219
+ # The reference does not exist. We should git pull
220
+ # in case we can get the reference
221
+ do_git_pull = True
222
+ else: # The reference exists
223
+ if not self._git_is_local_branch(self["reference"]):
224
+ # This is not a real branch where we can merge
225
+ disable_merge = True
226
+
226
227
  try:
227
- commit_ref = self._git_ref(cwd=self.git_local_dir)
228
- except subprocess.CalledProcessError:
229
- # Ignore git pull because the head is detached
230
- pass
228
+ # Returns the commit ref of the branch or commit
229
+ commit_ref_head = self._git_tags("HEAD")[0]
230
+ except GitReferenceDoesNotExist:
231
+ # HEAD is detached
232
+ commit_ref_head = None
233
+
234
+ # The wanted commit reference does not exist
235
+ # Or the commit ref of HEAD hasn't changed
236
+ if not commit_ref or commit_ref_head != commit_ref:
237
+ do_git_pull = True
231
238
  else:
232
- if (self.current_branch and
233
- (commit_ref == self["reference"] or
234
- self.current_branch == self["reference"])):
235
- ignore_git_pull = True
239
+ do_git_pull = False
236
240
 
237
- # 2. Ignore Git pull if it is not a local branch
238
- if (not ignore_git_pull and
239
- not self._git_is_local_branch(self["reference"])):
240
- ignore_git_pull = True
241
-
242
- if ignore_git_pull:
241
+ if not do_git_pull:
243
242
  self.add_output(self.indent_spaces +
244
243
  "[INFO] git pull ignored\n")
245
244
  else:
@@ -247,19 +246,20 @@ class BatchFetchGit(BatchFetchBase):
247
246
  self._run(cmd, cwd=str(self.git_local_dir), env=self.env)
248
247
 
249
248
  # TODO: only merge when difference from upstream
250
- commit_ref = self._git_ref(cwd=self.git_local_dir)
251
- self._run(["git", "merge", "--ff-only"],
252
- cwd=str(self.git_local_dir), env=self.env)
253
- git_ref_after_merge = self._git_ref(cwd=self.git_local_dir)
254
- if commit_ref != git_ref_after_merge:
255
- git_merge = True
256
- self.set_changed(True)
257
- self._run(["git", "log",
258
- '--pretty=format:"%h %ad %s [%cn]"',
259
- "--decorate", "--date=short",
260
- f"{commit_ref}..{git_ref_after_merge}"],
261
- cwd=str(self.git_local_dir),
262
- env=self.env)
249
+ commit_ref_head = self._git_ref(cwd=self.git_local_dir)
250
+ if not disable_merge:
251
+ self._run(["git", "merge", "--ff-only"],
252
+ cwd=str(self.git_local_dir), env=self.env)
253
+ git_ref_after_merge = self._git_ref(cwd=self.git_local_dir)
254
+ if commit_ref_head != git_ref_after_merge:
255
+ git_merge = True
256
+ self.set_changed(True)
257
+ self._run(["git", "log",
258
+ '--pretty=format:"%h %ad %s [%cn]"',
259
+ "--decorate", "--date=short",
260
+ f"{commit_ref_head}..{git_ref_after_merge}"],
261
+ cwd=str(self.git_local_dir),
262
+ env=self.env)
263
263
 
264
264
  return git_merge
265
265
 
@@ -283,10 +283,9 @@ class BatchFetchGit(BatchFetchBase):
283
283
  def _git_tags(self, branch: str) -> List[str]:
284
284
  stdout: List[str] = []
285
285
  try:
286
- stdout, _ = run_simple(
287
- ["git", "rev-parse", "--verify", branch],
288
- env=self.env,
289
- cwd=self.git_local_dir)
286
+ stdout, _ = run_simple(["git", "rev-parse", "--verify", branch],
287
+ env=self.env,
288
+ cwd=self.git_local_dir)
290
289
  except subprocess.CalledProcessError as err:
291
290
  raise GitReferenceDoesNotExist(
292
291
  f"The reference '{branch}' does not exist.") from err
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: batchfetch
3
- Version: 1.0.7
3
+ Version: 1.0.9
4
4
  Summary: Efficiently clone and pull multiple Git repositories.
5
5
  Home-page: https://github.com/jamescherti/batchfetch
6
6
  Author: James Cherti
@@ -17,6 +17,10 @@ Classifier: Topic :: Utilities
17
17
  Requires-Python: >=3.6, <4
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: colorama
21
+ Requires-Dist: schema
22
+ Requires-Dist: setproctitle
23
+ Requires-Dist: PyYAML
20
24
 
21
25
  # Batchfetch - Efficiently clone or pull multiple Git repositories in parallel
22
26
 
@@ -1,5 +1,7 @@
1
+ .gitignore
1
2
  LICENSE
2
3
  README.md
4
+ run_tests.sh
3
5
  setup.py
4
6
  batchfetch/__init__.py
5
7
  batchfetch/batchfetch_base.py
@@ -11,4 +13,7 @@ batchfetch.egg-info/SOURCES.txt
11
13
  batchfetch.egg-info/dependency_links.txt
12
14
  batchfetch.egg-info/entry_points.txt
13
15
  batchfetch.egg-info/requires.txt
14
- batchfetch.egg-info/top_level.txt
16
+ batchfetch.egg-info/top_level.txt
17
+ tests/test_helpers.py
18
+ tests/data/test-md5sum.txt
19
+ tests/data/test-run_simple.sh
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Copyright (c) James Cherti
4
+ # URL: https://github.com/jamescherti/batchfetch
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU General Public License as published by the Free Software
8
+ # Foundation, either version 3 of the License, or (at your option) any later
9
+ # version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License along with
16
+ # this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ cd "$(dirname "${BASH_SOURCE[0]}")"
19
+ export PYTHONPATH="$(pwd)"
20
+ exec pytest -v -v --cov=batchfetch --cov=tests \
21
+ --cov-report=term \
22
+ --cov-report=html:htmlcov \
23
+ tests/test_*py
@@ -22,7 +22,7 @@ from setuptools import find_packages, setup
22
22
 
23
23
  setup(
24
24
  name="batchfetch",
25
- version="1.0.7",
25
+ version="1.0.9",
26
26
  packages=find_packages(),
27
27
  description="Efficiently clone and pull multiple Git repositories.",
28
28
  license="GPLv3",
@@ -0,0 +1,3 @@
1
+ Test 1.
2
+ Test 2.
3
+ Test 3.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+
3
+ cd "$(dirname "${BASH_SOURCE[0]}")"
4
+ cat ./test-md5sum.txt
5
+ cat ./test-md5sum.txt | tail -n 1 >&2
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env python
2
+ #
3
+ # Copyright (c) James Cherti
4
+ # URL: https://github.com/jamescherti/batchfetch
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU General Public License as published by the Free Software
8
+ # Foundation, either version 3 of the License, or (at your option) any later
9
+ # version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License along with
16
+ # this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """Unit tests."""
19
+
20
+ from pathlib import Path
21
+
22
+ from batchfetch import helpers
23
+
24
+ DATA_PATH = Path(".").joinpath("tests", "data").absolute()
25
+ SCRIPT_RUN_SIMPLE = DATA_PATH / "test-run_simple.sh"
26
+ TEST_MD5SUM_FILE = DATA_PATH / "test-md5sum.txt"
27
+
28
+
29
+ def test_md5sum():
30
+ md5sum = helpers.md5sum(TEST_MD5SUM_FILE)
31
+ assert md5sum == "f31e127edc87a6aa2eb01b7d94d2ec58"
32
+
33
+
34
+ def test_run_simple():
35
+ # Stdout
36
+ stdout_lines, stderr_lines = helpers.run_simple(str(SCRIPT_RUN_SIMPLE))
37
+ assert stdout_lines == ['Test 1.',
38
+ 'Test 2.',
39
+ 'Test 3.']
40
+ assert stderr_lines == ['Test 3.']
41
+
42
+
43
+ def test_indent_raw_output():
44
+ list_str = \
45
+ helpers.indent_raw_output(["Test 1.", "Test 2."])
46
+
47
+ assert list_str == [" Test 1.", " Test 2."]
48
+
49
+
50
+ def test_run_indent():
51
+ stdout_lines, stderr_lines = helpers.run_indent(str(SCRIPT_RUN_SIMPLE))
52
+ assert stdout_lines == [f' [RUN] {str(SCRIPT_RUN_SIMPLE)}',
53
+ ' Test 1.',
54
+ ' Test 2.',
55
+ ' Test 3.']
56
+ assert stderr_lines == [' Test 3.']
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- PyYAML
2
1
  colorama
3
2
  schema
4
3
  setproctitle
4
+ PyYAML
File without changes