taskcluster-taskgraph 9.1.0__tar.gz → 9.2.0__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.
Files changed (139) hide show
  1. {taskcluster-taskgraph-9.1.0/src/taskcluster_taskgraph.egg-info → taskcluster-taskgraph-9.2.0}/PKG-INFO +1 -1
  2. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0/src/taskcluster_taskgraph.egg-info}/PKG-INFO +1 -1
  3. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/__init__.py +1 -1
  4. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/run-task/fetch-content +66 -32
  5. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_scripts_fetch_content.py +6 -0
  6. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/LICENSE +0 -0
  7. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/MANIFEST.in +0 -0
  8. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/README.rst +0 -0
  9. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/pyproject.toml +0 -0
  10. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/requirements/base.in +0 -0
  11. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/requirements/base.txt +0 -0
  12. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/requirements/dev.in +0 -0
  13. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/requirements/dev.txt +0 -0
  14. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/requirements/test.in +0 -0
  15. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/requirements/test.txt +0 -0
  16. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/setup.cfg +0 -0
  17. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/setup.py +0 -0
  18. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskcluster_taskgraph.egg-info/SOURCES.txt +0 -0
  19. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskcluster_taskgraph.egg-info/dependency_links.txt +0 -0
  20. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskcluster_taskgraph.egg-info/entry_points.txt +0 -0
  21. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskcluster_taskgraph.egg-info/requires.txt +0 -0
  22. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskcluster_taskgraph.egg-info/top_level.txt +0 -0
  23. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/__init__.py +0 -0
  24. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/add_new_jobs.py +0 -0
  25. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/cancel.py +0 -0
  26. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/cancel_all.py +0 -0
  27. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
  28. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/registry.py +0 -0
  29. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/retrigger.py +0 -0
  30. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/actions/util.py +0 -0
  31. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/config.py +0 -0
  32. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/create.py +0 -0
  33. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/decision.py +0 -0
  34. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/docker.py +0 -0
  35. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/filter_tasks.py +0 -0
  36. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/generator.py +0 -0
  37. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/graph.py +0 -0
  38. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/loader/__init__.py +0 -0
  39. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/loader/default.py +0 -0
  40. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/loader/transform.py +0 -0
  41. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/main.py +0 -0
  42. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/morph.py +0 -0
  43. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/optimize/__init__.py +0 -0
  44. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/optimize/base.py +0 -0
  45. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/optimize/strategies.py +0 -0
  46. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/parameters.py +0 -0
  47. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/run-task/hgrc +0 -0
  48. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
  49. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/run-task/run-task +0 -0
  50. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/target_tasks.py +0 -0
  51. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/task.py +0 -0
  52. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/taskgraph.py +0 -0
  53. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/__init__.py +0 -0
  54. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/base.py +0 -0
  55. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/cached_tasks.py +0 -0
  56. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/chunking.py +0 -0
  57. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/code_review.py +0 -0
  58. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/docker_image.py +0 -0
  59. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/fetch.py +0 -0
  60. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/from_deps.py +0 -0
  61. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/notify.py +0 -0
  62. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/run/__init__.py +0 -0
  63. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/run/common.py +0 -0
  64. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/run/index_search.py +0 -0
  65. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/run/run_task.py +0 -0
  66. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/run/toolchain.py +0 -0
  67. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/task.py +0 -0
  68. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/transforms/task_context.py +0 -0
  69. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/__init__.py +0 -0
  70. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/archive.py +0 -0
  71. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/attributes.py +0 -0
  72. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/cached_tasks.py +0 -0
  73. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/copy.py +0 -0
  74. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/dependencies.py +0 -0
  75. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/docker.py +0 -0
  76. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/hash.py +0 -0
  77. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/keyed_by.py +0 -0
  78. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/parameterization.py +0 -0
  79. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/path.py +0 -0
  80. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/python_path.py +0 -0
  81. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/readonlydict.py +0 -0
  82. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/schema.py +0 -0
  83. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/set_name.py +0 -0
  84. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/shell.py +0 -0
  85. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/taskcluster.py +0 -0
  86. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/taskgraph.py +0 -0
  87. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/templates.py +0 -0
  88. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/time.py +0 -0
  89. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/treeherder.py +0 -0
  90. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/vcs.py +0 -0
  91. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/verify.py +0 -0
  92. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/workertypes.py +0 -0
  93. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/src/taskgraph/util/yaml.py +0 -0
  94. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
  95. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_actions_registry.py +0 -0
  96. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_create.py +0 -0
  97. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_decision.py +0 -0
  98. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_docker.py +0 -0
  99. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_generator.py +0 -0
  100. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_graph.py +0 -0
  101. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_main.py +0 -0
  102. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_morph.py +0 -0
  103. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_optimize.py +0 -0
  104. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_optimize_strategies.py +0 -0
  105. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_parameters.py +0 -0
  106. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_scripts_run_task.py +0 -0
  107. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_target_tasks.py +0 -0
  108. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_taskgraph.py +0 -0
  109. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transform_chunking.py +0 -0
  110. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transform_docker_image.py +0 -0
  111. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transform_task_context.py +0 -0
  112. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_base.py +0 -0
  113. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_cached_tasks.py +0 -0
  114. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_fetch.py +0 -0
  115. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_from_deps.py +0 -0
  116. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_notify.py +0 -0
  117. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_run.py +0 -0
  118. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_run_run_task.py +0 -0
  119. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_run_toolchain.py +0 -0
  120. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_transforms_task.py +0 -0
  121. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_archive.py +0 -0
  122. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_attributes.py +0 -0
  123. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_cached_tasks.py +0 -0
  124. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_copy.py +0 -0
  125. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_dependencies.py +0 -0
  126. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_docker.py +0 -0
  127. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_parameterization.py +0 -0
  128. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_path.py +0 -0
  129. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_python_path.py +0 -0
  130. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_readonlydict.py +0 -0
  131. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_schema.py +0 -0
  132. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_taskcluster.py +0 -0
  133. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_templates.py +0 -0
  134. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_time.py +0 -0
  135. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_treeherder.py +0 -0
  136. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_vcs.py +0 -0
  137. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_verify.py +0 -0
  138. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_workertypes.py +0 -0
  139. {taskcluster-taskgraph-9.1.0 → taskcluster-taskgraph-9.2.0}/test/test_util_yaml.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: taskcluster-taskgraph
