python: Fix vpath builds, fix distcheck.
authorJustus Winter <justus@g10code.com>
Mon, 3 Apr 2017 13:44:14 +0000 (15:44 +0200)
committerJustus Winter <justus@g10code.com>
Wed, 5 Apr 2017 14:41:56 +0000 (16:41 +0200)
* lang/python/gpgme-h-clean.py: Delete file.
* lang/python/MANIFEST.in: Adapt accordingly.
* lang/python/Makefile.am (EXTRA_DIST): Likewise.
(COPY_FILES_GPG): Bring variable back.
(copystamp): Copy files.
(clean-local): Delete copied files.
(install-exec-local): Do not create and install list of installed
files.
(uninstall-local): Instead, create some explicit rules to uninstall
the extension.
* lang/python/setup.py.in: Parse arguments.  Locate files either in
the source directory, or in the build base directory.  Inline the code
from 'gpgme-h-clean.py'.  Copy 'helpers.c', add source directory as
include directory.

Fixes-commit: 801d7d8c5dd530d26ad6c4bcc94d986e6e022da4
Signed-off-by: Justus Winter <justus@g10code.com>
lang/python/MANIFEST.in
lang/python/Makefile.am
lang/python/gpgme-h-clean.py [deleted file]
lang/python/setup.py.in

index 8f63640..ff38172 100644 (file)
@@ -1,4 +1,4 @@
 recursive-include examples *.py
-include gpgme-h-clean.py gpgme.i
+include gpgme.i
 include helpers.c helpers.h private.h
 recursive-include gpg *.py
index b9145f5..42beeee 100644 (file)
@@ -21,12 +21,20 @@ EXTRA_DIST = \
        MANIFEST.in \
        gpgme.i \
        helpers.c helpers.h private.h \
-       gpgme-h-clean.py \
        examples \
        gpg
 
 SUBDIRS = . tests
 
+COPY_FILES_GPG = \
+       $(srcdir)/gpg/callbacks.py \
+       $(srcdir)/gpg/constants \
+       $(srcdir)/gpg/core.py \
+       $(srcdir)/gpg/errors.py \
+       $(srcdir)/gpg/__init__.py \
+       $(srcdir)/gpg/results.py \
+       $(srcdir)/gpg/util.py
+
 .PHONY: prepare
 prepare: copystamp
 
@@ -35,12 +43,14 @@ prepare: copystamp
 copystamp:
        ln -sf "$(abs_top_srcdir)/src/data.h" .
        ln -sf "$(abs_top_builddir)/config.h" .
+       if test $(srcdir) != . ; then cp -R $(COPY_FILES_GPG) gpg ; fi
        touch $@
 
 all-local: copystamp
        set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
          PYTHON="$$1" ; shift ; \
          CFLAGS="$(CFLAGS)" \
+         srcdir="$(srcdir)" \
          abs_top_builddir="$(abs_top_builddir)" \
            $$PYTHON setup.py build --verbose --build-base=python$${VERSION}-gpg ; \
        done
@@ -48,6 +58,7 @@ all-local: copystamp
 python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
        $(MKDIR_P) python$(PYTHON_VERSION)-gpg-dist
        CFLAGS="$(CFLAGS)" \
+       srcdir="$(srcdir)" \
        abs_top_builddir="$(abs_top_builddir)" \
          $(PYTHON) setup.py sdist --verbose --dist-dir=python$(PYTHON_VERSION)-gpg-dist \
                --manifest=python$(PYTHON_VERSION)-gpg-dist/MANIFEST
@@ -73,6 +84,12 @@ CLEANFILES = copystamp \
 # permissions.
 clean-local:
        rm -rf -- build
+       if test $(srcdir) != . ; then \
+         find gpg -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+         for FILE in $(COPY_FILES_GPG); do \
+           rm -rf -- gpg/$$(basename $$FILE) ; \
+         done \
+       fi
        for VERSION in $(PYTHON_VERSIONS); do \
          find python$${VERSION}-gpg -type d ! -perm -200 -exec chmod u+w {} ';' ; \
          rm -rf -- python$${VERSION}-gpg ; \
@@ -81,20 +98,18 @@ clean-local:
 install-exec-local:
        set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
          PYTHON="$$1" ; shift ; \
