2 # -*- coding: utf-8 -*-
3 ##############################################################################
5 # OpenERP, Open Source Management Solution
6 # Copyright (C) 2004-Today OpenERP SA (<http://www.openerp.com>).
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU Affero General Public License as
10 # published by the Free Software Foundation, either version 3 of the
11 # License, or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Affero General Public License for more details.
18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
32 from contextlib import contextmanager
34 from os.path import abspath, dirname, join
35 from tempfile import NamedTemporaryFile
38 #----------------------------------------------------------
40 #----------------------------------------------------------
41 execfile(join(dirname(__file__), '..', 'openerp', 'release.py'))
42 version = version.split('-')[0]
44 timestamp = time.strftime("%Y%m%d-%H%M%S", time.gmtime())
51 'deb.tar.gz': ['deb', 'tar.gz'],
57 if not os.path.isdir(d):
60 def system(l, chdir=None):
65 if isinstance(l, list):
66 rc = os.spawnvp(os.P_WAIT, l[0], l)
67 elif isinstance(l, str):
69 rc = os.spawnvp(os.P_WAIT, tmp[0], tmp)
74 def _rpc_count_modules(addr='http://127.0.0.1', port=8069, dbname='mycompany'):
76 modules = xmlrpclib.ServerProxy('%s:%s/xmlrpc/object' % (addr, port)).execute(
77 dbname, 1, 'admin', 'ir.module.module', 'search', [('state', '=', 'installed')]
79 if modules and len(modules) > 1:
81 toinstallmodules = xmlrpclib.ServerProxy('%s:%s/xmlrpc/object' % (addr, port)).execute(
82 dbname, 1, 'admin', 'ir.module.module', 'search', [('state', '=', 'to install')]
85 print("Package test: FAILED. Not able to install dependencies of base.")
86 raise Exception("Installation of package failed")
88 print("Package test: successfuly installed %s modules" % len(modules))
90 print("Package test: FAILED. Not able to install base.")
91 raise Exception("Installation of package failed")
93 def publish(o, releases):
94 def _publish(o, release):
95 extension = ''.join(release.split('.', 1)[1])
96 release_extension = PUBLISH_DIRS[extension][1] if isinstance(PUBLISH_DIRS[extension], list) else extension
97 release_dir = PUBLISH_DIRS[extension][0] if isinstance(PUBLISH_DIRS[extension], list) else PUBLISH_DIRS[extension]
99 release_filename = 'odoo_%s-%s.%s' % (version, timestamp, release_extension)
100 release_path = join(o.pub, release_dir, release_filename)
102 system('mkdir -p %s' % join(o.pub, release_dir))
103 shutil.move(join(o.build_dir, release), release_path)
105 if release_extension == 'deb':
106 temp_path = tempfile.mkdtemp(suffix='debPackages')
107 system(['cp', release_path, temp_path])
108 with open(os.path.join(o.pub, 'deb', 'Packages'), 'w') as out:
109 subprocess.call(['dpkg-scanpackages', '.'], stdout=out, cwd=temp_path)
110 shutil.rmtree(temp_path)
112 # Latest/symlink handler
113 release_abspath = abspath(release_path)
114 latest_abspath = release_abspath.replace(timestamp, 'latest')
116 if os.path.islink(latest_abspath):
117 os.unlink(latest_abspath)
119 os.symlink(release_abspath, latest_abspath)
121 if isinstance(releases, basestring):
122 _publish(o, releases)
123 elif isinstance(releases, list):
124 for release in releases:
127 class OdooDocker(object):
129 self.log_file = NamedTemporaryFile(mode='w+b', prefix="bash", suffix=".txt", delete=False)
130 self.port = 8069 # TODO sle: reliable way to get a free port?
131 self.prompt_re = '(\r\nroot@|bash-).*# '
134 def system(self, command):
135 self.docker.sendline(command)
136 self.docker.expect(self.prompt_re)
138 def start(self, docker_image, build_dir, pub_dir):
139 self.build_dir = build_dir
140 self.pub_dir = pub_dir
142 self.docker = pexpect.spawn(
143 'docker run -v %s:/opt/release -p 127.0.0.1:%s:8069'
144 ' -t -i %s /bin/bash --noediting' % (self.build_dir, self.port, docker_image),
147 time.sleep(2) # let the bash start
148 self.docker.logfile_read = self.log_file
149 self.id = subprocess.check_output('docker ps -l -q', shell=True)
153 _rpc_count_modules(port=str(self.port))
155 print('Exception during docker execution: %s:' % str(e))
156 print('Error during docker execution: printing the bash output:')
157 with open(self.log_file.name) as f:
158 print '\n'.join(f.readlines())
162 system('docker rm -f %s' % self.id)
163 self.log_file.close()
164 os.remove(self.log_file.name)
167 def docker(docker_image, build_dir, pub_dir):
168 _docker = OdooDocker()
170 _docker.start(docker_image, build_dir, pub_dir)
179 def __init__(self, o, image, ssh_key='', login='openerp'):
182 self.ssh_key = ssh_key
185 def timeout(self,signum,frame):
186 print "vm timeout kill",self.pid
190 l="kvm -net nic,model=rtl8139 -net user,hostfwd=tcp:127.0.0.1:10022-:22,hostfwd=tcp:127.0.0.1:18069-:8069,hostfwd=tcp:127.0.0.1:15432-:5432 -drive".split(" ")
191 #l.append('file=%s,if=virtio,index=0,boot=on,snapshot=on'%self.image)
192 l.append('file=%s,snapshot=on'%self.image)
193 #l.extend(['-vnc','127.0.0.1:1'])
194 l.append('-nographic')
196 self.pid=os.spawnvp(os.P_NOWAIT, l[0], l)
199 signal.signal(signal.SIGALRM, self.timeout)
203 signal.signal(signal.SIGALRM, signal.SIG_DFL)
208 l=['ssh','-o','UserKnownHostsFile=/dev/null','-o','StrictHostKeyChecking=no','-p','10022','-i',self.ssh_key,'%s@127.0.0.1'%self.login,cmd]
211 def rsync(self,args,options='--delete --exclude .bzrignore'):
212 cmd ='rsync -rt -e "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 10022 -i %s" %s %s' % (self.ssh_key, options, args)
218 class KVMWinBuildExe(KVM):
220 with open(join(self.o.build_dir, 'setup/win32/Makefile.version'), 'w') as f:
221 f.write("VERSION=%s\n" % self.o.version_full)
222 with open(join(self.o.build_dir, 'setup/win32/Makefile.python'), 'w') as f:
223 f.write("PYTHON_VERSION=%s\n" % self.o.vm_winxp_python_version.replace('.', ''))
225 self.ssh("mkdir -p build")
226 self.rsync('%s/ %s@127.0.0.1:build/server/' % (self.o.build_dir, self.login))
227 self.ssh("cd build/server/setup/win32;time make allinone;")
228 self.rsync('%s@127.0.0.1:build/server/setup/win32/release/ %s/' % (self.login, self.o.build_dir), '')
229 print "KVMWinBuildExe.run(): done"
231 class KVMWinTestExe(KVM):
233 # Cannot use o.version_full when the version is not correctly parsed
234 # (for instance, containing *rc* or *dev*)
235 setuppath = glob("%s/openerp-server-setup-*.exe" % self.o.build_dir)[0]
236 setupfile = setuppath.split('/')[-1]
237 setupversion = setupfile.split('openerp-server-setup-')[1].split('.exe')[0]
239 self.rsync('"%s" %s@127.0.0.1:' % (setuppath, self.login))
240 self.ssh("TEMP=/tmp ./%s /S" % setupfile)
241 self.ssh('PGPASSWORD=openpgpwd /cygdrive/c/"Program Files"/"Odoo %s"/PostgreSQL/bin/createdb.exe -e -U openpg mycompany' % setupversion)
242 self.ssh('/cygdrive/c/"Program Files"/"Odoo %s"/server/openerp-server.exe -d mycompany -i base --stop-after-init' % setupversion)
243 self.ssh('net start odoo-server-8.0')
244 _rpc_count_modules(port=18069)
246 #----------------------------------------------------------
248 #----------------------------------------------------------
249 def _prepare_build_dir(o):
250 cmd = ['rsync', '-a', '--exclude', '.git', '--exclude', '*.pyc', '--exclude', '*.pyo']
251 system(cmd + ['%s/' % o.odoo_dir, o.build_dir])
252 for i in glob(join(o.build_dir, 'addons/*')):
253 shutil.move(i, join(o.build_dir, 'openerp/addons'))
256 system(['python2', 'setup.py', '--quiet', 'sdist'], o.build_dir)
257 system(['cp', glob('%s/dist/openerp-*.tar.gz' % o.build_dir)[0], '%s/odoo.tar.gz' % o.build_dir])
260 system(['dpkg-buildpackage', '-rfakeroot', '-uc', '-us'], o.build_dir)
261 system(['cp', glob('%s/../odoo_*.deb' % o.build_dir)[0], '%s/odoo.deb' % o.build_dir])
262 system(['cp', glob('%s/../odoo_*.dsc' % o.build_dir)[0], '%s/odoo.dsc' % o.build_dir])
263 system(['cp', glob('%s/../odoo_*_amd64.changes' % o.build_dir)[0], '%s/odoo_amd64.changes' % o.build_dir])
264 system(['cp', glob('%s/../odoo_*.tar.gz' % o.build_dir)[0], '%s/odoo.deb.tar.gz' % o.build_dir])
267 system(['python2', 'setup.py', '--quiet', 'bdist_rpm'], o.build_dir)
268 system(['cp', glob('%s/dist/openerp-*.noarch.rpm' % o.build_dir)[0], '%s/odoo.noarch.rpm' % o.build_dir])
269 system(['cp', glob('%s/dist/openerp-*.src.rpm' % o.build_dir)[0], '%s/odoo.src.rpm' % o.build_dir])
272 KVMWinBuildExe(o, o.vm_winxp_image, o.vm_winxp_ssh_key, o.vm_winxp_login).start()
273 system(['cp', glob('%s/openerp*.exe' % o.build_dir)[0], '%s/odoo.exe' % o.build_dir])
275 #----------------------------------------------------------
277 #----------------------------------------------------------
279 with docker('debian:stable', o.build_dir, o.pub) as wheezy:
280 wheezy.release = 'odoo.tar.gz'
281 wheezy.system('apt-get update -qq && apt-get upgrade -qq -y')
282 wheezy.system("apt-get install postgresql python-dev postgresql-server-dev-all python-pip build-essential libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev libssl-dev libjpeg-dev -y")
283 wheezy.system("service postgresql start")
284 wheezy.system('su postgres -s /bin/bash -c "pg_dropcluster --stop 9.1 main"')
285 wheezy.system('su postgres -s /bin/bash -c "pg_createcluster --start -e UTF-8 9.1 main"')
286 wheezy.system('pip install -r /opt/release/requirements.txt')
287 wheezy.system('/usr/local/bin/pip install /opt/release/%s' % wheezy.release)
288 wheezy.system("useradd --system --no-create-home odoo")
289 wheezy.system('su postgres -s /bin/bash -c "createuser -s odoo"')
290 wheezy.system('su postgres -s /bin/bash -c "createdb mycompany"')
291 wheezy.system('mkdir /var/lib/odoo')
292 wheezy.system('chown odoo:odoo /var/lib/odoo')
293 wheezy.system('su odoo -s /bin/bash -c "odoo.py --addons-path=/usr/local/lib/python2.7/dist-packages/openerp/addons -d mycompany -i base --stop-after-init"')
294 wheezy.system('su odoo -s /bin/bash -c "odoo.py --addons-path=/usr/local/lib/python2.7/dist-packages/openerp/addons -d mycompany &"')
297 with docker('debian:stable', o.build_dir, o.pub) as wheezy:
298 wheezy.release = 'odoo.deb'
299 wheezy.system('/usr/bin/apt-get update -qq && /usr/bin/apt-get upgrade -qq -y')
300 wheezy.system("apt-get install postgresql -y")
301 wheezy.system("service postgresql start")
302 wheezy.system('su postgres -s /bin/bash -c "pg_dropcluster --stop 9.1 main"')
303 wheezy.system('su postgres -s /bin/bash -c "pg_createcluster --start -e UTF-8 9.1 main"')
304 wheezy.system('su postgres -s /bin/bash -c "createdb mycompany"')
305 wheezy.system('/usr/bin/dpkg -i /opt/release/%s' % wheezy.release)
306 wheezy.system('/usr/bin/apt-get install -f -y')
307 wheezy.system('su odoo -s /bin/bash -c "odoo.py -c /etc/odoo/openerp-server.conf -d mycompany -i base --stop-after-init"')
308 wheezy.system('su odoo -s /bin/bash -c "odoo.py -c /etc/odoo/openerp-server.conf -d mycompany &"')
311 with docker('centos:centos7', o.build_dir, o.pub) as centos7:
312 centos7.release = 'odoo.noarch.rpm'
313 centos7.system('rpm -Uvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-2.noarch.rpm')
314 centos7.system('yum update -y && yum upgrade -y')
315 centos7.system('yum install python-pip gcc python-devel -y')
316 centos7.system('pip install pydot pyPdf vatnumber xlwt http://download.gna.org/pychart/PyChart-1.39.tar.gz')
317 centos7.system('yum install postgresql postgresql-server postgresql-libs postgresql-contrib postgresql-devel -y')
318 centos7.system('mkdir -p /var/lib/postgres/data')
319 centos7.system('chown -R postgres:postgres /var/lib/postgres/data')
320 centos7.system('chmod 0700 /var/lib/postgres/data')
321 centos7.system('su postgres -c "initdb -D /var/lib/postgres/data -E UTF-8"')
322 centos7.system('cp /usr/share/pgsql/postgresql.conf.sample /var/lib/postgres/data/postgresql.conf')
323 centos7.system('su postgres -c "/usr/bin/pg_ctl -D /var/lib/postgres/data start"')
324 centos7.system('su postgres -c "createdb mycompany"')
325 centos7.system('export PYTHONPATH=${PYTHONPATH}:/usr/local/lib/python2.7/dist-packages')
326 centos7.system('su postgres -c "createdb mycompany"')
327 centos7.system('yum install /opt/release/%s -y' % centos7.release)
328 centos7.system('su odoo -s /bin/bash -c "openerp-server -c /etc/odoo/openerp-server.conf -d mycompany -i base --stop-after-init"')
329 centos7.system('su odoo -s /bin/bash -c "openerp-server -c /etc/odoo/openerp-server.conf -d mycompany &"')
332 KVMWinTestExe(o, o.vm_winxp_image, o.vm_winxp_ssh_key, o.vm_winxp_login).start()
334 #----------------------------------------------------------
336 #----------------------------------------------------------
338 op = optparse.OptionParser()
339 root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
340 build_dir = "%s-%s" % (root, timestamp)
342 op.add_option("-b", "--build-dir", default=build_dir, help="build directory (%default)", metavar="DIR")
343 op.add_option("-p", "--pub", default=None, help="pub directory (%default)", metavar="DIR")
344 op.add_option("", "--no-testing", action="store_true", help="don't test the builded packages")
345 op.add_option("-v", "--version", default='8.0', help="version (%default)")
347 op.add_option("", "--no-debian", action="store_true", help="don't build the debian package")
348 op.add_option("", "--no-rpm", action="store_true", help="don't build the rpm package")
349 op.add_option("", "--no-tarball", action="store_true", help="don't build the tarball")
350 op.add_option("", "--no-windows", action="store_true", help="don't build the windows package")
353 op.add_option("", "--vm-winxp-image", default='/home/odoo/vm/winxp27/winxp27.vdi', help="%default")
354 op.add_option("", "--vm-winxp-ssh-key", default='/home/odoo/vm/winxp27/id_rsa', help="%default")
355 op.add_option("", "--vm-winxp-login", default='Naresh', help="Windows login (%default)")
356 op.add_option("", "--vm-winxp-python-version", default='2.7', help="Windows Python version installed in the VM (default: %default)")
358 (o, args) = op.parse_args()
359 # derive other options
361 o.pkg = join(o.build_dir, 'pkg')
362 o.version_full = '%s-%s' % (o.version, timestamp)
363 o.work = join(o.build_dir, 'openerp-%s' % o.version_full)
364 o.work_addons = join(o.work, 'openerp', 'addons')
369 _prepare_build_dir(o)
376 publish(o, 'odoo.tar.gz')
378 print("Won't publish the tgz release.\n Exception: %s" % str(e))
384 publish(o, ['odoo.deb', 'odoo.dsc', 'odoo_amd64.changes', 'odoo.deb.tar.gz'])
386 print("Won't publish the deb release.\n Exception: %s" % str(e))
392 publish(o, ['odoo.noarch.rpm', 'odoo.src.rpm'])
394 print("Won't publish the rpm release.\n Exception: %s" % str(e))
400 publish(o, 'odoo.exe')
402 print("Won't publish the exe release.\n Exception: %s" % str(e))
406 for leftover in glob('%s/../odoo_*' % o.build_dir):
409 shutil.rmtree(o.build_dir)
410 print('Build dir %s removed' % o.build_dir)
413 system("docker rm -f `docker ps -a | awk '{print $1 }'` 2>>/dev/null")
414 print('Remaining dockers removed')
417 if __name__ == '__main__':