# 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/Chromium 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())