URL: https://github.com/freeipa/freeipa/pull/379 Author: tiran Title: #379: Packaging: Add placeholder and IPA commands packages Action: opened
PR body: """ The ipacommands package contains ipa-getkeytab and ipa-rmkeytab for installation in a virtual env. The programs are compiled with distutils / setuptools. The ipa and freeipa packages are placeholders to prevent PyPI squashing attacks and reserve the names for future use. `pip install ipa` installs ipaclient. https://fedorahosted.org/freeipa/ticket/6484 Signed-off-by: Christian Heimes <chei...@redhat.com> """ 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 b01a51e15c86601806318d5d096ac5286afbfbd7 Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Mon, 9 Jan 2017 11:02:25 +0100 Subject: [PATCH] Packaging: Add placeholder and IPA commands packages The ipacommands package contains ipa-getkeytab and ipa-rmkeytab for installation in a virtual env. The programs are compiled with distutils / setuptools. The ipa and freeipa packages are placeholders to prevent PyPI squashing attacks and reserve the names for future use. `pip install ipa` installs ipaclient. https://fedorahosted.org/freeipa/ticket/6484 Signed-off-by: Christian Heimes <chei...@redhat.com> --- .gitignore | 7 ++ Makefile.am | 5 +- configure.ac | 4 + packaging/Makefile.am | 11 +++ packaging/freeipa/Makefile.am | 1 + packaging/freeipa/README.txt | 2 + packaging/freeipa/setup.cfg | 6 ++ packaging/freeipa/setup.py | 36 +++++++ packaging/ipa/Makefile.am | 1 + packaging/ipa/README.txt | 2 + packaging/ipa/setup.cfg | 6 ++ packaging/ipa/setup.py | 36 +++++++ packaging/ipacommands/MANIFEST.in | 25 +++++ packaging/ipacommands/Makefile.am | 72 ++++++++++++++ packaging/ipacommands/setup.cfg | 5 + packaging/ipacommands/setup.py | 194 ++++++++++++++++++++++++++++++++++++++ 16 files changed, 412 insertions(+), 1 deletion(-) create mode 100644 packaging/Makefile.am create mode 100644 packaging/freeipa/Makefile.am create mode 100644 packaging/freeipa/README.txt create mode 100644 packaging/freeipa/setup.cfg create mode 100755 packaging/freeipa/setup.py create mode 100644 packaging/ipa/Makefile.am create mode 100644 packaging/ipa/README.txt create mode 100644 packaging/ipa/setup.cfg create mode 100755 packaging/ipa/setup.py create mode 100644 packaging/ipacommands/MANIFEST.in create mode 100644 packaging/ipacommands/Makefile.am create mode 100644 packaging/ipacommands/setup.cfg create mode 100644 packaging/ipacommands/setup.py diff --git a/.gitignore b/.gitignore index 6dcda76..ab00e98 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,10 @@ freeipa2-dev-doc /ipaplatform/paths.py /ipaplatform/services.py /ipaplatform/tasks.py + +/packaging/ipacommands/COPYING +/packaging/ipacommands/Contributors.txt +/packaging/ipacommands/asn1 +/packaging/ipacommands/client +/packaging/ipacommands/ipasetup.py +/packaging/ipacommands/util diff --git a/Makefile.am b/Makefile.am index 9bfc899..e25cea3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 IPACLIENT_SUBDIRS = ipaclient ipalib ipapython -SUBDIRS = asn1 util client contrib daemons init install $(IPACLIENT_SUBDIRS) ipaplatform ipaserver ipatests po +SUBDIRS = asn1 util client contrib daemons init install $(IPACLIENT_SUBDIRS) ipaplatform ipaserver ipatests packaging po MOSTLYCLEANFILES = ipasetup.pyc ipasetup.pyo \ ignore_import_errors.pyc ignore_import_errors.pyo \ @@ -202,6 +202,9 @@ $(WHEELBUNDLEDIR): mkdir -p $(WHEELBUNDLEDIR) bdist_wheel: $(WHEELDISTDIR) + $(MAKE) $(AM_MAKEFLAGS) -C packaging/ipacommands sdist || exit 1; + $(MAKE) $(AM_MAKEFLAGS) -C packaging/ipa bdist_wheel || exit 1; + $(MAKE) $(AM_MAKEFLAGS) -C packaging/freeipa bdist_wheel || exit 1; for dir in $(IPACLIENT_SUBDIRS); do \ $(MAKE) $(AM_MAKEFLAGS) -C $${dir} $@ || exit 1; \ done diff --git a/configure.ac b/configure.ac index e8a4701..58988f8 100644 --- a/configure.ac +++ b/configure.ac @@ -553,6 +553,10 @@ AC_CONFIG_FILES([ ipaserver/Makefile ipatests/Makefile ipatests/man/Makefile + packaging/Makefile + packaging/freeipa/Makefile + packaging/ipa/Makefile + packaging/ipacommands/Makefile po/Makefile.in po/Makefile.hack util/Makefile diff --git a/packaging/Makefile.am b/packaging/Makefile.am new file mode 100644 index 0000000..e033673 --- /dev/null +++ b/packaging/Makefile.am @@ -0,0 +1,11 @@ +# This file will be processed with automake-1.7 to create Makefile.in +# +AUTOMAKE_OPTIONS = 1.7 subdir-objects + +NULL = + +SUBDIRS = \ + freeipa \ + ipa \ + ipacommands \ + $(NULL) diff --git a/packaging/freeipa/Makefile.am b/packaging/freeipa/Makefile.am new file mode 100644 index 0000000..8be72b2 --- /dev/null +++ b/packaging/freeipa/Makefile.am @@ -0,0 +1 @@ +include $(top_srcdir)/Makefile.python.am diff --git a/packaging/freeipa/README.txt b/packaging/freeipa/README.txt new file mode 100644 index 0000000..b58448f --- /dev/null +++ b/packaging/freeipa/README.txt @@ -0,0 +1,2 @@ +This is a dummy package for FreeIPA's ipaclient. + diff --git a/packaging/freeipa/setup.cfg b/packaging/freeipa/setup.cfg new file mode 100644 index 0000000..62f65c7 --- /dev/null +++ b/packaging/freeipa/setup.cfg @@ -0,0 +1,6 @@ +[bdist_wheel] +universal = 1 + +[aliases] +packages = clean --all egg_info bdist_wheel +release = packages register upload diff --git a/packaging/freeipa/setup.py b/packaging/freeipa/setup.py new file mode 100755 index 0000000..9534c09 --- /dev/null +++ b/packaging/freeipa/setup.py @@ -0,0 +1,36 @@ +# Copyright (C) 2016 Red Hat +# see file 'COPYING' for use and warranty information +# +# 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>. +# +"""Dummy package for FreeIPA + +Please install ipaclient instead. +""" + +from os.path import abspath, dirname +import sys + +if __name__ == '__main__': + # include ../../ for ipasetup.py + sys.path.append(dirname(dirname(dirname(abspath(__file__))))) + from ipasetup import ipasetup # noqa: E402 + + ipasetup( + name='freeipa', + doc = __doc__, + install_requires=[ + "ipaclient", + ] + ) diff --git a/packaging/ipa/Makefile.am b/packaging/ipa/Makefile.am new file mode 100644 index 0000000..8be72b2 --- /dev/null +++ b/packaging/ipa/Makefile.am @@ -0,0 +1 @@ +include $(top_srcdir)/Makefile.python.am diff --git a/packaging/ipa/README.txt b/packaging/ipa/README.txt new file mode 100644 index 0000000..b58448f --- /dev/null +++ b/packaging/ipa/README.txt @@ -0,0 +1,2 @@ +This is a dummy package for FreeIPA's ipaclient. + diff --git a/packaging/ipa/setup.cfg b/packaging/ipa/setup.cfg new file mode 100644 index 0000000..62f65c7 --- /dev/null +++ b/packaging/ipa/setup.cfg @@ -0,0 +1,6 @@ +[bdist_wheel] +universal = 1 + +[aliases] +packages = clean --all egg_info bdist_wheel +release = packages register upload diff --git a/packaging/ipa/setup.py b/packaging/ipa/setup.py new file mode 100755 index 0000000..16b3310 --- /dev/null +++ b/packaging/ipa/setup.py @@ -0,0 +1,36 @@ +# Copyright (C) 2016 Red Hat +# see file 'COPYING' for use and warranty information +# +# 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>. +# +"""Dummy package for FreeIPA + +Please install ipaclient instead. +""" + +from os.path import abspath, dirname +import sys + +if __name__ == '__main__': + # include ../../ for ipasetup.py + sys.path.append(dirname(dirname(dirname(abspath(__file__))))) + from ipasetup import ipasetup # noqa: E402 + + ipasetup( + name='ipa', + doc = __doc__, + install_requires=[ + "ipaclient", + ] + ) diff --git a/packaging/ipacommands/MANIFEST.in b/packaging/ipacommands/MANIFEST.in new file mode 100644 index 0000000..659a1f5 --- /dev/null +++ b/packaging/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/packaging/ipacommands/Makefile.am b/packaging/ipacommands/Makefile.am new file mode 100644 index 0000000..b9c46fb --- /dev/null +++ b/packaging/ipacommands/Makefile.am @@ -0,0 +1,72 @@ +# 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 + ln -sf $< + +client: $(top_srcdir)/client + ln -sf $< + +util: $(top_srcdir)/util + ln -sf $< + +# 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: $(top_builddir)/ipasetup.py + $(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) + + +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/packaging/ipacommands/setup.cfg b/packaging/ipacommands/setup.cfg new file mode 100644 index 0000000..ccffb47 --- /dev/null +++ b/packaging/ipacommands/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal = 0 + +[metadata] +license_file = COPYING diff --git a/packaging/ipacommands/setup.py b/packaging/ipacommands/setup.py new file mode 100644 index 0000000..e50ee50 --- /dev/null +++ b/packaging/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