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()