| import fnmatch |
| import os |
| import re |
| import shutil |
| import sys |
| import uuid |
| |
| from .. import testloader |
| |
| from base import Step, StepRunner |
| from tree import Commit |
| |
| here = os.path.abspath(os.path.split(__file__)[0]) |
| |
| bsd_license = """W3C 3-clause BSD License |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| |
| * Redistributions of works must retain the original copyright notice, this |
| list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the original copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of the W3C nor the names of its contributors may be |
| used to endorse or promote products derived from this work without |
| specific prior written permission. |
| |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| POSSIBILITY OF SUCH DAMAGE. |
| """ |
| |
| |
| def copy_wpt_tree(tree, dest, excludes=None, includes=None): |
| """Copy the working copy of a Tree to a destination directory. |
| |
| :param tree: The Tree to copy. |
| :param dest: The destination directory""" |
| if os.path.exists(dest): |
| assert os.path.isdir(dest) |
| |
| shutil.rmtree(dest) |
| |
| os.mkdir(dest) |
| |
| if excludes is None: |
| excludes = [] |
| |
| excludes = [re.compile(fnmatch.translate(item)) for item in excludes] |
| |
| if includes is None: |
| includes = [] |
| |
| includes = [re.compile(fnmatch.translate(item)) for item in includes] |
| |
| for tree_path in tree.paths(): |
| if (any(item.match(tree_path) for item in excludes) and |
| not any(item.match(tree_path) for item in includes)): |
| continue |
| |
| source_path = os.path.join(tree.root, tree_path) |
| dest_path = os.path.join(dest, tree_path) |
| |
| dest_dir = os.path.split(dest_path)[0] |
| if not os.path.isdir(source_path): |
| if not os.path.exists(dest_dir): |
| os.makedirs(dest_dir) |
| shutil.copy2(source_path, dest_path) |
| |
| for source, destination in [("testharness_runner.html", ""), |
| ("testharnessreport.js", "resources/")]: |
| source_path = os.path.join(here, os.pardir, source) |
| dest_path = os.path.join(dest, destination, os.path.split(source)[1]) |
| shutil.copy2(source_path, dest_path) |
| |
| add_license(dest) |
| |
| |
| def add_license(dest): |
| """Write the bsd license string to a LICENSE file. |
| |
| :param dest: Directory in which to place the LICENSE file.""" |
| with open(os.path.join(dest, "LICENSE"), "w") as f: |
| f.write(bsd_license) |
| |
| |
| class UpdateCheckout(Step): |
| """Pull changes from upstream into the local sync tree.""" |
| |
| provides = ["local_branch"] |
| |
| def create(self, state): |
| sync_tree = state.sync_tree |
| state.local_branch = uuid.uuid4().hex |
| sync_tree.update(state.sync["remote_url"], |
| state.sync["branch"], |
| state.local_branch) |
| sync_path = os.path.abspath(sync_tree.root) |
| if not sync_path in sys.path: |
| from update import setup_paths |
| setup_paths(sync_path) |
| |
| def restore(self, state): |
| assert os.path.abspath(state.sync_tree.root) in sys.path |
| Step.restore(self, state) |
| |
| |
| class GetSyncTargetCommit(Step): |
| """Find the commit that we will sync to.""" |
| |
| provides = ["sync_commit"] |
| |
| def create(self, state): |
| if state.target_rev is None: |
| #Use upstream branch HEAD as the base commit |
| state.sync_commit = state.sync_tree.get_remote_sha1(state.sync["remote_url"], |
| state.sync["branch"]) |
| else: |
| state.sync_commit = Commit(state.sync_tree, state.rev) |
| |
| state.sync_tree.checkout(state.sync_commit.sha1, state.local_branch, force=True) |
| self.logger.debug("New base commit is %s" % state.sync_commit.sha1) |
| |
| |
| class LoadManifest(Step): |
| """Load the test manifest""" |
| |
| provides = ["manifest_path", "test_manifest"] |
| |
| def create(self, state): |
| from manifest import manifest |
| state.manifest_path = os.path.join(state.metadata_path, "MANIFEST.json") |
| state.test_manifest = manifest.Manifest("/") |
| |
| |
| class UpdateManifest(Step): |
| """Update the manifest to match the tests in the sync tree checkout""" |
| |
| def create(self, state): |
| from manifest import manifest, update |
| update.update(state.sync["path"], state.test_manifest) |
| manifest.write(state.test_manifest, state.manifest_path) |
| |
| |
| class CopyWorkTree(Step): |
| """Copy the sync tree over to the destination in the local tree""" |
| |
| def create(self, state): |
| copy_wpt_tree(state.sync_tree, |
| state.tests_path, |
| excludes=state.path_excludes, |
| includes=state.path_includes) |
| |
| |
| class CreateSyncPatch(Step): |
| """Add the updated test files to a commit/patch in the local tree.""" |
| |
| def create(self, state): |
| if not state.patch: |
| return |
| |
| local_tree = state.local_tree |
| sync_tree = state.sync_tree |
| |
| local_tree.create_patch("web-platform-tests_update_%s" % sync_tree.rev, |
| "Update %s to revision %s" % (state.suite_name, sync_tree.rev)) |
| local_tree.add_new(os.path.relpath(state.tests_path, |
| local_tree.root)) |
| updated = local_tree.update_patch(include=[state.tests_path, |
| state.metadata_path]) |
| local_tree.commit_patch() |
| |
| if not updated: |
| self.logger.info("Nothing to sync") |
| |
| |
| class SyncFromUpstreamRunner(StepRunner): |
| """(Sub)Runner for doing an upstream sync""" |
| steps = [UpdateCheckout, |
| GetSyncTargetCommit, |
| LoadManifest, |
| UpdateManifest, |
| CopyWorkTree, |
| CreateSyncPatch] |