From 8dcb5c0789a8065947eb66d08ceae730b6afae87 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 25 Aug 2020 20:52:32 +0200 Subject: [build] Add scripts/make_distribution_archives.py This standalone Python script should be equivalent to running "make dist" with the Make-based build system, with the following minor differences: - Since 'make distclean' doesn't always cleanup objs/ properly, the 'make dist' archives may contain some stale binaries like objs/.libs/libfreetype.so.6 or others. - The config.guess and config.sub files are not update, unless one uses the --gnu-config-dir=DIR option to specify were they are located. - Some bits of the auto-generated reference documentation may appear in slightly different order, probably due to issues related to mkdocs and docwriter. Usage example: scripts/make_distribution_archives.py /tmp/freetype2-dist Will create files the following files under /tmp/freetype2-dist: freetype-.tar.gz freetype-.tar.xz ft.zip --- scripts/make_distribution_archives.py | 188 ++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100755 scripts/make_distribution_archives.py diff --git a/scripts/make_distribution_archives.py b/scripts/make_distribution_archives.py new file mode 100755 index 000000000..cf2bb544f --- /dev/null +++ b/scripts/make_distribution_archives.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +"""Generate distribution archives for a given FreeType 2 release.""" + +from __future__ import print_function + +import argparse +import atexit +import os +import shutil +import subprocess +import sys +import tempfile + +_SCRIPT_DIR = os.path.dirname(__file__) +_TOP_DIR = os.path.abspath(os.path.join(_SCRIPT_DIR, "..")) + + +def get_cmd_output(cmd, cwd=None): + """Run a command and return its output as a string.""" + if cwd is not None: + out = subprocess.check_output(cmd, cwd=cwd) + else: + out = subprocess.check_output(cmd) + return out.decode("utf-8").rstrip() + + +def is_git_dir_clean(git_dir): + """Return True iff |git_dir| is a git directory in clean state.""" + out = get_cmd_output(["git", "status", "--porcelain"], cwd=git_dir) + return len(out) == 0 + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument("--source_dir", default=_TOP_DIR, help="Source directory path.") + + parser.add_argument( + "--version", + help="Specify alternate FreeType version (it is otherwise extracted from " + "current sources by default).", + ) + + parser.add_argument( + "--gnu-config-dir", + help=( + "Path of input directory containing recent `config.guess` and " + "`config.sub` files from GNU config." + ), + ) + + parser.add_argument( + "--build-dir", + help="Specify build directory. Only used for debugging this script.", + ) + + parser.add_argument( + "--ignore-clean-check", + action="store_true", + help="Do not check for a clean source git repository. Only used for " + "debugging this script.", + ) + + parser.add_argument("output_dir", help="Output directory for generated archives.") + + args = parser.parse_args() + + git_dir = args.source_dir if args.source_dir else _TOP_DIR + if not args.ignore_clean_check and not is_git_dir_clean(git_dir): + sys.stderr.write( + "ERROR: Your git repository is not in a clean state: %s\n" % git_dir + ) + return 1 + + if args.version: + version = args.version + else: + # Extract FreeType version from sources. + version = get_cmd_output( + [ + sys.executable, + os.path.join(_SCRIPT_DIR, "extract_freetype_version.py"), + os.path.join(_TOP_DIR, "include", "freetype", "freetype.h"), + ] + ) + + # Determine the build directory. This will be a temporary file that is + # cleaned up on script exit by default, unless --build-dir=DIR is used, + # in which case we only create and empty the directory, but never remove + # its content on exit. + if args.build_dir: + build_dir = args.build_dir + if not os.path.exists(build_dir): + os.makedirs(build_dir) + else: + # Remove anything from the build directory, if any. + for item in os.listdir(build_dir): + file_path = os.path.join(build_dir, item) + if os.path.isdir(file_path): + shutil.rmtree(file_path) + else: + os.unlink(file_path) + else: + # Create a temporary directory, and ensure it is removed on exit. + build_dir = tempfile.mkdtemp(prefix="freetype-dist-") + + def clean_build_dir(): + shutil.rmtree(build_dir) + + atexit.register(clean_build_dir) + + # Copy all source files known to git into $BUILD_DIR/freetype-$VERSION + # with the exception of .gitignore and .mailmap files. + source_files = [ + f + for f in get_cmd_output(["git", "ls-files"], cwd=git_dir).split("\n") + if os.path.basename(f) not in (".gitignore", ".mailmap") + ] + + freetype_dir = "freetype-" + version + tmp_src_dir = os.path.join(build_dir, freetype_dir) + os.makedirs(tmp_src_dir) + + for src in source_files: + dst = os.path.join(tmp_src_dir, src) + dst_dir = os.path.dirname(dst) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + shutil.copyfile(src, dst) + + # Run autogen.sh in directory. + subprocess.check_call(["/bin/sh", "autogen.sh"], cwd=tmp_src_dir) + shutil.rmtree(os.path.join(tmp_src_dir, "builds", "unix", "autom4te.cache")) + + # Copy config.guess and config.sub if possible! + if args.gnu_config_dir: + for f in ("config.guess", "config.sub"): + shutil.copyfile( + os.path.join(args.gnu_config_dir, f), + os.path.join(tmp_src_dir, "builds", "unix", f), + ) + + # Generate reference documentation under docs/ + subprocess.check_call( + [ + sys.executable, + os.path.join(_SCRIPT_DIR, "generate_reference_docs.py"), + "--input-dir", + tmp_src_dir, + "--version", + version, + "--output-dir", + os.path.join(tmp_src_dir, "docs"), + ] + ) + + shutil.rmtree(os.path.join(tmp_src_dir, "docs", "markdown")) + os.unlink(os.path.join(tmp_src_dir, "docs", "mkdocs.yml")) + + # Generate our archives + freetype_tar = freetype_dir + ".tar" + + subprocess.check_call( + ["tar", "-H", "ustar", "-chf", freetype_tar, freetype_dir], cwd=build_dir + ) + + subprocess.check_call(["gzip", "-9", "--keep", freetype_tar], cwd=build_dir) + + subprocess.check_call(["xz", "--keep", freetype_tar], cwd=build_dir) + + ftwinversion = "ft" + "".join(version.split(".")) + subprocess.check_call( + ["zip", "-qlr9", ftwinversion + ".zip", freetype_dir], cwd=build_dir + ) + + # Copy file to output directory now. + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir) + + for f in (freetype_tar + ".gz", freetype_tar + ".xz", ftwinversion + ".zip"): + shutil.copyfile(os.path.join(build_dir, f), os.path.join(args.output_dir, f)) + + # Done! + return 0 + + +if __name__ == "__main__": + sys.exit(main()) -- 2.20.1