Mercurial > libervia-web
diff setup.py @ 1124:28e3eb3bb217
files reorganisation and installation rework:
- files have been reorganised to follow other SàT projects and usual Python organisation (no more "/src" directory)
- VERSION file is now used, as for other SàT projects
- replace the overcomplicated setup.py be a more sane one. Pyjamas part is not compiled anymore by setup.py, it must be done separatly
- removed check for data_dir if it's empty
- installation tested working in virtual env
- libervia launching script is now in bin/libervia
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 25 Aug 2018 17:59:48 +0200 |
parents | 6d6c0694f72a |
children | b251c8bb6776 |
line wrap: on
line diff
--- a/setup.py Sat Aug 11 18:35:37 2018 +0200 +++ b/setup.py Sat Aug 25 17:59:48 2018 +0200 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Libervia: a Salut à Toi frontend -# Copyright (C) 2011-2016 Jérôme Poisson (goffi@goffi.org) +# Copyright (C) 2011-2018 Jérôme Poisson (goffi@goffi.org) # Copyright (C) 2013-2016 Adrien Cossa (souliane@mailoo.org) # This program is free software: you can redistribute it and/or modify @@ -18,293 +18,74 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from ez_setup import use_setuptools -use_setuptools() -from setuptools.command.install import install from setuptools import setup -from distutils.file_util import copy_file import os -import sys -import subprocess -from stat import ST_MODE -import shutil -from src.server.constants import Const as C -import tempfile -# seen here: http://stackoverflow.com/questions/7275295 -try: - from setuptools.command import egg_info - egg_info.write_toplevel_names -except (ImportError, AttributeError): - pass -else: - def _top_level_package(name): - return name.split('.', 1)[0] +NAME = "libervia" - def _hacked_write_toplevel_names(cmd, basename, filename): - pkgs = dict.fromkeys( - [_top_level_package(k) - for k in cmd.distribution.iter_distribution_names() - if _top_level_package(k) != "twisted" - ] - ) - cmd.write_file("top-level names", filename, '\n'.join(pkgs) + '\n') - - egg_info.write_toplevel_names = _hacked_write_toplevel_names - - -NAME = 'libervia' -LAUNCH_DAEMON_COMMAND = 'libervia' +install_requires = [ + "sat", + "sat-templates", + "twisted", + "txJSON-RPC==0.3.1", + "zope.interface", + "pyopenssl", + "jinja2>=2.9", + "shortuuid", + "autobahn", +] +long_description = u"""\ +Libervia is a web frontend for Salut à Toi (SàT), a multi-frontends and multi-purposes XMPP client. +It features chat, blog, forums, events, tickets, merge requests, file sharing, photo albums, etc. +It is also a decentralized, XMPP based web framework. +""" -ENV_LIBERVIA_INSTALL = "LIBERVIA_INSTALL" # environment variable to customise installation -JS_DEBUG = "jsdebug" # use debug mode with pyjsbuild -NO_PREINSTALL_OPT = 'nopreinstall' # skip all preinstallation checks -AUTO_DEB_OPT = 'autodeb' # automaticaly install debs -CLEAN_OPT = 'clean' # remove previous installation directories -PURGE_OPT = 'purge' # remove building and previous installation directories - - -class MercurialException(Exception): - pass - - -def module_installed(module_name): - """Try to import module_name, and return False if it failed - @param module_name: name of the module to test - @return: True if successful""" - try: - __import__(module_name) - except ImportError: - return False - return True +with open(os.path.join(NAME, "VERSION")) as v: + VERSION = v.read().strip() +is_dev_version = VERSION.endswith("D") -class CustomInstall(install): - - def custom_auto_options(self): - """Change options for twistd in the shell script - Mainly change the paths""" - sh_buffer = "" - with open(self.sh_script_path, 'r') as sh_file: - for ori_line in sh_file: - if ori_line.startswith('PLUGIN_OPTIONS='): - dest_line = 'PLUGIN_OPTIONS="-d %s"\n' % self.install_data_dir - elif ori_line.startswith('PYTHON='): - dest_line = 'PYTHON="%s"\n' % sys.executable - else: - dest_line = ori_line - sh_buffer += dest_line - - with open(self.sh_script_path, 'w') as sh_file: - sh_file.write(sh_buffer) - - def custom_create_links(self): - """Create symbolic links to executables""" - # the script which launch the daemon - for source, dest in self.sh_script_links: - if os.path.islink(dest) and os.readlink(dest) != source: - os.remove(dest) # copy_file doesn't force the link update - dest_name, copied = copy_file(source, dest, link='sym') - assert (copied) - # we change the perm in the same way as in the original install_scripts - mode = ((os.stat(dest_name)[ST_MODE]) | 0555) & 07777 - os.chmod(dest_name, mode) - - def pyjs_build(self): - """Build the browser side JS files from Python source.""" - cwd = os.getcwd() - os.chdir(os.path.join('src', 'browser')) - # we must have only certain package in the path, so we create a tmp dir to link only what we need - tmp_dir = tempfile.mkdtemp() - import sat, sat_frontends - os.symlink(os.path.dirname(sat.__file__), os.path.join(tmp_dir,"sat")) # FIXME: only work on unixes - os.symlink(os.path.dirname(sat_frontends.__file__), os.path.join(tmp_dir,"sat_frontends")) # FIXME: only work on unixes - libervia_files = os.path.abspath("../../src") - os.symlink(libervia_files, os.path.join(tmp_dir,"libervia")) # FIXME: only work on unixes - for module in ('libervia_main', 'libervia_test'): - build_args = ['pyjsbuild', module] + (['-d'] if JS_DEBUG in install_opt else []) + ['--no-compile-inplace', '-I', tmp_dir, '-o', self.pyjamas_output_dir] - result = subprocess.call(build_args) - if result != 0: - continue - shutil.rmtree(tmp_dir) - os.chdir(cwd) - return result - - def copy_data_files(self): - # XXX: To copy the JS files couldn't be done with the data_files parameter - # of setuptools.setup because all the files to be copied must exist before - # the call. Also, we need the value of self.install_lib to build the JS - # files (it's not easily predictable as it may vary from one system to - # another), so we can't call pyjsbuild before setuptools.setup. - - html = os.path.join(self.install_data_dir, C.HTML_DIR) - if os.path.isdir(html): - shutil.rmtree(html, ignore_errors=True) - shutil.copytree(self.pyjamas_output_dir, html) +def libervia_dev_version(): + """Use mercurial data to compute version""" - def run(self): - self.sh_script_path = os.path.join(self.install_lib, NAME, 'libervia.sh') - self.sh_script_links = [(self.sh_script_path, os.path.join(self.install_scripts, LAUNCH_DAEMON_COMMAND))] - self.install_data_dir = os.path.join(self.install_data, 'share', NAME) - self.pyjamas_output_dir = os.path.join(os.getcwd(), 'html') - sys.stdout.write('running pre installation stuff\n') - sys.stdout.flush() - if PURGE_OPT in install_opt: - self.purge() - elif CLEAN_OPT in install_opt: - self.clean() - install.run(self) - sys.stdout.write('running post installation stuff\n') - sys.stdout.flush() - try: - build_result = self.pyjs_build() # build after libervia.common is accessible - except OSError as e: - print "can't run pyjsbuild, are you sure pyjamas is installed?\nexception: {}".format(e) - return - if build_result == 127: # TODO: remove magic string # FIXME: seems useless as an OSError is raised if pyjsbuild is not accessible - print "pyjsbuild is not installed or not accessible from the PATH of user '%s'" % os.getenv('USERNAME') - return - if build_result != 0: - print "pyjsbuild failed to build libervia" - return - self.copy_data_files() - self.custom_auto_options() - if not "arch" in install_opt: - self.custom_create_links() + def version_scheme(version): + return VERSION.replace("D", ".dev0") - def confirm(self, message): - """Ask the user for a confirmation""" - message += 'Proceed' - while True: - res = raw_input("%s (y/n)? " % message) - if res not in ['y', 'Y', 'n', 'N']: - print "Your response ('%s') was not one of the expected responses: y, n" % res - message = 'Proceed' - continue - if res in ('y', 'Y'): - return True - return False - - def clean(self, message=None, to_remove=None): - """Clean previous installation directories + def local_scheme(version): + return "+{rev}.{distance}".format(rev=version.node[1:], distance=version.distance) - @param message (str): to use a non-default confirmation message - @param to_remove (str): extra files/directories to remove - """ - if message is None: - message = "Cleaning previous installation directories" - if to_remove is None: - to_remove = [] - for path in [os.path.join(self.install_lib, NAME), - self.install_data_dir, - os.path.join(self.install_data, 'share', 'doc', NAME), - os.path.join(self.install_lib, "%s.egg-info" % self.config_vars['dist_fullname']), - os.path.join(self.install_lib, "%s-py%s.egg-info" % (self.config_vars['dist_fullname'], self.config_vars['py_version_short'])), - ]: - if os.path.isdir(path): - to_remove.append(path) - for source, dest in self.sh_script_links: - if os.path.islink(dest): - to_remove.append(dest) - plugin_file = os.path.join(self.install_lib, 'twisted', 'plugins', NAME) - if os.path.isfile(plugin_file): - to_remove.append(plugin_file) - - message = "%s:\n%s\n" % (message, "\n".join([" %s" % path for path in to_remove])) - if not self.confirm(message): - return - sys.stdout.write('cleaning previous installation directories...\n') - sys.stdout.flush() - for path in to_remove: - if os.path.isdir(path): - shutil.rmtree(path, ignore_errors=True) - else: - os.remove(path) - - def purge(self): - """Clean building and previous installation directories""" - message = "Cleaning building and previous installation directories" - to_remove = [os.path.join(os.getcwd(), 'build'), self.pyjamas_output_dir] - self.clean(message, to_remove) + return {"version_scheme": version_scheme, "local_scheme": local_scheme} -def preinstall_check(install_opt): - """Check presence of problematic dependencies, and try to install them with package manager - This ugly stuff is necessary as distributions are not installed correctly with setuptools/distribute - Hope to remove this at some point""" - - modules_tocheck = [] # if empty this method is dummy - - package = {'twisted': 'python-twisted-core', - 'twisted.words': 'python-twisted-words', - 'twisted.web': 'python-twisted-web', - 'mercurial': 'mercurial'} # this dict map dependencies to packages names for debian distributions - - sys.stdout.write("Running pre-installation dependencies check\n") - - # which modules are not installed ? - modules_toinstall = [mod for mod in modules_tocheck if not module_installed(mod)] - """# is mercurial available ? - hg_installed = subprocess.call('which hg', stdout=open('/dev/null', 'w'), shell=True) == 0 - if not hg_installed: - modules_toinstall.append('mercurial')""" # hg can be installed from pypi - - if modules_toinstall: - if AUTO_DEB_OPT in install_opt: # auto debian installation is requested - # are we on a distribution using apt ? - apt_path = subprocess.Popen('which apt-get', stdout=subprocess.PIPE, shell=True).communicate()[0][:-1] - else: - apt_path = None - - not_installed = set() - if apt_path: - # we have apt, we'll try to use it - for module_name in modules_toinstall: - package_name = package[module_name] - sys.stdout.write("Installing %s\n" % package_name) - success = subprocess.call('%s -qy install %s' % (apt_path, package_name), shell=True) == 0 - if not success: - not_installed.add(module_name) - else: - not_installed = set(modules_toinstall) - - if not_installed: - # some packages can't be automatically installed, we print their name for manual installation - sys.stdout.write("You should install the following dependencies with your distribution recommanded tool before installing %s:\n" % NAME) - for module_name in not_installed: - sys.stdout.write("- %s (Debian name: %s)\n" % (module_name, package[module_name])) - sys.exit(2) - - -if sys.argv[1].lower() in ['egg_info', 'install']: - # we only check dependencies if egg_info or install is used - install_opt = os.environ.get(ENV_LIBERVIA_INSTALL, "").split() - if not NO_PREINSTALL_OPT in install_opt: # user can force preinstall skipping - preinstall_check(install_opt) - -setup(name=NAME, - version='0.7.0a2.post1', - description=u'Web frontend for Salut à Toi', - long_description=u'Libervia is a web frontend for Salut à Toi (SàT), a multi-frontends and multi-purposes XMPP client.', - author='Association « Salut à Toi »', - author_email='contact@goffi.org', - url='http://www.salut-a-toi.org', - classifiers=['Development Status :: 3 - Alpha', - 'Environment :: Web Environment', - 'Framework :: Twisted', - 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', - 'Operating System :: POSIX :: Linux', - 'Topic :: Communications :: Chat'], - package_dir={'libervia': 'src', 'twisted.plugins': 'src/twisted/plugins'}, - packages=['libervia', 'libervia.common', 'libervia.server', 'twisted.plugins'], - package_data={'libervia': ['libervia.sh']}, - include_package_data=True, - data_files=[(os.path.join('share', 'doc', NAME), ['COPYING', 'README', 'INSTALL']), ] + - [(os.path.join('share', NAME, root), - [os.path.join(root, f) for f in files]) - for root, dirs, files in os.walk(C.THEMES_DIR)], - scripts=[], - zip_safe=False, - install_requires=['sat', 'twisted', 'txJSON-RPC==0.3.1', 'zope.interface', 'pyopenssl', 'jinja2>=2.9', 'shortuuid', 'autobahn'], - cmdclass={'install': CustomInstall}, - ) +setup( + name=NAME, + version=VERSION, + description=u"Web frontend for Salut à Toi", + long_description=long_description, + author="Association « Salut à Toi »", + author_email="contact@goffi.org", + url="https://www.salut-a-toi.org", + classifiers=[ + "Development Status :: 3 - Alpha", + "Environment :: Web Environment", + "Framework :: Twisted", + "License :: OSI Approved :: GNU Affero General Public License v3 " + "or later (AGPLv3+)", + "Operating System :: POSIX :: Linux", + "Topic :: Communications :: Chat", + ], + packages=["libervia", "libervia.common", "libervia.server", "twisted.plugins"], + include_package_data=True, + data_files=[(os.path.join("share", "doc", NAME), ["COPYING", "README", "INSTALL"])] + + [ + (os.path.join("share", NAME, root), [os.path.join(root, f) for f in files]) + for root, dirs, files in os.walk(u"themes") + ], + scripts=["bin/libervia"], + zip_safe=False, + setup_requires=["setuptools_scm"] if is_dev_version else [], + use_scm_version=libervia_dev_version if is_dev_version else False, + install_requires=install_requires, + package_data={"libervia": ["VERSION"]}, + python_requires="~=2.7", +)