3 """Software Carpentry Windows Installer
5 Helps mimic a *nix environment on Windows with as little work as possible.
8 * Installs nano and makes it accessible from msysgit
9 * Installs sqlite3 and makes it accessible from msysGit
10 * Creates ~/nano.rc with links to syntax highlighting configs
11 * Provides standard nosetests behavior for msysgit
15 1. Install Python, IPython, and Nose. An easy way to do this is with
16 the Anaconda CE Python distribution
17 http://continuum.io/anacondace.html
19 http://code.google.com/p/msysgit/downloads/list
20 3. Run swc_windows_installer.py
21 You should be able to simply double click the file in Windows
27 from io import BytesIO as _BytesIO
28 except ImportError: # Python 2
29 from StringIO import StringIO as _BytesIO
35 from urllib.request import urlopen as _urlopen
36 except ImportError: # Python 2
37 from urllib2 import urlopen as _urlopen
41 if sys.version_info >= (3, 0): # Python 3
44 def open3(file, mode='r', newline=None):
47 raise NotImplementedError(newline)
48 f = open(file, mode + 'b')
54 def download(url, sha1):
55 """Download a file and verify it's hash"""
57 byte_content = r.read()
58 download_sha1 = hashlib.sha1(byte_content).hexdigest()
59 if download_sha1 != sha1:
61 'downloaded {!r} has the wrong SHA1 hash: {} != {}'.format(
62 url, download_sha1, sha1))
67 """Split a path into a list of components
69 >>> splitall('nano-2.2.6/doc/Makefile.am')
70 ['nano-2.2.6', 'doc', 'Makefile.am']
74 head, tail = os.path.split(path)
86 def transform(tarinfo, strip_components=0):
87 """Transform TarInfo objects for extraction"""
88 path_components = splitall(tarinfo.name)
90 tarinfo.name = os.path.join(*path_components[strip_components:])
92 if len(path_components) <= strip_components:
98 def tar_install(url, sha1, install_directory, compression='*',
100 """Download and install a tar bundle"""
101 if not os.path.isdir(install_directory):
102 tar_bytes = download(url=url, sha1=sha1)
103 tar_io = _BytesIO(tar_bytes)
104 filename = os.path.basename(url)
105 mode = 'r:{}'.format(compression)
106 tar_file = tarfile.open(filename, mode, tar_io)
107 os.makedirs(install_directory)
109 transform(tarinfo=tarinfo, strip_components=strip_components)
110 for tarinfo in tar_file]
112 path=install_directory,
113 members=[m for m in members if m is not None])
116 def zip_install(url, sha1, install_directory):
117 """Download and install a zipped bundle"""
118 if not os.path.isdir(install_directory):
119 zip_bytes = download(url=url, sha1=sha1)
120 zip_io = _BytesIO(zip_bytes)
121 zip_file = zipfile.ZipFile(zip_io)
122 os.makedirs(install_directory)
123 zip_file.extractall(install_directory)
126 def install_nano(install_directory):
127 """Download and install the nano text editor"""
129 url='http://www.nano-editor.org/dist/v2.2/NT/nano-2.2.6.zip',
130 sha1='f5348208158157060de0a4df339401f36250fe5b',
131 install_directory=install_directory)
134 def install_nanorc(install_directory):
135 """Download and install nano syntax highlighting"""
137 url='http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz',
138 sha1='f2a628394f8dda1b9f28c7e7b89ccb9a6dbd302a',
139 install_directory=install_directory,
141 home = os.path.expanduser('~')
142 nanorc = os.path.join(home, 'nano.rc')
143 if not os.path.isfile(nanorc):
144 syntax_dir = os.path.join(install_directory, 'doc', 'syntax')
145 with open3(nanorc, 'w', newline='\n') as f:
146 for filename in os.listdir(syntax_dir):
147 if filename.endswith('.nanorc'):
148 path = os.path.join(syntax_dir, filename)
149 rel_path = os.path.relpath(path, home)
150 include_path = make_posix_path(os.path.join('~', rel_path))
151 f.write('include {}\n'.format(include_path))
154 def install_sqlite(install_directory):
155 """Download and install the sqlite3 shell"""
157 url='https://sqlite.org/2014/sqlite-shell-win32-x86-3080403.zip',
158 sha1='1a8ab0ca9f4c51afeffeb49bd301e1d7f64741bb',
159 install_directory=install_directory)
162 def create_nosetests_entry_point(python_scripts_directory):
163 """Creates a terminal-based nosetests entry point for msysgit"""
164 contents = '\n'.join([
165 '#!/usr/bin/env/ python',
168 "if __name__ == '__main__':",
169 ' sys.exit(nose.core.main())',
172 if not os.path.isdir(python_scripts_directory):
173 os.makedirs(python_scripts_directory)
174 with open(os.path.join(python_scripts_directory, 'nosetests'), 'w') as f:
178 def update_bash_profile(extra_paths=()):
179 """Create or append to a .bash_profile for Software Carpentry
181 Adds nano to the path, sets the default editor to nano, and adds
182 additional paths for other executables.
186 '# Add paths for Software-Carpentry-installed scripts and executables',
187 'export PATH=\"$PATH:{}\"'.format(':'.join(
188 make_posix_path(path) for path in extra_paths),),
190 '# Make nano the default editor',
191 'export EDITOR=nano',
194 config_path = os.path.join(os.path.expanduser('~'), '.bash_profile')
195 with open(config_path, 'a') as f:
196 f.write('\n'.join(lines))
199 def make_posix_path(windows_path):
200 """Convert a Windows path to a posix path"""
202 (re.compile(r'\\'), '/'),
203 (re.compile('^[Cc]:'), '/c'),
205 windows_path = regex.sub(sub, windows_path)
210 swc_dir = os.path.join(os.path.expanduser('~'), '.swc')
211 bin_dir = os.path.join(swc_dir, 'bin')
212 nano_dir = os.path.join(swc_dir, 'lib', 'nano')
213 nanorc_dir = os.path.join(swc_dir, 'share', 'nanorc')
214 sqlite_dir = os.path.join(swc_dir, 'lib', 'sqlite')
215 create_nosetests_entry_point(python_scripts_directory=bin_dir)
216 install_nano(install_directory=nano_dir)
217 install_nanorc(install_directory=nanorc_dir)
218 install_sqlite(install_directory=sqlite_dir)
219 update_bash_profile(extra_paths=(nano_dir, sqlite_dir, bin_dir))
222 if __name__ == '__main__':
223 print("Preparing your Software Carpentry awesomeness!")