Add python script for building tarballs.

* scripts/make_distribution_archives.py: New file.

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 clean up `objs/` properly,
  `make dist` archives may contain some stale binaries like
  `objs/.libs/libfreetype.so.6` or others.

- `config.guess` and `config.sub` are not updated unless option
  `--gnu-config-dir=DIR` is used to specify the location of these
  files.

- Some bits of the auto-generated reference documentation may
  appear in slightly different order, probably due to issues related
  to mkdocs and docwriter.

As an example, the call

  scripts/make_distribution_archives.py /tmp/freetype2-dist

creates the following files under `/tmp/freetype2-dist`:

  freetype-<version>.tar.gz
  freetype-<version>.tar.xz
  ft<winversion>.zip
This commit is contained in:
David Turner 2020-08-25 20:52:32 +02:00 committed by Werner Lemberg
parent 46417607e6
commit d686f2ff9c
2 changed files with 240 additions and 0 deletions

View File

@ -1,3 +1,35 @@
2020-09-21 David Turner <david@freetype.org>
Add python script for building tarballs.
* scripts/make_distribution_archives.py: New file.
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 clean up `objs/` properly,
`make dist` archives may contain some stale binaries like
`objs/.libs/libfreetype.so.6` or others.
- `config.guess` and `config.sub` are not updated unless option
`--gnu-config-dir=DIR` is used to specify the location of these
files.
- Some bits of the auto-generated reference documentation may
appear in slightly different order, probably due to issues related
to mkdocs and docwriter.
As an example, the call
scripts/make_distribution_archives.py /tmp/freetype2-dist
creates the following files under `/tmp/freetype2-dist`:
freetype-<version>.tar.gz
freetype-<version>.tar.xz
ft<winversion>.zip
2020-09-21 Werner Lemberg <wl@gnu.org>
* scripts/extract_freetype_version.py: Fix regex typos.

View File

@ -0,0 +1,208 @@
#!/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())