3
- Version: 9.1.0
3
+ Version: 9.2.0
4
4
  Summary: Build taskcluster taskgraphs
5
5
  Home-page: https://github.com/taskcluster/taskgraph
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: taskcluster-taskgraph
3
- Version: 9.1.0
3
+ Version: 9.2.0
4
4
  Summary: Build taskcluster taskgraphs
5
5
  Home-page: https://github.com/taskcluster/taskgraph
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -2,7 +2,7 @@
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
- __version__ = "9.1.0"
5
+ __version__ = "9.2.0"
6
6
 
7
7
  # Maximum number of dependencies a single task can have
8
8
  # https://docs.taskcluster.net/reference/platform/taskcluster-queue/references/api#createTask
@@ -10,6 +10,7 @@ import contextlib
10
10
  import datetime
11
11
  import gzip
12
12
  import hashlib
13
+ import io
13
14
  import json
14
15
  import lzma
15
16
  import multiprocessing
@@ -194,6 +195,25 @@ def stream_download(url, sha256=None, size=None, headers=None):
194
195
  ) if certifi else urllib.request.urlopen(req, timeout=60) as fh:
195
196
  if not url.endswith(".gz") and fh.info().get("Content-Encoding") == "gzip":
196
197
  fh = gzip.GzipFile(fileobj=fh)
