URL: https://github.com/freeipa/freeipa/pull/379 Author: tiran Title: #379: Packaging: Add IPA commands package Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/379/head:pr379 git checkout pr379
From 0544a3834cb23d0664300d1f577a1d30ccc59610 Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Thu, 16 Feb 2017 15:27:49 +0100 Subject: [PATCH] Packaging: Add IPA commands package The ipacommands package contains ipa-getkeytab and ipa-rmkeytab for installation in a virtual env. The programs are compiled with distutils / setuptools. https://fedorahosted.org/freeipa/ticket/6484 Signed-off-by: Christian Heimes <chei...@redhat.com> --- .gitignore | 7 ++ Makefile.am | 2 + configure.ac | 1 + pypi/Makefile.am | 1 + pypi/ipacommands/MANIFEST.in | 25 ++++++ pypi/ipacommands/Makefile.am | 79 ++++++++++++++++++ pypi/ipacommands/setup.cfg | 5 ++ pypi/ipacommands/setup.py | 194 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 314 insertions(+) create mode 100644 pypi/ipacommands/MANIFEST.in create mode 100644 pypi/ipacommands/Makefile.am create mode 100644 pypi/ipacommands/setup.cfg create mode 100644 pypi/ipacommands/setup.py diff --git a/.gitignore b/.gitignore index 8b57dbc..e18bcf0 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,10 @@ freeipa2-dev-doc /ipaplatform/paths.py /ipaplatform/services.py /ipaplatform/tasks.py + +/pypi/ipacommands/COPYING +/pypi/ipacommands/Contributors.txt +/pypi/ipacommands/asn1 +/pypi/ipacommands/client +/pypi/ipacommands/ipasetup.py +/pypi/ipacommands/util diff --git a/Makefile.am b/Makefile.am index cbe4f2d..b395033 100644 --- a/Makefile.am +++ b/Makefile.am @@ -285,6 +285,8 @@ bdist_wheel: $(WHEELDISTDIR) for dir in $(IPA_WHEEL_PACKAGES) ipatests; do \ $(MAKE) $(AM_MAKEFLAGS) -C $${dir} $@ || exit 1; \ done + rm -f $(WHEELDISTDIR)/ipacommands-*.tar.gz + $(MAKE) $(AM_MAKEFLAGS) -C pypi/ipacommands sdist || exit 1; wheel_bundle: $(WHEELBUNDLEDIR) bdist_wheel .wheelconstraints rm -f $(foreach item,$(IPA_WHEEL_PACKAGES) ipatests,$(WHEELBUNDLEDIR)/$(item)-*.whl) diff --git a/configure.ac b/configure.ac index c43759c..24e9408 100644 --- a/configure.ac +++ b/configure.ac @@ -593,6 +593,7 @@ AC_CONFIG_FILES([ pypi/Makefile pypi/freeipa/Makefile pypi/ipa/Makefile + pypi/ipacommands/Makefile pypi/ipaplatform/Makefile pypi/ipaserver/Makefile pypi/ipatests/Makefile diff --git a/pypi/Makefile.am b/pypi/Makefile.am index 5d8be9c..be572c6 100644 --- a/pypi/Makefile.am +++ b/pypi/Makefile.am @@ -7,6 +7,7 @@ NULL = SUBDIRS = \ freeipa \ ipa \ + ipacommands \ ipaplatform \ ipaserver \ ipatests \ diff --git a/pypi/ipacommands/MANIFEST.in b/pypi/ipacommands/MANIFEST.in new file mode 100644 index 0000000..659a1f5 --- /dev/null +++ b/pypi/ipacommands/MANIFEST.in @@ -0,0 +1,25 @@ +include asn1/*.c +include asn1/*.h +include asn1/asn1c/*.c +include asn1/asn1c/*.h +include asn1/asn1c/ipa.asn1 + +include client/config.c +include client/config.h +include client/ipa-client-common.c +include client/ipa-client-common.h +include client/ipa-getkeytab.c +include client/ipa-join.c +include client/ipa-rmkeytab.c + +include util/ipa_krb5.c +include util/ipa_krb5.h + +prune client/asn1 +prune client/client +prune client/util + +include Contributors.txt COPYING +include config.h +include ipasetup.py +include setup.cfg diff --git a/pypi/ipacommands/Makefile.am b/pypi/ipacommands/Makefile.am new file mode 100644 index 0000000..645ce7a --- /dev/null +++ b/pypi/ipacommands/Makefile.am @@ -0,0 +1,79 @@ +# This file will be processed with automake-1.7 to create Makefile.in +# +AUTOMAKE_OPTIONS = 1.7 + +NULL = + +pkgname = $(shell basename "$(abs_srcdir)") + +# hack to handle back-in-the-hierarchy depedency on ipasetup.py +.PHONY: $(top_builddir)/ipasetup.py +$(top_builddir)/ipasetup.py: + (cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) ipasetup.py) + +DEPENDENCIES = \ + asn1 \ + client \ + util \ + COPYING \ + Contributors.txt \ + config.h \ + ipasetup.py \ + $(NULL) + +# Python setup.py can handle symlinks to directories fine +asn1: $(top_srcdir)/asn1 + if [ ! -e "$@" ]; then ln -rs "$<"; fi + +client: $(top_srcdir)/client + if [ ! -e "$@" ]; then ln -rs "$<"; fi + +util: $(top_srcdir)/util + if [ ! -e "$@" ]; then ln -rs "$<"; fi + +# On the other hand files must be copied to create proper sdist +COPYING: $(top_srcdir)/COPYING + cp -p "$<" "$@" + +Contributors.txt: $(top_srcdir)/Contributors.txt + cp -p "$<" "$@" + +ipasetup.py: $(top_builddir)/ipasetup.py + cp -p "$<" "$@" + +config.h: $(top_builddir)/config.h + cp -p "$<" "$@" + + +all-local: $(DEPENDENCIES) + + +check-local: $(DEPENDENCIES) + cd $(srcdir); $(PYTHON) setup.py \ + $(VERBOSITY) \ + build \ + --build-base "$(abs_builddir)/build" + +clean-local: $(DEPENDENCIES) + $(PYTHON) "$(srcdir)/setup.py" clean --all + rm -rf "$(srcdir)/build" "$(srcdir)/dist" "$(srcdir)/MANIFEST" + find "$(srcdir)" \ + -name "*.py[co]" -delete -o \ + -name "__pycache__" -delete -o \ + -name "*.egg-info" -exec rm -rf {} + + rm -f $(DEPENDENCIES) + +dist-hook: $(DEPENDENCIES) + $(PYTHON) "$(srcdir)/setup.py" egg_info + PYTHON_SOURCES=$$(cat "$(srcdir)/$(pkgname).egg-info/SOURCES.txt") || exit $$?; \ + for FILEN in $${PYTHON_SOURCES}; \ + do \ + if test -x "$(srcdir)/$${FILEN}"; then MODE=755; else MODE=644; fi; \ + $(INSTALL) -D -m $${MODE} "$(srcdir)/$${FILEN}" "$(distdir)/$${FILEN}" || exit $$?; \ + done + +WHEELDISTDIR = $(top_builddir)/dist/wheels +.PHONY: sdist +sdist: $(DEPENDENCIES) + rm -rf $(WHEELDISTDIR)/$(pkgname)*.tar.gz + $(PYTHON) "$(srcdir)/setup.py" sdist --format=gztar --dist-dir=$(WHEELDISTDIR) diff --git a/pypi/ipacommands/setup.cfg b/pypi/ipacommands/setup.cfg new file mode 100644 index 0000000..ccffb47 --- /dev/null +++ b/pypi/ipacommands/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal = 0 + +[metadata] +license_file = COPYING diff --git a/pypi/ipacommands/setup.py b/pypi/ipacommands/setup.py new file mode 100644 index 0000000..e50ee50 --- /dev/null +++ b/pypi/ipacommands/setup.py @@ -0,0 +1,194 @@ +"""IPA commands +""" +import glob +import os +import shlex +import subprocess +import sys + +from distutils import unixccompiler +from distutils.command.build_scripts import build_scripts \ + as distutils_build_scripts +from setuptools import Extension +from setuptools.command.build_ext import build_ext as setuptools_build_ext +from setuptools.command.install_lib import install_lib \ + as setuptools_install_lib + + +class CustomUnixCCompiler(unixccompiler.UnixCCompiler): + """Custom unix C compiler + + Redirect link_shared_object to link_executable + """ + + def link_shared_object(self, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, + runtime_library_dirs=None, export_symbols=None, + debug=0, extra_preargs=None, extra_postargs=None, + build_temp=None, target_lang=None): + # unused: export_symbols, build_temp + # remove pythonX.Y lib + libraries = list( + lib for lib in libraries + if not lib.startswith('python') + ) + return self.link_executable( + objects, + output_progname=output_filename, + output_dir=output_dir, + libraries=libraries, library_dirs=library_dirs, + runtime_library_dirs=runtime_library_dirs, + debug=debug, extra_preargs=extra_preargs, + extra_postargs=extra_postargs, + target_lang=target_lang) + + def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): + return libraries, library_dirs, runtime_library_dirs + + +# distutils does not have an API to override compiler class. +# Let's monkey patch! +unixccompiler.UnixCCompiler = CustomUnixCCompiler + + +class build_ext(setuptools_build_ext): + """Custom build_ext + + Don't add '.so' extension + """ + def get_ext_filename(self, ext_name): + return ext_name + + +class build_scripts(distutils_build_scripts): + """Custom build_scripts + + Copy executables form build_lib to script dir. + """ + def run(self): + # run and get build_ext + self.run_command('build_ext') + build_ext = self.get_finalized_command('build_ext') + for i, name in enumerate(self.scripts): + libfile = os.path.join(build_ext.build_lib, name) + # add binary as script + self.scripts[i] = libfile + distutils_build_scripts.run(self) + + def copy_scripts(self): + # simple version of copy_script that does not try to read the + # executable as Python scripts. + self.mkpath(self.build_dir) + outfiles = [] + for script in self.scripts: + outfile = os.path.join(self.build_dir, os.path.basename(script)) + self.copy_file(script, outfile) + os.chmod(outfile, 0o755) + outfiles.append(outfile) + return outfiles, outfiles + + +class install_lib(setuptools_install_lib): + """Custom install_lib + + Don't install the executables as libraries. + """ + def install(self): + return [] + + +def pkgconfig(flags, *pkgs): + cmd = ['pkg-config', flags] + cmd.extend(pkgs) + out = subprocess.check_output(cmd) + if isinstance(out, bytes): + out = out.decode(sys.getfilesystemencoding()) + return shlex.split(out) + + +def get_extensions(ipajoin=False): + cfiles = [ + 'asn1/ipa_asn1.c', + 'client/config.c', + 'client/ipa-client-common.c', + 'util/ipa_krb5.c' + ] + glob.glob('asn1/asn1c/*.c') + + headers = [ + 'config.h', + 'asn1/ipa_asn1.h', + 'client/config.h', + 'client/ipa-client-common.h', + 'util/ipa_krb5.h' + ] + glob.glob('asn1/asn1c/*.h') + + include_dirs = ['.', 'asn1', 'asn1/asn1c', 'client', 'util'] + + pkgs = ('nss', 'krb5', 'libcrypto', 'popt', 'libsasl2', 'ini_config') + + extra_compile_args = [] + extra_compile_args.extend(pkgconfig('--cflags', *pkgs)) + + extra_link_args = ['-lldap_r', '-llber'] # OpenLDAP has no .pc + extra_link_args.extend(pkgconfig('--libs', *pkgs)) + + macros = [ + ('IPACONFFILE', '"/etc/ipa/default.conf"'), + ('LOCALEDIR', '"/usr/share/locale"'), + ] + + extensions = [ + Extension( + 'ipa-getkeytab', + sources=['client/ipa-getkeytab.c'] + cfiles, + depends=headers, + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, + include_dirs=include_dirs, + define_macros=macros, + ), + Extension( + 'ipa-rmkeytab', + sources=['client/ipa-rmkeytab.c'] + cfiles, + depends=headers, + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, + include_dirs=include_dirs, + define_macros=macros, + ), + ] + + if ipajoin: + xmlrpc_compile_args = pkgconfig('--cflags', 'xmlrpc_client') + xmlrpc_link_args = pkgconfig('--libs', 'xmlrpc_client') + extensions.append( + Extension( + 'ipa-join', + sources=['client/ipa-join.c'] + cfiles, + depends=headers, + extra_compile_args=extra_compile_args + xmlrpc_compile_args, + extra_link_args=extra_link_args + xmlrpc_link_args, + include_dirs=include_dirs, + define_macros=macros, + ) + ) + + return extensions + + +if __name__ == '__main__': + from ipasetup import ipasetup # noqa: E402 + + exts = get_extensions(ipajoin=False) + + ipasetup( + name='ipacommands', + doc=__doc__, + ext_modules=exts, + cmdclass={ + 'build_ext': build_ext, + 'build_scripts': build_scripts, + 'install_lib': install_lib, + }, + scripts=[ext.name for ext in exts], + )
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code