summaryrefslogtreecommitdiffstats
path: root/js/src/make-source-package.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/make-source-package.py
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/make-source-package.py')
-rwxr-xr-xjs/src/make-source-package.py480
1 files changed, 480 insertions, 0 deletions
diff --git a/js/src/make-source-package.py b/js/src/make-source-package.py
new file mode 100755
index 0000000000..5a42ff1602
--- /dev/null
+++ b/js/src/make-source-package.py
@@ -0,0 +1,480 @@
+#!/usr/bin/env -S python3 -B
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import argparse
+import enum
+import logging
+import os
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO)
+
+
+def find_command(names):
+ """Search for command in `names`, and returns the first one that exists."""
+
+ for name in names:
+ path = shutil.which(name)
+ if path is not None:
+ return name
+
+ return None
+
+
+def assert_command(env_var, name):
+ """Assert that the command is not empty
+ The command name comes from either environment variable or find_command.
+ """
+ if not name:
+ logging.error("{} command not found".format(env_var))
+ sys.exit(1)
+
+
+def parse_version(topsrc_dir):
+ """Parse milestone.txt and return the entire milestone and major version."""
+ milestone_file = topsrc_dir / "config" / "milestone.txt"
+ if not milestone_file.is_file():
+ return ("", "", "")
+
+ with milestone_file.open("r") as f:
+ for line in f:
+ line = line.strip()
+ if not line:
+ continue
+ if line.startswith("#"):
+ continue
+
+ v = line.split(".")
+ return tuple((v + ["", ""])[:3])
+
+ return ("", "", "")
+
+
+tmp_dir = Path("/tmp")
+
+tar = os.environ.get("TAR", find_command(["tar"]))
+assert_command("TAR", tar)
+
+rsync = os.environ.get("RSYNC", find_command(["rsync"]))
+assert_command("RSYNC", rsync)
+
+m4 = os.environ.get("M4", find_command(["m4"]))
+assert_command("M4", m4)
+
+awk = os.environ.get("AWK", find_command(["awk"]))
+assert_command("AWK", awk)
+
+src_dir = Path(os.environ.get("SRC_DIR", Path(__file__).parent.absolute()))
+mozjs_name = os.environ.get("MOZJS_NAME", "mozjs")
+staging_dir = Path(os.environ.get("STAGING", tmp_dir / "mozjs-src-pkg"))
+dist_dir = Path(os.environ.get("DIST", tmp_dir))
+topsrc_dir = src_dir.parent.parent.absolute()
+
+parsed_major_version, parsed_minor_version, parsed_patch_version = parse_version(
+ topsrc_dir
+)
+
+major_version = os.environ.get("MOZJS_MAJOR_VERSION", parsed_major_version)
+minor_version = os.environ.get("MOZJS_MINOR_VERSION", parsed_minor_version)
+patch_version = os.environ.get("MOZJS_PATCH_VERSION", parsed_patch_version)
+alpha = os.environ.get("MOZJS_ALPHA", "")
+
+version = "{}-{}.{}.{}".format(
+ mozjs_name, major_version, minor_version, patch_version or alpha or "0"
+)
+target_dir = staging_dir / version
+package_name = "{}.tar.xz".format(version)
+package_file = dist_dir / package_name
+tar_opts = ["-Jcf"]
+
+# Given there might be some external program that reads the following output,
+# use raw `print`, instead of logging.
+print("Environment:")
+print(" TAR = {}".format(tar))
+print(" RSYNC = {}".format(rsync))
+print(" M4 = {}".format(m4))
+print(" AWK = {}".format(awk))
+print(" STAGING = {}".format(staging_dir))
+print(" DIST = {}".format(dist_dir))
+print(" SRC_DIR = {}".format(src_dir))
+print(" MOZJS_NAME = {}".format(mozjs_name))
+print(" MOZJS_MAJOR_VERSION = {}".format(major_version))
+print(" MOZJS_MINOR_VERSION = {}".format(minor_version))
+print(" MOZJS_PATCH_VERSION = {}".format(patch_version))
+print(" MOZJS_ALPHA = {}".format(alpha))
+print("")
+
+rsync_filter_list = """
+# Top-level config and build files
+
++ /aclocal.m4
++ /client.mk
++ /configure.py
++ /LICENSE
++ /mach
++ /Makefile.in
++ /moz.build
++ /moz.configure
++ /test.mozbuild
++ /.babel-eslint.rc.js
++ /.eslintignore
++ /.eslintrc.js
++ /.flake8
++ /.gitignore
++ /.hgignore
++ /.lldbinit
++ /.prettierignore
++ /.prettierrc
++ /.ycm_extra_conf.py
+
+# Additional libraries (optionally) used by SpiderMonkey
+
++ /mfbt/**
++ /nsprpub/**
+
+- /intl/icu/source/data
+- /intl/icu/source/test
+- /intl/icu/source/tools
++ /intl/icu/**
+
+- /intl/components/gtest
++ /intl/components/**
+
++ /memory/replace/dmd/dmd.py
++ /memory/build/**
++ /memory/moz.build
++ /memory/mozalloc/**
+
++ /modules/fdlibm/**
++ /modules/zlib/**
+
++ /mozglue/baseprofiler/**
++ /mozglue/build/**
++ /mozglue/interposers/**
++ /mozglue/misc/**
++ /mozglue/moz.build
++ /mozglue/static/**
+
++ /tools/rb/fix_stacks.py
++ /tools/fuzzing/moz.build
++ /tools/fuzzing/interface/**
++ /tools/fuzzing/registry/**
++ /tools/fuzzing/libfuzzer/**
++ /tools/fuzzing/*.mozbuild
+
+# Build system and dependencies
+
++ /Cargo.lock
++ /build/**
++ /config/**
++ /python/**
+
++ /.cargo/config.in
+
++ /third_party/function2/**
+- /third_party/python/gyp
++ /third_party/python/**
++ /third_party/rust/**
++ /third_party/gemmology/**
++ /third_party/xsimd/**
++ /layout/tools/reftest/reftest/**
+
++ /testing/mach_commands.py
++ /testing/moz.build
++ /testing/mozbase/**
++ /testing/performance/**
++ /testing/web-platform/*.ini
++ /testing/web-platform/*.py
++ /testing/web-platform/meta/streams/**
++ /testing/web-platform/mozilla/**
++ /testing/web-platform/tests/resources/**
++ /testing/web-platform/tests/streams/**
++ /testing/web-platform/tests/tools/**
+
++ /toolkit/crashreporter/tools/symbolstore.py
++ /toolkit/mozapps/installer/package-name.mk
+
++ /xpcom/geckoprocesstypes_generator/**
+
+# SpiderMonkey itself
+
++ /js/src/**
++ /js/app.mozbuild
++ /js/*.configure
++ /js/examples/**
++ /js/public/**
+
++ */
+- /**
+"""
+
+INSTALL_CONTENT = """\
+Documentation for SpiderMonkey is available at:
+
+ https://spidermonkey.dev/
+
+In particular, it points to build documentation at
+
+ https://firefox-source-docs.mozilla.org/js/build.html
+
+Note that the libraries produced by the build system include symbols,
+causing the binaries to be extremely large. It is highly suggested that `strip`
+be run over the binaries before deploying them.
+
+Building with default options may be performed as follows:
+
+ ./mach build
+
+This will produce a debug build (much more suitable for developing against the
+SpiderMonkey JSAPI). To produce an optimized build:
+
+ export MOZCONFIG=$(pwd)/mozconfig.opt
+ ./mach build
+
+You may edit the mozconfig and mozconfig.opt files to configure your own build
+appropriately.
+"""
+
+MOZCONFIG_DEBUG_CONTENT = """\
+# Much slower when running, but adds assertions that are much better for
+# developing against the JSAPI.
+ac_add_options --enable-debug
+
+# Much faster when running, worse for debugging.
+ac_add_options --enable-optimize
+
+mk_add_options MOZ_OBJDIR=obj-debug
+"""
+
+MOZCONFIG_OPT_CONTENT = """\
+# Much faster when running, but very error-prone to develop against because
+# this will skip all the assertions critical to using the JSAPI properly.
+ac_add_options --disable-debug
+
+# Much faster when running, worse for debugging.
+ac_add_options --enable-optimize
+
+mk_add_options MOZ_OBJDIR=obj-opt
+"""
+
+README_CONTENT = """\
+This directory contains SpiderMonkey {major_version}.
+
+This release is based on a revision of Mozilla {major_version}:
+ https://hg.mozilla.org/releases/
+The changes in the patches/ directory were applied.
+
+See https://spidermonkey.dev/ for documentation, examples, and release notes.
+""".format(
+ major_version=major_version
+)
+
+
+def is_mozjs_cargo_member(line):
+ """Checks if the line in workspace.members is mozjs-related"""
+
+ return '"js/' in line
+
+
+def is_mozjs_crates_io_local_patch(line):
+ """Checks if the line in patch.crates-io is mozjs-related"""
+
+ return any(f'path = "{p}' in line for p in ("js", "build", "third_party/rust"))
+
+
+def clean():
+ """Remove temporary directory and package file."""
+ logging.info("Cleaning {} and {} ...".format(package_file, target_dir))
+ if package_file.exists():
+ package_file.unlink()
+ if target_dir.exists():
+ shutil.rmtree(str(target_dir))
+
+
+def assert_clean():
+ """Assert that target directory does not contain generated files."""
+ makefile_file = target_dir / "js" / "src" / "Makefile"
+ if makefile_file.exists():
+ logging.error("found js/src/Makefile. Please clean before packaging.")
+ sys.exit(1)
+
+
+def create_target_dir():
+ if target_dir.exists():
+ logging.warning("dist tree {} already exists!".format(target_dir))
+ else:
+ target_dir.mkdir(parents=True)
+
+
+def sync_files():
+ # Output of the command should directly go to stdout/stderr.
+ p = subprocess.Popen(
+ [
+ str(rsync),
+ "--delete-excluded",
+ "--prune-empty-dirs",
+ "--quiet",
+ "--recursive",
+ "{}/".format(topsrc_dir),
+ "{}/".format(target_dir),
+ "--filter=. -",
+ ],
+ stdin=subprocess.PIPE,
+ )
+
+ p.communicate(rsync_filter_list.encode())
+
+ if p.returncode != 0:
+ sys.exit(p.returncode)
+
+
+def copy_cargo_toml():
+ cargo_toml_file = topsrc_dir / "Cargo.toml"
+ target_cargo_toml_file = target_dir / "Cargo.toml"
+
+ with cargo_toml_file.open("r") as f:
+
+ class State(enum.Enum):
+ BEFORE_MEMBER = 1
+ INSIDE_MEMBER = 2
+ AFTER_MEMBER = 3
+ INSIDE_PATCH = 4
+ AFTER_PATCH = 5
+
+ content = ""
+ state = State.BEFORE_MEMBER
+ for line in f:
+ if state == State.BEFORE_MEMBER:
+ if line.strip() == "members = [":
+ state = State.INSIDE_MEMBER
+ elif state == State.INSIDE_MEMBER:
+ if line.strip() == "]":
+ state = State.AFTER_MEMBER
+ elif not is_mozjs_cargo_member(line):
+ continue
+ elif state == State.AFTER_MEMBER:
+ if line.strip() == "[patch.crates-io]":
+ state = State.INSIDE_PATCH
+ elif state == State.INSIDE_PATCH:
+ if line.startswith("["):
+ state = State.AFTER_PATCH
+ if "path = " in line:
+ if not is_mozjs_crates_io_local_patch(line):
+ continue
+
+ content += line
+
+ with target_cargo_toml_file.open("w") as f:
+ f.write(content)
+
+
+def generate_configure():
+ """Generate configure files to avoid build dependency on autoconf-2.13"""
+
+ src_old_configure_in_file = topsrc_dir / "js" / "src" / "old-configure.in"
+ dest_old_configure_file = target_dir / "js" / "src" / "old-configure"
+
+ js_src_dir = topsrc_dir / "js" / "src"
+
+ env = os.environ.copy()
+ env["M4"] = m4
+ env["AWK"] = awk
+ env["AC_MACRODIR"] = topsrc_dir / "build" / "autoconf"
+
+ with dest_old_configure_file.open("w") as f:
+ subprocess.run(
+ [
+ "sh",
+ str(topsrc_dir / "build" / "autoconf" / "autoconf.sh"),
+ "--localdir={}".format(js_src_dir),
+ str(src_old_configure_in_file),
+ ],
+ stdout=f,
+ check=True,
+ env=env,
+ )
+
+
+def copy_file(filename, content):
+ """Copy an existing file from the staging area, or create a new file
+ with the given contents if it does not exist."""
+
+ staging_file = staging_dir / filename
+ target_file = target_dir / filename
+
+ if staging_file.exists():
+ shutil.copy2(str(staging_file), str(target_file))
+ else:
+ with target_file.open("w") as f:
+ f.write(content)
+
+
+def copy_patches():
+ """Copy patches dir, if it exists."""
+
+ staging_patches_dir = staging_dir / "patches"
+ top_patches_dir = topsrc_dir / "patches"
+ target_patches_dir = target_dir / "patches"
+
+ if staging_patches_dir.is_dir():
+ shutil.copytree(str(staging_patches_dir), str(target_patches_dir))
+ elif top_patches_dir.is_dir():
+ shutil.copytree(str(top_patches_dir), str(target_patches_dir))
+
+
+def remove_python_cache():
+ """Remove *.pyc and *.pyo files if any."""
+ for f in target_dir.glob("**/*.pyc"):
+ f.unlink()
+ for f in target_dir.glob("**/*.pyo"):
+ f.unlink()
+
+
+def stage():
+ """Stage source tarball content."""
+ logging.info("Staging source tarball in {}...".format(target_dir))
+
+ create_target_dir()
+ sync_files()
+ copy_cargo_toml()
+ generate_configure()
+ copy_file("INSTALL", INSTALL_CONTENT)
+ copy_file("README", README_CONTENT)
+ copy_file("mozconfig", MOZCONFIG_DEBUG_CONTENT)
+ copy_file("mozconfig.opt", MOZCONFIG_OPT_CONTENT)
+ copy_patches()
+ remove_python_cache()
+
+
+def create_tar():
+ """Roll the tarball."""
+
+ logging.info("Packaging source tarball at {}...".format(package_file))
+
+ subprocess.run(
+ [str(tar)] + tar_opts + [str(package_file), "-C", str(staging_dir), version],
+ check=True,
+ )
+
+
+def build():
+ assert_clean()
+ stage()
+ create_tar()
+
+
+parser = argparse.ArgumentParser(description="Make SpiderMonkey source package")
+subparsers = parser.add_subparsers(dest="COMMAND")
+subparser_update = subparsers.add_parser("clean", help="")
+subparser_update = subparsers.add_parser("build", help="")
+args = parser.parse_args()
+
+if args.COMMAND == "clean":
+ clean()
+elif not args.COMMAND or args.COMMAND == "build":
+ build()