198
+ else:
199
+ # when using gzip we can't compare size or length (inflated) against content-length (compressed)
200
+ content_length = fh.getheader("content-length")
201
+ if content_length:
202
+ try:
203
+ content_length = int(content_length)
204
+ except ValueError:
205
+ raise IntegrityError(
206
+ "content-length header for %s is not an integer; got %s"
207
+ % (url, content_length)
208
+ )
209
+ if size:
210
+ if size != content_length:
211
+ raise IntegrityError(
212
+ "size mismatch on %s: wanted %d; content-length is %d"
213
+ % (url, size, content_length)
214
+ )
215
+ else:
216
+ size = content_length
197
217
 
198
218
  while True:
199
219
  chunk = fh.read(65536)
@@ -252,8 +272,6 @@ def download_to_path(url, path, sha256=None, size=None, headers=None):
252
272
  fh.write(chunk)
253
273
 
254
274
  return
255
- except IntegrityError:
256
- raise
257
275
  except Exception as e:
258
276
  log("Download failed: {}".format(e))
259
277
  continue
@@ -264,17 +282,15 @@ def download_to_path(url, path, sha256=None, size=None, headers=None):
264
282
  def download_to_memory(url, sha256=None, size=None):
265
283
  """Download a URL to memory, possibly with verification."""
266
284
 
267
- data = b""
268
285
  for _ in retrier(attempts=5, sleeptime=60):
269
- try:
270
- log("Downloading %s" % (url))
286
+ data = b""
287
+ log("Downloading %s" % (url))
271
288
 
289
+ try:
272
290
  for chunk in stream_download(url, sha256=sha256, size=size):
273
291
  data += chunk
274
292
 
275
293
  return data
276
- except IntegrityError:
277
- raise
278
294
  except Exception as e:
279
295
  log("Download failed: {}".format(e))
280
296
  continue
