def setup_npm(revealjs_dir): if query_yes_no('\nSet up npm for serving presentation?', default='no'): run(flo('cd {revealjs_dir} && ' 'npm install')) print_msg( flo('\nServe presentation locally ' '(monitors source files for changes):\n\n' ' cd {revealjs_dir} && npm start\n\n' 'View presentation in a browser:\n\n' ' http://localhost:8000'))
def setup_npm(revealjs_dir): if query_yes_no('\nSet up npm for serving presentation?', default='no'): run(flo('cd {revealjs_dir} && ' 'npm install')) print_msg(flo('\nServe presentation locally ' '(monitors source files for changes):\n\n' ' cd {revealjs_dir} && npm start\n\n' 'View presentation in a browser:\n\n' ' http://localhost:8000'))
def create_github_remote_repo(basedir, github_user, github_repo): repo_url = cyan(flo('https://github.com/{github_user}/{github_repo}')) question = flo('Create remote repo {repo_url} at github.com?') if query_yes_no(question, default='yes'): run(flo("cd {basedir} && " "curl -u '{github_user}' https://api.github.com/user/repos " "-d '") + '{"name":"' + flo('{github_repo}"') + "}'") run(flo('cd {basedir} && ' 'git remote add origin ' '[email protected]:{github_user}/{github_repo}.git')) run(flo('cd {basedir} && git push origin master')) else: print('\nplease, do it yourself:\n' ' https://help.github.com/articles/' 'adding-an-existing-project-to-github-using-the-command-line/')
def powerline_for_bash_or_powerline_shell(bindings_dir): '''Set up the bash extension of powerline or powerline_shell (another task). ''' question = '\nSet up powerline-shell instead of powerline bash extension?' if query_yes_no(question, default='yes'): from setup import powerline_shell powerline_shell() # disable powerline bash extension if it has been set up powerline_bash_enabler = 'if [ -f ~/.bashrc_powerline_bash ]; then ' \ 'source ~/.bashrc_powerline_bash; fi' comment_out_line(filename='~/.bashrc', line=powerline_bash_enabler) else: powerline_for_bash(bindings_dir) # disable powerline_shell if it has been set up powerline_shell_enabler = 'if [ -f ~/.bashrc_powerline_shell ]; then ' \ 'source ~/.bashrc_powerline_shell; fi' comment_out_line(filename='~/.bashrc', line=powerline_shell_enabler)
def powerline_shell(): '''Install and set up powerline-shell prompt. More infos: * https://github.com/banga/powerline-shell * https://github.com/ohnonot/powerline-shell * https://askubuntu.com/questions/283908/how-can-i-install-and-use-powerline-plugin ''' assert env.host == 'localhost', 'This task cannot run on a remote host' # set up fonts for powerline checkup_git_repo_legacy('https://github.com/powerline/fonts.git', name='powerline-fonts') run('cd ~/repos/powerline-fonts && ./install.sh') # run('fc-cache -vf ~/.local/share/fonts') prefix = 'URxvt*font: ' from config import fontlist line = prefix + fontlist update_or_append_line(filename='~/.Xresources', prefix=prefix, new_line=line) if env.host_string == 'localhost': run('xrdb ~/.Xresources') # set up powerline-shell checkup_git_repo_legacy('https://github.com/banga/powerline-shell.git') # checkup_git_repo_legacy('https://github.com/ohnonot/powerline-shell.git') install_file_legacy(path='~/repos/powerline-shell/config.py') run('cd ~/repos/powerline-shell && ./install.py') question = 'Use normal question mark (u003F) for untracked files instead '\ 'of fancy "black question mark ornament" (u2753, which may not work)?' if query_yes_no(question, default='yes'): filename = '~/repos/powerline-shell/powerline-shell.py' update_or_append_line(filename, keep_backup=False, prefix=" 'untracked': u'\u2753',", new_line=" 'untracked': u'\u003F',") run(flo('chmod u+x {filename}')) bash_snippet = '~/.bashrc_powerline_shell' install_file_legacy(path=bash_snippet) prefix = flo('if [ -f {bash_snippet} ]; ') enabler = flo('if [ -f {bash_snippet} ]; then source {bash_snippet}; fi') uncomment_or_update_or_append_line(filename='~/.bashrc', prefix=prefix, new_line=enabler)
def set_up_vim_addon_vim_instant_markdown(): print_msg('\ninstall instant-markdown-d with npm (node.js) ' 'for vim addon vim-instant-markdown') install_cmd = 'npm install -g instant-markdown-d' with warn_only(): res = run(install_cmd) if res.return_code != 0: print_msg('npm is not installed') query = "Run fabric task 'setup.nvm' in order to install npm?" if query_yes_no(query, default='yes'): from nvm import nvm execute(nvm) run('bash -c "source ~/.bashrc_nvm && nvm install node"', msg='\ninstall latest version of npm') run(flo('bash -c "source ~/.bashrc_nvm && {install_cmd}"'), msg="\nfabric task 'setup.nvm' finished\n\n" '----\ninstall instant-markdown-d')
def revealjs(basedir=None, title=None, subtitle=None, description=None, github_user=None, github_repo=None): '''Set up or update a reveals.js presentation with slides written in markdown. Several reveal.js plugins will be set up, too. More info: Demo: https://theno.github.io/revealjs_template http://lab.hakim.se/reveal-js/ https://github.com/hakimel/reveal.js plugins: https://github.com/hakimel/reveal.js/wiki/Plugins,-Tools-and-Hardware https://github.com/rajgoel/reveal.js-plugins/ https://github.com/e-gor/Reveal.js-TOC-Progress https://github.com/e-gor/Reveal.js-Title-Footer ''' basedir = basedir or query_input('Base dir of the presentation?', default='~/repos/my_presi') revealjs_repo_name = 'reveal.js' revealjs_dir = flo('{basedir}/{revealjs_repo_name}') _lazy_dict['presi_title'] = title _lazy_dict['presi_subtitle'] = subtitle _lazy_dict['presi_description'] = description _lazy_dict['github_user'] = github_user _lazy_dict['github_repo'] = github_repo question = flo( "Base dir already contains a sub dir '{revealjs_repo_name}'." ' Reset (and re-download) reveal.js codebase?') if not exists(revealjs_dir) or query_yes_no(question, default='no'): run(flo('mkdir -p {basedir}')) set_up_revealjs_codebase(basedir, revealjs_repo_name) install_plugins(revealjs_dir) apply_customizations(repo_dir=revealjs_dir) if exists(revealjs_dir): install_files_in_basedir(basedir, repo_dir=revealjs_dir) init_git_repo(basedir) create_github_remote_repo(basedir) setup_npm(revealjs_dir) else: print('abort')
def virtualbox_host(): '''Install a VirtualBox host system. More Infos: * overview: https://wiki.ubuntuusers.de/VirtualBox/ * installation: https://wiki.ubuntuusers.de/VirtualBox/Installation/ ''' if query_yes_no(question='Uninstall virtualbox-dkms?', default='yes'): run('sudo apt-get remove virtualbox-dkms') install_packages([ 'virtualbox', 'virtualbox-qt', 'virtualbox-dkms', 'virtualbox-guest-dkms', 'virtualbox-guest-additions-iso', ]) users = [env.user] for username in users: run(flo('sudo adduser {username} vboxusers'))
def revealjs(basedir=None, title=None, subtitle=None, description=None, github_user=None, github_repo=None): '''Set up or update a reveals.js presentation with slides written in markdown. Several reveal.js plugins will be set up, too. More info: Demo: https://theno.github.io/revealjs_template http://lab.hakim.se/reveal-js/ https://github.com/hakimel/reveal.js plugins: https://github.com/hakimel/reveal.js/wiki/Plugins,-Tools-and-Hardware https://github.com/rajgoel/reveal.js-plugins/ https://github.com/e-gor/Reveal.js-TOC-Progress https://github.com/e-gor/Reveal.js-Title-Footer ''' basedir = basedir or query_input('Base dir of the presentation?', default='~/repos/my_presi') revealjs_repo_name = 'reveal.js' revealjs_dir = flo('{basedir}/{revealjs_repo_name}') _lazy_dict['presi_title'] = title _lazy_dict['presi_subtitle'] = subtitle _lazy_dict['presi_description'] = description _lazy_dict['github_user'] = github_user _lazy_dict['github_repo'] = github_repo question = flo("Base dir already contains a sub dir '{revealjs_repo_name}'." ' Reset (and re-download) reveal.js codebase?') if not exists(revealjs_dir) or query_yes_no(question, default='no'): run(flo('mkdir -p {basedir}')) set_up_revealjs_codebase(basedir, revealjs_repo_name) install_plugins(revealjs_dir) apply_customizations(repo_dir=revealjs_dir) if exists(revealjs_dir): install_files_in_basedir(basedir, repo_dir=revealjs_dir) init_git_repo(basedir) create_github_remote_repo(basedir) setup_npm(revealjs_dir) else: print('abort')
def new_addon(): '''Create a repository for a new fabsetup-task addon. The repo will contain the fabsetup addon boilerplate. Running this task you have to enter: * your github user account (your pypi account should be the same or similar) * addon name * task name * headline, short description, and touched (and created) files and dirs for the task docstring and the README.md Created files and dirs: ~/.fabsetup-addon-repos/fabsetup-{user}-{addon} ├── fabfile-dev.py ├── fabfile.py ├── fabsetup_{user}_{task} │ ├── files │ │ └── home │ │ └── USERNAME │ │ └── bin │ │ └── termdown.template │ ├── __init__.py <--. │ └── _version.py `- task definition ├── .git │ ├── ... │ ├── config │ └── ... ├── .gitignore ├── README.md ├── requirements.txt └── setup.py ''' author, author_email = git_name_and_email_or_die() username = query_input('github username:'******'\naddon name:', default='termdown') addonname = addonname.replace('_', '-').replace(' ', '-') # minus only full_addonname = flo('fabsetup-{username}-{addonname}') print('└─> full addon name: {0}\n'.format( cyan(full_addonname))) taskname = query_input('task name:', default=addonname.replace('-', '_')) taskname = taskname.replace('-', '_').replace(' ', '_') # underscores only print('└─> full task name: {0}'.format( cyan(flo('{username}.{taskname}\n')))) addon_dir = os.path.expanduser(flo( '~/.fabsetup-addon-repos/fabsetup-{username}-{addonname}')) if os.path.exists(addon_dir): print(red(flo('\n{addon_dir} already exists.'))) print('abort') else: print('~/.gitconfig') print('├─> author: {0} ─> LICENSE, setup.py'.format(cyan(author))) print('└─> author email: {0} ─> setup.py'.format(cyan(author_email))) headline = query_input( '\nshort task headline:', default='Install or update termdown.') description = query_input( '\ndescribing infos:', default='''Termdown (https://github.com/trehn/termdown) is a "[c]ountdown timer and stopwatch in your terminal". It installs termdown via `pip install --user termdown`. Also, it installs a bash-wrapper script at `~/bin/termdown` which is convenient to time pomodoro sessions and pops up a notification when the timer finishes.''') touched_files = query_input( '\naffected files, dirs, and installed packages:', default='~/bin/termdown\n ' 'pip-package termdown (`--user` install)') print('\naddon git-repository dir: {0}'.format(cyan(addon_dir))) if not query_yes_no('\ncreate new addon?', default='yes'): print('abort') else: create_files(addon_dir, username, addonname, taskname, author, author_email, headline, description, touched_files) init_git_repo(addon_dir) create_github_remote_repo(basedir=addon_dir, github_user=username, github_repo=full_addonname) summary(addon_dir, username, taskname)
def trac(): '''Set up or update a trac project. This trac installation uses python2, git, sqlite (trac-default), gunicorn, and nginx. The connection is https-only and secured by a letsencrypt certificate. This certificate must be created separately with task setup.server_letsencrypt. This task installes or updates to the latest trac version hosted at https://pypi.python.org/pypi/Trac Created and modified files and dirs of this task: ``` ~/sites/<sitename> <--- example: sitename = trac.example.com │ ├── backup.sh <--- create a local backup (deletes dir backup/ ├── backup | before it creates │ └── <sitename>_tracenv_hotcopy.tar.gz <--´ the tarball) ├── run │ └── trac.sock <--- file-socket for binding to nginx ├── scripts │ └── tracwsgi.py ├── tracenv │ ├── conf │ │ ├── trac.htpasswd <--- trac user password hashes │ │ └── trac.ini <--- trac config file │ ├── db │ │ └── trac.db <--- sqlite database │ ├── files │ ├── git │ ├── htdocs │ ├── log │ ├── plugins │ ├── README │ ├── templates │ └── VERSION └── virtualenv ├── bin ├── include ├── lib ├── local └── pip-selfcheck.json ``` How to create a backup tarball "manually": `~/sites/<sitename>/backup/tracenv_hotcopy_<yyyy-mm-dd>.tar.gz`: ``` cd ~/sites/<sitename> && rm -rf ./backup ./virtualenv/bin/trac-admin ./tracenv hotcopy ./backup/tracenv_hotcopy mkdir -p ./backup && cd ./backup tar czf <sitename>_tracenv_hotcopy_$(date +%F).tar.gz tracenv_hotcopy/ rm -rf tracenv_hotcopy; ls -hl ``` More infos: https://trac.edgewall.org/wiki/TracInstall https://trac.edgewall.org/wiki/TracFastCgi#NginxConfiguration https://trac.edgewall.org/wiki/TracNginxRecipe https://trac.edgewall.org/wiki/Gunicorn http://www.obeythetestinggoat.com/book/chapter_08.html#_getting_to_a_production_ready_deployment Setting REMOTE_USER for Trac in Gunicorn behind Nginx: http://serverfault.com/a/392096 https://trac.edgewall.org/wiki/TracBackup ''' hostname = re.sub(r'^[^@]+@', '', env.host) # without username if any sitename = query_input( question='\nEnter site-name of Your trac web service', default=flo('trac.{hostname}')) username = env.user site_dir = flo('/home/{username}/sites/{sitename}') bin_dir = flo('{site_dir}/virtualenv/bin') # provisioning steps install_or_upgrade_virtualenv_pip_package() create_directory_structure(site_dir) update_virtualenv(site_dir, sitename) set_up_trac_plugins(sitename, site_dir, bin_dir) set_up_gunicorn(site_dir, sitename) configure_nginx(username, sitename, hostname) if query_yes_no('\nRestore trac environment from backup tarball?', default='no'): restore_tracenv_from_backup_tarball(site_dir, bin_dir) elif not tracenv_exists(site_dir): init_tracenv(site_dir, bin_dir, username) upgrade_tracenv(site_dir, bin_dir) set_up_upstart_for_gunicorn(sitename, username, site_dir)
def fdroid(): '''Set up an F-Droid App Repo. More infos: * https://f-droid.org/wiki/page/Setup_an_FDroid_App_Repo * https://f-droid.org/wiki/page/Installing_the_Server_and_Repo_Tools ''' hostname = re.sub(r'^[^@]+@', '', env.host) # without username if any sitename = query_input( question='\nEnter site-name of Your F-Droid web service', default=flo('fdroid.{hostname}')) username = env.user fabfile_data_dir = FABFILE_DATA_DIR print(magenta(' install fdroidserver')) res = run('dpkg --get-selections | ' 'grep -q "^fdroidserver[[:space:]]*install$" >/dev/null', warn_only=True) package_installed = res.return_code == 0 question = 'package fdroidserver already installed, update? ' \ '(needs some time)' if package_installed and not query_yes_no(question, default='no'): print('skip update') else: with hide('output'): sudo('yes "" | add-apt-repository ppa:guardianproject/ppa') sudo('apt-get update') # why 'android-libhost-dev' (avoid "Failed to get apk information" # on 'fdroid update --create-metadata'): # https://f-droid.org/forums/topic/failed-to-get-apk-information-2/#post-15777 install_packages(['fdroidserver', 'android-libhost-dev']) sudo('yes "" | add-apt-repository --remove ' 'ppa:guardianproject/ppa') sudo('apt-get update') site_dir = flo('/home/{username}/sites/{sitename}') apks_dir = flo('{site_dir}/apks') fdroid_dir = flo('{site_dir}/fdroid') repo_dir = flo('{site_dir}/fdroid/repo') print(magenta(' init f-droid repo')) question = ' '.join(['already initialized, initialize again?', '(creates a new repo key)']) if exists(repo_dir) and not query_yes_no(question, default='no'): print('skip initialization') else: with warn_only(): run(flo('rm -rf {fdroid_dir}')) run(flo('mkdir -p {repo_dir}')) run(flo('cd {fdroid_dir} && fdroid init')) run(flo('cd {site_dir} && tree')) print(magenta(' update apk files of the fdroid repo')) run(flo('mkdir -p {apks_dir}')) run(flo('rm -rf {repo_dir}/*.apk')) run(flo("find {apks_dir} -type f | rename 's/ /_/g'")) run(flo("find {apks_dir} -type f | rename 's/[^[:ascii:]]//g'")) run(flo('chmod 644 {apks_dir}/*.apk')) run(flo('cp -v {apks_dir}/*.apk {repo_dir}'), warn_only=True) run(flo('cd {fdroid_dir} && fdroid update --create-metadata')) print(magenta(' setup nginx for F-Droid')) run(flo('echo -e "User-agent: *\\nDisallow: /" > {fdroid_dir}/robots.txt')) filename = 'fdroid_site_config.template' path = flo('{fabfile_data_dir}/files/etc/nginx/sites-available/{filename}') from_str = filled_out_template(path, username=username, sitename=sitename, hostname=hostname) with tempfile.NamedTemporaryFile(prefix=filename) as tmp_file: with open(tmp_file.name, 'w') as fp: fp.write(from_str) put(tmp_file.name, flo('/tmp/{filename}')) to = flo('/etc/nginx/sites-available/{sitename}') sudo(flo('mv /tmp/{filename} {to}')) sudo(flo('chown root.root {to}')) sudo(flo('chmod 644 {to}')) sudo(flo(' '.join([ 'ln -snf ../sites-available/{sitename}', '/etc/nginx/sites-enabled/{sitename}', ]))) sudo('service nginx reload')
def create_github_remote_repo(basedir): '''Create a remote origin repo at github.com if wanted.''' if remote_origin_configured(basedir): print_msg('remote origin already configured (skip)') elif query_yes_no('Create remote repo at github.com?', default='no'): _create_github_remote_repo(basedir)
def fdroid(): '''Set up an F-Droid App Repo. More infos: * https://f-droid.org/wiki/page/Setup_an_FDroid_App_Repo * https://f-droid.org/wiki/page/Installing_the_Server_and_Repo_Tools ''' hostname = re.sub(r'^[^@]+@', '', env.host) # without username if any sitename = query_input( question='\nEnter site-name of Your F-Droid web service', default=flo('fdroid.{hostname}')) username = env.user fabfile_data_dir = FABFILE_DATA_DIR print(magenta(' install fdroidserver')) res = run( 'dpkg --get-selections | ' 'grep -q "^fdroidserver[[:space:]]*install$" >/dev/null', warn_only=True) package_installed = res.return_code == 0 question = 'package fdroidserver already installed, update? ' \ '(needs some time)' if package_installed and not query_yes_no(question, default='no'): print('skip update') else: with hide('output'): sudo('yes "" | add-apt-repository ppa:guardianproject/ppa') sudo('apt-get update') # why 'android-libhost-dev' (avoid "Failed to get apk information" # on 'fdroid update --create-metadata'): # https://f-droid.org/forums/topic/failed-to-get-apk-information-2/#post-15777 install_packages(['fdroidserver', 'android-libhost-dev']) sudo('yes "" | add-apt-repository --remove ' 'ppa:guardianproject/ppa') sudo('apt-get update') site_dir = flo('/home/{username}/sites/{sitename}') apks_dir = flo('{site_dir}/apks') fdroid_dir = flo('{site_dir}/fdroid') repo_dir = flo('{site_dir}/fdroid/repo') print(magenta(' init f-droid repo')) question = ' '.join( ['already initialized, initialize again?', '(creates a new repo key)']) if exists(repo_dir) and not query_yes_no(question, default='no'): print('skip initialization') else: with warn_only(): run(flo('rm -rf {fdroid_dir}')) run(flo('mkdir -p {repo_dir}')) run(flo('cd {fdroid_dir} && fdroid init')) run(flo('cd {site_dir} && tree')) print(magenta(' update apk files of the fdroid repo')) run(flo('mkdir -p {apks_dir}')) run(flo('rm -rf {repo_dir}/*.apk')) run(flo("find {apks_dir} -type f | rename 's/ /_/g'")) run(flo("find {apks_dir} -type f | rename 's/[^[:ascii:]]//g'")) run(flo('chmod 644 {apks_dir}/*.apk')) run(flo('cp -v {apks_dir}/*.apk {repo_dir}'), warn_only=True) run(flo('cd {fdroid_dir} && fdroid update --create-metadata')) print(magenta(' setup nginx for F-Droid')) run(flo('echo -e "User-agent: *\\nDisallow: /" > {fdroid_dir}/robots.txt')) filename = 'fdroid_site_config.template' path = flo('{fabfile_data_dir}/files/etc/nginx/sites-available/{filename}') from_str = filled_out_template(path, username=username, sitename=sitename, hostname=hostname) with tempfile.NamedTemporaryFile(prefix=filename) as tmp_file: with open(tmp_file.name, 'w') as fp: fp.write(from_str) put(tmp_file.name, flo('/tmp/{filename}')) to = flo('/etc/nginx/sites-available/{sitename}') sudo(flo('mv /tmp/{filename} {to}')) sudo(flo('chown root.root {to}')) sudo(flo('chmod 644 {to}')) sudo( flo(' '.join([ 'ln -snf ../sites-available/{sitename}', '/etc/nginx/sites-enabled/{sitename}', ]))) sudo('service nginx reload')