Mercurial > dotfiles
diff install.py @ 407:c6da0c9f40ae
Replace subrepos with an install script. Finally.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 10 Jan 2018 00:00:00 -0800 |
parents | |
children | 222b477ad678 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/install.py Wed Jan 10 00:00:00 2018 -0800 @@ -0,0 +1,260 @@ +import os +import os.path +import sys +import stat +import argparse +import functools +import subprocess +import configparser + + +dotfiles_dir = os.path.abspath(os.path.dirname(__file__)) + +is_nix = True +is_windows = False +if sys.platform == "win32": + is_nix = False + is_windows = True + + +def _p(*paths): + return os.path.join(dotfiles_dir, *paths).replace('/', os.sep) + + +def nixslash(path): + return path.replace('\\', '/') + + +def ensure_dir(path): + full_path = os.path.abspath(os.path.expanduser(path)) + if not os.path.isdir(full_path): + os.makedirs(full_path, mode=0o700) + + +def mklink(orig_rel_path, link_path, mode=None): + orig_full_path = os.path.join(dotfiles_dir, orig_rel_path) + link_full_path = os.path.abspath(os.path.expanduser(link_path)) + if os.path.islink(link_full_path): + print("Unlinking %s" % link_full_path) + os.unlink(link_full_path) + elif os.path.exists(link_full_path): + print("Removing %s" % link_full_path) + os.remove(link_full_path) + + print("%s -> %s" % (link_full_path, orig_full_path)) + os.symlink(orig_full_path, link_full_path) + if mode is not None: + os.chmod(link_full_path, mode) + + +def writelines(path, lines): + full_path = os.path.abspath(os.path.expanduser(path)) + print("%d lines to %s" % (len(lines), full_path)) + with open(full_path, 'w') as fp: + for l in lines: + fp.write(l) + fp.write('\n') + + +def only_on_nix(f): + @functools.wraps(f) + def decorator(*args, **kwargs): + if is_nix: + return f(*args, **kwargs) + return decorator + + +def only_on_win(f): + @functools.wraps(f) + def decorator(*args, **kwargs): + if is_windows: + return f(*args, **kwargs) + return decorator + + +def needs_config(f): + f.__dotfiles_needs_config__ = True + return f + + +def run_priority(prio): + def wrapper(f): + f.__dotfiles_priority__ = prio + return f + return wrapper + + +@only_on_nix +def install_bash(): + mklink('bashrc/bashrc', '.bashrc') + mklink('bashrc/bash_profile', '.bash_profile') + + +@only_on_nix +def install_fish(): + ensure_dir('~/.config') + mklink('fish', '~/.config/fish') + + +def install_vim(): + vimrc_path = '~/.vimrc' + if is_windows: + vimrc_path = '~/_vimrc' + writelines(vimrc_path, [ + 'set runtimepath+=%s' % nixslash(_p('vim')), + 'source %s' % nixslash(_p('vim', 'vimrc')) + ]) + + +@run_priority(2) # Needs to run before `fish`. +def install_mercurial(): + hgrc_path = '~/.hgrc' + if is_windows: + hgrc_path = '~/mercurial.ini' + writelines(hgrc_path, [ + '%%include %s' % _p('hgrc/hgrc'), + '[ui]', + 'ignore = %s' % _p('hgrc/hgignore'), + '[subrepos]', + 'git:allowed = true', + '[extensions]', + 'hggit = %s' % _p('lib/hg/hg-git/hggit/'), + 'onsub = %s' % _p('lib/hg/onsub/onsub.py'), + 'allpaths = %s' % _p('lib/hg/allpaths/mercurial_all_paths.py'), + 'prompt = %s' % _p('lib/hg/hg-prompt/prompt.py'), + 'evolve = %s' % _p('lib/hg/mutable-history/hgext3rd/evolve'), + 'terse-status = %s' % _p('lib/hg/terse-status/terse-status.py') + ]) + if is_nix: + print("Building fast-hg-prompt...") + compile_ok = True + try: + subprocess.check_call(['make'], cwd=_p('lib/hg/fast-hg-prompt')) + except subprocess.CalledProcessError: + compile_ok = False + + for n in ['bookmark', 'remote', 'status']: + link_path = os.path.expanduser('~/.local/bin/fast-hg-%s' % n) + if compile_ok: + mklink('lib/hg/fast-hg-prompt/fast-hg-%s' % n, link_path, + mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)) + elif os.path.islink(link_path): + os.unlink(link_path) + elif os.path.exists(link_path): + os.remove(link_path) + + +def install_git(): + writelines('~/.gitconfig', [ + '[include]', + 'path = %s' % _p('git/gitconfig') + ]) + if is_windows: + subprocess.check_call( + ['setx', 'GIT_SSH', + '%USERPROFILE%\\Dropbox\\Utilities\\plink.exe'], + shell=True) + + +@only_on_nix +def install_tmux(): + mklink('tmux/tmux.conf', '~/.tmux.conf') + + +@only_on_nix +def install_weechat(): + mklink('weechat', '~/.weechat') + + +@only_on_nix +def install_mutt(): + writelines('~/.muttrc', [ + 'source "gpg2 -dq %s |"' % _p('mutt/variables.gpg'), + 'source "%s"' % _p('mutt/muttrc'), + 'source "%s"' % _p('lib/mutt/mutt-colors-solarized/' + 'mutt-colors-solarized-dark-256.muttrc') + ]) + + +def clone_git(url, path): + if os.path.isdir(path): + print("Skipping git clone of %s -- directory exists" % path) + print("git clone %s %s" % (url, path)) + ensure_dir(os.path.dirname(path)) + subprocess.check_call(['git', 'clone', url, path]) + + +def clone_hg(url, path): + if os.path.isdir(path): + print("Skipping hg clone of %s -- directory exists" % path) + print("hg clone %s %s" % (url, path)) + ensure_dir(os.path.dirname(path)) + env = dict(os.environ) + env.update({'HGPLAIN': '1'}) + subprocess.check_call(['hg', 'clone', url, path], env=env) + + +@needs_config +@run_priority(100) +def install_subrepos(cfg): + if not cfg.has_section('subrepos'): + return + + for path, url in cfg.items('subrepos'): + full_path = _p(path) + if url.startswith('[git]'): + clone_git(url[len('[git]'):], full_path) + else: + clone_hg(url, full_path) + + +def main(): + print("dotfiles installer") + print("python %s" % sys.version) + print("on %s" % sys.platform) + print('') + + cfg = configparser.ConfigParser() + cfg.read(_p('install.cfg')) + + mod_names = ['all'] + this_mod = sys.modules[__name__] + for an in dir(this_mod): + if not an.startswith('install_'): + continue + + name = an[len('install_'):] + mod_names.append(name) + + parser = argparse.ArgumentParser() + parser.add_argument( + 'module', nargs='*', + choices=mod_names, + help="Which module(s) to install. Defaults to all modules.") + args = parser.parse_args() + + funcs = [] + selected_mods = set(args.module) + if 'all' in selected_mods: + selected_mods = set(mod_names) + selected_mods.remove('all') + for mn in selected_mods: + func = getattr(this_mod, 'install_%s' % mn) + funcs.append((mn, func)) + + funcs = sorted(funcs, key=_get_install_func_priority, reverse=True) + for name, func in funcs: + print("Installing %s" % name) + if hasattr(func, '__dotfiles_needs_config__'): + func(cfg) + else: + func() + + +def _get_install_func_priority(func_info): + func = func_info[1] + return getattr(func, '__dotfiles_priority__', 0) + + +if __name__ == '__main__': + main()