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('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
))
380 def install(recipe_name
):
382 Install a module given the recipe name
384 RECIPES
[recipe_name
]()
388 def init_submodules(src_dir
='.'):
390 Initialize submodules (fetch them from external Git repos)
393 print green("Initializing submodules")
396 local('git submodule update --init --recursive')
401 Install asset dependencies
403 print green("Installing asset dependencies...")
404 for recipe_name
in RECIPES
:
405 print cyan("Installing {0}".format(recipe_name
))
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
,
432 if not system_node
and not os
.path
.exists(n_env
):
436 local('npm install -g grunt-cli')
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)
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
))
460 def tarball(src_dir
=None):
462 Create a source Indico distribution (tarball)
465 src_dir
= src_dir
or env
.src_dir
469 setup_deps(n_env
=os
.path
.join(src_dir
, 'ext_modules', 'node_env'),
471 local('python setup.py -q sdist')
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))
487 def make_docs(src_dir
=None, build_dir
=None, force
=False):
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')
498 target_dir
= os
.path
.join(build_dir
or env
.build_dir
, 'indico', 'htdocs', 'ihelp')
501 print yellow("Checking if docs need to be generated... "),
502 if _find_most_recent(target_dir
) > _find_most_recent(doc_src_dir
):
507 _check_present('pdflatex')
509 print green('Generating documentation')
510 with
lcd(doc_src_dir
):
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')
528 def _check_request_error(r
):
529 if r
.status_code
>= 400:
531 msg
= j
.get('message', DEFAULT_REQUEST_ERROR_MSG
)
532 print red("ERROR: {0} ({1})".format(msg
, r
.status_code
))
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']))
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
)
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
)
566 if j
.get('name') == name
:
567 asset_id
= j
.get('id')
568 return (True, asset_id
)
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'])
592 'tag_name': tag_name
,
593 'target_commitish': indico_version
,
594 'name': 'Indico {0}'.format(tag_name
),
598 (exists
, rel_id
, release_data
) = _release_exists(tag_name
, auth_token
)
601 if overwrite
is None:
602 overwrite
= _yes_no_input('Release already exists, do you want to overwrite', 'n')
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('.'):
626 if os
.path
.isfile(os
.path
.join(binaries_dir
, f
)):
627 (exists
, asset_id
) = _asset_exists(release_id
, f
, auth_token
)
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
:
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
)
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
)
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
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
)
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')
683 # Build binaries (EGG)
684 print green('Generating '), cyan('eggs')
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
)
721 _package_release(os
.path
.dirname(__file__
), py_versions
, system_node
)
724 if os
.path
.exists(os
.path
.join(build_dir
, 'indico')):
725 print yellow("Repository seems to already exist.")
727 local('git fetch {0}'.format(upstream
))
728 local('git reset --hard FETCH_HEAD')
730 local('git clean -df')
732 local('git clone {0}'.format(upstream
))
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
)
741 upload_github(build_dir
, tag_name
, github_auth
, overwrite
, indico_version
)
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)