comparison setup.py @ 449:981ed669d3b3

/!\ reorganize all the file hierarchy, move the code and launching script to src: - browser_side --> src/browser - public --> src/browser_side/public - libervia.py --> src/browser/libervia_main.py - libervia_server --> src/server - libervia_server/libervia.sh --> src/libervia.sh - twisted --> src/twisted - new module src/common - split constants.py in 3 files: - src/common/constants.py - src/browser/constants.py - src/server/constants.py - output --> html (generated by pyjsbuild during the installation) - new option/parameter "data_dir" (-d) to indicates the directory containing html and server_css - setup.py installs libervia to the following paths: - src/common --> <LIB>/libervia/common - src/server --> <LIB>/libervia/server - src/twisted --> <LIB>/twisted - html --> <SHARE>/libervia/html - server_side --> <SHARE>libervia/server_side - LIBERVIA_INSTALL environment variable takes 2 new options with prompt confirmation: - clean: remove previous installation directories - purge: remove building and previous installation directories You may need to update your sat.conf and/or launching script to update the following options/parameters: - ssl_certificate - data_dir
author souliane <souliane@mailoo.org>
date Tue, 20 May 2014 06:41:16 +0200
parents f94c3caea2ba
children 1a0cec9b0f1e
comparison
equal deleted inserted replaced
448:14c35f7f1ef5 449:981ed669d3b3
1 #!/usr/bin/python 1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 3
4 # Libervia: a Salut à Toi frontend 4 # Libervia: a Salut à Toi frontend
5 # Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org> 5 # Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
6 # Copyright (C) 2013, 2014 Adrien Cossa (souliane@mailoo.org)
6 7
7 # This program is free software: you can redistribute it and/or modify 8 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by 9 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or 10 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version. 11 # (at your option) any later version.
24 from distutils.file_util import copy_file 25 from distutils.file_util import copy_file
25 import os 26 import os
26 import sys 27 import sys
27 import subprocess 28 import subprocess
28 from stat import ST_MODE 29 from stat import ST_MODE
30 import shutil
31 from src.server.constants import Const as C
29 32
30 # seen here: http://stackoverflow.com/questions/7275295 33 # seen here: http://stackoverflow.com/questions/7275295
31 try: 34 try:
32 from setuptools.command import egg_info 35 from setuptools.command import egg_info
33 egg_info.write_toplevel_names 36 egg_info.write_toplevel_names
50 53
51 54
52 NAME = 'libervia' 55 NAME = 'libervia'
53 LAUNCH_DAEMON_COMMAND = 'libervia' 56 LAUNCH_DAEMON_COMMAND = 'libervia'
54 57
58 ENV_LIBERVIA_INSTALL = "LIBERVIA_INSTALL" # environment variable to customise installation
59 NO_PREINSTALL_OPT = 'nopreinstall' # skip all preinstallation checks
60 AUTO_DEB_OPT = 'autodeb' # automaticaly install debs
61 CLEAN_OPT = 'clean' # remove previous installation directories
62 PURGE_OPT = 'purge' # remove building and previous installation directories
63
55 64
56 class MercurialException(Exception): 65 class MercurialException(Exception):
57 pass 66 pass
58 67
59 68
76 sh_buffer = "" 85 sh_buffer = ""
77 run_dir = os.path.dirname(self.sh_script_path) 86 run_dir = os.path.dirname(self.sh_script_path)
78 with open(self.sh_script_path, 'r') as sh_file: 87 with open(self.sh_script_path, 'r') as sh_file:
79 for ori_line in sh_file: 88 for ori_line in sh_file:
80 if ori_line.startswith('DAEMON='): 89 if ori_line.startswith('DAEMON='):
81 dest_line = 'DAEMON=""\n' # we want to launch sat as a daemon 90 dest_line = 'DAEMON=""\n' # we want to launch libervia as a daemon
82 elif ori_line.startswith('TAP_PATH='): 91 elif ori_line.startswith('DATA_DIR='):
83 dest_line = 'TAP_PATH="%s/"\n' % run_dir 92 dest_line = 'DATA_DIR="%s"\n' % self.install_data_dir
84 elif ori_line.startswith('PYTHON='): 93 elif ori_line.startswith('PYTHON='):
85 dest_line = 'PYTHON="%s"\n' % sys.executable 94 dest_line = 'PYTHON="%s"\n' % sys.executable
86 else: 95 else:
87 dest_line = ori_line 96 dest_line = ori_line
88 sh_buffer += dest_line 97 sh_buffer += dest_line
91 sh_file.write(sh_buffer) 100 sh_file.write(sh_buffer)
92 101
93 def custom_create_links(self): 102 def custom_create_links(self):
94 """Create symbolic links to executables""" 103 """Create symbolic links to executables"""
95 # the script which launch the daemon 104 # the script which launch the daemon
96 links = [(self.sh_script_path, LAUNCH_DAEMON_COMMAND)] 105 for source, dest in self.sh_script_links:
97 for source, dest in links: 106 dest = os.path.join(self.install_scripts, dest)
98 dest_name, copied = copy_file(source, os.path.join(self.install_scripts, dest), link='sym') 107 if os.path.islink(dest) and os.readlink(dest) != source:
108 os.remove(dest) # copy_file doesn't force the link update
109 dest_name, copied = copy_file(source, dest, link='sym')
99 assert (copied) 110 assert (copied)
100 # we change the perm in the same way as in the original install_scripts 111 # we change the perm in the same way as in the original install_scripts
101 mode = ((os.stat(dest_name)[ST_MODE]) | 0555) & 07777 112 mode = ((os.stat(dest_name)[ST_MODE]) | 0555) & 07777
102 os.chmod(dest_name, mode) 113 os.chmod(dest_name, mode)
103 114
104 def pyjs_build(self): 115 def pyjs_build(self):
105 return subprocess.call('pyjsbuild libervia --no-compile-inplace -m -I %s' % self.install_lib, shell=True) 116 """Build the browser side JS files from Python source."""
117 cwd = os.getcwd()
118 os.chdir(os.path.join('src', 'browser'))
119 result = subprocess.call('pyjsbuild libervia_main --no-compile-inplace -I %s -o %s' %
120 (self.install_lib, self.pyjamas_output_dir), shell=True)
121 os.chdir(cwd)
122 return result
123
124 def copy_data_files(self):
125 """To copy the JS files couldn't be done with the data_files parameter
126 of setuptools.setup because all the files to be copied must exist before
127 the call. Also, we need the value of self.install_lib to build the JS
128 files (it's not easily predictable as it may vary from one system to
129 another), so we can't call pyjsbuild before setuptools.setup.
130 """
131 html = os.path.join(self.install_data_dir, C.HTML_DIR)
132 if os.path.isdir(html):
133 shutil.rmtree(html, ignore_errors=True)
134 shutil.copytree(self.pyjamas_output_dir, html)
106 135
107 def run(self): 136 def run(self):
137 self.sh_script_path = os.path.join(self.install_lib, NAME, 'libervia.sh')
138 self.sh_script_links = [(self.sh_script_path, LAUNCH_DAEMON_COMMAND)]
139 self.install_data_dir = os.path.join(self.install_data, 'share', NAME)
140 self.pyjamas_output_dir = os.path.join(os.getcwd(), 'html')
108 sys.stdout.write('running pre installation stuff\n') 141 sys.stdout.write('running pre installation stuff\n')
109 sys.stdout.flush() 142 sys.stdout.flush()
110 build_result = self.pyjs_build() 143 if PURGE_OPT in install_opt:
144 self.purge()
145 elif CLEAN_OPT in install_opt:
146 self.clean()
147 install.run(self)
148 sys.stdout.write('running post installation stuff\n')
149 sys.stdout.flush()
150 build_result = self.pyjs_build() # build after libervia.common is accessible
111 if build_result == 127: # TODO: remove magic string 151 if build_result == 127: # TODO: remove magic string
112 print "pyjsbuild is not installed or not accessible from the PATH of user '%s'" % os.getenv('USERNAME') 152 print "pyjsbuild is not installed or not accessible from the PATH of user '%s'" % os.getenv('USERNAME')
113 return 153 return
114 if build_result != 0: 154 if build_result != 0:
115 print "pyjsbuild failed to build libervia" 155 print "pyjsbuild failed to build libervia"
116 return 156 return
117 install.run(self) 157 self.copy_data_files()
118 sys.stdout.write('running post installation stuff\n')
119 sys.stdout.flush()
120 self.sh_script_path = os.path.join(self.install_lib, 'libervia_server', 'libervia.sh')
121 self.custom_auto_options() 158 self.custom_auto_options()
122 self.custom_create_links() 159 self.custom_create_links()
123 160
124 161 def confirm(self, message):
125 def preinstall_check(): 162 """Ask the user for a confirmation"""
163 message += 'Proceed'
164 while True:
165 res = raw_input("%s (y/n)? " % message)
166 if res not in ['y', 'Y', 'n', 'N']:
167 print "Your response ('%s') was not one of the expected responses: y, n" % res
168 message = 'Proceed'
169 continue
170 if res in ('y', 'Y'):
171 return True
172 return False
173
174 def clean(self, message=None, to_remove=None):
175 """Clean previous installation directories
176
177 @param message (str): to use a non-default confirmation message
178 @param to_remove (str): extra files/directories to remove
179 """
180 if message is None:
181 message = "Cleaning previous installation directories"
182 if to_remove is None:
183 to_remove = []
184 to_remove.extend([os.path.join(self.install_lib, NAME),
185 self.install_data_dir,
186 os.path.join(self.install_data, 'share', 'doc', NAME),
187 os.path.join(self.install_lib, "%s-py%s.egg-info" % (self.config_vars['dist_fullname'], self.config_vars['py_version_short'])),
188 ])
189 for source, dest in self.sh_script_links:
190 dest = os.path.join(self.install_scripts, dest)
191 if os.path.islink(dest):
192 to_remove.append(dest)
193 plugin_file = os.path.join(self.install_lib, 'twisted', 'plugins', NAME)
194 if os.path.isfile(plugin_file):
195 to_remove.append(plugin_file)
196
197 message = "%s:\n%s\n" % (message, "\n".join([" %s" % path for path in to_remove]))
198 if not self.confirm(message):
199 return
200 sys.stdout.write('cleaning previous installation directories...\n')
201 sys.stdout.flush()
202 for path in to_remove:
203 if os.path.isdir(path):
204 shutil.rmtree(path, ignore_errors=True)
205 else:
206 os.remove(path)
207
208 def purge(self):
209 """Clean building and previous installation directories"""
210 message = "Cleaning building and previous installation directories"
211 to_remove = [os.path.join(os.getcwd(), 'build'), self.pyjamas_output_dir]
212 self.clean(message, to_remove)
213
214
215 def preinstall_check(install_opt):
126 """Check presence of problematic dependencies, and try to install them with package manager 216 """Check presence of problematic dependencies, and try to install them with package manager
127 This ugly stuff is necessary as distributions are not installed correctly with setuptools/distribute 217 This ugly stuff is necessary as distributions are not installed correctly with setuptools/distribute
128 Hope to remove this at some point""" 218 Hope to remove this at some point"""
129 219
130 modules_tocheck = [] # if empty this method is dummy 220 modules_tocheck = [] # if empty this method is dummy
136 226
137 sys.stdout.write("Running pre-installation dependencies check\n") 227 sys.stdout.write("Running pre-installation dependencies check\n")
138 228
139 # which modules are not installed ? 229 # which modules are not installed ?
140 modules_toinstall = [mod for mod in modules_tocheck if not module_installed(mod)] 230 modules_toinstall = [mod for mod in modules_tocheck if not module_installed(mod)]
231 """# is mercurial available ?
232 hg_installed = subprocess.call('which hg', stdout=open('/dev/null', 'w'), shell=True) == 0
233 if not hg_installed:
234 modules_toinstall.append('mercurial')""" # hg can be installed from pypi
141 235
142 if modules_toinstall: 236 if modules_toinstall:
143 # are we on a distribution using apt ? 237 if AUTO_DEB_OPT in install_opt: # auto debian installation is requested
144 apt_path = subprocess.Popen('which apt-get', stdout=subprocess.PIPE, shell=True).communicate()[0][:-1] 238 # are we on a distribution using apt ?
239 apt_path = subprocess.Popen('which apt-get', stdout=subprocess.PIPE, shell=True).communicate()[0][:-1]
240 else:
241 apt_path = None
242
145 not_installed = set() 243 not_installed = set()
146 if apt_path: 244 if apt_path:
147 # we have apt, we'll try to use it 245 # we have apt, we'll try to use it
148 for module_name in modules_toinstall: 246 for module_name in modules_toinstall:
149 package_name = package[module_name] 247 package_name = package[module_name]
162 sys.exit(2) 260 sys.exit(2)
163 261
164 262
165 if sys.argv[1].lower() in ['egg_info', 'install']: 263 if sys.argv[1].lower() in ['egg_info', 'install']:
166 # we only check dependencies if egg_info or install is used 264 # we only check dependencies if egg_info or install is used
167 install_opt = os.environ.get("LIBERVIA_INSTALL", "") 265 install_opt = os.environ.get(ENV_LIBERVIA_INSTALL, "").split()
168 if not "nopreinstall" in install_opt: # user can force preinstall skipping 266 if not NO_PREINSTALL_OPT in install_opt: # user can force preinstall skipping
169 preinstall_check() 267 preinstall_check(install_opt)
170 268
171 setup(name=NAME, 269 setup(name=NAME,
172 version='0.4.0', 270 version='0.4.0',
173 description=u'Web frontend for Salut à Toi', 271 description=u'Web frontend for Salut à Toi',
174 long_description=u'Libervia is a web frontend for Salut à Toi (SàT), a multi-frontends and multi-purposes XMPP client.', 272 long_description=u'Libervia is a web frontend for Salut à Toi (SàT), a multi-frontends and multi-purposes XMPP client.',
179 'Environment :: Web Environment', 277 'Environment :: Web Environment',
180 'Framework :: Twisted', 278 'Framework :: Twisted',
181 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', 279 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
182 'Operating System :: POSIX :: Linux', 280 'Operating System :: POSIX :: Linux',
183 'Topic :: Communications :: Chat'], 281 'Topic :: Communications :: Chat'],
184 package_dir={'libervia': '.', 'libervia_server': 'libervia_server'}, 282 package_dir={'libervia': 'src', 'twisted.plugins': 'src/twisted/plugins'},
185 packages=['libervia', 'libervia.output', 'libervia_server', 'twisted.plugins'], 283 packages=['libervia', 'libervia.common', 'libervia.server', 'twisted.plugins'],
186 package_data={'libervia': ['libervia.py'], 'libervia.output': ['**/*.*'], 'libervia_server': ['libervia.sh']}, 284 package_data={'libervia': ['libervia.sh']},
187 data_files=[('share/doc/%s' % NAME, ['COPYING', 'README'])], 285 data_files=[(os.path.join('share', 'doc', NAME), ['COPYING', 'README', 'INSTALL']),
286 (os.path.join('share', NAME, C.SERVER_CSS_DIR), [os.path.join(C.SERVER_CSS_DIR, filename) for filename in os.listdir(C.SERVER_CSS_DIR)]),
287 ],
188 scripts=[], 288 scripts=[],
189 zip_safe=False, 289 zip_safe=False,
190 dependency_links=['http://www.blarg.net/%7Esteveha/pyfeed-0.7.4.tar.gz', 'http://www.blarg.net/%7Esteveha/xe-0.7.4.tar.gz'], 290 dependency_links=['http://www.blarg.net/%7Esteveha/pyfeed-0.7.4.tar.gz', 'http://www.blarg.net/%7Esteveha/xe-0.7.4.tar.gz'],
191 install_requires=['sat', 'twisted', 'pyfeed', 'xe', 'txJSON-RPC', 'zope.interface', 'pyopenssl'], 291 install_requires=['sat', 'twisted', 'pyfeed', 'xe', 'txJSON-RPC', 'zope.interface', 'pyopenssl'],
192 cmdclass={'install': CustomInstall}, 292 cmdclass={'install': CustomInstall},
193 ) 293 )
194