Mercurial > dotfiles
comparison install.py @ 414:72365ec18f54
Merge changes
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Thu, 18 Jan 2018 16:27:32 -0800 |
parents | c6da0c9f40ae |
children | 222b477ad678 |
comparison
equal
deleted
inserted
replaced
413:4a2468f72e44 | 414:72365ec18f54 |
---|---|
1 import os | |
2 import os.path | |
3 import sys | |
4 import stat | |
5 import argparse | |
6 import functools | |
7 import subprocess | |
8 import configparser | |
9 | |
10 | |
11 dotfiles_dir = os.path.abspath(os.path.dirname(__file__)) | |
12 | |
13 is_nix = True | |
14 is_windows = False | |
15 if sys.platform == "win32": | |
16 is_nix = False | |
17 is_windows = True | |
18 | |
19 | |
20 def _p(*paths): | |
21 return os.path.join(dotfiles_dir, *paths).replace('/', os.sep) | |
22 | |
23 | |
24 def nixslash(path): | |
25 return path.replace('\\', '/') | |
26 | |
27 | |
28 def ensure_dir(path): | |
29 full_path = os.path.abspath(os.path.expanduser(path)) | |
30 if not os.path.isdir(full_path): | |
31 os.makedirs(full_path, mode=0o700) | |
32 | |
33 | |
34 def mklink(orig_rel_path, link_path, mode=None): | |
35 orig_full_path = os.path.join(dotfiles_dir, orig_rel_path) | |
36 link_full_path = os.path.abspath(os.path.expanduser(link_path)) | |
37 if os.path.islink(link_full_path): | |
38 print("Unlinking %s" % link_full_path) | |
39 os.unlink(link_full_path) | |
40 elif os.path.exists(link_full_path): | |
41 print("Removing %s" % link_full_path) | |
42 os.remove(link_full_path) | |
43 | |
44 print("%s -> %s" % (link_full_path, orig_full_path)) | |
45 os.symlink(orig_full_path, link_full_path) | |
46 if mode is not None: | |
47 os.chmod(link_full_path, mode) | |
48 | |
49 | |
50 def writelines(path, lines): | |
51 full_path = os.path.abspath(os.path.expanduser(path)) | |
52 print("%d lines to %s" % (len(lines), full_path)) | |
53 with open(full_path, 'w') as fp: | |
54 for l in lines: | |
55 fp.write(l) | |
56 fp.write('\n') | |
57 | |
58 | |
59 def only_on_nix(f): | |
60 @functools.wraps(f) | |
61 def decorator(*args, **kwargs): | |
62 if is_nix: | |
63 return f(*args, **kwargs) | |
64 return decorator | |
65 | |
66 | |
67 def only_on_win(f): | |
68 @functools.wraps(f) | |
69 def decorator(*args, **kwargs): | |
70 if is_windows: | |
71 return f(*args, **kwargs) | |
72 return decorator | |
73 | |
74 | |
75 def needs_config(f): | |
76 f.__dotfiles_needs_config__ = True | |
77 return f | |
78 | |
79 | |
80 def run_priority(prio): | |
81 def wrapper(f): | |
82 f.__dotfiles_priority__ = prio | |
83 return f | |
84 return wrapper | |
85 | |
86 | |
87 @only_on_nix | |
88 def install_bash(): | |
89 mklink('bashrc/bashrc', '.bashrc') | |
90 mklink('bashrc/bash_profile', '.bash_profile') | |
91 | |
92 | |
93 @only_on_nix | |
94 def install_fish(): | |
95 ensure_dir('~/.config') | |
96 mklink('fish', '~/.config/fish') | |
97 | |
98 | |
99 def install_vim(): | |
100 vimrc_path = '~/.vimrc' | |
101 if is_windows: | |
102 vimrc_path = '~/_vimrc' | |
103 writelines(vimrc_path, [ | |
104 'set runtimepath+=%s' % nixslash(_p('vim')), | |
105 'source %s' % nixslash(_p('vim', 'vimrc')) | |
106 ]) | |
107 | |
108 | |
109 @run_priority(2) # Needs to run before `fish`. | |
110 def install_mercurial(): | |
111 hgrc_path = '~/.hgrc' | |
112 if is_windows: | |
113 hgrc_path = '~/mercurial.ini' | |
114 writelines(hgrc_path, [ | |
115 '%%include %s' % _p('hgrc/hgrc'), | |
116 '[ui]', | |
117 'ignore = %s' % _p('hgrc/hgignore'), | |
118 '[subrepos]', | |
119 'git:allowed = true', | |
120 '[extensions]', | |
121 'hggit = %s' % _p('lib/hg/hg-git/hggit/'), | |
122 'onsub = %s' % _p('lib/hg/onsub/onsub.py'), | |
123 'allpaths = %s' % _p('lib/hg/allpaths/mercurial_all_paths.py'), | |
124 'prompt = %s' % _p('lib/hg/hg-prompt/prompt.py'), | |
125 'evolve = %s' % _p('lib/hg/mutable-history/hgext3rd/evolve'), | |
126 'terse-status = %s' % _p('lib/hg/terse-status/terse-status.py') | |
127 ]) | |
128 if is_nix: | |
129 print("Building fast-hg-prompt...") | |
130 compile_ok = True | |
131 try: | |
132 subprocess.check_call(['make'], cwd=_p('lib/hg/fast-hg-prompt')) | |
133 except subprocess.CalledProcessError: | |
134 compile_ok = False | |
135 | |
136 for n in ['bookmark', 'remote', 'status']: | |
137 link_path = os.path.expanduser('~/.local/bin/fast-hg-%s' % n) | |
138 if compile_ok: | |
139 mklink('lib/hg/fast-hg-prompt/fast-hg-%s' % n, link_path, | |
140 mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)) | |
141 elif os.path.islink(link_path): | |
142 os.unlink(link_path) | |
143 elif os.path.exists(link_path): | |
144 os.remove(link_path) | |
145 | |
146 | |
147 def install_git(): | |
148 writelines('~/.gitconfig', [ | |
149 '[include]', | |
150 'path = %s' % _p('git/gitconfig') | |
151 ]) | |
152 if is_windows: | |
153 subprocess.check_call( | |
154 ['setx', 'GIT_SSH', | |
155 '%USERPROFILE%\\Dropbox\\Utilities\\plink.exe'], | |
156 shell=True) | |
157 | |
158 | |
159 @only_on_nix | |
160 def install_tmux(): | |
161 mklink('tmux/tmux.conf', '~/.tmux.conf') | |
162 | |
163 | |
164 @only_on_nix | |
165 def install_weechat(): | |
166 mklink('weechat', '~/.weechat') | |
167 | |
168 | |
169 @only_on_nix | |
170 def install_mutt(): | |
171 writelines('~/.muttrc', [ | |
172 'source "gpg2 -dq %s |"' % _p('mutt/variables.gpg'), | |
173 'source "%s"' % _p('mutt/muttrc'), | |
174 'source "%s"' % _p('lib/mutt/mutt-colors-solarized/' | |
175 'mutt-colors-solarized-dark-256.muttrc') | |
176 ]) | |
177 | |
178 | |
179 def clone_git(url, path): | |
180 if os.path.isdir(path): | |
181 print("Skipping git clone of %s -- directory exists" % path) | |
182 print("git clone %s %s" % (url, path)) | |
183 ensure_dir(os.path.dirname(path)) | |
184 subprocess.check_call(['git', 'clone', url, path]) | |
185 | |
186 | |
187 def clone_hg(url, path): | |
188 if os.path.isdir(path): | |
189 print("Skipping hg clone of %s -- directory exists" % path) | |
190 print("hg clone %s %s" % (url, path)) | |
191 ensure_dir(os.path.dirname(path)) | |
192 env = dict(os.environ) | |
193 env.update({'HGPLAIN': '1'}) | |
194 subprocess.check_call(['hg', 'clone', url, path], env=env) | |
195 | |
196 | |
197 @needs_config | |
198 @run_priority(100) | |
199 def install_subrepos(cfg): | |
200 if not cfg.has_section('subrepos'): | |
201 return | |
202 | |
203 for path, url in cfg.items('subrepos'): | |
204 full_path = _p(path) | |
205 if url.startswith('[git]'): | |
206 clone_git(url[len('[git]'):], full_path) | |
207 else: | |
208 clone_hg(url, full_path) | |
209 | |
210 | |
211 def main(): | |
212 print("dotfiles installer") | |
213 print("python %s" % sys.version) | |
214 print("on %s" % sys.platform) | |
215 print('') | |
216 | |
217 cfg = configparser.ConfigParser() | |
218 cfg.read(_p('install.cfg')) | |
219 | |
220 mod_names = ['all'] | |
221 this_mod = sys.modules[__name__] | |
222 for an in dir(this_mod): | |
223 if not an.startswith('install_'): | |
224 continue | |
225 | |
226 name = an[len('install_'):] | |
227 mod_names.append(name) | |
228 | |
229 parser = argparse.ArgumentParser() | |
230 parser.add_argument( | |
231 'module', nargs='*', | |
232 choices=mod_names, | |
233 help="Which module(s) to install. Defaults to all modules.") | |
234 args = parser.parse_args() | |
235 | |
236 funcs = [] | |
237 selected_mods = set(args.module) | |
238 if 'all' in selected_mods: | |
239 selected_mods = set(mod_names) | |
240 selected_mods.remove('all') | |
241 for mn in selected_mods: | |
242 func = getattr(this_mod, 'install_%s' % mn) | |
243 funcs.append((mn, func)) | |
244 | |
245 funcs = sorted(funcs, key=_get_install_func_priority, reverse=True) | |
246 for name, func in funcs: | |
247 print("Installing %s" % name) | |
248 if hasattr(func, '__dotfiles_needs_config__'): | |
249 func(cfg) | |
250 else: | |
251 func() | |
252 | |
253 | |
254 def _get_install_func_priority(func_info): | |
255 func = func_info[1] | |
256 return getattr(func, '__dotfiles_priority__', 0) | |
257 | |
258 | |
259 if __name__ == '__main__': | |
260 main() |