+         srcdir="$(srcdir)" \
          abs_top_builddir="$(abs_top_builddir)" \
          $$PYTHON setup.py \
          build \
          --build-base=python$${VERSION}-gpg \
          install \
          --prefix "$(DESTDIR)$(prefix)" \
-         --record files.txt \
          --verbose ; \
-         cat files.txt >> install_files.txt ; \
-         rm files.txt ; \
        done
-       $(MKDIR_P) "$(DESTDIR)$(pythondir)/gpg"
-       mv install_files.txt "$(DESTDIR)$(pythondir)/gpg"
 
 uninstall-local:
-       xargs < "$(DESTDIR)$(pythondir)/gpg/install_files.txt" -- rm -rf --
-       rm -rf -- "$(DESTDIR)$(pythondir)/gpg"
+       GV=$$(echo $(VERSION) | tr - _); for PV in $(PYTHON_VERSIONS); do \
+         rm -rf -- "$(DESTDIR)$(prefix)/lib/python$$PV/site-packages/gpg" \
+"$(DESTDIR)$(prefix)/lib/python$$PV/site-packages/gpg-$$GV-py$$PV.egg-info" ; \
+       done
diff --git a/lang/python/gpgme-h-clean.py b/lang/python/gpgme-h-clean.py
deleted file mode 100755 (executable)
index 52f8676..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2016 g10 Code GmbH
-# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
-#
-#    This library is free software; you can redistribute it and/or
-#    modify it under the terms of the GNU Lesser General Public
-#    License as published by the Free Software Foundation; either
-#    version 2.1 of the License, or (at your option) any later version.
-#
-#    This library 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
-#    Lesser General Public License for more details.
-#
-#    You should have received a copy of the GNU Lesser General Public
-#    License along with this library; if not, write to the Free Software
-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
-
-from __future__ import absolute_import, print_function, unicode_literals
-del absolute_import, print_function, unicode_literals
-
-import sys, re
-
-if len(sys.argv) != 2:
-    sys.stderr.write("Usage: %s path/to/[gpgme|gpg-error].h\n" % sys.argv[0])
-    sys.exit(1)
-
-deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
-                         + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
-                         re.S)
-line_break = re.compile(';|\\$|\\x0c|^\s*#|{');
-
-if 'gpgme.h' in sys.argv[1]:
-    gpgme = open(sys.argv[1])
-    tmp = gpgme.readline()
-    text = ''
-    while tmp:
-        text += re.sub(' class ', ' _py_obsolete_class ', tmp)
-        if line_break.search(tmp):
-            if not deprec_func.search(text):
-                sys.stdout.write(text)
-            text = ''
-        tmp = gpgme.readline()
-    sys.stdout.write(text)
-    gpgme.close()
-else:
-    filter_re = re.compile(r'GPG_ERR_[^ ]* =')
-    rewrite_re = re.compile(r' *(.*) = .*')
-    for line in open(sys.argv[1]):
-        if not filter_re.search(line):
-            continue
-        print(rewrite_re.sub(r'%constant long \1 = \1;', line.strip()))
index 6692de6..2114aaf 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
-# Copyright (C) 2016 g10 Code GmbH
-# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2016-2017 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
 # Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
 #
 #    This library is free software; you can redistribute it and/or
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 
 from distutils.core import setup, Extension
+import argparse
 import os, os.path, sys
 import glob
+import re
 import shutil
 import subprocess
 
+# We parse a subset of the arguments.
+parser = argparse.ArgumentParser(add_help=False)
+parser.add_argument('--build-base', default='')
+options, _ = parser.parse_known_args()
+
 # Out-of-tree build of the gpg bindings.
 gpg_error_config = ["gpg-error-config"]
 gpgme_config_flags = ["--thread=pthread"]
@@ -31,6 +38,7 @@ gpgme_config = ["gpgme-config"] + gpgme_config_flags
 gpgme_h = ""
 include_dirs = [os.getcwd()]
 library_dirs = []
+vpath_build = os.environ.get('srcdir', '.') != '.'
 in_tree = False
 extra_swig_opts = []
 extra_macros = dict()
@@ -133,6 +141,14 @@ if uname_s.startswith("MINGW32"):
                library_dirs.append(os.path.join(tgt, item))
                break
 
