From 532d7a4218b43859db36b12b3a87e59ffb90a1f6 Mon Sep 17 00:00:00 2001 From: Kjell Ahlstedt Date: Wed, 25 Sep 2019 15:02:45 +0200 Subject: util/meson_aux: Replace shell scripts with Python scripts Python scripts can be used on all operating systems where Meson can be used. Shell scripts are restricted to Unix-like systems. --- Makefile.am | 8 ++-- meson.build | 47 ++++++++++++++-------- util/meson_aux/extra-dist-cmd.py | 39 ++++++++++++++++++ util/meson_aux/extra-dist-cmd.sh | 17 -------- util/meson_aux/extra-install-cmd.py | 43 ++++++++++++++++++++ util/meson_aux/extra-install-cmd.sh | 25 ------------ util/meson_aux/libstdcxx-tag.py | 77 ++++++++++++++++++++++++++++++++++++ util/meson_aux/libstdcxx-tag.sh | 45 --------------------- util/meson_aux/skeletonmm-tarball.py | 53 +++++++++++++++++++++++++ util/meson_aux/skeletonmm-tarball.sh | 24 ----------- 10 files changed, 246 insertions(+), 132 deletions(-) create mode 100755 util/meson_aux/extra-dist-cmd.py delete mode 100755 util/meson_aux/extra-dist-cmd.sh create mode 100755 util/meson_aux/extra-install-cmd.py delete mode 100755 util/meson_aux/extra-install-cmd.sh create mode 100755 util/meson_aux/libstdcxx-tag.py delete mode 100755 util/meson_aux/libstdcxx-tag.sh create mode 100755 util/meson_aux/skeletonmm-tarball.py delete mode 100755 util/meson_aux/skeletonmm-tarball.sh diff --git a/Makefile.am b/Makefile.am index 4f7ad94..9b59a9f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -128,10 +128,10 @@ MAINTAINERCLEANFILES = $(dist_doctags_DATA) EXTRA_DIST = \ meson.build \ meson_options.txt \ - util/meson_aux/extra-dist-cmd.sh \ - util/meson_aux/extra-install-cmd.sh \ - util/meson_aux/libstdcxx-tag.sh \ - util/meson_aux/skeletonmm-tarball.sh + util/meson_aux/extra-dist-cmd.py \ + util/meson_aux/extra-install-cmd.py \ + util/meson_aux/libstdcxx-tag.py \ + util/meson_aux/skeletonmm-tarball.py # Remote location of the GNU libstdc++ Doxygen tag file. libstdcxx_tag_url = http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/libstdc++.tag diff --git a/meson.build b/meson.build index 57fe072..f61fa9e 100644 --- a/meson.build +++ b/meson.build @@ -2,10 +2,24 @@ project('mm-common', version: '0.9.12', - meson_version: '>= 0.49.0', + meson_version: '>= 0.50.0', # required for python3.path() license: 'GPLv2+' ) +python3 = import('python').find_installation('python3') +python_version = python3.language_version() +python_version_req = '>= 3.5' +if not python_version.version_compare(python_version_req) + error('Requires Python @0@, found @1@.'.format(python_version_req, python_version)) +endif + +# Use these instead of meson.source_root() and meson.build_root(). +# source_root() and build_root() are not useful, if this is a subproject. +project_source_root = meson.current_source_dir() +project_build_root = meson.current_build_dir() + +script_dir = project_source_root / 'util' / 'meson_aux' + # Install directories are relative to {prefix}. install_prefix = get_option('prefix') install_bindir = get_option('bindir') @@ -84,7 +98,8 @@ configure_file( if find_program('aclocal', required: false).found() meson.add_install_script( - 'util' / 'meson_aux' / 'extra-install-cmd.sh', + python3.path(), + script_dir / 'extra-install-cmd.py', install_prefix / install_aclocal_macrodir ) endif @@ -201,22 +216,18 @@ foreach file : skeletonmm_basefiles skeletonmm_files += 'skeletonmm' / file endforeach -# tar and either xz or gzip are required for the skeletonmm.tar.[xz|gz] file. -tar = find_program('tar', required: true) -xz = find_program('xz', required: false) -if not xz.found() - gzip = find_program('gzip', required: true) -endif - # Create tar archive of skeletonmm for installation. -tarball_filename = xz.found() ? 'skeletonmm.tar.xz' : 'skeletonmm.tar.gz' +skeletonmm_tarball_script = script_dir / 'skeletonmm-tarball.py' +tarball_filetype = run_command(python3, skeletonmm_tarball_script, 'check') +tarball_filename = 'skeletonmm' + tarball_filetype.stdout() custom_target(tarball_filename, input: skeletonmm_files, output: tarball_filename, command: [ - files('util' / 'meson_aux' / 'skeletonmm-tarball.sh'), - meson.current_source_dir(), + python3, + skeletonmm_tarball_script, '@OUTPUT@', + project_source_root, skeletonmm_files, ], build_by_default: true, @@ -241,9 +252,10 @@ endif custom_target('libstdc++.tag', output: 'libstdc++.tag', command: [ - files('util' / 'meson_aux' / 'libstdcxx-tag.sh'), + python3, + script_dir / 'libstdcxx-tag.py', download_cmd, - meson.current_source_dir() / 'doctags', + project_source_root / 'doctags', '@OUTPUT@', ], build_by_default: true, @@ -255,9 +267,10 @@ custom_target('libstdc++.tag', if not meson.is_subproject() # Modify the contents of the distribution directory. (not allowed in a subproject) meson.add_dist_script( - 'util' / 'meson_aux' / 'extra-dist-cmd.sh', - meson.current_source_dir(), - meson.current_build_dir(), + python3.path(), + script_dir / 'extra-dist-cmd.py', + project_source_root, + project_build_root, ) endif diff --git a/util/meson_aux/extra-dist-cmd.py b/util/meson_aux/extra-dist-cmd.py new file mode 100755 index 0000000..5b04f06 --- /dev/null +++ b/util/meson_aux/extra-dist-cmd.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +# External command, intended to be called with meson.add_dist_script() in meson.build + +# argv[1] argv[2] +# extra-dist-cmd.py + +# Meson does not preserve timestamps on distributed files. +# But this script preserves the timestamps on libstdc++.tag. + +import os +import sys +import subprocess +import shutil + +root_source_dir = sys.argv[1] +root_build_dir = sys.argv[2] + +# Make a ChangeLog file for distribution. +cmd = [ + 'git', + '--git-dir=' + os.path.join(root_source_dir, '.git'), + '--work-tree=' + root_source_dir, + 'log', + '--no-merges', + '--date=short', + '--max-count=200', + '--pretty=tformat:%cd %an <%ae>%n%n %s%n%w(0,0,2)%+b', +] +logfile = open(os.path.join(os.getenv('MESON_DIST_ROOT'), 'ChangeLog'), mode='w') +result = subprocess.run(cmd, stdout=logfile) +logfile.close() + +# Distribute the libstdc++.tag file in addition to the files in the local git clone. +# shutil.copy2() copies timestamps and some other file metadata. +shutil.copy2(os.path.join(root_build_dir, 'libstdc++.tag'), + os.path.join(os.getenv('MESON_DIST_ROOT'), 'doctags')) + +sys.exit(result.returncode) diff --git a/util/meson_aux/extra-dist-cmd.sh b/util/meson_aux/extra-dist-cmd.sh deleted file mode 100755 index 1c61ed1..0000000 --- a/util/meson_aux/extra-dist-cmd.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -e - -# External command, intended to be called with meson.add_dist_script() in meson.build - -# extra-dist-cmd.sh - -# Meson does not preserve timestamps on distributed files. -# But this script preserves the timestamps on libstdc++.tag. - -# Make a ChangeLog file for distribution. -git --git-dir="$1/.git" --work-tree="$1" log --no-merges --date=short --max-count=200 \ - --pretty='tformat:%cd %an <%ae>%n%n %s%n%w(0,0,2)%+b' > "$MESON_DIST_ROOT/ChangeLog" - -# Distribute the libstdc++.tag file in addition to the files in the local git clone. -# -p == --preserve=mode,ownership,timestamps (Posix does not support long options.) -# Only the preservation of timestamps is essential here. -cp -p "$2/libstdc++.tag" "$MESON_DIST_ROOT/doctags/" diff --git a/util/meson_aux/extra-install-cmd.py b/util/meson_aux/extra-install-cmd.py new file mode 100755 index 0000000..8414847 --- /dev/null +++ b/util/meson_aux/extra-install-cmd.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +# External command, intended to be called with meson.add_install_script() in meson.build + +# argv[1] +# extra-install-cmd.py + +import os +import sys +import subprocess + +if not os.getenv('DESTDIR'): + # Inform the installer that M4 macro files installed in a directory + # not known to aclocal will not be picked up automatically. + # (Starting with Python 3.7 text=True is a more understandable equivalent to + # universal_newlines=True. Let's use only features in Python 3.5.) + result = subprocess.run(['aclocal', '--print-ac-dir'], + stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, + universal_newlines=True) + acdir = result.stdout + aclocal_path = os.getenv('ACLOCAL_PATH') + # acdir and aclocal_path can be sequences of os.pathsep-separated paths. + # Merge them to one sequence with leading and trailing os.pathsep. + # os.pathsep is ':' for Linux, ';' for Windows. + acdirs = os.pathsep + if aclocal_path: + acdirs += aclocal_path + os.pathsep + if acdir: + acdirs += acdir + os.pathsep + + if (os.pathsep + sys.argv[1] + os.pathsep) not in acdirs: + # f'''.....''' would require Python 3.6. Avoid it. + print('''\ + NOTE + ---- +The mm-common Autoconf macro files have been installed in a different +directory than the system aclocal directory. In order for the installed +macros to be found, it may be necessary to add the mm-common include +path to the ACLOCAL_PATH environment variable: + ACLOCAL_PATH="$ACLOCAL_PATH:{}" + export ACLOCAL_PATH'''.format(sys.argv[1]) + ) +sys.exit(0) diff --git a/util/meson_aux/extra-install-cmd.sh b/util/meson_aux/extra-install-cmd.sh deleted file mode 100755 index e07a692..0000000 --- a/util/meson_aux/extra-install-cmd.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -e - -# External command, intended to be called with meson.add_install_script() in meson.build - -# extra-install-cmd.sh - -if [ -z "$DESTDIR" ]; then - # Inform the installer that M4 macro files installed in a directory - # not known to aclocal will not be picked up automatically. - acdir="$(aclocal --print-ac-dir 2>/dev/null || :)" - case ":$ACLOCAL_PATH:$acdir:" in - *":$1:"*) - ;; - *) - echo "NOTE" - echo "----" - echo "The mm-common Autoconf macro files have been installed in a different" - echo "directory than the system aclocal directory. In order for the installed" - echo "macros to be found, it may be necessary to add the mm-common include" - echo "path to the ACLOCAL_PATH environment variable:" - echo " ACLOCAL_PATH=\"\$ACLOCAL_PATH:$1\"" - echo " export ACLOCAL_PATH" - ;; - esac -fi diff --git a/util/meson_aux/libstdcxx-tag.py b/util/meson_aux/libstdcxx-tag.py new file mode 100755 index 0000000..2873498 --- /dev/null +++ b/util/meson_aux/libstdcxx-tag.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +# External command, intended to be called with custom_target() in meson.build + +# argv[1] argv[2] argv[3] +# libstdcxx-tag.py + +import os +import sys +import subprocess +import shutil + +subcommand = sys.argv[1] +srcdir = sys.argv[2] +output_path = sys.argv[3] +output_dirname, output_filename = os.path.split(output_path) +if not output_dirname: + output_dirname = '.' + +# Remote location of the GNU libstdc++ Doxygen tag file. +libstdcxx_tag_url = 'http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/' + output_filename + +def curl(): + cmd = [ + 'curl', + '--compressed', + '--connect-timeout', '300', + '--globoff', + '--location', + '--max-time', '3600', + '--remote-time', + '--retry', '5', + ] + if os.path.isfile(output_path): + # Don't download the tag file unless it's newer than the local file. + cmd += ['--time-cond', output_path] + + cmd += [ + '--output', output_path, + libstdcxx_tag_url, + ] + return subprocess.run(cmd).returncode + +def wget(): + cmd = [ + 'wget', + '--timestamping', + '--no-directories', + '--timeout=300', + '--tries=5', + '--directory-prefix=' + output_dirname, + libstdcxx_tag_url, + ] + return subprocess.run(cmd).returncode + +def dont_download_tag_file(): + if os.path.isfile(output_path): + print('Did not check status of', output_path, 'because network is disabled.') + elif os.path.isfile(os.path.join(srcdir, output_filename)): + print('Warning:', output_path, 'does not exist.') + print('Copying from the source directory because network is disabled.') + print('If you want an up-to-date copy, reconfigure with the -Duse-network=true option.') + # shutil.copy2() copies timestamps and some other file metadata. + shutil.copy2(os.path.join(srcdir, output_filename), output_path) + else: + print('Error:', output_path, 'does not exist.', file=sys.stderr) + print('Downloading it is not possible because network is disabled.', file=sys.stderr) + print('Please reconfigure with the -Duse-network=true option.', file=sys.stderr) + return 1 + return 0 + +# ----- Main ----- +if subcommand == 'curl': + sys.exit(curl()) +if subcommand == 'wget': + sys.exit(wget()) +sys.exit(dont_download_tag_file()) diff --git a/util/meson_aux/libstdcxx-tag.sh b/util/meson_aux/libstdcxx-tag.sh deleted file mode 100755 index c05d8e8..0000000 --- a/util/meson_aux/libstdcxx-tag.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -e - -# External command, intended to be called with custom_target() in meson.build - -# libstdcxx-tag.sh - -output_dirname="$(dirname "$3")" -output_filename="$(basename "$3")" - -# Remote location of the GNU libstdc++ Doxygen tag file. -libstdcxx_tag_url="http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/$output_filename" - -case "$1" in - curl) - # These options don't contain filenames, and thus no spaces that - # must be preserved in the call to curl. - simple_curl_options="--compressed --connect-timeout 300 --globoff --location --max-time 3600 --remote-time --retry 5" - if [ -f "$3" ]; then - curl $simple_curl_options --time-cond "$3" --output "$3" "$libstdcxx_tag_url" - else - curl $simple_curl_options --output "$3" "$libstdcxx_tag_url" - fi - ;; - wget) - wget --timestamping --no-directories --timeout=300 --tries=5 \ - --directory-prefix="$output_dirname" "$libstdcxx_tag_url" - ;; - *) - if [ -f "$3" ]; then - echo "Did not check status of $3 because network is disabled." - elif [ -f "$2/$output_filename" ]; then - echo "Warning: $3 does not exist." - echo "Copying from the source directory because network is disabled." - echo "If you want an up-to-date copy, reconfigure with the -Duse-network=true option." - # -p == --preserve=mode,ownership,timestamps (Posix does not support long options.) - # Only the preservation of timestamps is essential here. - cp -p "$2/$output_filename" "$3" - else - echo "Error: $3 does not exist." >&2 - echo "Downloading it is not possible because network is disabled." >&2 - echo "Please reconfigure with the -Duse-network=true option." >&2 - exit 1 - fi - ;; -esac diff --git a/util/meson_aux/skeletonmm-tarball.py b/util/meson_aux/skeletonmm-tarball.py new file mode 100755 index 0000000..576b522 --- /dev/null +++ b/util/meson_aux/skeletonmm-tarball.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +# External command, intended to be called with run_command() or custom_target() +# in meson.build + +# argv[1] argv[2] argv[3:] +# skeletonmm-tarball.py + +import os +import sys +import shutil +import tarfile + +if sys.argv[1] == 'check': + # Called from run_command() during setup or configuration. + # Check which archive format can be used. + # In order from most wanted to least wanted: .tar.xz, .tar.gz, .tar + available_archive_formats = [] + for af in shutil.get_archive_formats(): + # Keep the formats in a list, skip the descriptions. + available_archive_formats += [af[0]] + if 'xztar' in available_archive_formats: + suffix = '.tar.xz' + elif 'gztar' in available_archive_formats: + suffix = '.tar.gz' + else: # Uncompressed tar format is always available. + suffix = '.tar' + print(suffix, end='') # stdout can be read in the meson.build file. + sys.exit(0) + +# Create an archive. +output_file = sys.argv[1] +source_dir = sys.argv[2] + +if output_file.endswith('.xz'): + mode = 'w:xz' +elif output_file.endswith('.gz'): + mode = 'w:gz' +else: + mode = 'w' + +tar_file = tarfile.open(output_file, mode=mode) +os.chdir(source_dir) # Input filenames are relative to source_dir. +for file in sys.argv[3:]: + tar_file.add(file) +tar_file.close() +# Errors raise exceptions. If an exception is raised, Meson+ninja will notice +# that the command failed, despite exit(0). +sys.exit(0) + +# shutil.make_archive() might be an alternative, but it only archives +# whole directories. It's not useful, if you want to have full control +# of which files are archived. diff --git a/util/meson_aux/skeletonmm-tarball.sh b/util/meson_aux/skeletonmm-tarball.sh deleted file mode 100755 index f0fd17d..0000000 --- a/util/meson_aux/skeletonmm-tarball.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -e - -# External command, intended to be called with custom_target() in meson.build - -# skeletonmm-tarball.sh - -source_dir="$1" -output_file="$2" -shift 2 - -# -chof == --create --dereference --old-archive --file (Posix does not support long options.) -tar_options="-chof -" - -case "$output_file" in - *.xz) - ( cd "$source_dir"; tar $tar_options "$@" ) | xz --to-stdout --extreme >"$output_file" - ;; - *.gz) - ( cd "$source_dir"; tar $tar_options "$@" ) | gzip --to-stdout --best --no-name >"$output_file" - ;; - *) echo "Error: Unknown filetype, $output_file" - exit 1 - ;; -esac -- cgit v1.2.1