@@ -317,21 +333,41 @@ def gpg_verify_path(path: pathlib.Path, public_key_data: bytes, signature_data:
317
333
  subprocess.run(["gpgconf", "--kill", "gpg-agent"], env=env)
318
334
 
319
335
 
320
- def open_tar_stream(path: pathlib.Path):
321
- """"""
322
- if path.suffix == ".bz2":
323
- return bz2.open(str(path), "rb")
324
- elif path.suffix in (".gz", ".tgz") :
325
- return gzip.open(str(path), "rb")
326
- elif path.suffix == ".xz":
327
- return lzma.open(str(path), "rb")
328
- elif path.suffix == ".zst":
329
- dctx = ZstdDecompressor()
330
- return dctx.stream_reader(path.open("rb"))
331
- elif path.suffix == ".tar":
332
- return path.open("rb")
333
- else:
334
- raise ValueError("unknown archive format for tar file: %s" % path)
336
+ class ArchiveTypeNotSupported(Exception):
337
+ def __init__(self, path: pathlib.Path):
338
+ super(Exception, self).__init__("Archive type not supported for %s" % path)
339
+
340
+
341
+ def open_stream(path: pathlib.Path):
342
+ """Attempt to identify a path as an extractable archive by looking at its
343
+ content."""
344
+ fh = path.open(mode="rb")
345
+ magic = fh.read(6)
346
+ fh.seek(0)
347
+ if magic[:2] == b"PK":
348
+ return "zip", fh
349
+ if magic[:2] == b"\x1f\x8b":
350
+ fh = gzip.GzipFile(fileobj=fh)
351
+ elif magic[:3] == b"BZh":
352
+ fh = bz2.BZ2File(fh)
353
+ elif magic == b"\xfd7zXZ\x00":
354
+ fh = lzma.LZMAFile(fh)
355
+ elif magic[:4] == b"\x28\xb5\x2f\xfd":
356
+ fh = ZstdDecompressor().stream_reader(fh)
357
+ fh = io.BufferedReader(fh)
358
+ try:
359
+ # A full tar info header is 512 bytes.
360
+ headers = fh.peek(512)
361
+ # 257 is the offset of the ustar magic.
362
+ magic = headers[257 : 257 + 8]
363
+ # For older unix tar, rely on TarInfo.frombuf's checksum check
364
+ if magic in (b"ustar\x0000", b"ustar \x00") or tarfile.TarInfo.frombuf(
365
+ headers[:512], tarfile.ENCODING, "surrogateescape"
366
+ ):
367
+ return "tar", fh
368
+ except Exception as e:
369
+ pass
370
+ raise ArchiveTypeNotSupported(path)
335
371
 
336
372
 
337
373
  def archive_type(path: pathlib.Path):
@@ -344,7 +380,7 @@ def archive_type(path: pathlib.Path):
344
380
  return None
345
381
 
346
382
 
347
- def extract_archive(path, dest_dir, typ):
383
+ def extract_archive(path, dest_dir):
348
384
  """Extract an archive to a destination directory."""
349
385
 
350
386
  # Resolve paths to absolute variants.
@@ -356,8 +392,8 @@ def extract_archive(path, dest_dir, typ):
356
392
 
357
393
  # We pipe input to the decompressor program so that we can apply
358
394
  # custom decompressors that the program may not know about.
395
+ typ, ifh = open_stream(path)
359
396
  if typ == "tar":
360
- ifh = open_tar_stream(path)
361
397
  # On Windows, the tar program doesn't support things like symbolic
362
398
  # links, while Windows actually support them. The tarfile module in
363
399
  # python does. So use that. But since it's significantly slower than
@@ -404,10 +440,8 @@ def repack_archive(
404
440
  ):
405
441
  assert orig != dest
406
442
  log("Repacking as %s" % dest)
407
- orig_typ = archive_type(orig)
443
+ orig_typ, ifh = open_stream(orig)
408
444
  typ = archive_type(dest)
409
- if not orig_typ:
410
- raise Exception("Archive type not supported for %s" % orig.name)
411
445
  if not typ:
412
446
  raise Exception("Archive type not supported for %s" % dest.name)
413
447
 
@@ -433,7 +467,7 @@ def repack_archive(
433
467
  ctx = ZstdCompressor()
434
468
  if orig_typ == "zip":
435
469
  assert typ == "tar"
436
- zip = zipfile.ZipFile(orig)
470
+ zip = zipfile.ZipFile(ifh)
437
471
  # Convert the zip stream to a tar on the fly.
438
472
  with ctx.stream_writer(fh) as compressor, tarfile.open(
439
473
  fileobj=compressor, mode="w:"
@@ -475,7 +509,6 @@ def repack_archive(
475
509
  raise Exception("Repacking a tar to zip is not supported")
476
510
  assert typ == "tar"
477
511
 
478
- ifh = open_tar_stream(orig)
479
512
  if filter:
480
513
  # To apply the filter, we need to open the tar stream and
481
514
  # tweak it.
@@ -518,11 +551,12 @@ def fetch_and_extract(url, dest_dir, extract=True, sha256=None, size=None):
518
551
  if not extract:
519
552
  return
520
553
 
521
- typ = archive_type(dest_path)
522
- if typ:
523
- extract_archive(dest_path, dest_dir, typ)
554
+ try:
555
+ extract_archive(dest_path, dest_dir)
524
556
  log("Removing %s" % dest_path)
525
557
  dest_path.unlink()
558
+ except ArchiveTypeNotSupported:
559
+ pass
526
560
 
527
561
 
528
562
  def fetch_urls(downloads):
@@ -73,7 +73,13 @@ def test_stream_download(
73
73
  # create a mock context manager
74
74
  cm = MagicMock()
75
75
  cm.getcode.return_value = 200
76
+
77
+ def getheader(field):
78
+ if field.lower() == "content-length":
79
+ return size
80
+
76
81
  # simulates chunking
82
+ cm.getheader = getheader
77
83
  cm.read.side_effect = [b"foo", b"bar", None]
78
84
  cm.__enter__.return_value = cm
79
85
  return cm