1import fnmatch 2import os 3import re 4import shutil 5import sys 6import uuid 7 8from .base import Step, StepRunner 9from .tree import Commit 10 11here = os.path.abspath(os.path.dirname(__file__)) 12 13 14def copy_wpt_tree(tree, dest, excludes=None, includes=None): 15 """Copy the working copy of a Tree to a destination directory. 16 17 :param tree: The Tree to copy. 18 :param dest: The destination directory""" 19 if os.path.exists(dest): 20 assert os.path.isdir(dest) 21 22 shutil.rmtree(dest) 23 24 os.mkdir(dest) 25 26 if excludes is None: 27 excludes = [] 28 29 excludes = [re.compile(fnmatch.translate(item)) for item in excludes] 30 31 if includes is None: 32 includes = [] 33 34 includes = [re.compile(fnmatch.translate(item)) for item in includes] 35 36 for tree_path in tree.paths(): 37 if (any(item.match(tree_path) for item in excludes) and 38 not any(item.match(tree_path) for item in includes)): 39 continue 40 41 source_path = os.path.join(tree.root, tree_path) 42 dest_path = os.path.join(dest, tree_path) 43 44 dest_dir = os.path.dirname(dest_path) 45 if not os.path.isdir(source_path): 46 if not os.path.exists(dest_dir): 47 os.makedirs(dest_dir) 48 shutil.copy2(source_path, dest_path) 49 50 for source, destination in [("testharness_runner.html", ""), 51 ("testdriver-vendor.js", "resources/")]: 52 source_path = os.path.join(here, os.pardir, source) 53 dest_path = os.path.join(dest, destination, os.path.basename(source)) 54 shutil.copy2(source_path, dest_path) 55 56 57class UpdateCheckout(Step): 58 """Pull changes from upstream into the local sync tree.""" 59 60 provides = ["local_branch"] 61 62 def create(self, state): 63 sync_tree = state.sync_tree 64 state.local_branch = uuid.uuid4().hex 65 sync_tree.update(state.sync["remote_url"], 66 state.sync["branch"], 67 state.local_branch) 68 sync_path = os.path.abspath(sync_tree.root) 69 if sync_path not in sys.path: 70 from .update import setup_paths 71 setup_paths(sync_path) 72 73 def restore(self, state): 74 assert os.path.abspath(state.sync_tree.root) in sys.path 75 Step.restore(self, state) 76 77 78class GetSyncTargetCommit(Step): 79 """Find the commit that we will sync to.""" 80 81 provides = ["sync_commit"] 82 83 def create(self, state): 84 if state.target_rev is None: 85 #Use upstream branch HEAD as the base commit 86 state.sync_commit = state.sync_tree.get_remote_sha1(state.sync["remote_url"], 87 state.sync["branch"]) 88 else: 89 state.sync_commit = Commit(state.sync_tree, state.rev) 90 91 state.sync_tree.checkout(state.sync_commit.sha1, state.local_branch, force=True) 92 self.logger.debug("New base commit is %s" % state.sync_commit.sha1) 93 94 95class UpdateManifest(Step): 96 """Update the manifest to match the tests in the sync tree checkout""" 97 98 provides = ["manifest_path", "test_manifest"] 99 100 def create(self, state): 101 from manifest import manifest # type: ignore 102 state.manifest_path = os.path.join(state.metadata_path, "MANIFEST.json") 103 state.test_manifest = manifest.load_and_update(state.sync["path"], 104 state.manifest_path, 105 "/", 106 write_manifest=True) 107 108 109class CopyWorkTree(Step): 110 """Copy the sync tree over to the destination in the local tree""" 111 112 def create(self, state): 113 copy_wpt_tree(state.sync_tree, 114 state.tests_path, 115 excludes=state.path_excludes, 116 includes=state.path_includes) 117 118 119class CreateSyncPatch(Step): 120 """Add the updated test files to a commit/patch in the local tree.""" 121 122 def create(self, state): 123 if not state.patch: 124 return 125 126 local_tree = state.local_tree 127 sync_tree = state.sync_tree 128 129 local_tree.create_patch("web-platform-tests_update_%s" % sync_tree.rev, 130 "Update %s to revision %s" % (state.suite_name, sync_tree.rev)) 131 test_prefix = os.path.relpath(state.tests_path, local_tree.root) 132 local_tree.add_new(test_prefix) 133 local_tree.add_ignored(sync_tree, test_prefix) 134 updated = local_tree.update_patch(include=[state.tests_path, 135 state.metadata_path]) 136 local_tree.commit_patch() 137 138 if not updated: 139 self.logger.info("Nothing to sync") 140 141 142class SyncFromUpstreamRunner(StepRunner): 143 """(Sub)Runner for doing an upstream sync""" 144 steps = [UpdateCheckout, 145 GetSyncTargetCommit, 146 UpdateManifest, 147 CopyWorkTree, 148 CreateSyncPatch] 149