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
12 * Add R's bin directory to the path (if we can find it)
16 1. Install Python, IPython, and Nose. An easy way to do this is with
17 the Anaconda CE Python distribution
18 http://continuum.io/anacondace.html
20 http://code.google.com/p/msysgit/downloads/list
21 3. Run swc_windows_installer.py
22 You should be able to simply double click the file in Windows
29 from io import BytesIO as _BytesIO
30 except ImportError: # Python 2
31 from StringIO import StringIO as _BytesIO
37 from urllib.request import urlopen as _urlopen
38 except ImportError: # Python 2
39 from urllib2 import urlopen as _urlopen
43 if sys.version_info >= (3, 0): # Python 3
46 def open3(file, mode='r', newline=None):
49 raise NotImplementedError(newline)
50 f = open(file, mode + 'b')
56 def download(url, sha1):
57 """Download a file and verify it's hash"""
59 byte_content = r.read()
60 download_sha1 = hashlib.sha1(byte_content).hexdigest()
61 if download_sha1 != sha1:
63 'downloaded {!r} has the wrong SHA1 hash: {} != {}'.format(
64 url, download_sha1, sha1))
69 """Split a path into a list of components
71 >>> splitall('nano-2.2.6/doc/Makefile.am')
72 ['nano-2.2.6', 'doc', 'Makefile.am']
76 head, tail = os.path.split(path)
88 def transform(tarinfo, strip_components=0):
89 """Transform TarInfo objects for extraction"""
90 path_components = splitall(tarinfo.name)
92 tarinfo.name = os.path.join(*path_components[strip_components:])
94 if len(path_components) <= strip_components:
100 def tar_install(url, sha1, install_directory, compression='*',
102 """Download and install a tar bundle"""
103 if not os.path.isdir(install_directory):
104 tar_bytes = download(url=url, sha1=sha1)
105 tar_io = _BytesIO(tar_bytes)
106 filename = os.path.basename(url)
107 mode = 'r:{}'.format(compression)
108 tar_file = tarfile.open(filename, mode, tar_io)
109 os.makedirs(install_directory)
111 transform(tarinfo=tarinfo, strip_components=strip_components)
112 for tarinfo in tar_file]
114 path=install_directory,
115 members=[m for m in members if m is not None])
118 def zip_install(url, sha1, install_directory):
119 """Download and install a zipped bundle"""
120 if not os.path.isdir(install_directory):
121 zip_bytes = download(url=url, sha1=sha1)
122 zip_io = _BytesIO(zip_bytes)
123 zip_file = zipfile.ZipFile(zip_io)
124 os.makedirs(install_directory)
125 zip_file.extractall(install_directory)
128 def install_nano(install_directory):
129 """Download and install the nano text editor"""
131 url='http://www.nano-editor.org/dist/v2.2/NT/nano-2.2.6.zip',
132 sha1='f5348208158157060de0a4df339401f36250fe5b',
133 install_directory=install_directory)
136 def install_nanorc(install_directory):
137 """Download and install nano syntax highlighting"""
139 url='http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz',
140 sha1='f2a628394f8dda1b9f28c7e7b89ccb9a6dbd302a',
141 install_directory=install_directory,
143 home = os.path.expanduser('~')
144 nanorc = os.path.join(home, 'nano.rc')
145 if not os.path.isfile(nanorc):
146 syntax_dir = os.path.join(install_directory, 'doc', 'syntax')
147 with open3(nanorc, 'w', newline='\n') as f:
148 for filename in os.listdir(syntax_dir):
149 if filename.endswith('.nanorc'):
150 path = os.path.join(syntax_dir, filename)
151 rel_path = os.path.relpath(path, home)
152 include_path = make_posix_path(os.path.join('~', rel_path))
153 f.write('include {}\n'.format(include_path))
156 def install_sqlite(install_directory):
157 """Download and install the sqlite3 shell"""
159 url='https://sqlite.org/2014/sqlite-shell-win32-x86-3080403.zip',
160 sha1='1a8ab0ca9f4c51afeffeb49bd301e1d7f64741bb',
161 install_directory=install_directory)
164 def create_nosetests_entry_point(python_scripts_directory):
165 """Creates a terminal-based nosetests entry point for msysgit"""
166 contents = '\n'.join([
167 '#!/usr/bin/env/ python',
170 "if __name__ == '__main__':",
171 ' sys.exit(nose.core.main())',
174 if not os.path.isdir(python_scripts_directory):
175 os.makedirs(python_scripts_directory)
176 with open(os.path.join(python_scripts_directory, 'nosetests'), 'w') as f:
180 def get_r_bin_directory():
181 """Locate the R bin directory (if R is installed
183 pf = _os.environ.get('ProgramFiles', r'c:\ProgramFiles')
184 bin_glob = os.path.join(pf, 'R', 'R-[0-9]*.[0-9]*.[0-9]*', 'bin')
185 version_re = re.compile('^R-(\d+)[.](\d+)[.](\d+)$')
187 for path in glob.glob(bin_glob):
188 version_dir = os.path.basename(os.path.dirname(path))
189 version_match = version_re.match(version_dir)
191 paths[version_match.groups()] = path
192 version = sorted(paths.keys())[-1]
193 return paths[version]
196 def update_bash_profile(extra_paths=()):
197 """Create or append to a .bash_profile for Software Carpentry
199 Adds nano to the path, sets the default editor to nano, and adds
200 additional paths for other executables.
204 '# Add paths for Software-Carpentry-installed scripts and executables',
205 'export PATH=\"$PATH:{}\"'.format(':'.join(
206 make_posix_path(path) for path in extra_paths),),
208 '# Make nano the default editor',
209 'export EDITOR=nano',
212 config_path = os.path.join(os.path.expanduser('~'), '.bash_profile')
213 with open(config_path, 'a') as f:
214 f.write('\n'.join(lines))
217 def make_posix_path(windows_path):
218 """Convert a Windows path to a posix path"""
220 (re.compile(r'\\'), '/'),
221 (re.compile('^[Cc]:'), '/c'),
223 windows_path = regex.sub(sub, windows_path)
228 swc_dir = os.path.join(os.path.expanduser('~'), '.swc')
229 bin_dir = os.path.join(swc_dir, 'bin')
230 nano_dir = os.path.join(swc_dir, 'lib', 'nano')
231 nanorc_dir = os.path.join(swc_dir, 'share', 'nanorc')
232 sqlite_dir = os.path.join(swc_dir, 'lib', 'sqlite')
233 create_nosetests_entry_point(python_scripts_directory=bin_dir)
234 install_nano(install_directory=nano_dir)
235 install_nanorc(install_directory=nanorc_dir)
236 install_sqlite(install_directory=sqlite_dir)
237 paths = [nano_dir, sqlite_dir, bin_dir]
238 r_dir = get_r_bin_directory()
241 update_bash_profile(extra_paths=paths)
244 if __name__ == '__main__':
245 print("Preparing your Software Carpentry awesomeness!")