def clean_nightlies(self, force=False, keep=None): self.set_use_stable_rust(False) rust_current_nightly = self.rust_version() self.set_use_stable_rust(True) rust_current_stable = self.rust_version() cargo_current = self.cargo_build_id() print("Current Rust nightly version: {}".format(rust_current_nightly)) print("Current Rust stable version: {}".format(rust_current_stable)) print("Current Cargo version: {}".format(cargo_current)) to_keep = { 'rust': set(), 'cargo': set(), } if int(keep) == 1: # Optimize keep=1 case to not invoke git to_keep['rust'].add(rust_current_nightly) to_keep['rust'].add(rust_current_stable) to_keep['cargo'].add(cargo_current) else: for tool, version_files in { 'rust': ['rust-commit-hash', 'rust-stable-version'], 'cargo': ['cargo-commit-hash'], }.items(): for version_file in version_files: cmd = subprocess.Popen([ 'git', 'log', '--oneline', '--no-color', '-n', keep, '--patch', version_file ], stdout=subprocess.PIPE, universal_newlines=True) stdout, _ = cmd.communicate() for line in stdout.splitlines(): if line.startswith( b"+") and not line.startswith(b"+++"): to_keep[tool].add(line[1:]) removing_anything = False for tool in ["rust", "cargo"]: base = path.join(self.context.sharedir, tool) if not path.isdir(base): continue for name in os.listdir(base): # We append `-alt` if LLVM assertions aren't enabled, # so use just the commit hash itself. # This may occasionally leave an extra nightly behind # but won't remove too many nightlies. if name.partition('-')[0] not in to_keep[tool]: removing_anything = True full_path = path.join(base, name) if force: print("Removing {}".format(full_path)) delete(full_path) else: print("Would remove {}".format(full_path)) if not removing_anything: print("Nothing to remove.") elif not force: print("Nothing done. " "Run `./mach clean-nightlies -f` to actually remove.")
def clean_nightlies(self, force=False, keep=None): self.set_use_stable_rust(False) rust_current_nightly = self.rust_version() self.set_use_stable_rust(True) rust_current_stable = self.rust_version() cargo_current = self.cargo_build_id() print("Current Rust nightly version: {}".format(rust_current_nightly)) print("Current Rust stable version: {}".format(rust_current_stable)) print("Current Cargo version: {}".format(cargo_current)) to_keep = { 'rust': set(), 'cargo': set(), } if int(keep) == 1: # Optimize keep=1 case to not invoke git to_keep['rust'].add(rust_current_nightly) to_keep['rust'].add(rust_current_stable) to_keep['cargo'].add(cargo_current) else: for tool, version_files in { 'rust': ['rust-commit-hash', 'rust-stable-version'], 'cargo': ['cargo-commit-hash'], }.items(): for version_file in version_files: cmd = subprocess.Popen( ['git', 'log', '--oneline', '--no-color', '-n', keep, '--patch', version_file], stdout=subprocess.PIPE, universal_newlines=True ) stdout, _ = cmd.communicate() for line in stdout.splitlines(): if line.startswith(b"+") and not line.startswith(b"+++"): to_keep[tool].add(line[1:]) removing_anything = False for tool in ["rust", "cargo"]: base = path.join(self.context.sharedir, tool) if not path.isdir(base): continue for name in os.listdir(base): # We append `-alt` if LLVM assertions aren't enabled, # so use just the commit hash itself. # This may occasionally leave an extra nightly behind # but won't remove too many nightlies. if name.partition('-')[0] not in to_keep[tool]: removing_anything = True full_path = path.join(base, name) if force: print("Removing {}".format(full_path)) delete(full_path) else: print("Would remove {}".format(full_path)) if not removing_anything: print("Nothing to remove.") elif not force: print("Nothing done. " "Run `./mach clean-nightlies -f` to actually remove.")
def clean_nightlies(self, force=False, keep=None): rust_current = self.rust_version() cargo_current = self.cargo_build_id() print("Current Rust version: {}".format(rust_current)) print("Current Cargo version: {}".format(cargo_current)) to_keep = { 'rust': set(), 'cargo': set(), } if int(keep) == 1: # Optimize keep=1 case to not invoke git to_keep['rust'].add(rust_current) to_keep['cargo'].add(cargo_current) else: for tool in ["rust", "cargo"]: commit_file = '{}-commit-hash'.format(tool) cmd = subprocess.Popen( ['git', 'log', '--pretty=format:%H', '-n', keep, commit_file], stdout=subprocess.PIPE, universal_newlines=True ) stdout, _ = cmd.communicate() for commit in stdout.splitlines(): cmd = subprocess.Popen( ['git', 'show', '{}:{}'.format(commit, commit_file)], stdout=subprocess.PIPE, universal_newlines=True ) commit_hash, _ = cmd.communicate() to_keep[tool].add(commit_hash.rstrip()) removing_anything = False for tool in ["rust", "cargo"]: base = path.join(self.context.sharedir, tool) for name in os.listdir(base): # We append `-alt` if LLVM assertions aren't enabled, # so use just the commit hash itself. # This may occasionally leave an extra nightly behind # but won't remove too many nightlies. if name.partition('-')[0] not in to_keep[tool]: removing_anything = True full_path = path.join(base, name) if force: print("Removing {}".format(full_path)) delete(full_path) else: print("Would remove {}".format(full_path)) if not removing_anything: print("Nothing to remove.") elif not force: print("Nothing done. " "Run `./mach clean-nightlies -f` to actually remove.")
def clean_nightlies(self, force=False, keep=None): rust_current_nightly = self.rust_nightly_date() rust_current_stable = self.rust_stable_version() print("Current Rust nightly version: {}".format(rust_current_nightly)) print("Current Rust stable version: {}".format(rust_current_stable)) to_keep = set() if int(keep) == 1: # Optimize keep=1 case to not invoke git to_keep.add(rust_current_nightly) to_keep.add(rust_current_stable) else: for version_file in ['rust-toolchain', 'rust-stable-version']: cmd = subprocess.Popen([ 'git', 'log', '--oneline', '--no-color', '-n', keep, '--patch', version_file ], stdout=subprocess.PIPE, universal_newlines=True) stdout, _ = cmd.communicate() for line in stdout.splitlines(): if line.startswith(b"+") and not line.startswith(b"+++"): line = line[len(b"+"):] if line.startswith(b"nightly-"): line = line[len(b"nightly-"):] to_keep.add(line) removing_anything = False for tool in ["rust", "cargo"]: base = path.join(self.context.sharedir, tool) if not path.isdir(base): continue for name in os.listdir(base): full_path = path.join(base, name) if name.startswith("rust-"): name = name[len("rust-"):] if name.endswith("-alt"): name = name[:-len("-alt")] if name not in to_keep: removing_anything = True if force: print("Removing {}".format(full_path)) try: delete(full_path) except OSError as e: print("Removal failed with error {}".format(e)) else: print("Would remove {}".format(full_path)) if not removing_anything: print("Nothing to remove.") elif not force: print("Nothing done. " "Run `./mach clean-nightlies -f` to actually remove.")
def clean_nightlies(self, force=False, keep=None): rust_current_nightly = self.rust_nightly_date() rust_current_stable = self.rust_stable_version() print("Current Rust nightly version: {}".format(rust_current_nightly)) print("Current Rust stable version: {}".format(rust_current_stable)) to_keep = set() if int(keep) == 1: # Optimize keep=1 case to not invoke git to_keep.add(rust_current_nightly) to_keep.add(rust_current_stable) else: for version_file in ['rust-toolchain', 'rust-stable-version']: cmd = subprocess.Popen( ['git', 'log', '--oneline', '--no-color', '-n', keep, '--patch', version_file], stdout=subprocess.PIPE, universal_newlines=True ) stdout, _ = cmd.communicate() for line in stdout.splitlines(): if line.startswith(b"+") and not line.startswith(b"+++"): line = line[len(b"+"):] if line.startswith(b"nightly-"): line = line[len(b"nightly-"):] to_keep.add(line) removing_anything = False for tool in ["rust", "cargo"]: base = path.join(self.context.sharedir, tool) if not path.isdir(base): continue for name in os.listdir(base): full_path = path.join(base, name) if name.startswith("rust-"): name = name[len("rust-"):] if name.endswith("-alt"): name = name[:-len("-alt")] if name not in to_keep: removing_anything = True if force: print("Removing {}".format(full_path)) try: delete(full_path) except OSError as e: print("Removal failed with error {}".format(e)) else: print("Would remove {}".format(full_path)) if not removing_anything: print("Nothing to remove.") elif not force: print("Nothing done. " "Run `./mach clean-nightlies -f` to actually remove.")
def change_prefs(resources_path, platform): print("Swapping prefs") prefs_path = path.join(resources_path, "prefs.json") package_prefs_path = path.join(resources_path, "package-prefs.json") os_type = "os:{}".format(platform) with open(prefs_path) as prefs, open(package_prefs_path) as package_prefs: prefs = json.load(prefs) package_prefs = json.load(package_prefs) for pref in package_prefs: if os_type in pref: prefs[pref.split(";")[1]] = package_prefs[pref] if pref in prefs: prefs[pref] = package_prefs[pref] with open(prefs_path, "w") as out: json.dump(prefs, out, sort_keys=True, indent=2) delete(package_prefs_path)
def change_prefs(resources_path, platform, vr=False): print("Swapping prefs") prefs_path = path.join(resources_path, "prefs.json") package_prefs_path = path.join(resources_path, "package-prefs.json") with open(prefs_path) as prefs, open(package_prefs_path) as package_prefs: prefs = json.load(prefs) pref_sets = [] package_prefs = json.load(package_prefs) if "all" in package_prefs: pref_sets += [package_prefs["all"]] if vr and "vr" in package_prefs: pref_sets += [package_prefs["vr"]] if platform in package_prefs: pref_sets += [package_prefs[platform]] for pref_set in pref_sets: for pref in pref_set: if pref in prefs: prefs[pref] = pref_set[pref] with open(prefs_path, "w") as out: json.dump(prefs, out, sort_keys=True, indent=2) delete(package_prefs_path)
def package(self, release=False, dev=False, android=None, magicleap=None, debug=False, debugger=None, target=None, flavor=None, maven=False): if android is None: android = self.config["build"]["android"] if target and android: print("Please specify either --target or --android.") sys.exit(1) if not android: android = self.handle_android_target(target) else: target = self.config["android"]["target"] if target and magicleap: print("Please specify either --target or --magicleap.") sys.exit(1) if magicleap: target = "aarch64-linux-android" env = self.build_env(target=target) binary_path = self.get_binary_path(release, dev, android=android, magicleap=magicleap) dir_to_root = self.get_top_dir() target_dir = path.dirname(binary_path) if magicleap: if platform.system() not in ["Darwin"]: raise Exception("Magic Leap builds are only supported on macOS.") if not env.get("MAGICLEAP_SDK"): raise Exception("Magic Leap builds need the MAGICLEAP_SDK environment variable") if not env.get("MLCERT"): raise Exception("Magic Leap builds need the MLCERT environment variable") mabu = path.join(env.get("MAGICLEAP_SDK"), "mabu") package = "./support/magicleap/Servo2D/Servo2D.package" if dev: build_type = "lumin_debug" else: build_type = "lumin_release" argv = [ mabu, "-o", target_dir, "-t", build_type, package ] try: subprocess.check_call(argv, env=env) except subprocess.CalledProcessError as e: print("Packaging Magic Leap exited with return value %d" % e.returncode) return e.returncode elif android: android_target = self.config["android"]["target"] if "aarch64" in android_target: build_type = "Arm64" elif "armv7" in android_target: build_type = "Armv7" elif "i686" in android_target: build_type = "x86" else: build_type = "Arm" if dev: build_mode = "Debug" else: build_mode = "Release" flavor_name = "Main" if flavor is not None: flavor_name = flavor.title() vr = flavor == "googlevr" or flavor == "oculusvr" dir_to_resources = path.join(self.get_top_dir(), 'target', 'android', 'resources') if path.exists(dir_to_resources): delete(dir_to_resources) shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) change_prefs(dir_to_resources, "android", vr=vr) variant = ":assemble" + flavor_name + build_type + build_mode apk_task_name = ":servoapp" + variant aar_task_name = ":servoview" + variant maven_task_name = ":servoview:uploadArchive" argv = ["./gradlew", "--no-daemon", apk_task_name, aar_task_name] if maven: argv.append(maven_task_name) try: with cd(path.join("support", "android", "apk")): subprocess.check_call(argv, env=env) except subprocess.CalledProcessError as e: print("Packaging Android exited with return value %d" % e.returncode) return e.returncode elif is_macosx(): print("Creating Servo.app") dir_to_dmg = path.join(target_dir, 'dmg') dir_to_app = path.join(dir_to_dmg, 'Servo.app') dir_to_resources = path.join(dir_to_app, 'Contents', 'Resources') if path.exists(dir_to_dmg): print("Cleaning up from previous packaging") delete(dir_to_dmg) print("Copying files") shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy2(path.join(dir_to_root, 'Info.plist'), path.join(dir_to_app, 'Contents', 'Info.plist')) content_dir = path.join(dir_to_app, 'Contents', 'MacOS') os.makedirs(content_dir) shutil.copy2(binary_path, content_dir) change_prefs(dir_to_resources, "macosx") print("Finding dylibs and relinking") copy_dependencies(path.join(content_dir, 'servo'), content_dir) print("Adding version to Credits.rtf") version_command = [binary_path, '--version'] p = subprocess.Popen(version_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) version, stderr = p.communicate() if p.returncode != 0: raise Exception("Error occurred when getting Servo version: " + stderr) version = "Nightly version: " + version import mako.template template_path = path.join(dir_to_resources, 'Credits.rtf.mako') credits_path = path.join(dir_to_resources, 'Credits.rtf') with open(template_path) as template_file: template = mako.template.Template(template_file.read()) with open(credits_path, "w") as credits_file: credits_file.write(template.render(version=version)) delete(template_path) print("Creating dmg") os.symlink('/Applications', path.join(dir_to_dmg, 'Applications')) dmg_path = path.join(target_dir, "servo-tech-demo.dmg") if path.exists(dmg_path): print("Deleting existing dmg") os.remove(dmg_path) try: subprocess.check_call(['hdiutil', 'create', '-volname', 'Servo', '-megabytes', '900', dmg_path, '-srcfolder', dir_to_dmg]) except subprocess.CalledProcessError as e: print("Packaging MacOS dmg exited with return value %d" % e.returncode) return e.returncode print("Cleaning up") delete(dir_to_dmg) print("Packaged Servo into " + dmg_path) print("Creating brew package") dir_to_brew = path.join(target_dir, 'brew_tmp') dir_to_tar = path.join(target_dir, 'brew') if not path.exists(dir_to_tar): os.makedirs(dir_to_tar) tar_path = path.join(dir_to_tar, "servo.tar.gz") if path.exists(dir_to_brew): print("Cleaning up from previous packaging") delete(dir_to_brew) if path.exists(tar_path): print("Deleting existing package") os.remove(tar_path) shutil.copytree(path.join(dir_to_root, 'resources'), path.join(dir_to_brew, 'resources')) os.makedirs(path.join(dir_to_brew, 'bin')) shutil.copy2(binary_path, path.join(dir_to_brew, 'bin', 'servo')) # Note that in the context of Homebrew, libexec is reserved for private use by the formula # and therefore is not symlinked into HOMEBREW_PREFIX. os.makedirs(path.join(dir_to_brew, 'libexec')) copy_dependencies(path.join(dir_to_brew, 'bin', 'servo'), path.join(dir_to_brew, 'libexec')) archive_deterministically(dir_to_brew, tar_path, prepend_path='servo/') delete(dir_to_brew) print("Packaged Servo into " + tar_path) elif is_windows(): dir_to_msi = path.join(target_dir, 'msi') if path.exists(dir_to_msi): print("Cleaning up from previous packaging") delete(dir_to_msi) os.makedirs(dir_to_msi) print("Copying files") dir_to_temp = path.join(dir_to_msi, 'temp') dir_to_resources = path.join(dir_to_temp, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy(binary_path, dir_to_temp) copy_windows_dependencies(target_dir, dir_to_temp) change_prefs(dir_to_resources, "windows") # generate Servo.wxs import mako.template template_path = path.join(dir_to_root, "support", "windows", "Servo.wxs.mako") template = mako.template.Template(open(template_path).read()) wxs_path = path.join(dir_to_msi, "Installer.wxs") open(wxs_path, "w").write(template.render( exe_path=target_dir, dir_to_temp=dir_to_temp, resources_path=dir_to_resources)) # run candle and light print("Creating MSI") try: with cd(dir_to_msi): subprocess.check_call(['candle', wxs_path]) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path]) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode dir_to_installer = path.join(dir_to_msi, "Installer.msi") print("Packaged Servo into " + dir_to_installer) # Generate bundle with Servo installer. print("Creating bundle") shutil.copy(path.join(dir_to_root, 'support', 'windows', 'Servo.wxs'), dir_to_msi) bundle_wxs_path = path.join(dir_to_msi, 'Servo.wxs') try: with cd(dir_to_msi): subprocess.check_call(['candle', bundle_wxs_path, '-ext', 'WixBalExtension']) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(bundle_wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path, '-ext', 'WixBalExtension']) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode print("Packaged Servo into " + path.join(dir_to_msi, "Servo.exe")) print("Creating ZIP") zip_path = path.join(dir_to_msi, "Servo.zip") archive_deterministically(dir_to_temp, zip_path, prepend_path='servo/') print("Packaged Servo into " + zip_path) print("Cleaning up") delete(dir_to_temp) delete(dir_to_installer) else: dir_to_temp = path.join(target_dir, 'packaging-temp') if path.exists(dir_to_temp): # TODO(aneeshusa): lock dir_to_temp to prevent simultaneous builds print("Cleaning up from previous packaging") delete(dir_to_temp) print("Copying files") dir_to_resources = path.join(dir_to_temp, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy(binary_path, dir_to_temp) change_prefs(dir_to_resources, "linux") print("Creating tarball") tar_path = path.join(target_dir, 'servo-tech-demo.tar.gz') archive_deterministically(dir_to_temp, tar_path, prepend_path='servo/') print("Cleaning up") delete(dir_to_temp) print("Packaged Servo into " + tar_path)
def clean_cargo_cache(self, force=False, show_size=False, keep=None, custom_path=False): def get_size(path): if os.path.isfile(path): return os.path.getsize(path) / (1024 * 1024.0) total_size = 0 for dirpath, dirnames, filenames in os.walk(path): for f in filenames: fp = os.path.join(dirpath, f) total_size += os.path.getsize(fp) return total_size / (1024 * 1024.0) removing_anything = False packages = { 'crates': {}, 'git': {}, } import toml if os.environ.get("CARGO_HOME", "") and custom_path: cargo_dir = os.environ.get("CARGO_HOME") else: cargo_dir = path.join(self.context.topdir, ".cargo") if not os.path.isdir(cargo_dir): return cargo_file = open(path.join(self.context.topdir, "Cargo.lock")) content = toml.load(cargo_file) for package in content.get("package", []): source = package.get("source", "") version = package["version"] if source == u"registry+https://github.com/rust-lang/crates.io-index": crate_name = "{}-{}".format(package["name"], version) if not packages["crates"].get(crate_name, False): packages["crates"][package["name"]] = { "current": [], "exist": [], } packages["crates"][package["name"]]["current"].append(crate_name) elif source.startswith("git+"): name = source.split("#")[0].split("/")[-1].replace(".git", "") branch = "" crate_name = "{}-{}".format(package["name"], source.split("#")[1]) crate_branch = name.split("?") if len(crate_branch) > 1: branch = crate_branch[1].replace("branch=", "") name = crate_branch[0] if not packages["git"].get(name, False): packages["git"][name] = { "current": [], "exist": [], } packages["git"][name]["current"].append(source.split("#")[1][:7]) if branch: packages["git"][name]["current"].append(branch) crates_dir = path.join(cargo_dir, "registry") crates_cache_dir = "" crates_src_dir = "" if os.path.isdir(path.join(crates_dir, "cache")): for p in os.listdir(path.join(crates_dir, "cache")): crates_cache_dir = path.join(crates_dir, "cache", p) crates_src_dir = path.join(crates_dir, "src", p) git_dir = path.join(cargo_dir, "git") git_db_dir = path.join(git_dir, "db") git_checkout_dir = path.join(git_dir, "checkouts") git_db_list = filter(lambda f: not f.startswith('.'), os.listdir(git_db_dir)) git_checkout_list = os.listdir(git_checkout_dir) for d in list(set(git_db_list + git_checkout_list)): crate_name = d.replace("-{}".format(d.split("-")[-1]), "") if not packages["git"].get(crate_name, False): packages["git"][crate_name] = { "current": [], "exist": [], } if os.path.isdir(path.join(git_checkout_dir, d)): with cd(path.join(git_checkout_dir, d)): git_crate_hash = glob.glob('*') if not git_crate_hash or not os.path.isdir(path.join(git_db_dir, d)): packages["git"][crate_name]["exist"].append(("del", d, "")) continue for d2 in git_crate_hash: dep_path = path.join(git_checkout_dir, d, d2) if os.path.isdir(dep_path): packages["git"][crate_name]["exist"].append((path.getmtime(dep_path), d, d2)) elif os.path.isdir(path.join(git_db_dir, d)): packages["git"][crate_name]["exist"].append(("del", d, "")) for d in os.listdir(crates_src_dir): crate_name = re.sub(r"\-\d+(\.\d+){1,3}.+", "", d) if not packages["crates"].get(crate_name, False): packages["crates"][crate_name] = { "current": [], "exist": [], } packages["crates"][crate_name]["exist"].append(d) total_size = 0 for packages_type in ["git", "crates"]: sorted_packages = sorted(packages[packages_type]) for crate_name in sorted_packages: crate_count = 0 existed_crates = packages[packages_type][crate_name]["exist"] for exist in sorted(existed_crates, reverse=True): current_crate = packages[packages_type][crate_name]["current"] size = 0 exist_name = path.join(exist[1], exist[2]) if packages_type == "git" else exist exist_item = exist[2] if packages_type == "git" else exist if exist_item not in current_crate: crate_count += 1 if int(crate_count) >= int(keep) or not current_crate or \ exist[0] == "del" or exist[2] == "master": removing_anything = True crate_paths = [] if packages_type == "git": exist_checkout_path = path.join(git_checkout_dir, exist[1]) exist_db_path = path.join(git_db_dir, exist[1]) exist_path = path.join(git_checkout_dir, exist_name) if exist[0] == "del": if os.path.isdir(exist_checkout_path): crate_paths.append(exist_checkout_path) if os.path.isdir(exist_db_path): crate_paths.append(exist_db_path) crate_count += -1 else: crate_paths.append(exist_path) exist_checkout_list = glob.glob(path.join(exist_checkout_path, '*')) if len(exist_checkout_list) <= 1: crate_paths.append(exist_checkout_path) if os.path.isdir(exist_db_path): crate_paths.append(exist_db_path) else: crate_paths.append(path.join(crates_cache_dir, "{}.crate".format(exist))) crate_paths.append(path.join(crates_src_dir, exist)) size = sum(get_size(p) for p in crate_paths) if show_size else 0 total_size += size print_msg = (exist_name, " ({}MB)".format(round(size, 2)) if show_size else "", cargo_dir) if force: print("Removing `{}`{} package from {}".format(*print_msg)) for crate_path in crate_paths: if os.path.exists(crate_path): delete(crate_path) else: print("Would remove `{}`{} package from {}".format(*print_msg)) if removing_anything and show_size: print("\nTotal size of {} MB".format(round(total_size, 2))) if not removing_anything: print("Nothing to remove.") elif not force: print("\nNothing done. " "Run `./mach clean-cargo-cache -f` to actually remove.")
def clean_cargo_cache(self, force=False, show_size=False, keep=None): def get_size(path): if os.path.isfile(path): return os.path.getsize(path) / (1024 * 1024.0) total_size = 0 for dirpath, dirnames, filenames in os.walk(path): for f in filenames: fp = os.path.join(dirpath, f) total_size += os.path.getsize(fp) return total_size / (1024 * 1024.0) removing_anything = False packages = { 'crates': {}, 'git': {}, } import toml if os.environ.get("CARGO_HOME", ""): cargo_dir = os.environ.get("CARGO_HOME") else: home_dir = os.path.expanduser("~") cargo_dir = path.join(home_dir, ".cargo") if not os.path.isdir(cargo_dir): return cargo_file = open(path.join(self.context.topdir, "Cargo.lock")) content = toml.load(cargo_file) for package in content.get("package", []): source = package.get("source", "") version = package["version"] if source == u"registry+https://github.com/rust-lang/crates.io-index": crate_name = "{}-{}".format(package["name"], version) if not packages["crates"].get(crate_name, False): packages["crates"][package["name"]] = { "current": [], "exist": [], } packages["crates"][package["name"]]["current"].append( crate_name) elif source.startswith("git+"): name = source.split("#")[0].split("/")[-1].replace(".git", "") branch = "" crate_name = "{}-{}".format(package["name"], source.split("#")[1]) crate_branch = name.split("?") if len(crate_branch) > 1: branch = crate_branch[1].replace("branch=", "") name = crate_branch[0] if not packages["git"].get(name, False): packages["git"][name] = { "current": [], "exist": [], } packages["git"][name]["current"].append( source.split("#")[1][:7]) if branch: packages["git"][name]["current"].append(branch) crates_dir = path.join(cargo_dir, "registry") crates_cache_dir = "" crates_src_dir = "" if os.path.isdir(path.join(crates_dir, "cache")): for p in os.listdir(path.join(crates_dir, "cache")): crates_cache_dir = path.join(crates_dir, "cache", p) crates_src_dir = path.join(crates_dir, "src", p) git_dir = path.join(cargo_dir, "git") git_db_dir = path.join(git_dir, "db") git_checkout_dir = path.join(git_dir, "checkouts") if os.path.isdir(git_db_dir): git_db_list = filter(lambda f: not f.startswith('.'), os.listdir(git_db_dir)) else: git_db_list = [] if os.path.isdir(git_checkout_dir): git_checkout_list = os.listdir(git_checkout_dir) else: git_checkout_list = [] for d in list(set(git_db_list + git_checkout_list)): crate_name = d.replace("-{}".format(d.split("-")[-1]), "") if not packages["git"].get(crate_name, False): packages["git"][crate_name] = { "current": [], "exist": [], } if os.path.isdir(path.join(git_checkout_dir, d)): with cd(path.join(git_checkout_dir, d)): git_crate_hash = glob.glob('*') if not git_crate_hash or not os.path.isdir( path.join(git_db_dir, d)): packages["git"][crate_name]["exist"].append(("del", d, "")) continue for d2 in git_crate_hash: dep_path = path.join(git_checkout_dir, d, d2) if os.path.isdir(dep_path): packages["git"][crate_name]["exist"].append( (path.getmtime(dep_path), d, d2)) elif os.path.isdir(path.join(git_db_dir, d)): packages["git"][crate_name]["exist"].append(("del", d, "")) for d in os.listdir(crates_src_dir): crate_name = re.sub(r"\-\d+(\.\d+){1,3}.+", "", d) if not packages["crates"].get(crate_name, False): packages["crates"][crate_name] = { "current": [], "exist": [], } packages["crates"][crate_name]["exist"].append(d) total_size = 0 for packages_type in ["git", "crates"]: sorted_packages = sorted(packages[packages_type]) for crate_name in sorted_packages: crate_count = 0 existed_crates = packages[packages_type][crate_name]["exist"] for exist in sorted(existed_crates, reverse=True): current_crate = packages[packages_type][crate_name][ "current"] size = 0 exist_name = path.join( exist[1], exist[2]) if packages_type == "git" else exist exist_item = exist[2] if packages_type == "git" else exist if exist_item not in current_crate: crate_count += 1 if int(crate_count) >= int(keep) or not current_crate or \ exist[0] == "del" or exist[2] == "master": removing_anything = True crate_paths = [] if packages_type == "git": exist_checkout_path = path.join( git_checkout_dir, exist[1]) exist_db_path = path.join(git_db_dir, exist[1]) exist_path = path.join(git_checkout_dir, exist_name) if exist[0] == "del": if os.path.isdir(exist_checkout_path): crate_paths.append(exist_checkout_path) if os.path.isdir(exist_db_path): crate_paths.append(exist_db_path) crate_count += -1 else: crate_paths.append(exist_path) exist_checkout_list = glob.glob( path.join(exist_checkout_path, '*')) if len(exist_checkout_list) <= 1: crate_paths.append(exist_checkout_path) if os.path.isdir(exist_db_path): crate_paths.append(exist_db_path) else: crate_paths.append( path.join(crates_cache_dir, "{}.crate".format(exist))) crate_paths.append( path.join(crates_src_dir, exist)) size = sum( get_size(p) for p in crate_paths) if show_size else 0 total_size += size print_msg = (exist_name, " ({}MB)".format( round(size, 2)) if show_size else "", cargo_dir) if force: print("Removing `{}`{} package from {}".format( *print_msg)) for crate_path in crate_paths: if os.path.exists(crate_path): try: delete(crate_path) except: print(traceback.format_exc()) print("Delete %s failed!" % crate_path) else: print("Would remove `{}`{} package from {}". format(*print_msg)) if removing_anything and show_size: print("\nTotal size of {} MB".format(round(total_size, 2))) if not removing_anything: print("Nothing to remove.") elif not force: print("\nNothing done. " "Run `./mach clean-cargo-cache -f` to actually remove.")
def package(self, release=False, dev=False, android=None, debug=False, debugger=None, target=None): env = self.build_env() if android is None: android = self.config["build"]["android"] if target and android: print("Please specify either --target or --android.") sys.exit(1) if not android: android = self.handle_android_target(target) binary_path = self.get_binary_path(release, dev, android=android) dir_to_root = self.get_top_dir() target_dir = path.dirname(binary_path) if android: android_target = self.config["android"]["target"] if "aarch64" in android_target: build_type = "Arm64" elif "armv7" in android_target: build_type = "Armv7" else: build_type = "Arm" if dev: build_mode = "Debug" else: build_mode = "Release" task_name = "assemble" + build_type + build_mode try: with cd(path.join("support", "android", "apk")): subprocess.check_call(["./gradlew", "--no-daemon", task_name], env=env) except subprocess.CalledProcessError as e: print("Packaging Android exited with return value %d" % e.returncode) return e.returncode elif is_macosx(): print("Creating Servo.app") dir_to_dmg = path.join(target_dir, 'dmg') dir_to_app = path.join(dir_to_dmg, 'Servo.app') dir_to_resources = path.join(dir_to_app, 'Contents', 'Resources') if path.exists(dir_to_dmg): print("Cleaning up from previous packaging") delete(dir_to_dmg) browserhtml_path = get_browserhtml_path(binary_path) print("Copying files") shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copytree(browserhtml_path, path.join(dir_to_resources, 'browserhtml')) shutil.copy2(path.join(dir_to_root, 'Info.plist'), path.join(dir_to_app, 'Contents', 'Info.plist')) content_dir = path.join(dir_to_app, 'Contents', 'MacOS') os.makedirs(content_dir) shutil.copy2(binary_path, content_dir) change_prefs(dir_to_resources, "macosx") print("Finding dylibs and relinking") copy_dependencies(path.join(content_dir, 'servo'), content_dir) print("Adding version to Credits.rtf") version_command = [binary_path, '--version'] p = subprocess.Popen(version_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) version, stderr = p.communicate() if p.returncode != 0: raise Exception("Error occurred when getting Servo version: " + stderr) version = "Nightly version: " + version import mako.template template_path = path.join(dir_to_resources, 'Credits.rtf.mako') credits_path = path.join(dir_to_resources, 'Credits.rtf') with open(template_path) as template_file: template = mako.template.Template(template_file.read()) with open(credits_path, "w") as credits_file: credits_file.write(template.render(version=version)) delete(template_path) print("Writing run-servo") bhtml_path = path.join('${0%/*}', '..', 'Resources', 'browserhtml', 'index.html') runservo = os.open( path.join(content_dir, 'run-servo'), os.O_WRONLY | os.O_CREAT, int("0755", 8) ) os.write(runservo, '#!/bin/bash\nexec ${0%/*}/servo ' + bhtml_path) os.close(runservo) print("Creating dmg") os.symlink('/Applications', path.join(dir_to_dmg, 'Applications')) dmg_path = path.join(target_dir, "servo-tech-demo.dmg") if path.exists(dmg_path): print("Deleting existing dmg") os.remove(dmg_path) try: subprocess.check_call(['hdiutil', 'create', '-volname', 'Servo', '-megabytes', '900', dmg_path, '-srcfolder', dir_to_dmg]) except subprocess.CalledProcessError as e: print("Packaging MacOS dmg exited with return value %d" % e.returncode) return e.returncode print("Cleaning up") delete(dir_to_dmg) print("Packaged Servo into " + dmg_path) print("Creating brew package") dir_to_brew = path.join(target_dir, 'brew_tmp') dir_to_tar = path.join(target_dir, 'brew') if not path.exists(dir_to_tar): os.makedirs(dir_to_tar) tar_path = path.join(dir_to_tar, "servo.tar.gz") if path.exists(dir_to_brew): print("Cleaning up from previous packaging") delete(dir_to_brew) if path.exists(tar_path): print("Deleting existing package") os.remove(tar_path) shutil.copytree(path.join(dir_to_root, 'resources'), path.join(dir_to_brew, 'resources')) os.makedirs(path.join(dir_to_brew, 'bin')) shutil.copy2(binary_path, path.join(dir_to_brew, 'bin', 'servo')) # Note that in the context of Homebrew, libexec is reserved for private use by the formula # and therefore is not symlinked into HOMEBREW_PREFIX. os.makedirs(path.join(dir_to_brew, 'libexec')) copy_dependencies(path.join(dir_to_brew, 'bin', 'servo'), path.join(dir_to_brew, 'libexec')) archive_deterministically(dir_to_brew, tar_path, prepend_path='servo/') delete(dir_to_brew) print("Packaged Servo into " + tar_path) elif is_windows(): dir_to_msi = path.join(target_dir, 'msi') if path.exists(dir_to_msi): print("Cleaning up from previous packaging") delete(dir_to_msi) os.makedirs(dir_to_msi) browserhtml_path = get_browserhtml_path(binary_path) print("Copying files") dir_to_temp = path.join(dir_to_msi, 'temp') dir_to_temp_servo = path.join(dir_to_temp, 'servo') dir_to_resources = path.join(dir_to_temp_servo, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copytree(browserhtml_path, path.join(dir_to_temp_servo, 'browserhtml')) shutil.copy(binary_path, dir_to_temp_servo) shutil.copy("{}.manifest".format(binary_path), dir_to_temp_servo) copy_windows_dependencies(target_dir, dir_to_temp_servo) change_prefs(dir_to_resources, "windows") # generate Servo.wxs import mako.template template_path = path.join(dir_to_root, "support", "windows", "Servo.wxs.mako") template = mako.template.Template(open(template_path).read()) wxs_path = path.join(dir_to_msi, "Servo.wxs") open(wxs_path, "w").write(template.render( exe_path=target_dir, dir_to_temp=dir_to_temp_servo, resources_path=dir_to_resources)) # run candle and light print("Creating MSI") try: with cd(dir_to_msi): subprocess.check_call(['candle', wxs_path]) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path]) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode print("Packaged Servo into " + path.join(dir_to_msi, "Servo.msi")) print("Creating ZIP") shutil.make_archive(path.join(dir_to_msi, "Servo"), "zip", dir_to_temp) print("Packaged Servo into " + path.join(dir_to_msi, "Servo.zip")) print("Cleaning up") delete(dir_to_temp) else: dir_to_temp = path.join(target_dir, 'packaging-temp') browserhtml_path = get_browserhtml_path(binary_path) if path.exists(dir_to_temp): # TODO(aneeshusa): lock dir_to_temp to prevent simultaneous builds print("Cleaning up from previous packaging") delete(dir_to_temp) print("Copying files") dir_to_resources = path.join(dir_to_temp, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copytree(browserhtml_path, path.join(dir_to_temp, 'browserhtml')) shutil.copy(binary_path, dir_to_temp) change_prefs(dir_to_resources, "linux") print("Creating tarball") tar_path = path.join(target_dir, 'servo-tech-demo.tar.gz') archive_deterministically(dir_to_temp, tar_path, prepend_path='servo/') print("Cleaning up") delete(dir_to_temp) print("Packaged Servo into " + tar_path)
def package(self, release=False, dev=False, android=None, debug=False, debugger=None, target=None, flavor=None): if android is None: android = self.config["build"]["android"] if target and android: print("Please specify either --target or --android.") sys.exit(1) if not android: android = self.handle_android_target(target) else: target = self.config["android"]["target"] env = self.build_env(target=target) binary_path = self.get_binary_path(release, dev, android=android) dir_to_root = self.get_top_dir() target_dir = path.dirname(binary_path) if android: android_target = self.config["android"]["target"] if "aarch64" in android_target: build_type = "Arm64" elif "armv7" in android_target: build_type = "Armv7" elif "i686" in android_target: build_type = "x86" else: build_type = "Arm" if dev: build_mode = "Debug" else: build_mode = "Release" flavor_name = "Main" if flavor is not None: flavor_name = flavor.title() variant = ":assemble" + flavor_name + build_type + build_mode apk_task_name = ":servoapp" + variant aar_task_name = ":servoview" + variant try: with cd(path.join("support", "android", "apk")): subprocess.check_call([ "./gradlew", "--no-daemon", apk_task_name, aar_task_name ], env=env) except subprocess.CalledProcessError as e: print("Packaging Android exited with return value %d" % e.returncode) return e.returncode elif is_macosx(): print("Creating Servo.app") dir_to_dmg = path.join(target_dir, 'dmg') dir_to_app = path.join(dir_to_dmg, 'Servo.app') dir_to_resources = path.join(dir_to_app, 'Contents', 'Resources') if path.exists(dir_to_dmg): print("Cleaning up from previous packaging") delete(dir_to_dmg) print("Copying files") shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy2(path.join(dir_to_root, 'Info.plist'), path.join(dir_to_app, 'Contents', 'Info.plist')) content_dir = path.join(dir_to_app, 'Contents', 'MacOS') os.makedirs(content_dir) shutil.copy2(binary_path, content_dir) change_prefs(dir_to_resources, "macosx") print("Finding dylibs and relinking") copy_dependencies(path.join(content_dir, 'servo'), content_dir) print("Adding version to Credits.rtf") version_command = [binary_path, '--version'] p = subprocess.Popen(version_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) version, stderr = p.communicate() if p.returncode != 0: raise Exception("Error occurred when getting Servo version: " + stderr) version = "Nightly version: " + version import mako.template template_path = path.join(dir_to_resources, 'Credits.rtf.mako') credits_path = path.join(dir_to_resources, 'Credits.rtf') with open(template_path) as template_file: template = mako.template.Template(template_file.read()) with open(credits_path, "w") as credits_file: credits_file.write(template.render(version=version)) delete(template_path) print("Creating dmg") os.symlink('/Applications', path.join(dir_to_dmg, 'Applications')) dmg_path = path.join(target_dir, "servo-tech-demo.dmg") if path.exists(dmg_path): print("Deleting existing dmg") os.remove(dmg_path) try: subprocess.check_call([ 'hdiutil', 'create', '-volname', 'Servo', '-megabytes', '900', dmg_path, '-srcfolder', dir_to_dmg ]) except subprocess.CalledProcessError as e: print("Packaging MacOS dmg exited with return value %d" % e.returncode) return e.returncode print("Cleaning up") delete(dir_to_dmg) print("Packaged Servo into " + dmg_path) print("Creating brew package") dir_to_brew = path.join(target_dir, 'brew_tmp') dir_to_tar = path.join(target_dir, 'brew') if not path.exists(dir_to_tar): os.makedirs(dir_to_tar) tar_path = path.join(dir_to_tar, "servo.tar.gz") if path.exists(dir_to_brew): print("Cleaning up from previous packaging") delete(dir_to_brew) if path.exists(tar_path): print("Deleting existing package") os.remove(tar_path) shutil.copytree(path.join(dir_to_root, 'resources'), path.join(dir_to_brew, 'resources')) os.makedirs(path.join(dir_to_brew, 'bin')) shutil.copy2(binary_path, path.join(dir_to_brew, 'bin', 'servo')) # Note that in the context of Homebrew, libexec is reserved for private use by the formula # and therefore is not symlinked into HOMEBREW_PREFIX. os.makedirs(path.join(dir_to_brew, 'libexec')) copy_dependencies(path.join(dir_to_brew, 'bin', 'servo'), path.join(dir_to_brew, 'libexec')) archive_deterministically(dir_to_brew, tar_path, prepend_path='servo/') delete(dir_to_brew) print("Packaged Servo into " + tar_path) elif is_windows(): dir_to_msi = path.join(target_dir, 'msi') if path.exists(dir_to_msi): print("Cleaning up from previous packaging") delete(dir_to_msi) os.makedirs(dir_to_msi) print("Copying files") dir_to_temp = path.join(dir_to_msi, 'temp') dir_to_temp_servo = path.join(dir_to_temp, 'servo') dir_to_resources = path.join(dir_to_temp_servo, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy(binary_path, dir_to_temp_servo) copy_windows_dependencies(target_dir, dir_to_temp_servo) change_prefs(dir_to_resources, "windows") # generate Servo.wxs import mako.template template_path = path.join(dir_to_root, "support", "windows", "Servo.wxs.mako") template = mako.template.Template(open(template_path).read()) wxs_path = path.join(dir_to_msi, "Installer.wxs") open(wxs_path, "w").write( template.render(exe_path=target_dir, dir_to_temp=dir_to_temp_servo, resources_path=dir_to_resources)) # run candle and light print("Creating MSI") try: with cd(dir_to_msi): subprocess.check_call(['candle', wxs_path]) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path]) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode print("Packaged Servo into " + path.join(dir_to_msi, "Installer.msi")) # Download GStreamer installer. Only once. dir_to_gst_deps = path.join(dir_to_msi, 'Gstreamer.msi') gstreamer_msi_path = path.join(target_dir, 'Gstreamer.msi') if not os.path.exists(gstreamer_msi_path): print('Fetching GStreamer installer. This may take a while...') gstreamer_url = 'https://gstreamer.freedesktop.org/data/pkg/windows/1.14.2/gstreamer-1.0-x86-1.14.2.msi' urllib.urlretrieve(gstreamer_url, gstreamer_msi_path) shutil.copy(gstreamer_msi_path, dir_to_gst_deps) # Generate bundle with GStreamer and Servo installers. print("Creating bundle") shutil.copy( path.join(dir_to_root, 'support', 'windows', 'Servo.wxs'), dir_to_msi) bundle_wxs_path = path.join(dir_to_msi, 'Servo.wxs') try: with cd(dir_to_msi): subprocess.check_call( ['candle', bundle_wxs_path, '-ext', 'WixBalExtension']) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format( path.splitext(bundle_wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call( ['light', wxsobj_path, '-ext', 'WixBalExtension']) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode print("Packaged Servo into " + path.join(dir_to_msi, "Servo.msi")) print("Creating ZIP") shutil.make_archive(path.join(dir_to_msi, "Servo"), "zip", dir_to_temp) print("Packaged Servo into " + path.join(dir_to_msi, "Servo.zip")) print("Cleaning up") delete(dir_to_temp) else: dir_to_temp = path.join(target_dir, 'packaging-temp') if path.exists(dir_to_temp): # TODO(aneeshusa): lock dir_to_temp to prevent simultaneous builds print("Cleaning up from previous packaging") delete(dir_to_temp) print("Copying files") dir_to_resources = path.join(dir_to_temp, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy(binary_path, dir_to_temp) change_prefs(dir_to_resources, "linux") print("Creating tarball") tar_path = path.join(target_dir, 'servo-tech-demo.tar.gz') archive_deterministically(dir_to_temp, tar_path, prepend_path='servo/') print("Cleaning up") delete(dir_to_temp) print("Packaged Servo into " + tar_path)
def package(self, release=False, dev=False, android=None, magicleap=None, debug=False, debugger=None, target=None, flavor=None, maven=False): if android is None: android = self.config["build"]["android"] if target and android: print("Please specify either --target or --android.") sys.exit(1) if not android: android = self.handle_android_target(target) else: target = self.config["android"]["target"] env = self.build_env(target=target) binary_path = self.get_binary_path(release, dev, android=android, magicleap=magicleap) dir_to_root = self.get_top_dir() target_dir = path.dirname(binary_path) if magicleap: if platform.system() not in ["Darwin"]: raise Exception("Magic Leap builds are only supported on macOS.") if not env.get("MAGICLEAP_SDK"): raise Exception("Magic Leap builds need the MAGICLEAP_SDK environment variable") if not env.get("MLCERT"): raise Exception("Magic Leap builds need the MLCERT environment variable") mabu = path.join(env.get("MAGICLEAP_SDK"), "mabu") package = "./support/magicleap/Servo2D/Servo2D.package" if dev: build_type = "lumin_debug" else: build_type = "lumin_release" argv = [ mabu, "-o", target_dir, "-t", build_type, # Servo SEGVs if we don't set the debuggable flag in the mpk's taildata # https://github.com/servo/servo/issues/22188 "--add-tail-data-args=--debuggable", package ] try: subprocess.check_call(argv, env=env) except subprocess.CalledProcessError as e: print("Packaging Magic Leap exited with return value %d" % e.returncode) return e.returncode elif android: android_target = self.config["android"]["target"] if "aarch64" in android_target: build_type = "Arm64" elif "armv7" in android_target: build_type = "Armv7" elif "i686" in android_target: build_type = "x86" else: build_type = "Arm" if dev: build_mode = "Debug" else: build_mode = "Release" flavor_name = "Main" if flavor is not None: flavor_name = flavor.title() vr = flavor == "googlevr" or flavor == "oculusvr" dir_to_resources = path.join(self.get_top_dir(), 'target', 'android', 'resources') if path.exists(dir_to_resources): delete(dir_to_resources) shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) change_prefs(dir_to_resources, "android", vr=vr) variant = ":assemble" + flavor_name + build_type + build_mode apk_task_name = ":servoapp" + variant aar_task_name = ":servoview" + variant maven_task_name = ":servoview:uploadArchive" argv = ["./gradlew", "--no-daemon", apk_task_name, aar_task_name] if maven: argv.append(maven_task_name) try: with cd(path.join("support", "android", "apk")): subprocess.check_call(argv, env=env) except subprocess.CalledProcessError as e: print("Packaging Android exited with return value %d" % e.returncode) return e.returncode elif is_macosx(): print("Creating Servo.app") dir_to_dmg = path.join(target_dir, 'dmg') dir_to_app = path.join(dir_to_dmg, 'Servo.app') dir_to_resources = path.join(dir_to_app, 'Contents', 'Resources') if path.exists(dir_to_dmg): print("Cleaning up from previous packaging") delete(dir_to_dmg) print("Copying files") shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy2(path.join(dir_to_root, 'Info.plist'), path.join(dir_to_app, 'Contents', 'Info.plist')) content_dir = path.join(dir_to_app, 'Contents', 'MacOS') os.makedirs(content_dir) shutil.copy2(binary_path, content_dir) change_prefs(dir_to_resources, "macosx") print("Finding dylibs and relinking") copy_dependencies(path.join(content_dir, 'servo'), content_dir) print("Adding version to Credits.rtf") version_command = [binary_path, '--version'] p = subprocess.Popen(version_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) version, stderr = p.communicate() if p.returncode != 0: raise Exception("Error occurred when getting Servo version: " + stderr) version = "Nightly version: " + version import mako.template template_path = path.join(dir_to_resources, 'Credits.rtf.mako') credits_path = path.join(dir_to_resources, 'Credits.rtf') with open(template_path) as template_file: template = mako.template.Template(template_file.read()) with open(credits_path, "w") as credits_file: credits_file.write(template.render(version=version)) delete(template_path) print("Creating dmg") os.symlink('/Applications', path.join(dir_to_dmg, 'Applications')) dmg_path = path.join(target_dir, "servo-tech-demo.dmg") if path.exists(dmg_path): print("Deleting existing dmg") os.remove(dmg_path) try: subprocess.check_call(['hdiutil', 'create', '-volname', 'Servo', '-megabytes', '900', dmg_path, '-srcfolder', dir_to_dmg]) except subprocess.CalledProcessError as e: print("Packaging MacOS dmg exited with return value %d" % e.returncode) return e.returncode print("Cleaning up") delete(dir_to_dmg) print("Packaged Servo into " + dmg_path) print("Creating brew package") dir_to_brew = path.join(target_dir, 'brew_tmp') dir_to_tar = path.join(target_dir, 'brew') if not path.exists(dir_to_tar): os.makedirs(dir_to_tar) tar_path = path.join(dir_to_tar, "servo.tar.gz") if path.exists(dir_to_brew): print("Cleaning up from previous packaging") delete(dir_to_brew) if path.exists(tar_path): print("Deleting existing package") os.remove(tar_path) shutil.copytree(path.join(dir_to_root, 'resources'), path.join(dir_to_brew, 'resources')) os.makedirs(path.join(dir_to_brew, 'bin')) shutil.copy2(binary_path, path.join(dir_to_brew, 'bin', 'servo')) # Note that in the context of Homebrew, libexec is reserved for private use by the formula # and therefore is not symlinked into HOMEBREW_PREFIX. os.makedirs(path.join(dir_to_brew, 'libexec')) copy_dependencies(path.join(dir_to_brew, 'bin', 'servo'), path.join(dir_to_brew, 'libexec')) archive_deterministically(dir_to_brew, tar_path, prepend_path='servo/') delete(dir_to_brew) print("Packaged Servo into " + tar_path) elif is_windows(): dir_to_msi = path.join(target_dir, 'msi') if path.exists(dir_to_msi): print("Cleaning up from previous packaging") delete(dir_to_msi) os.makedirs(dir_to_msi) print("Copying files") dir_to_temp = path.join(dir_to_msi, 'temp') dir_to_temp_servo = path.join(dir_to_temp, 'servo') dir_to_resources = path.join(dir_to_temp_servo, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy(binary_path, dir_to_temp_servo) copy_windows_dependencies(target_dir, dir_to_temp_servo) change_prefs(dir_to_resources, "windows") # generate Servo.wxs import mako.template template_path = path.join(dir_to_root, "support", "windows", "Servo.wxs.mako") template = mako.template.Template(open(template_path).read()) wxs_path = path.join(dir_to_msi, "Installer.wxs") open(wxs_path, "w").write(template.render( exe_path=target_dir, dir_to_temp=dir_to_temp_servo, resources_path=dir_to_resources)) # run candle and light print("Creating MSI") try: with cd(dir_to_msi): subprocess.check_call(['candle', wxs_path]) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path]) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode dir_to_installer = path.join(dir_to_msi, "Installer.msi") print("Packaged Servo into " + dir_to_installer) # Download GStreamer installer. Only once. gstreamer_msi_path = path.join(dir_to_msi, 'Gstreamer.msi') if not os.path.exists(gstreamer_msi_path): print('Fetching GStreamer installer. This may take a while...') gstreamer_url = 'https://gstreamer.freedesktop.org/data/pkg/windows/1.14.2/gstreamer-1.0-x86-1.14.2.msi' urllib.urlretrieve(gstreamer_url, gstreamer_msi_path) # Generate bundle with GStreamer and Servo installers. print("Creating bundle") shutil.copy(path.join(dir_to_root, 'support', 'windows', 'Servo.wxs'), dir_to_msi) bundle_wxs_path = path.join(dir_to_msi, 'Servo.wxs') try: with cd(dir_to_msi): subprocess.check_call(['candle', bundle_wxs_path, '-ext', 'WixBalExtension']) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(bundle_wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path, '-ext', 'WixBalExtension']) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode print("Packaged Servo into " + path.join(dir_to_msi, "Servo.msi")) print("Creating ZIP") shutil.make_archive(path.join(dir_to_msi, "Servo"), "zip", dir_to_temp) print("Packaged Servo into " + path.join(dir_to_msi, "Servo.zip")) print("Cleaning up") delete(dir_to_temp) delete(dir_to_installer) else: dir_to_temp = path.join(target_dir, 'packaging-temp') if path.exists(dir_to_temp): # TODO(aneeshusa): lock dir_to_temp to prevent simultaneous builds print("Cleaning up from previous packaging") delete(dir_to_temp) print("Copying files") dir_to_resources = path.join(dir_to_temp, 'resources') shutil.copytree(path.join(dir_to_root, 'resources'), dir_to_resources) shutil.copy(binary_path, dir_to_temp) change_prefs(dir_to_resources, "linux") print("Creating tarball") tar_path = path.join(target_dir, 'servo-tech-demo.tar.gz') archive_deterministically(dir_to_temp, tar_path, prepend_path='servo/') print("Cleaning up") delete(dir_to_temp) print("Packaged Servo into " + tar_path)
def package(self, release=False, dev=False, android=None, debug=False, debugger=None, target=None): env = self.build_env() if android is None: android = self.config["build"]["android"] if target and android: print("Please specify either --target or --android.") sys.exit(1) if not android: android = self.handle_android_target(target) binary_path = self.get_binary_path(release, dev, android=android) dir_to_root = self.get_top_dir() target_dir = path.dirname(binary_path) if android: android_target = self.config["android"]["target"] if "aarch64" in android_target: build_type = "Arm64" elif "armv7" in android_target: build_type = "Armv7" else: build_type = "Arm" if dev: build_mode = "Debug" else: build_mode = "Release" task_name = "assemble" + build_type + build_mode try: with cd(path.join("support", "android", "apk")): subprocess.check_call(["./gradlew", "--no-daemon", task_name], env=env) except subprocess.CalledProcessError as e: print("Packaging Android exited with return value %d" % e.returncode) return e.returncode elif is_macosx(): print("Creating ServoShell.app") dir_to_dmg = path.join(target_dir, 'dmg') dir_to_app = path.join(dir_to_dmg, 'ServoShell.app') dir_to_resources = path.join(dir_to_app, 'Contents', 'Resources') if path.exists(dir_to_dmg): print("Cleaning up from previous packaging") delete(dir_to_dmg) mmtabbar_path = path.join(self.get_target_dir(), 'MMTabBarView', 'Release', 'MMTabBarView.framework') if path.exists(mmtabbar_path): dir_to_framework = path.join(dir_to_app, 'Contents', 'Frameworks', 'MMTabBarView.framework') shutil.copytree(mmtabbar_path, dir_to_framework) nibs_path = path.join(self.get_target_dir(), 'nibs') shutil.copytree(nibs_path, dir_to_resources + '/nibs') print("Copying files") shutil.copytree(path.join(dir_to_root, 'servo_resources'), path.join(dir_to_resources, 'servo_resources')) shutil.copytree(path.join(dir_to_root, 'shell_resources'), path.join(dir_to_resources, 'shell_resources')) content_dir = path.join(dir_to_app, 'Contents', 'MacOS') os.makedirs(content_dir) shutil.copy2(binary_path, content_dir) print("Finding dylibs and relinking") copy_dependencies(path.join(content_dir, 'servoshell'), content_dir) print("Adding version to Credits.rtf") version_command = [binary_path, '--version'] p = subprocess.Popen(version_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) version, stderr = p.communicate() if p.returncode != 0: raise Exception("Error occurred when getting ServoShell version: " + stderr) import mako.template template_path = path.join(dir_to_root, "support", "macos", "Credits.rtf.mako") credits_path = path.join(dir_to_resources, 'Credits.rtf') with open(template_path) as template_file: template = mako.template.Template(template_file.read()) with open(credits_path, "w") as credits_file: credits_file.write(template.render(version=version)) template_path = path.join(dir_to_root, "support", "macos", "Info.plist.mako") plist_path = path.join(dir_to_app, 'Contents', 'Info.plist') with open(template_path) as template_file: template = mako.template.Template(template_file.read()) with open(plist_path, "w") as plist_file: plist_file.write(template.render(version=version)) print("Creating dmg") os.symlink('/Applications', path.join(dir_to_dmg, 'Applications')) dmg_path = path.join(target_dir, "servoshell.dmg") if path.exists(dmg_path): print("Deleting existing dmg") os.remove(dmg_path) try: subprocess.check_call(['hdiutil', 'create', '-volname', 'Servo', '-megabytes', '900', dmg_path, '-srcfolder', dir_to_dmg]) except subprocess.CalledProcessError as e: print("Packaging MacOS dmg exited with return value %d" % e.returncode) return e.returncode print("Cleaning up") delete(dir_to_dmg) print("Packaged Servo into " + dmg_path) elif is_windows(): dir_to_msi = path.join(target_dir, 'msi') if path.exists(dir_to_msi): print("Cleaning up from previous packaging") delete(dir_to_msi) os.makedirs(dir_to_msi) print("Copying files") dir_to_temp = path.join(dir_to_msi, 'temp') dir_to_temp_servo = path.join(dir_to_temp, 'servoshell') dir_to_resources = path.join(dir_to_temp_servo, 'resources') shutil.copytree(path.join(dir_to_root, 'shell_resources'), path.join(dir_to_resources, 'shell_resources')) shutil.copytree(path.join(dir_to_root, 'servo_resources'), path.join(dir_to_resources, 'servo_resources')) shutil.copy(binary_path, dir_to_temp_servo) shutil.copy("{}.manifest".format(binary_path), dir_to_temp_servo) copy_windows_dependencies(target_dir, dir_to_temp_servo) # generate Servo.wxs import mako.template template_path = path.join(dir_to_root, "support", "windows", "ServoShell.wxs.mako") template = mako.template.Template(open(template_path).read()) wxs_path = path.join(dir_to_msi, "ServoShell.wxs") open(wxs_path, "w").write(template.render( exe_path=target_dir, dir_to_temp=dir_to_temp_servo, resources_path=dir_to_resources)) # run candle and light print("Creating MSI: " + wxs_path) try: with cd(dir_to_msi): subprocess.check_call(['candle', wxs_path]) except subprocess.CalledProcessError as e: print("WiX candle exited with return value %d" % e.returncode) return e.returncode try: wxsobj_path = "{}.wixobj".format(path.splitext(wxs_path)[0]) with cd(dir_to_msi): subprocess.check_call(['light', wxsobj_path]) except subprocess.CalledProcessError as e: print("WiX light exited with return value %d" % e.returncode) return e.returncode print("Packaged ServoShell into " + path.join(dir_to_msi, "ServoShell.msi")) print("Creating ZIP") shutil.make_archive(path.join(dir_to_msi, "ServoShell"), "zip", dir_to_temp) print("Packaged ServoShell into " + path.join(dir_to_msi, "ServoShell.zip")) print("Cleaning up") delete(dir_to_temp) else: dir_to_temp = path.join(target_dir, 'packaging-temp') if path.exists(dir_to_temp): # TODO(aneeshusa): lock dir_to_temp to prevent simultaneous builds print("Cleaning up from previous packaging") delete(dir_to_temp) print("Copying files") dir_to_resources = path.join(dir_to_temp, 'resources') shutil.copytree(path.join(dir_to_root, 'shell_resources'), path.join(dir_to_resources, 'shell_resources')) shutil.copytree(path.join(dir_to_root, 'servo_resources'), path.join(dir_to_resources, 'servo_resources')) shutil.copy(binary_path, dir_to_temp) print("Creating tarball") tar_path = path.join(target_dir, 'servoshell.tar.gz') archive_deterministically(dir_to_temp, tar_path, prepend_path='servoshell/') print("Cleaning up") delete(dir_to_temp) print("Packaged ServoShell into " + tar_path)