From 4d56417ff87bbb4beffc6f09d106df86b8877723 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 | 178 ++++++++++++++++++++++++++ 1 file changed, 178 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..1cc685ffe --- /dev/null +++ b/scripts/make_distribution_archives.py @@ -0,0 +1,178 @@ +#!/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