Do not duplicate news entry when editing it
[cds-indico.git] / fabfile.py
blob45f526bc3b65d5f7ebdb25d62827ebb5b8b728df
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 """
18 fabfile for Indico development operations
19 """
21 import os
22 import re
23 import sys
24 import glob
25 import shutil
26 import requests
27 import json
28 import getpass
29 from contextlib import contextmanager
30 import operator
32 from fabric.api import local, lcd, task, env
33 from fabric.context_managers import prefix, settings
34 from fabric.colors import red, green, yellow, cyan
35 from fabric.contrib import console
36 from fabric.operations import put, run
39 ASSET_TYPES = ['js', 'sass', 'css']
40 DOC_DIRS = ['guides']
41 RECIPES = {}
42 DEFAULT_REQUEST_ERROR_MSG = 'UNDEFINED ERROR (no error description from server)'
43 CONF_FILE_NAME = 'fabfile.conf'
44 SOURCE_DIR = os.path.dirname(__file__)
46 execfile(CONF_FILE_NAME, {}, env)
48 env.update({
49 'conf': CONF_FILE_NAME,
50 'src_dir': SOURCE_DIR,
51 'ext_dir': os.path.join(SOURCE_DIR, env.ext_dirname),
52 'target_dir': os.path.join(SOURCE_DIR, env.target_dirname),
53 'node_env_path': os.path.join(SOURCE_DIR, env.node_env_dirname)
57 def recipe(name):
58 def _wrapper(f):
59 RECIPES[name] = f
60 return _wrapper
63 # Decorators
65 @contextmanager
66 def node_env():
67 if env.system_node:
68 yield
69 else:
70 with prefix('. {0}'.format(os.path.join(env.node_env_path, 'bin/activate'))):
71 yield
74 @contextmanager
75 def pyenv_env(version):
76 cmd_dir = os.path.join(env.pyenv_dir, 'versions', 'indico-build-{0}'.format(version), 'bin')
77 with prefix('PATH={0}:$PATH'.format(cmd_dir)):
78 yield
81 def pyenv_cmd(cmd, **kwargs):
82 cmd_dir = os.path.join(env.pyenv_dir, 'bin')
83 return local('{0}/pyenv {1}'.format(cmd_dir, cmd), **kwargs)
86 # Util functions
88 def _yes_no_input(message, default):
89 c = '? '
90 if default.lower() == 'y':
91 c = ' [Y/n]? '
92 elif default.lower() == 'n':
93 c = ' [y/N]? '
94 s = raw_input(message+c) or default
95 if s.lower() == 'y':
96 return True
97 else:
98 return False
101 def _putl(source_file, dest_dir):
103 To be used instead of put, since it doesn't support symbolic links
106 put(source_file, '/')
107 run("mkdir -p {0}".format(dest_dir))
108 run("mv -f /{0} {1}".format(os.path.basename(source_file), dest_dir))
111 def create_node_env():
112 with settings(warn_only=True):
113 local('nodeenv -c -n {0} {1}'.format(env.node_version, env.node_env_path))
116 def lib_dir(src_dir, dtype):
117 target_dir = os.path.join(src_dir, 'indico', 'htdocs')
118 return os.path.join(target_dir, dtype, 'lib')
121 def _check_pyenv(py_versions):
123 Check that pyenv and pyenv-virtualenv are installed and set up the
124 compilers/virtual envs in case they do not exist
127 if os.system('which pyenv'):
128 print red("Can't find pyenv!")
129 print yellow("Are you sure you have installed it?")
130 sys.exit(-2)
131 elif os.system('which pyenv-virtualenv'):
132 print red("Can't find pyenv-virtualenv!")
133 print yellow("Are you sure you have installed it?")
134 sys.exit(-2)
136 # list available pyenv versions
137 av_versions = os.listdir(os.path.join(env.pyenv_dir, 'versions'))
139 for py_version in py_versions:
140 if py_version not in av_versions:
141 print green('Installing Python {0}'.format(py_version))
142 pyenv_cmd('install {0}'.format(py_version), capture=True)
144 local("echo \'y\' | pyenv virtualenv {0} indico-build-{0}".format(py_version))
146 with pyenv_env(py_version):
147 local("pip install -r requirements.dev.txt")
150 def _check_present(executable, message="Please install it first."):
152 Check that executable exists in $PATH
155 with settings(warn_only=True):
156 if local('which {0} > /dev/null && echo $?'.format(executable), capture=True) != '0':
157 print red('{0} is not available in this system. {1}'.format(executable, message))
158 sys.exit(-2)
161 def _safe_rm(path, recursive=False, ask=True):
162 if path[0] != '/':
163 path = os.path.join(env.lcwd, path)
164 if ask:
165 files = glob.glob(path)
166 if files:
167 print yellow("The following files are going to be deleted:\n ") + '\n '.join(files)
168 if console.confirm(cyan("Are you sure you want to delete them?")):
169 local('rm {0}{1}'.format('-rf ' if recursive else '', path))
170 else:
171 print red("Delete operation cancelled")
172 else:
173 local('rm {0}{1}'.format('-rf ' if recursive else '', path))
176 def _cp_tree(dfrom, dto, exclude=[]):
178 Simple copy with exclude option
180 if dfrom[0] != '/':
181 dfrom = os.path.join(env.lcwd, dfrom)
182 if dto[0] != '/':
183 dto = os.path.join(env.lcwd, dto)
185 print "{0} -> {1}".format(dfrom, dto)
187 shutil.copytree(dfrom, dto, ignore=shutil.ignore_patterns(*exclude))
190 def _find_most_recent(path, cmp=operator.gt, maxt=0):
191 for dirpath, __, fnames in os.walk(path):
192 for fname in fnames:
194 # ignore hidden files and ODTs
195 if fname.startswith(".") or fname.endswith(".odt"):
196 continue
198 mtime = os.stat(os.path.join(dirpath, fname)).st_mtime
199 if cmp(mtime, maxt):
200 maxt = mtime
201 return maxt
204 def _find_least_recent(path):
205 return _find_most_recent(path, cmp=operator.lt, maxt=sys.maxint)
208 def _install_dependencies(mod_name, sub_path, dtype, dest_subpath=None):
209 l_dir = lib_dir(env.src_dir, dtype)
210 dest_dir = os.path.join(l_dir, dest_subpath) if dest_subpath else l_dir
211 local('mkdir -p {0}'.format(dest_dir))
212 local('cp -R {0} {1}/'.format(
213 os.path.join(env.ext_dir, mod_name, sub_path),
214 dest_dir))
217 # Recipes
219 @recipe('angular')
220 def install_angular():
221 with node_env():
222 with lcd(os.path.join(env.ext_dir, 'angular')):
223 local('npm install')
224 local('grunt clean buildall copy write compress')
225 dest_dir_js = lib_dir(env.src_dir, 'js')
226 dest_dir_css = lib_dir(env.src_dir, 'css')
227 local('mkdir -p {0}'.format(dest_dir_js))
228 local('cp build/angular.js {0}/'.format(dest_dir_js))
229 local('cp build/angular-resource.js {0}/'.format(dest_dir_js))
230 local('cp build/angular-sanitize.js {0}/'.format(dest_dir_js))
231 local('cp css/angular.css {0}'.format(dest_dir_css))
234 @recipe('ui-sortable')
235 def install_ui_sortable():
236 with node_env():
237 with lcd(os.path.join(env.ext_dir, 'ui-sortable')):
238 dest_dir_js = lib_dir(env.src_dir, 'js')
239 local('mkdir -p {0}'.format(dest_dir_js))
240 local('cp src/sortable.js {0}/'.format(dest_dir_js))
243 @recipe('compass')
244 def install_compass():
245 _install_dependencies('compass', 'frameworks/compass/stylesheets/*', 'sass', 'compass')
248 @recipe('jquery')
249 def install_jquery():
250 with node_env():
251 with lcd(os.path.join(env.ext_dir, 'jquery')):
252 local('npm install')
253 local('grunt')
254 dest_dir = lib_dir(env.src_dir, 'js')
255 local('mkdir -p {0}'.format(dest_dir))
256 local('cp dist/jquery.js {0}/'.format(dest_dir))
259 @recipe('jed')
260 def install_jed():
261 with lcd(os.path.join(env.ext_dir, 'Jed')):
262 dest_dir = lib_dir(env.src_dir, 'js')
263 local('mkdir -p {0}'.format(dest_dir))
264 local('cp jed.js {0}/'.format(dest_dir))
267 @recipe('jqplot')
268 def install_jqplot():
269 """Install jQPlot from Git"""
270 plugins = ['axis', 'bar', 'cursor', 'highlighter', 'points', 'text']
271 with lcd(os.path.join(env.ext_dir, 'jqplot')):
272 dest_dir_js = os.path.join(lib_dir(env.src_dir, 'js'), 'jqplot')
273 dest_dir_css = lib_dir(env.src_dir, 'css')
274 dest_dir_js_core = os.path.join(dest_dir_js, 'core')
275 dest_dir_js_plugins = os.path.join(dest_dir_js, 'plugins')
276 local('mkdir -p {0} {1}'.format(dest_dir_js_core, dest_dir_css))
277 local('cp src/core/*.js {0}'.format(dest_dir_js_core))
278 local('cp src/core/*.css {0}'.format(dest_dir_css))
279 for plugin_name in plugins:
280 dest = os.path.join(dest_dir_js_plugins, plugin_name)
281 local('mkdir -p {0}'.format(dest))
282 local('cp src/plugins/{0}/* {1}'.format(plugin_name, dest))
285 @recipe('underscore')
286 def install_underscore():
288 Install underscore from Git
290 _install_dependencies('underscore', 'underscore.js', 'js')
293 @recipe('rrule') # rrule.js
294 def install_rrule():
296 Install rrule from Git
298 _install_dependencies('rrule', 'lib/rrule.js', 'js')
301 @recipe('qtip2')
302 def install_qtip2():
303 with node_env():
304 with lcd(os.path.join(env.ext_dir, 'qtip2')):
305 local('npm install')
306 local('grunt --plugins="tips modal viewport svg" init clean concat:dist concat:css concat:libs replace')
307 dest_dir_js, dest_dir_css = lib_dir(env.src_dir, 'js'), lib_dir(env.src_dir, 'css')
308 local('mkdir -p {0} {1}'.format(dest_dir_js, dest_dir_css))
309 local('cp dist/jquery.qtip.js {0}/'.format(dest_dir_js))
310 local('cp dist/jquery.qtip.css {0}/'.format(dest_dir_css))
313 @recipe('jquery-ui-multiselect')
314 def install_jquery_ui_multiselect():
315 with node_env():
316 with lcd(os.path.join(env.ext_dir, 'jquery-ui-multiselect')):
317 dest_dir_js = lib_dir(env.src_dir, 'js')
318 dest_dir_css = lib_dir(env.src_dir, 'css')
319 local('mkdir -p {0} {1}'.format(dest_dir_js, dest_dir_css))
320 local('cp src/jquery.multiselect.js {0}/'.format(dest_dir_js))
321 local('cp src/jquery.multiselect.filter.js {0}/'.format(dest_dir_js))
322 local('cp jquery.multiselect.css {0}/'.format(dest_dir_css))
323 local('cp jquery.multiselect.filter.css {0}/'.format(dest_dir_css))
326 @recipe('MathJax')
327 def install_mathjax():
328 dest_dir = os.path.join(lib_dir(env.src_dir, 'js'), 'mathjax/')
329 mathjax_js = os.path.join(dest_dir, 'MathJax.js')
331 with lcd(os.path.join(env.ext_dir, 'mathjax')):
332 local('rm -rf {0}'.format(os.path.join(dest_dir)))
333 _cp_tree('unpacked/', dest_dir, exclude=["AM*", "MML*", "Accessible*", "Safe*"])
334 _cp_tree('images/', os.path.join(dest_dir, 'images'))
335 _cp_tree('fonts/', os.path.join(dest_dir, 'fonts'), exclude=["png"])
337 with open(mathjax_js, 'r') as f:
338 data = f.read()
339 # Uncomment 'isPacked = true' line
340 data = re.sub(r'//\s*(MathJax\.isPacked\s*=\s*true\s*;)', r'\1', data, re.MULTILINE)
342 with open(mathjax_js, 'w') as f:
343 f.write(data)
346 @recipe('PageDown')
347 def install_pagedown():
348 with lcd(os.path.join(env.ext_dir, 'pagedown')):
349 dest_dir = os.path.join(lib_dir(env.src_dir, 'js'), 'pagedown/')
350 local('mkdir -p {0}'.format(dest_dir))
351 local('cp *.js {0}'.format(dest_dir))
354 @recipe('ZeroClipboard')
355 def install_zeroclipboard():
357 Install ZeroClipboard from Git
359 with lcd(os.path.join(env.ext_dir, 'zeroclipboard')):
360 dest_dir = os.path.join(lib_dir(env.src_dir, 'js'), 'zeroclipboard/')
361 local('mkdir -p {0}'.format(dest_dir))
362 local('cp dist/ZeroClipboard.js {0}/'.format(dest_dir))
363 local('cp dist/ZeroClipboard.swf {0}/'.format(dest_dir))
366 @recipe('selectize.js')
367 def install_selectize_js():
368 with lcd(os.path.join(env.ext_dir, 'selectize.js')):
369 dest_js_dir = os.path.join(lib_dir(env.src_dir, 'js'), 'selectize.js/')
370 dest_css_dir = os.path.join(lib_dir(env.src_dir, 'css'), 'selectize.js/')
371 local('mkdir -p {0} {1}'.format(dest_js_dir, dest_css_dir))
372 local('cp dist/js/standalone/selectize.js {0}/'.format(dest_js_dir))
373 local('cp dist/css/selectize.css {0}/'.format(dest_css_dir))
374 local('cp dist/css/selectize.default.css {0}/'.format(dest_css_dir))
377 # Tasks
379 @task
380 def install(recipe_name):
382 Install a module given the recipe name
384 RECIPES[recipe_name]()
387 @task
388 def init_submodules(src_dir='.'):
390 Initialize submodules (fetch them from external Git repos)
393 print green("Initializing submodules")
394 with lcd(src_dir):
395 local('pwd')
396 local('git submodule update --init --recursive')
399 def _install_deps():
401 Install asset dependencies
403 print green("Installing asset dependencies...")
404 for recipe_name in RECIPES:
405 print cyan("Installing {0}".format(recipe_name))
406 install(recipe_name)
409 @task
410 def setup_deps(n_env=None, n_version=None, src_dir=None, system_node=None):
412 Setup (fetch and install) dependencies for Indico assets
415 src_dir = src_dir or env.src_dir
416 n_env = n_env or env.node_env_path
417 system_node = system_node.lower() in ('1', 'true') if system_node is not None else env.system_node
419 # initialize submodules if they haven't yet been
420 init_submodules(src_dir)
422 ext_dir = os.path.join(src_dir, 'ext_modules')
424 _check_present('curl')
426 with settings(node_env_path=n_env or os.path.join(ext_dir, 'node_env'),
427 node_version=n_version or env.node_version,
428 system_node=system_node,
429 src_dir=src_dir,
430 ext_dir=ext_dir):
432 if not system_node and not os.path.exists(n_env):
433 create_node_env()
435 with node_env():
436 local('npm install -g grunt-cli')
438 _install_deps()
441 @task
442 def clean_deps(src_dir=None):
444 Clean up generated files
447 for dtype in ASSET_TYPES:
448 _safe_rm('{0}/*'.format(lib_dir(src_dir or env.src_dir, dtype)), recursive=True)
451 @task
452 def cleanup(build_dir=None, force=False):
454 Clean up build environment
456 _safe_rm('{0}'.format(build_dir or env.build_dir), recursive=True, ask=(not force))
459 @task
460 def tarball(src_dir=None):
462 Create a source Indico distribution (tarball)
465 src_dir = src_dir or env.src_dir
467 make_docs(src_dir)
469 setup_deps(n_env=os.path.join(src_dir, 'ext_modules', 'node_env'),
470 src_dir=src_dir)
471 local('python setup.py -q sdist')
474 @task
475 def egg(py_versions=None):
477 Create a binary Indico distribution (egg)
480 for py_version in py_versions:
481 cmd_dir = os.path.join(env.pyenv_dir, 'versions', 'indico-build-{0}'.format(py_version), 'bin')
482 local('{0} setup.py -q bdist_egg'.format(os.path.join(cmd_dir, 'python')))
483 print green(local('ls -lah dist/', capture=True))
486 @task
487 def make_docs(src_dir=None, build_dir=None, force=False):
489 Generate Indico docs
492 src_dir = src_dir or env.src_dir
493 doc_src_dir = os.path.join(src_dir, 'doc')
495 if build_dir is None:
496 target_dir = os.path.join(src_dir, 'indico', 'htdocs', 'ihelp')
497 else:
498 target_dir = os.path.join(build_dir or env.build_dir, 'indico', 'htdocs', 'ihelp')
500 if not force:
501 print yellow("Checking if docs need to be generated... "),
502 if _find_most_recent(target_dir) > _find_most_recent(doc_src_dir):
503 print green("Nope.")
504 return
506 print red("Yes :(")
507 _check_present('pdflatex')
509 print green('Generating documentation')
510 with lcd(doc_src_dir):
511 for d in DOC_DIRS:
512 with lcd(d):
513 local('make html')
514 local('make latex')
515 local('rm -rf {0}/*'.format(os.path.join(target_dir, 'html')))
516 local('mv build/html/* {0}'.format(os.path.join(target_dir, 'html')))
518 with lcd(os.path.join('guides', 'build', 'latex')):
519 local('make all-pdf')
520 local('mv *.pdf {0}'.format(os.path.join(target_dir, 'pdf')))
522 print green('Cleaning up')
523 for d in DOC_DIRS:
524 with lcd(d):
525 local('make clean')
528 def _check_request_error(r):
529 if r.status_code >= 400:
530 j = r.json()
531 msg = j.get('message', DEFAULT_REQUEST_ERROR_MSG)
532 print red("ERROR: {0} ({1})".format(msg, r.status_code))
533 sys.exit(-2)
536 def _valid_github_credentials(auth):
537 url = "https://api.github.com/repos/{0}/{1}".format(env.github['org'], env.github['repo'])
538 r = requests.get(url, auth=(env.github['user'], auth))
539 if (r.status_code == 401) and (r.json().get('message') == 'Bad credentials'):
540 print red('Invalid Github credentials for user \'{0}\''.format(env.github['user']))
541 return False
543 return True
546 def _release_exists(tag_name, auth):
547 url = "https://api.github.com/repos/{0}/{1}/releases".format(env.github['org'], env.github['repo'])
548 r = requests.get(url, auth=(env.github['user'], auth))
549 _check_request_error(r)
550 parsed = r.json()
551 for release in parsed:
552 if release.get('tag_name') == tag_name:
553 rel_id = release.get('id')
554 return (True, rel_id, release)
556 return (False, 0, None)
559 def _asset_exists(rel_id, name, auth):
560 url = "https://api.github.com/repos/{0}/{1}/releases/{2}/assets" \
561 .format(env.github['org'], env.github['repo'], rel_id)
562 r = requests.get(url, auth=(env.github['user'], auth))
563 _check_request_error(r)
564 parsed = r.json()
565 for j in parsed:
566 if j.get('name') == name:
567 asset_id = j.get('id')
568 return (True, asset_id)
570 return (False, 0)
573 @task
574 def upload_github(build_dir=None, tag_name=None, auth_token=None,
575 overwrite=None, indico_version='master'):
577 build_dir = build_dir or env.build_dir
578 auth_token = auth_token or env.github['auth_token']
580 while (auth_token is None) or (not _valid_github_credentials(auth_token)):
581 auth_token = getpass.getpass(
582 'Insert the Github password/OAuth token for user \'{0}\': '.format(env.github['user']))
584 auth_creds = (env.github['user'], auth_token)
586 overwrite = overwrite or env.github['overwrite']
588 # Create a new release
589 tag_name = tag_name or indico_version
590 url = "https://api.github.com/repos/{0}/{1}/releases".format(env.github['org'], env.github['repo'])
591 payload = {
592 'tag_name': tag_name,
593 'target_commitish': indico_version,
594 'name': 'Indico {0}'.format(tag_name),
595 'draft': True
598 (exists, rel_id, release_data) = _release_exists(tag_name, auth_token)
600 if exists:
601 if overwrite is None:
602 overwrite = _yes_no_input('Release already exists, do you want to overwrite', 'n')
603 if overwrite:
604 release_id = rel_id
605 else:
606 return
607 else:
608 # We will need to get a new release id from github
609 r = requests.post(url, auth=auth_creds, data=json.dumps(payload))
610 _check_request_error(r)
611 release_data = r.json()
612 release_id = release_data.get('id')
614 # Upload binaries to the new release
615 binaries_dir = os.path.join(build_dir, 'indico', 'dist')
617 # awful way to handle this, but a regex seems like too much
618 url = release_data['upload_url'][:-7]
620 for f in os.listdir(binaries_dir):
622 # jump over hidden/system files
623 if f.startswith('.'):
624 continue
626 if os.path.isfile(os.path.join(binaries_dir, f)):
627 (exists, asset_id) = _asset_exists(release_id, f, auth_token)
629 if exists:
630 # delete previous version
631 del_url = "https://api.github.com/repos/{0}/{1}/releases/assets/{2}" \
632 .format(env.github['org'], env.github['repo'], asset_id)
633 r = requests.delete(del_url, auth=auth_creds)
634 _check_request_error(r)
636 with open(os.path.join(binaries_dir, f), 'rb') as ff:
637 data = ff.read()
638 extension = os.path.splitext(f)[1]
640 # upload eggs using zip mime type
641 if extension == '.gz':
642 headers = {'Content-Type': 'application/x-gzip'}
643 elif extension == '.egg':
644 headers = {'Content-Type': 'application/zip'}
646 headers['Accept'] = 'application/vnd.github.v3+json'
647 headers['Content-Length'] = len(data)
648 params = {'name': f}
650 print green("Uploading \'{0}\' to Github".format(f))
651 r = requests.post(url, auth=auth_creds, headers=headers, data=data, params=params, verify=False)
652 _check_request_error(r)
655 @task
656 def upload_ssh(build_dir=None, server_host=None, server_port=None,
657 ssh_user=None, ssh_key=None, dest_dir=None):
659 build_dir = build_dir or env.build_dir
660 server_host = server_host or env.ssh['host']
661 server_port = server_port or env.ssh['port']
662 ssh_user = ssh_user or env.ssh['user']
663 ssh_key = ssh_key or env.ssh['key']
664 dest_dir = dest_dir or env.ssh['dest_dir']
666 env.host_string = server_host + ':' + server_port
667 env.user = ssh_user
668 env.key_filename = ssh_key
670 binaries_dir = os.path.join(build_dir, 'indico', 'dist')
671 for f in os.listdir(binaries_dir):
672 if os.path.isfile(os.path.join(binaries_dir, f)):
673 _putl(os.path.join(binaries_dir, f), dest_dir)
676 @task
677 def _package_release(build_dir, py_versions, system_node):
678 # Build source tarball
679 with settings(system_node=system_node):
680 print green('Generating '), cyan('tarball')
681 tarball(build_dir)
683 # Build binaries (EGG)
684 print green('Generating '), cyan('eggs')
685 egg(py_versions)
688 @task
689 def package_release(py_versions=None, build_dir=None, system_node=False,
690 indico_version=None, upstream=None, tag_name=None,
691 github_auth=None, overwrite=None, ssh_server_host=None,
692 ssh_server_port=None, ssh_user=None, ssh_key=None,
693 ssh_dest_dir=None, no_clean=False, force_clean=False,
694 upload_to=None, build_here=False):
696 Create an Indico release - source and binary distributions
699 DEVELOP_REQUIRES = ['pojson>=0.4', 'termcolor', 'werkzeug', 'nodeenv', 'fabric',
700 'sphinx', 'repoze.sphinx.autointerface']
702 py_versions = py_versions.split('/') if py_versions else env.py_versions
703 upload_to = upload_to.split('/') if upload_to else []
705 build_dir = build_dir or env.build_dir
706 upstream = upstream or env.github['upstream']
708 ssh_server_host = ssh_server_host or env.ssh['host']
709 ssh_server_port = ssh_server_port or env.ssh['port']
710 ssh_user = ssh_user or env.ssh['user']
711 ssh_key = ssh_key or env.ssh['key']
712 ssh_dest_dir = ssh_dest_dir or env.ssh['dest_dir']
714 indico_version = indico_version or 'master'
716 local('mkdir -p {0}'.format(build_dir))
718 _check_pyenv(py_versions)
720 if build_here:
721 _package_release(os.path.dirname(__file__), py_versions, system_node)
722 else:
723 with lcd(build_dir):
724 if os.path.exists(os.path.join(build_dir, 'indico')):
725 print yellow("Repository seems to already exist.")
726 with lcd('indico'):
727 local('git fetch {0}'.format(upstream))
728 local('git reset --hard FETCH_HEAD')
729 if not no_clean:
730 local('git clean -df')
731 else:
732 local('git clone {0}'.format(upstream))
733 with lcd('indico'):
734 print green("Checking out branch \'{0}\'".format(indico_version))
735 local('git checkout {0}'.format(indico_version))
737 _package_release(os.path.join(build_dir, 'indico'), py_versions, system_node)
739 for u in upload_to:
740 if u == 'github':
741 upload_github(build_dir, tag_name, github_auth, overwrite, indico_version)
742 elif u == 'ssh':
743 upload_ssh(build_dir, ssh_server_host, ssh_server_port, ssh_user, ssh_key, ssh_dest_dir)
745 if not build_here and force_clean:
746 cleanup(build_dir, force=True)