+def in_srcdir(name):
+    return os.path.join(os.environ.get("srcdir", ""), name)
+def in_build_base(name):
+    return os.path.join(options.build_base, name)
+def up_to_date(source, target):
+    return (os.path.exists(target)
+            and os.path.getmtime(source) <= os.path.getmtime(target))
+
 # We build an Extension using SWIG, which generates a Python module.
 # By default, the 'build_py' step is run before 'build_ext', and
 # therefore the generated Python module is not copied into the build
@@ -143,25 +159,60 @@ if uname_s.startswith("MINGW32"):
 from distutils.command.build import build
 class BuildExtFirstHack(build):
 
+    def _generate_gpgme_h(self, source_name, sink_name):
+        if up_to_date(source_name, sink_name):
+            return
+
+        deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
+                                 + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
+                                 re.S)
+        line_break = re.compile(';|\\$|\\x0c|^\s*#|{')
+
+        with open(sink_name, "w") as sink, open(source_name) as source:
+            text = ''
+            for line in source:
+                text += re.sub(' class ', ' _py_obsolete_class ', line)
+                if line_break.search(line):
+                    if not deprec_func.search(text):
+                        sink.write(text)
+                    text = ''
+            sink.write(text)
+
+    def _generate_errors_i(self, source_name, sink_name):
+        if up_to_date(source_name, sink_name):
+            return
+
+        filter_re = re.compile(r'GPG_ERR_[^ ]* =')
+        rewrite_re = re.compile(r' *(.*) = .*')
+
+        with open(sink_name, "w") as sink, open(source_name) as source:
+            for line in source:
+                if not filter_re.search(line):
+                    continue
+                sink.write(rewrite_re.sub(r'%constant long \1 = \1;'+'\n', line.strip()))
+
     def _generate(self):
         print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
 
         # Cleanup gpgme.h from deprecated functions and typedefs.
-        # Keep timestamp to avoid rebuild
         if not os.path.exists(self.build_base):
             os.makedirs(self.build_base)
 
-        for src, dst in (
-            (gpgme_h, os.path.join(self.build_base, "gpgme.h")),
-            (gpg_error_h, os.path.join(self.build_base, "errors.i"))
-        ):
-            subprocess.check_call([sys.executable, "gpgme-h-clean.py", src],
-                                  stdout=open(dst, "w"))
-            shutil.copystat(src, dst)
+        self._generate_gpgme_h(gpgme_h, in_build_base("gpgme.h"))
+        self._generate_errors_i(gpg_error_h, in_build_base("errors.i"))
+
+        # Keep timestamp to avoid rebuild
+        for source, target in ((gpgme_h, in_build_base("gpgme.h")),
+                               (gpg_error_h, in_build_base("errors.i"))):
+            if not up_to_date(source, target):
+                shutil.copystat(source, target)
 
         # Copy due to http://bugs.python.org/issue2624
         # Avoid creating in srcdir
-        shutil.copy2("gpgme.i", self.build_base)
+        for source, target in ((in_srcdir(n), in_build_base(n))
+                               for n in ('gpgme.i', 'helpers.c')):
+            if not up_to_date(source, target):
+                shutil.copy2(source, target)
 
     def run(self):
         self._generate()
@@ -171,14 +222,18 @@ class BuildExtFirstHack(build):
             os.makedirs(os.path.join(self.build_lib, "gpg"))
 
         swig_sources.append(os.path.join(self.build_base, 'gpgme.i'))
-        swig_opts.extend(['-I' + self.build_base, '-outdir', os.path.join(self.build_lib, 'gpg')])
+        swig_opts.extend(['-I' + self.build_base,
+                          '-I' + in_srcdir('.'),
+                          '-outdir', os.path.join(self.build_lib, 'gpg')])
+        if vpath_build:
+            include_dirs.append(in_srcdir('.'))
         include_dirs.append(self.build_base)
 
         self.run_command('build_ext')
         build.run(self)
 
 py3 = [] if sys.version_info.major < 3 else ['-py3']
-swig_sources = ['helpers.c']
+swig_sources = [in_build_base('helpers.c')]
 swig_opts = ['-threads'] + py3 + extra_swig_opts
 swige = Extension("gpg._gpgme",
                   sources = swig_sources,