1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 from datetime
import datetime
, timedelta
9 import mozversioncontrol
14 from cStringIO
import StringIO
as BytesIO
16 from io
import BytesIO
18 HEADERS
= {"User-Agent": "wpt manifest download"}
21 def get(logger
, url
, **kwargs
):
23 if "headers" not in kwargs
:
24 kwargs
["headers"] = HEADERS
25 return requests
.get(url
, **kwargs
)
29 return os
.path
.abspath(os
.path
.expanduser(path
))
32 def get_commits(logger
, repo_root
):
34 repo
= mozversioncontrol
.get_repository_object(repo_root
)
35 except mozversioncontrol
.InvalidRepoPath
:
36 logger
.warning("No VCS found for path %s" % repo_root
)
39 # The base_ref doesn't actually return a ref, sadly
40 base_rev
= repo
.base_ref
41 if repo
.name
== "git":
42 logger
.debug("Found git repo")
43 logger
.debug("Base rev is %s" % base_rev
)
44 if not repo
.has_git_cinnabar
:
45 logger
.error("git cinnabar not found")
48 repo
._run
("cinnabar", "git2hg", rev
).strip()
54 "testing/web-platform/tests",
55 "testing/web-platform/mozilla/tests",
59 logger
.debug("Found hg repo")
60 logger
.debug("Base rev is %s" % base_rev
)
61 changeset_iter
= repo
._run
(
64 "--template={node}\n",
67 "testing/web-platform/tests",
68 "testing/web-platform/mozilla/tests",
73 def should_download(logger
, manifest_paths
, rebuild_time
=timedelta(days
=5)):
74 # TODO: Improve logic for when to download. Maybe if x revisions behind?
75 for manifest_path
in manifest_paths
:
76 if not os
.path
.exists(manifest_path
):
78 mtime
= datetime
.fromtimestamp(os
.path
.getmtime(manifest_path
))
79 if mtime
< datetime
.now() - rebuild_time
:
81 if os
.path
.getsize(manifest_path
) == 0:
84 logger
.info("Skipping manifest download because existing file is recent")
88 def taskcluster_url(logger
, commits
):
89 artifact_path
= "/artifacts/public/manifests.tar.gz"
92 "mozilla-central": "mozilla-central",
93 "integration/autoland": "autoland",
94 "releases/mozilla-esr115": "mozilla-esr115",
97 "https://hg.mozilla.org/{repo}/json-pushes?"
98 "changeset={changeset}&version=2&tipsonly=1"
102 "https://firefox-ci-tc.services.mozilla.com/api/index/v1/"
103 "task/gecko.v2.{name}."
104 "revision.{changeset}.source.manifest-upload"
108 "https://firefox-ci-tc.services.mozilla.com/api/index/v1/"
109 "task/gecko.v2.mozilla-central.latest.source.manifest-upload" + artifact_path
112 for revision
in commits
:
115 if revision
== 40 * "0":
118 for repo_path
, index_name
in six
.iteritems(repos
):
120 req_headers
= HEADERS
.copy()
121 req_headers
.update({"Accept": "application/json"})
124 cset_url
.format(changeset
=revision
, repo
=repo_path
),
127 req
.raise_for_status()
128 except requests
.exceptions
.RequestException
:
129 if req
is not None and req
.status_code
== 404:
130 # The API returns a 404 if it can't find a changeset for the revision.
131 logger
.debug("%s not found in %s" % (revision
, repo_path
))
138 pushes
= result
["pushes"]
140 logger
.debug("Error reading response; 'pushes' key not found")
142 [cset
] = next(iter(pushes
.values()))["changesets"]
144 tc_index_url
= tc_url
.format(changeset
=cset
, name
=index_name
)
146 req
= get(logger
, tc_index_url
)
147 except requests
.exceptions
.RequestException
:
150 if req
.status_code
== 200:
151 return tc_index_url
+ artifact_path
154 "Can't find a commit-specific manifest so just using the most " "recent one"
160 def download_manifest(logger
, test_paths
, commits_func
, url_func
, force
=False):
162 (item
["manifest_path"] if isinstance(item
, dict) else item
.manifest_path
)
163 for item
in test_paths
.values()
166 if not force
and not should_download(logger
, manifest_paths
):
169 commits
= commits_func()
171 url
= url_func(logger
, commits
)
173 logger
.warning("No generated manifest found")
176 logger
.info("Downloading manifest from %s" % url
)
178 req
= get(logger
, url
)
180 logger
.warning("Downloading pregenerated manifest failed")
183 if req
.status_code
!= 200:
185 "Downloading pregenerated manifest failed; got "
186 "HTTP status %d" % req
.status_code
190 tar
= tarfile
.open(mode
="r:gz", fileobj
=BytesIO(req
.content
))
191 for paths
in six
.itervalues(test_paths
):
192 manifest_rel_path
= (
193 paths
["manifest_rel_path"]
194 if isinstance(paths
, dict)
195 else paths
.manifest_rel_path
198 paths
["manifest_path"] if isinstance(paths
, dict) else paths
.manifest_path
202 member
= tar
.getmember(manifest_rel_path
.replace(os
.path
.sep
, "/"))
204 logger
.warning("Failed to find downloaded manifest %s" % manifest_rel_path
)
207 logger
.debug("Unpacking %s to %s" % (member
.name
, manifest_path
))
208 src
= tar
.extractfile(member
)
209 with
open(manifest_path
, "wb") as dest
:
210 dest
.write(src
.read())
216 "Failed to decompress %s:\n%s"
217 % (manifest_rel_path
, traceback
.format_exc())
221 os
.utime(manifest_path
, None)
226 def download_from_taskcluster(logger
, repo_root
, test_paths
, force
=False):
227 return download_manifest(
230 lambda: get_commits(logger
, repo_root
),