| # Upgrading Dart's SDK for HTML (blink IDLs). | |
| # | |
| # Typically this is done using the Dart WebCore branch (as it has to be | |
| # staged to get most things working). | |
| # | |
| # Enlist in third_party/WebCore: | |
| # > cd src/dart/third_party | |
| # > rm -rf WebCore (NOTE: Normally detached head using gclient sync) | |
| # > git clone https://github.com/dart-lang/webcore.git WebCore | |
| # | |
| # To update all *.idl, *.py, LICENSE files, and IDLExtendedAttributes.txt: | |
| # > cd sdk | |
| # > python3 tools/dom/scripts/idlsync.py | |
| # | |
| # Display blink files to delete, copy, update, and collisions to review: | |
| # > python3 tools/dom/scripts/idlsync.py --check | |
| # | |
| # Bring over all blink files to dart/third_party/WebCore (*.py, *.idl, and | |
| # IDLExtendedAttributes.txt): | |
| # > python3 tools/dom/scripts/idlsync.py | |
| # | |
| # Update the DEPS file SHA for "WebCore_rev" with the committed changes of files | |
| # in WebCore e.g., "WebCore_rev": "@NNNNNNNNNNNNNNNNNNNNNNNNN" | |
| # | |
| # Generate the sdk/*.dart files from the new IDLs and PYTHON IDL parsing code | |
| # copied to in dart/third_party/WebCore from src/third_party/WebKit (blink). | |
| # | |
| # > cd src/dart/tools/dom/script | |
| # > ./go.sh | |
| # | |
| # Finally, commit the files in dart/third_party/WebCore. | |
| import errno | |
| import optparse | |
| import os.path | |
| import re | |
| import requests | |
| import subprocess | |
| import sys | |
| import time | |
| from shutil import copyfile | |
| # Dart DEPS file checked into the dart-lang/sdk master. | |
| DEPS_GIT = "https://raw.githubusercontent.com/dart-lang/sdk/master/DEPS" | |
| CHROME_TRUNK = "https://chromium.googlesource.com" | |
| WEBKIT_SHA_PATTERN = r'"WebCore_rev": "(\S+)",' | |
| # Chromium remote (GIT repository) | |
| GIT_REMOTES_CHROMIUM = 'https://chromium.googlesource.com/chromium/src.git' | |
| # location of this file | |
| SOURCE_FILE_DIR = 'tools/dom/scripts' | |
| WEBKIT_SOURCE = 'src/third_party/WebKit/Source' | |
| WEBCORE_SOURCE = 'third_party/WebCore' | |
| WEBKIT_BLINK_SOURCE = 'src/third_party/blink' | |
| WEBCORE_BLINK_SOURCE = 'third_party/WebCore/blink' | |
| # Never automatically git add bindings/IDLExtendedAttributes.txt this file has | |
| # been modified by Dart but is usually changed by WebKit blink too. | |
| IDL_EXTENDED_ATTRIBUTES_FILE = 'IDLExtendedAttributes.txt' | |
| # Don't automatically update, delete or add anything in this directory: | |
| # bindings/dart/scripts | |
| # The scripts in the above directory is the source for our Dart generators that | |
| # is driven from the blink IDL parser AST | |
| DART_SDK_GENERATOR_SCRIPTS = 'bindings/dart/scripts' | |
| # The __init__.py files allow Python to treat directories as packages. Used to | |
| # allow Dart's Python scripts to interact with Chrome's IDL parsing scripts. | |
| PYTHON_INITS = '__init__.py' | |
| # sub directories containing IDLs (core and modules) from the base directory | |
| # src/third_party/WebKit/Source | |
| SUBDIRS = [ | |
| 'bindings', | |
| 'core', | |
| 'modules', | |
| ] | |
| IDL_EXT = '.idl' | |
| PY_EXT = '.py' | |
| LICENSE_FILE_PREFIX = 'LICENSE' # e.g., LICENSE-APPLE, etc. | |
| # Look in any file in WebCore we copy from WebKit if this comment is in the file | |
| # then flag this as a special .py or .idl file that needs to be looked at. | |
| DART_CHANGES = ' FIXMEDART: ' | |
| # application options passed in. | |
| options = None | |
| warning_messages = [] | |
| # Is --dry_run passed in. | |
| def isDryRun(): | |
| global options | |
| return options['dry_run'] is not None | |
| # Is --verbose passed in. | |
| def isVerbose(): | |
| global options | |
| return options['verbose'] is not None | |
| # If --WebKit= is specified then compute the directory of the Chromium | |
| # source. | |
| def chromiumDirectory(): | |
| global options | |
| if options['chromium_dir'] is not None: | |
| return os.path.expanduser(options['chromium_dir']) | |
| return os.cwd() | |
| def RunCommand(cmd, valid_exits=[0]): | |
| """Executes a shell command and return its stdout.""" | |
| if isVerbose(): | |
| print(' '.join(cmd)) | |
| pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| output = pipe.communicate() | |
| if pipe.returncode in valid_exits: | |
| return output[0] | |
| else: | |
| print(output[1]) | |
| print('FAILED. RET_CODE=%d' % pipe.returncode) | |
| sys.exit(pipe.returncode) | |
| # returns True if // FIXMEDART: is in the file. | |
| def anyDartFixMe(filepath): | |
| if os.path.exists(filepath): | |
| data = open(filepath, 'r').read() | |
| return data.find(DART_CHANGES) != -1 | |
| else: | |
| return False | |
| # Give a base_dir compute the trailing directory after base_dir | |
| # returns the subpath from base_dir for the path passed in. | |
| def subpath(path, base_dir): | |
| dir_portion = '' | |
| head = path | |
| while True: | |
| head, tail = os.path.split(head) | |
| dir_portion = os.path.join(tail, dir_portion) | |
| if head == base_dir or tail == '': | |
| break | |
| return dir_portion | |
| # Copy any file in source_dir (WebKit) to destination_dir (dart/third_party/WebCore) | |
| # source_dir is the src/third_party/WebKit/Source location (blink) | |
| # destination_dir is the src/dart/third_party/WebCore location | |
| # returns idls_copied, py_copied, other_copied | |
| def copy_files(source_dir, src_prefix, destination_dir): | |
| original_cwd = os.getcwd() | |
| try: | |
| os.makedirs(destination_dir) | |
| except OSError as e: | |
| if e.errno != errno.EEXIST: | |
| raise | |
| os.chdir(destination_dir) | |
| idls = 0 # *.idl files copied | |
| pys = 0 # *.py files copied | |
| others = 0 # all other files copied | |
| for (root, _, files) in os.walk(source_dir, topdown=False): | |
| dir_portion = subpath(root, source_dir) | |
| for f in files: | |
| # Never automatically add any Dart generator scripts (these are the original | |
| # sources in WebCore) from WebKit to WebCore. | |
| if dir_portion != DART_SDK_GENERATOR_SCRIPTS: | |
| if (f.endswith(IDL_EXT) or f == IDL_EXTENDED_ATTRIBUTES_FILE or | |
| f.endswith(PY_EXT) or | |
| f.startswith(LICENSE_FILE_PREFIX)): | |
| if f.endswith(IDL_EXT): | |
| idls += 1 | |
| elif f.endswith(PY_EXT): | |
| pys += 1 | |
| else: | |
| others += 1 | |
| src_file = os.path.join(root, f) | |
| # Compute the destination path using sdk/third_party/WebCore | |
| subdir_root = src_file[src_file.rfind(src_prefix) + | |
| len(src_prefix):] | |
| if subdir_root.startswith(os.path.sep): | |
| subdir_root = subdir_root[1:] | |
| dst_file = os.path.join(destination_dir, subdir_root) | |
| # Need to make src/third_party/WebKit/Source/* to sdk/third_party/WebCore/* | |
| destination = os.path.dirname(dst_file) | |
| if not os.path.exists(destination): | |
| os.makedirs(destination) | |
| has_Dart_fix_me = anyDartFixMe(dst_file) | |
| if not isDryRun(): | |
| copyfile(src_file, dst_file) | |
| if isVerbose(): | |
| #print('...copying %s' % os.path.split(dst_file)[1]) | |
| print('...copying %s' % dst_file) | |
| if f == IDL_EXTENDED_ATTRIBUTES_FILE: | |
| warning_messages.append(dst_file) | |
| else: | |
| if has_Dart_fix_me: | |
| warning_messages.append(dst_file) | |
| if not (isDryRun() or has_Dart_fix_me): | |
| # git add the file | |
| RunCommand(['git', 'add', dst_file]) | |
| os.chdir(original_cwd) | |
| return [idls, pys, others] | |
| # Remove any file in webcore_dir that no longer exist in the webkit_dir | |
| # webcore_dir src/dart/third_party/WebCore location | |
| # webkit_dir src/third_party/WebKit/Source location (blink) | |
| # only check if the subdir off from webcore_dir | |
| # return list of files deleted | |
| def remove_obsolete_webcore_files(webcore_dir, webkit_dir, subdir): | |
| files_to_delete = [] | |
| original_cwd = os.getcwd() | |
| if os.path.exists(webcore_dir): | |
| os.chdir(webcore_dir) | |
| for (root, _, files) in os.walk( | |
| os.path.join(webcore_dir, subdir), topdown=False): | |
| dir_portion = subpath(root, webcore_dir) | |
| for f in files: | |
| # Never automatically deleted any Dart generator scripts (these are the | |
| # original sources in WebCore). | |
| if dir_portion != DART_SDK_GENERATOR_SCRIPTS: | |
| check_file = os.path.join(dir_portion, f) | |
| check_file_full_path = os.path.join(webkit_dir, check_file) | |
| if not os.path.exists(check_file_full_path) and \ | |
| not(check_file_full_path.endswith(PYTHON_INITS)): | |
| if not isDryRun(): | |
| # Remove the file using git | |
| RunCommand(['git', 'rm', check_file]) | |
| files_to_delete.append(check_file) | |
| os.chdir(original_cwd) | |
| return files_to_delete | |
| def ParseOptions(): | |
| parser = optparse.OptionParser() | |
| parser.add_option( | |
| '--chromium', | |
| '-c', | |
| dest='chromium_dir', | |
| action='store', | |
| type='string', | |
| help='WebKit Chrome directory (e.g., --chromium=~/chrome63', | |
| default=None) | |
| parser.add_option( | |
| '--verbose', | |
| '-v', | |
| dest='verbose', | |
| action='store_true', | |
| help='Dump all information', | |
| default=None) | |
| parser.add_option( | |
| '--dry_run', | |
| '-d', | |
| dest='dry_run', | |
| action='store_true', | |
| help='Display results without adding, updating or deleting any files', | |
| default=None) | |
| args, _ = parser.parse_args() | |
| argOptions = {} | |
| argOptions['chromium_dir'] = args.chromium_dir | |
| argOptions['verbose'] = args.verbose | |
| argOptions['dry_run'] = args.dry_run | |
| return argOptions | |
| # Fetch the DEPS file in src/dart/tools/deps/dartium.deps/DEPS from the GIT repro. | |
| def GetDepsFromGit(): | |
| req = requests.get(DEPS_GIT) | |
| return req.text | |
| def ValidateGitRemotes(): | |
| #origin https://chromium.googlesource.com/dart/dartium/src.git (fetch) | |
| remotes_list = RunCommand(['git', 'remote', '--verbose']).split() | |
| if (len(remotes_list) > 2 and remotes_list[0] == 'origin' and | |
| remotes_list[1] == GIT_REMOTES_CHROMIUM): | |
| return True | |
| print('ERROR: Unable to find dart/dartium/src repository %s' % | |
| GIT_REMOTES_CHROMIUM) | |
| return False | |
| def getChromiumSHA(): | |
| cwd = os.getcwd() | |
| chromiumDir = chromiumDirectory() | |
| webkit_dir = os.path.join(chromiumDir, WEBKIT_SOURCE) | |
| os.chdir(webkit_dir) | |
| if ValidateGitRemotes(): | |
| chromium_sha = RunCommand(['git', 'log', '--format=format:%H', '-1']) | |
| else: | |
| chromium_sha = -1 | |
| os.chdir(cwd) | |
| return chromium_sha | |
| def getCurrentDartSHA(): | |
| cwd = os.getcwd() | |
| if cwd.endswith('dart'): | |
| # In src/dart | |
| src_dir, _ = os.path.split(cwd) | |
| elif cwd.endswith('sdk'): | |
| src_dir = cwd | |
| else: | |
| src_dir = os.path.join(cwd, 'sdk') | |
| os.chdir(src_dir) | |
| if ValidateGitRemotes(): | |
| dart_sha = RunCommand(['git', 'log', '--format=format:%H', '-1']) | |
| else: | |
| dart_sha = -1 | |
| os.chdir(cwd) | |
| return dart_sha | |
| # Returns the SHA of the Dartium/Chromiun in the DEPS file. | |
| def GetDEPSWebCoreGitRevision(deps, component): | |
| """Returns a tuple with the (dartium chromium repo, latest revision).""" | |
| foundIt = re.search(WEBKIT_SHA_PATTERN, deps) | |
| #url_base, url_pattern = DEPS_PATTERNS[component] | |
| #url = url_base + re.search(url_pattern, deps).group(1) | |
| # Get the SHA for the Chromium/WebKit changes for Dartium. | |
| #revision = url[len(url_base):] | |
| revision = foundIt.group(1)[1:] | |
| print('%s' % revision) | |
| return revision | |
| def copy_subdir(src, src_prefix, dest, subdir): | |
| idls_deleted = remove_obsolete_webcore_files(dest, src, subdir) | |
| print("%s files removed in WebCore %s" % (idls_deleted.__len__(), subdir)) | |
| if isVerbose(): | |
| for delete_file in idls_deleted: | |
| print(" %s" % delete_file) | |
| idls_copied, py_copied, other_copied = copy_files( | |
| os.path.join(src, subdir), src_prefix, dest) | |
| if idls_copied > 0: | |
| print("Copied %s IDLs to %s" % (idls_copied, subdir)) | |
| if py_copied > 0: | |
| print("Copied %s PYs to %s" % (py_copied, subdir)) | |
| if other_copied > 0: | |
| print("Copied %s other to %s\n" % (other_copied, subdir)) | |
| def main(): | |
| global options | |
| options = ParseOptions() | |
| current_dir = os.path.dirname(os.path.abspath(__file__)) | |
| if not current_dir.endswith(SOURCE_FILE_DIR): | |
| print('ERROR: idlsync.py not run in proper directory (%s)\n', | |
| current_dir) | |
| base_directory = current_dir[:current_dir.rfind(SOURCE_FILE_DIR)] | |
| # Validate DEPS WebCore_rev SHA DOES NOT match the SHA of chromium master. | |
| deps = GetDepsFromGit() | |
| webcore_revision = GetDEPSWebCoreGitRevision(deps, 'webkit') | |
| chromium_sha = getChromiumSHA() | |
| if webcore_revision == chromium_sha: | |
| print("ERROR: Nothing to update in WebCore, WebCore_rev SHA in DEPS " | |
| "matches Chromium GIT master SHA in %s" % options['webkit_dir']) | |
| return | |
| start_time = time.time() | |
| # Copy scripts from third_party/blink/tools to third_party/WebCore/blink/tools | |
| # | |
| # This also implies that the files: | |
| # WebCore/bindings/scripts/code_generator_web_agent_api.py | |
| # WebCore/bindings/scripts/utilities.py | |
| # | |
| # Need to have sys.path.append at beginning of the above files changed from: | |
| # | |
| # sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..', | |
| # 'third_party', 'blink', 'tools')) | |
| # to | |
| # | |
| # sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', | |
| # 'blink', 'tools')) | |
| # | |
| webkit_blink_dir = os.path.join(chromiumDirectory(), WEBKIT_BLINK_SOURCE) | |
| webcore_blink_dir = os.path.join(base_directory, WEBCORE_BLINK_SOURCE) | |
| copy_subdir(webkit_blink_dir, WEBKIT_BLINK_SOURCE, webcore_blink_dir, "") | |
| chromium_webkit_dir = os.path.join(chromiumDirectory(), WEBKIT_SOURCE) | |
| dart_webcore_dir = os.path.join(base_directory, WEBCORE_SOURCE) | |
| for subdir in SUBDIRS: | |
| copy_subdir(chromium_webkit_dir, WEBKIT_SOURCE, dart_webcore_dir, | |
| subdir) | |
| end_time = time.time() | |
| print( | |
| 'WARNING: File(s) contain FIXMEDART and are NOT "git add " please review:' | |
| ) | |
| for warning in warning_messages: | |
| print(' %s' % warning) | |
| print('\nDone idlsync completed in %s seconds' % | |
| round(end_time - start_time, 2)) | |
| if __name__ == '__main__': | |
| sys.exit(main()) |