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/>.
18 fabfile for Indico development operations
29 from contextlib
import contextmanager
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']
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
)
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
)
70 with
prefix('. {0}'.format(os
.path
.join(env
.node_env_path
, 'bin/activate'))):
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
)):
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
)
88 def _yes_no_input(message
, default
):
90 if default
.lower() == 'y':
92 elif default
.lower() == 'n':
94 s
= raw_input(message
+c
) or default
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?")
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?")
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
))
161 def _safe_rm(path
, recursive
=False, ask
=True):
163 path
= os
.path
.join(env
.lcwd
, path
)
165 files
= glob
.glob(path
)
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
))
171 print red("Delete operation cancelled")
173 local('rm {0}{1}'.format('-rf ' if recursive
else '', path
))
176 def _cp_tree(dfrom
, dto
, exclude
=[]):
178 Simple copy with exclude option
181 dfrom
= os
.path
.join(env
.lcwd
, dfrom
)
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
):
194 # ignore hidden files and ODTs
195 if fname
.startswith(".") or fname
.endswith(".odt"):
198 mtime
= os
.stat(os
.path
.join(dirpath
, fname
)).st_mtime
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
),
220 def install_angular():
222 with
lcd(os
.path
.join(env
.ext_dir
, 'angular')):
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():
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
))
244 def install_compass():
245 _install_dependencies('compass', 'frameworks/compass/stylesheets/*', 'sass', 'compass')
249 def install_jquery():
251 with
lcd(os
.path
.join(env
.ext_dir
, 'jquery')):
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
))
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
))
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
296 Install rrule from Git
298 _install_dependencies('rrule', 'lib/rrule.js', 'js')
304 with
lcd(os
.path
.join(env
.ext_dir
, 'qtip2')):
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():
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
))
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
:
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
:
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('dropzone.js')
367 def install_dropzone_js():
369 Install Dropzone from Git
371 with
lcd(os
.path
.join(env
.ext_dir
, 'dropzone')):
372 dest_js_dir
= os
.path
.join(lib_dir(env
.src_dir
, 'js'), 'dropzone.js/')
373 dest_css_dir
= os
.path
.join(lib_dir(env
.src_dir
, 'css'), 'dropzone.js/')
374 local('mkdir -p {0} {1}'.format(dest_js_dir
, dest_css_dir
))
375 local('cp dist/dropzone.js {0}/'.format(dest_js_dir
))
376 local('cp dist/dropzone.css {0}/'.format(dest_css_dir
))
379 @recipe('selectize.js')
380 def install_selectize_js():
381 with
lcd(os
.path
.join(env
.ext_dir
, 'selectize.js')):
382 dest_js_dir
= os
.path
.join(lib_dir(env
.src_dir
, 'js'), 'selectize.js/')
383 dest_css_dir
= os
.path
.join(lib_dir(env
.src_dir
, 'css'), 'selectize.js/')
384 local('mkdir -p {0} {1}'.format(dest_js_dir
, dest_css_dir
))
385 local('cp dist/js/standalone/selectize.js {0}/'.format(dest_js_dir
))
386 local('cp dist/css/selectize.css {0}/'.format(dest_css_dir
))
387 local('cp dist/css/selectize.default.css {0}/'.format(dest_css_dir
))
393 def install(recipe_name
):
395 Install a module given the recipe name
397 RECIPES
[recipe_name
]()
401 def init_submodules(src_dir
='.'):
403 Initialize submodules (fetch them from external Git repos)
406 print green("Initializing submodules")
409 local('git submodule update --init --recursive')
414 Install asset dependencies
416 print green("Installing asset dependencies...")
417 for recipe_name
in RECIPES
:
418 print cyan("Installing {0}".format(recipe_name
))
423 def setup_deps(n_env
=None, n_version
=None, src_dir
=None, system_node
=None):
425 Setup (fetch and install) dependencies for Indico assets
428 src_dir
= src_dir
or env
.src_dir
429 n_env
= n_env
or env
.node_env_path
430 system_node
= system_node
.lower() in ('1', 'true') if system_node
is not None else env
.system_node
432 # initialize submodules if they haven't yet been
433 init_submodules(src_dir
)
435 ext_dir
= os
.path
.join(src_dir
, 'ext_modules')
437 _check_present('curl')
439 with
settings(node_env_path
=n_env
or os
.path
.join(ext_dir
, 'node_env'),
440 node_version
=n_version
or env
.node_version
,
441 system_node
=system_node
,
445 if not system_node
and not os
.path
.exists(n_env
):
449 local('npm install -g grunt-cli')
455 def clean_deps(src_dir
=None):
457 Clean up generated files
460 for dtype
in ASSET_TYPES
:
461 _safe_rm('{0}/*'.format(lib_dir(src_dir
or env
.src_dir
, dtype
)), recursive
=True)
465 def cleanup(build_dir
=None, force
=False):
467 Clean up build environment
469 _safe_rm('{0}'.format(build_dir
or env
.build_dir
), recursive
=True, ask
=(not force
))
473 def tarball(src_dir
=None):
475 Create a source Indico distribution (tarball)
478 src_dir
= src_dir
or env
.src_dir
482 setup_deps(n_env
=os
.path
.join(src_dir
, 'ext_modules', 'node_env'),
484 local('python setup.py -q sdist')
488 def egg(py_versions
=None):
490 Create a binary Indico distribution (egg)
493 for py_version
in py_versions
:
494 cmd_dir
= os
.path
.join(env
.pyenv_dir
, 'versions', 'indico-build-{0}'.format(py_version
), 'bin')
495 local('{0} setup.py -q bdist_egg'.format(os
.path
.join(cmd_dir
, 'python')))
496 print green(local('ls -lah dist/', capture
=True))
500 def make_docs(src_dir
=None, build_dir
=None, force
=False):
505 src_dir
= src_dir
or env
.src_dir
506 doc_src_dir
= os
.path
.join(src_dir
, 'doc')
508 if build_dir
is None:
509 target_dir
= os
.path
.join(src_dir
, 'indico', 'htdocs', 'ihelp')
511 target_dir
= os
.path
.join(build_dir
or env
.build_dir
, 'indico', 'htdocs', 'ihelp')
514 print yellow("Checking if docs need to be generated... "),
515 if _find_most_recent(target_dir
) > _find_most_recent(doc_src_dir
):
520 _check_present('pdflatex')
522 print green('Generating documentation')
523 with
lcd(doc_src_dir
):
528 local('rm -rf {0}/*'.format(os
.path
.join(target_dir
, 'html')))
529 local('mv build/html/* {0}'.format(os
.path
.join(target_dir
, 'html')))
531 with
lcd(os
.path
.join('guides', 'build', 'latex')):
532 local('make all-pdf')
533 local('mv *.pdf {0}'.format(os
.path
.join(target_dir
, 'pdf')))
535 print green('Cleaning up')
541 def _check_request_error(r
):
542 if r
.status_code
>= 400:
544 msg
= j
.get('message', DEFAULT_REQUEST_ERROR_MSG
)
545 print red("ERROR: {0} ({1})".format(msg
, r
.status_code
))
549 def _valid_github_credentials(auth
):
550 url
= "https://api.github.com/repos/{0}/{1}".format(env
.github
['org'], env
.github
['repo'])
551 r
= requests
.get(url
, auth
=(env
.github
['user'], auth
))
552 if (r
.status_code
== 401) and (r
.json().get('message') == 'Bad credentials'):
553 print red('Invalid Github credentials for user \'{0}\''.format(env
.github
['user']))
559 def _release_exists(tag_name
, auth
):
560 url
= "https://api.github.com/repos/{0}/{1}/releases".format(env
.github
['org'], env
.github
['repo'])
561 r
= requests
.get(url
, auth
=(env
.github
['user'], auth
))
562 _check_request_error(r
)
564 for release
in parsed
:
565 if release
.get('tag_name') == tag_name
:
566 rel_id
= release
.get('id')
567 return (True, rel_id
, release
)
569 return (False, 0, None)
572 def _asset_exists(rel_id
, name
, auth
):
573 url
= "https://api.github.com/repos/{0}/{1}/releases/{2}/assets" \
574 .format(env
.github
['org'], env
.github
['repo'], rel_id
)
575 r
= requests
.get(url
, auth
=(env
.github
['user'], auth
))
576 _check_request_error(r
)
579 if j
.get('name') == name
:
580 asset_id
= j
.get('id')
581 return (True, asset_id
)
587 def upload_github(build_dir
=None, tag_name
=None, auth_token
=None,
588 overwrite
=None, indico_version
='master'):
590 build_dir
= build_dir
or env
.build_dir
591 auth_token
= auth_token
or env
.github
['auth_token']
593 while (auth_token
is None) or (not _valid_github_credentials(auth_token
)):
594 auth_token
= getpass
.getpass(
595 'Insert the Github password/OAuth token for user \'{0}\': '.format(env
.github
['user']))
597 auth_creds
= (env
.github
['user'], auth_token
)
599 overwrite
= overwrite
or env
.github
['overwrite']
601 # Create a new release
602 tag_name
= tag_name
or indico_version
603 url
= "https://api.github.com/repos/{0}/{1}/releases".format(env
.github
['org'], env
.github
['repo'])
605 'tag_name': tag_name
,
606 'target_commitish': indico_version
,
607 'name': 'Indico {0}'.format(tag_name
),
611 (exists
, rel_id
, release_data
) = _release_exists(tag_name
, auth_token
)
614 if overwrite
is None:
615 overwrite
= _yes_no_input('Release already exists, do you want to overwrite', 'n')
621 # We will need to get a new release id from github
622 r
= requests
.post(url
, auth
=auth_creds
, data
=json
.dumps(payload
))
623 _check_request_error(r
)
624 release_data
= r
.json()
625 release_id
= release_data
.get('id')
627 # Upload binaries to the new release
628 binaries_dir
= os
.path
.join(build_dir
, 'indico', 'dist')
630 # awful way to handle this, but a regex seems like too much
631 url
= release_data
['upload_url'][:-7]
633 for f
in os
.listdir(binaries_dir
):
635 # jump over hidden/system files
636 if f
.startswith('.'):
639 if os
.path
.isfile(os
.path
.join(binaries_dir
, f
)):
640 (exists
, asset_id
) = _asset_exists(release_id
, f
, auth_token
)
643 # delete previous version
644 del_url
= "https://api.github.com/repos/{0}/{1}/releases/assets/{2}" \
645 .format(env
.github
['org'], env
.github
['repo'], asset_id
)
646 r
= requests
.delete(del_url
, auth
=auth_creds
)
647 _check_request_error(r
)
649 with
open(os
.path
.join(binaries_dir
, f
), 'rb') as ff
:
651 extension
= os
.path
.splitext(f
)[1]
653 # upload eggs using zip mime type
654 if extension
== '.gz':
655 headers
= {'Content-Type': 'application/x-gzip'}
656 elif extension
== '.egg':
657 headers
= {'Content-Type': 'application/zip'}
659 headers
['Accept'] = 'application/vnd.github.v3+json'
660 headers
['Content-Length'] = len(data
)
663 print green("Uploading \'{0}\' to Github".format(f
))
664 r
= requests
.post(url
, auth
=auth_creds
, headers
=headers
, data
=data
, params
=params
, verify
=False)
665 _check_request_error(r
)
669 def upload_ssh(build_dir
=None, server_host
=None, server_port
=None,
670 ssh_user
=None, ssh_key
=None, dest_dir
=None):
672 build_dir
= build_dir
or env
.build_dir
673 server_host
= server_host
or env
.ssh
['host']
674 server_port
= server_port
or env
.ssh
['port']
675 ssh_user
= ssh_user
or env
.ssh
['user']
676 ssh_key
= ssh_key
or env
.ssh
['key']
677 dest_dir
= dest_dir
or env
.ssh
['dest_dir']
679 env
.host_string
= server_host
+ ':' + server_port
681 env
.key_filename
= ssh_key
683 binaries_dir
= os
.path
.join(build_dir
, 'indico', 'dist')
684 for f
in os
.listdir(binaries_dir
):
685 if os
.path
.isfile(os
.path
.join(binaries_dir
, f
)):
686 _putl(os
.path
.join(binaries_dir
, f
), dest_dir
)
690 def _package_release(build_dir
, py_versions
, system_node
):
691 # Build source tarball
692 with
settings(system_node
=system_node
):
693 print green('Generating '), cyan('tarball')
696 # Build binaries (EGG)
697 print green('Generating '), cyan('eggs')
702 def package_release(py_versions
=None, build_dir
=None, system_node
=False,
703 indico_version
=None, upstream
=None, tag_name
=None,
704 github_auth
=None, overwrite
=None, ssh_server_host
=None,
705 ssh_server_port
=None, ssh_user
=None, ssh_key
=None,
706 ssh_dest_dir
=None, no_clean
=False, force_clean
=False,
707 upload_to
=None, build_here
=False):
709 Create an Indico release - source and binary distributions
712 DEVELOP_REQUIRES
= ['pojson>=0.4', 'termcolor', 'werkzeug', 'nodeenv', 'fabric',
713 'sphinx', 'repoze.sphinx.autointerface']
715 py_versions
= py_versions
.split('/') if py_versions
else env
.py_versions
716 upload_to
= upload_to
.split('/') if upload_to
else []
718 build_dir
= build_dir
or env
.build_dir
719 upstream
= upstream
or env
.github
['upstream']
721 ssh_server_host
= ssh_server_host
or env
.ssh
['host']
722 ssh_server_port
= ssh_server_port
or env
.ssh
['port']
723 ssh_user
= ssh_user
or env
.ssh
['user']
724 ssh_key
= ssh_key
or env
.ssh
['key']
725 ssh_dest_dir
= ssh_dest_dir
or env
.ssh
['dest_dir']
727 indico_version
= indico_version
or 'master'
729 local('mkdir -p {0}'.format(build_dir
))
731 _check_pyenv(py_versions
)
734 _package_release(os
.path
.dirname(__file__
), py_versions
, system_node
)
737 if os
.path
.exists(os
.path
.join(build_dir
, 'indico')):
738 print yellow("Repository seems to already exist.")
740 local('git fetch {0}'.format(upstream
))
741 local('git reset --hard FETCH_HEAD')
743 local('git clean -df')
745 local('git clone {0}'.format(upstream
))
747 print green("Checking out branch \'{0}\'".format(indico_version
))
748 local('git checkout {0}'.format(indico_version
))
750 _package_release(os
.path
.join(build_dir
, 'indico'), py_versions
, system_node
)
754 upload_github(build_dir
, tag_name
, github_auth
, overwrite
, indico_version
)
756 upload_ssh(build_dir
, ssh_server_host
, ssh_server_port
, ssh_user
, ssh_key
, ssh_dest_dir
)
758 if not build_here
and force_clean
:
759 cleanup(build_dir
, force
=True)