From f9a6bd109425d9b22fbb66f7b6666e40ae583de7 Mon Sep 17 00:00:00 2001 From: Romain Failliot Date: Tue, 11 Aug 2020 12:12:41 -0400 Subject: [PATCH 1/5] Add `builddir` to ignored git directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 118662e..eac5adc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ __pycache__/ # Distribution / packaging .Python build/ +builddir/ develop-eggs/ dist/ downloads/ From b12f4612a52c4c70aa85c3543590b4ed7219c389 Mon Sep 17 00:00:00 2001 From: Romain Failliot Date: Tue, 11 Aug 2020 13:27:23 -0400 Subject: [PATCH 2/5] Add meson build system --- build-scripts/meson-postinstall.py | 15 ++++++++++++++ meson.build | 28 ++++++++++++++++++++++++++ src/etc/{diffuserc => diffuserc.py.in} | 2 +- src/meson.build | 26 ++++++++++++++++++++++++ src/usr/bin/{diffuse => diffuse.py.in} | 2 +- translations/LINGUAS | 14 +++++++++++++ translations/meson.build | 1 + 7 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 build-scripts/meson-postinstall.py create mode 100644 meson.build rename src/etc/{diffuserc => diffuserc.py.in} (74%) create mode 100644 src/meson.build rename src/usr/bin/{diffuse => diffuse.py.in} (99%) create mode 100644 translations/LINGUAS create mode 100644 translations/meson.build diff --git a/build-scripts/meson-postinstall.py b/build-scripts/meson-postinstall.py new file mode 100644 index 0000000..6999cb4 --- /dev/null +++ b/build-scripts/meson-postinstall.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +import sysconfig +from compileall import compile_dir +from os import environ, path +from subprocess import call + +prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local') +datadir = path.join(prefix, 'share') +destdir = environ.get('DESTDIR', '') + +# Package managers set this so we don't need to run +if not destdir: + print('Updating icon cache...') + call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')]) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..b169d87 --- /dev/null +++ b/meson.build @@ -0,0 +1,28 @@ +project('diffuse', + version: '0.6.0', + meson_version: '>= 0.50', + license: 'GPL-2.0-or-later') + +i18n = import('i18n') +python = import('python') + +py_installation = python.find_installation('python3') + +find_program('gtk-update-icon-cache', required: false) + +prefix = get_option('prefix') + +bindir = prefix / get_option('bindir') +datadir = prefix / get_option('datadir') +localedir = prefix / get_option('localedir') +libexecdir = prefix / get_option('libexecdir') +sysconfdir = prefix / get_option('sysconfdir') +pythondir = py_installation.get_path('purelib') + +pkgdatadir = join_paths(datadir, meson.project_name()) +podir = join_paths(meson.source_root(), 'translations') + +subdir('translations') +subdir('src') + +meson.add_install_script('build-scripts/meson-postinstall.py') diff --git a/src/etc/diffuserc b/src/etc/diffuserc.py.in similarity index 74% rename from src/etc/diffuserc rename to src/etc/diffuserc.py.in index c10ba74..9a2f221 100644 --- a/src/etc/diffuserc +++ b/src/etc/diffuserc.py.in @@ -2,4 +2,4 @@ # # Copyright (C) 2006-2009 Derrick Moser -import ../usr/share/diffuse/syntax/*.syntax +import @PKGDATADIR@/syntax/*.syntax diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..e30b432 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,26 @@ +# Diffuse binary file +diffuse_conf = configuration_data() +diffuse_conf.set('SYSCONFIGDIR', sysconfdir) + +configure_file( + input: 'usr/bin/diffuse.py.in', + output: 'diffuse', + configuration: diffuse_conf, + install: true, + install_dir: bindir +) + +# Diffuse config file +diffuserc_conf = configuration_data() +diffuserc_conf.set('PKGDATADIR', pkgdatadir) + +configure_file( + input: 'etc/diffuserc.py.in', + output: 'diffuserc', + configuration: diffuserc_conf, + install: true, + install_dir: sysconfdir +) + +# Data files +install_subdir('usr/share', install_dir: datadir, strip_directory: true) diff --git a/src/usr/bin/diffuse b/src/usr/bin/diffuse.py.in similarity index 99% rename from src/usr/bin/diffuse rename to src/usr/bin/diffuse.py.in index 9ed6e0c..41142fc 100755 --- a/src/usr/bin/diffuse +++ b/src/usr/bin/diffuse.py.in @@ -8345,7 +8345,7 @@ if __name__ == '__main__': if isWindows(): rc_file = os.path.join(bin_dir, 'diffuserc') else: - rc_file = os.path.join(bin_dir, '../../etc/diffuserc') + rc_file = os.path.join(bin_dir, '@SYSCONFIGDIR@/diffuserc') for rc_file in rc_file, os.path.join(rc_dir, 'diffuserc'): if os.path.isfile(rc_file): rc_files.append(rc_file) diff --git a/translations/LINGUAS b/translations/LINGUAS new file mode 100644 index 0000000..bdb3627 --- /dev/null +++ b/translations/LINGUAS @@ -0,0 +1,14 @@ +# Please keep this list sorted alphabetically +cs +de +es +it +ja +ko +pl +pt +ru +sv +th +zh_CN +zh_TW diff --git a/translations/meson.build b/translations/meson.build new file mode 100644 index 0000000..e9b77d7 --- /dev/null +++ b/translations/meson.build @@ -0,0 +1 @@ +i18n.gettext(meson.project_name(), preset: 'glib') From 750d5a668b3d753fc8b20dc8619b91c4026263a1 Mon Sep 17 00:00:00 2001 From: Romain Failliot Date: Tue, 11 Aug 2020 13:44:49 -0400 Subject: [PATCH 3/5] Remove install.py --- install.py | 294 ----------------------------------------------------- 1 file changed, 294 deletions(-) delete mode 100755 install.py diff --git a/install.py b/install.py deleted file mode 100755 index f3928f5..0000000 --- a/install.py +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (C) 2009-2010 Derrick Moser -# Copyright (C) 2015-2020 Romain "Creak" Failliot -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the licence, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program. You may also obtain a copy of the GNU General Public License -# from the Free Software Foundation by visiting their web site -# (http://www.fsf.org/) or by writing to the Free Software Foundation, Inc., -# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -import glob -import os -import stat -import subprocess -import sys - -app_path = sys.argv[0] - -# print a message to stderr -def logError(s): - sys.stderr.write(f'{app_path}: {s}\n') - -# this install script should not be used on Windows -if os.name == 'nt': - logError('Wrong platform. Use scripts from the "windows-installer" directory instead.') - sys.exit(1) - -# reset the umask so files we create will have the expected permissions -os.umask(stat.S_IWGRP | stat.S_IWOTH) - -# option defaults -options = { 'destdir': '/', - 'prefix': '/usr/local/', - 'sysconfdir': '/etc/', - 'examplesdir': '${sysconfdir}', - 'mandir': '${prefix}/share/man/', - 'pythonbin': '/usr/bin/env python' } -install = True -files_only = False - -# process --help option -if len(sys.argv) == 2 and sys.argv[1] == '--help': - print(f"""Usage: {app_path} [OPTION...] - -Install or remove Diffuse. - -Options: - --help - print this help text and quit - - --remove - remove the program - - --destdir=PATH - path to the installation's root directory - default: {options['destdir']} - - --prefix=PATH - common installation prefix for files - default: {options['prefix']} - - --sysconfdir=PATH - directory for installing read-only single-machine data - default: {options['sysconfdir']} - - --examplesdir=PATH - directory for example configuration files - default: {options['examplesdir']} - - --mandir=PATH - directory for man pages - default: {options['mandir']} - - --pythonbin=PATH - command for python interpreter - default: {options['pythonbin']} - - --files-only - only install/remove files; skip the post install/removal tasks""") - sys.exit(0) - -# returns the list of components used in a path -def components(s): - return [ p for p in s.split(os.sep) if p != '' ] - -# returns a relative path from 'src' to 'dst' -def relpath(src, dst): - s1, s2, i = components(src), components(dst), 0 - while i < len(s1) and i < len(s2) and s1[i] == s2[i]: - i += 1 - s = [ os.pardir ] * (len(s1) - i) - s.extend(s2[i:]) - return os.sep.join(s) - -# apply a set of text substitution rules on a string -def replace(s, rules, i=0): - if i < len(rules): - k, v = rules[i] - a = s.split(k) - for j in range(len(a)): - a[j] = replace(a[j], rules, i + 1) - s = v.join(a) - return s - -# create directories -def createDirs(d): - p = os.sep - for c in components(d): - p = os.path.join(p, c) - if not os.path.isdir(p): - os.mkdir(p) - -# remove a file -def removeFile(f): - try: - os.unlink(f) - except OSError: - logError(f'Error removing "{f}".') - -# install/remove sets of files -def processFiles(install, dst, src, template): - for k, v in template.items(): - for s in glob.glob(os.path.join(src, k)): - d = s.replace(src, dst, 1) - if install: - createDirs(os.path.dirname(d)) - # install file - f = open(s, 'rb') - c = f.read() - f.close() - if v is not None: - c = replace(c, v) - print(f'Installing {d}') - f = open(d, 'wb') - f.write(c) - f.close() - if k == 'bin/diffuse': - # turn on the execute bits - os.chmod(d, 0o755) - else: - # remove file - print(f'Removing {d}') - removeFile(d) - -# compile .po files and install -def processTranslations(install, dst): - for s in glob.glob('translations/*.po'): - lang = s[13:-3] - d = os.path.join(dst, f'share/locale/{lang}/LC_MESSAGES/diffuse.mo') - if install: - # install file - try: - print(f'Installing {d}') - createDirs(os.path.dirname(d)) - if subprocess.Popen(['msgfmt', '-o', d, s]).wait() != 0: - raise OSError() - except OSError: - logError(f'WARNING: Failed to compile "{lang}" localisation.') - else: - # remove file - removeFile(d) - -# parse command line arguments -for arg in sys.argv[1:]: - if arg == '--remove': - install = False - elif arg == '--files-only': - files_only = True - else: - for opt in options.keys(): - key = f'--{opt}=' - if arg.startswith(key): - options[opt] = arg[len(key):] - break - else: - logError(f'Unknown option "{arg}".') - sys.exit(1) - -# expand variables -for s in 'sysconfdir', 'examplesdir', 'mandir': - for k in 'prefix', 'sysconfdir': - if s != k: - options[s] = options[s].replace(f'${{{k}}}', options[k]) - -# validate inputs -if options['destdir'] == '': - options['destdir'] = '/' -for opt in 'prefix', 'sysconfdir', 'examplesdir', 'mandir': - p = options[opt] - c = components(p) - if os.pardir in c or os.curdir in c: - logError(f'Bad value for option "{opt}".') - sys.exit(1) - c.insert(0, '') - c.append('') - options[opt] = os.sep.join(c) - -destdir = options['destdir'] -prefix = options['prefix'] -sysconfdir = options['sysconfdir'] -examplesdir = options['examplesdir'] -mandir = options['mandir'] -pythonbin = options['pythonbin'] - -# tell the user what we are about to do -if install: - stage = 'install' -else: - stage = 'removal' -print(f'''Performing {stage} with: - destdir={destdir} - prefix={prefix} - sysconfdir={sysconfdir} - examplesdir={examplesdir} - mandir={mandir} - pythonbin={pythonbin}''') - -# install files to prefix -processFiles(install, os.path.join(destdir, prefix[1:]), 'src/usr/', { - 'bin/diffuse': [ (b"'../../etc/diffuserc'", repr(relpath(os.path.join(prefix, 'bin'), os.path.join(sysconfdir, 'diffuserc'))).encode()), - (b'/usr/bin/env python', pythonbin.encode()) ], - 'share/applications/diffuse.desktop': None, - 'share/diffuse/syntax/*.syntax': None, - 'share/gnome/help/diffuse/*/diffuse.xml': [ (b'/usr/', prefix.encode()), (b'/etc/', sysconfdir.encode()) ], - 'share/omf/diffuse/diffuse-*.omf': [ (b'/usr/', prefix.encode()) ], - 'share/icons/hicolor/*/apps/diffuse.png': None - }) - -# install manual -processFiles(install, os.path.join(destdir, mandir[1:]), 'src/usr/share/man/', { - 'man1/diffuse.1': [ (b'/usr/', prefix.encode()), (b'/etc/', sysconfdir.encode()) ], - '*/man1/diffuse.1': [ (b'/usr/', prefix.encode()), (b'/etc/', sysconfdir.encode()) ] - }) - -# install files to sysconfdir -processFiles(install, os.path.join(destdir, examplesdir[1:]), 'src/etc/', { 'diffuserc': [ (b'/etc/', sysconfdir.encode()), - (b'../usr', relpath(sysconfdir, prefix).encode()) ] }) - -# install translations -processTranslations(install, os.path.join(destdir, prefix[1:])) - -if not install: - # remove directories we own - dirs_to_remove = [ - 'share/omf/diffuse', - 'share/gnome/help/diffuse/C', - 'share/gnome/help/diffuse/cs', - 'share/gnome/help/diffuse/it', - 'share/gnome/help/diffuse/ru', - 'share/gnome/help/diffuse', - 'share/diffuse/syntax', - 'share/diffuse' - ] - for s in dirs_to_remove: - d = os.path.join(destdir, os.path.join(prefix, s)[1:]) - try: - os.rmdir(d) - except OSError: - logError(f'Error removing "{d}".') - -# do post install/removal tasks -if not files_only: - print(f'Performing post {stage} tasks.') - - cmds = [ [ 'update-desktop-database' ], - [ 'gtk-update-icon-cache', os.path.join(destdir, os.path.join(prefix, 'share/icons/hicolor')[1:]) ] ] - if install: - cmds.append([ 'scrollkeeper-update', '-q', '-o', os.path.join(destdir, os.path.join(prefix, 'share/omf/diffuse')[1:]) ]) - else: - cmds.append([ 'scrollkeeper-update', '-q' ]) - for c in cmds: - for p in os.environ['PATH'].split(os.pathsep): - if os.path.exists(os.path.join(p, c[0])): - print(' '.join(c)) - try: - if subprocess.Popen(c).wait() != 0: - raise OSError() - except OSError: - logError(f'WARNING: Failed to update documentation database with {c[0]}.') - break - else: - print(f'WARNING: {c[0]} is not installed') From 942c20e4c1974022f4994cea16e966b2c2447c59 Mon Sep 17 00:00:00 2001 From: Romain Failliot Date: Tue, 11 Aug 2020 13:46:56 -0400 Subject: [PATCH 4/5] Update README with new Meson instructions --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8b09e67..d731dfc 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,20 @@ fixed by removing the offending lines (or the entire file) from ## Installing on POSIX systems -Run the `install.py` script to install Diffuse. The script accepts several -options for customising the installation behaviour. Use the `--help` option -to obtain a full listing. +Diffuse build system is meson. -Diffuse can be removed by running the `install.py` script with the `--remove` -option. +To install diffuse locally: -Specify the `--destdir=` and `--files-only` options for the `install.py` -script when using it to build a platform specific package of Diffuse. + meson builddir + meson install -C builddir + +To uninstall diffuse afterwards: + + sudo ninja uninstall -C builddir + sudo rm -v /usr/local/share/locale/*/LC_MESSAGES/diffuse.mo + +Meson allows to change the default installation directories, see +[command-line documentation](https://mesonbuild.com/Commands.html#configure). ## Installing on Windows From 71cc152a9802d930aa2c93ee0032b3d14bb3a225 Mon Sep 17 00:00:00 2001 From: Romain Failliot Date: Tue, 11 Aug 2020 13:47:17 -0400 Subject: [PATCH 5/5] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f9b7c2..41a022d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### Changed +- Replace old install.py with the more standard Meson - Remove `u` string prefixes since Python 3 is in UTF-8 by default - Replaced some interpolation operators (`%`) for the `f` string prefix - Use the window scale factor for the icons generation