From 30d776f527247f111e1030a78f372e4d0e825759 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Wed, 5 Mar 2014 09:40:42 -0800 Subject: [PATCH] swc-windows-installer.py: Install nano source syntax highlighters Make writing Python source code (and a number of other languages) a bit more exciting for the eyes and easier on the brain by coloring strings, comments, and such. We need to install the source tarball because the compiled zip doesn't include the syntax highlighting scripts. To make that easier, I've extracted out the download / hash-check functionality into a new download(), which I use in both the old zip_install() and the new tar_install(). If the user doesn't have an existing ~/.nanorc, we populate it by adding 'include' options for each of the syntax files in the Nano tarball. If they do have an existing ~/.nanorc, I assume they know what they're doing ;). The default '*' compression is for transparent detection [1], but you can override it to explicitly select the compression type if you like. There's a bit of ugliness to work around the lack of a --strip-components analog in TarFile.extractall [2]. Instead, we iterate over the TarInfo members and strip leading components from their 'name' by hand [3]. [1]: http://docs.python.org/3/library/tarfile.html#tarfile.open [2]: http://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall [3]: http://docs.python.org/3/library/tarfile.html#tarfile.TarInfo.name --- swc-windows-installer.py | 93 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 8 deletions(-) diff --git a/swc-windows-installer.py b/swc-windows-installer.py index f10377d..3c9d9f9 100755 --- a/swc-windows-installer.py +++ b/swc-windows-installer.py @@ -6,6 +6,7 @@ Helps mimic a *nix environment on Windows with as little work as possible. The script: * Installs nano and makes it accessible from msysgit +* Creates ~/.nanorc with links to syntax highlighting configs * Provides standard nosetests behavior for msysgit To use: @@ -27,6 +28,7 @@ except ImportError: # Python 2 from StringIO import StringIO as _BytesIO import os import re +import tarfile try: # Python 3 from urllib.request import urlopen as _urlopen except ImportError: # Python 2 @@ -34,18 +36,74 @@ except ImportError: # Python 2 import zipfile -def zip_install(url, sha1, install_directory): - """Download and install a zipped bundle of compiled software""" +def download(url, sha1): + """Download a file and verify it's hash""" r = _urlopen(url) - zip_bytes = r.read() - download_sha1 = hashlib.sha1(zip_bytes).hexdigest() + byte_content = r.read() + download_sha1 = hashlib.sha1(byte_content).hexdigest() if download_sha1 != sha1: raise ValueError( 'downloaded {!r} has the wrong SHA1 hash: {} != {}'.format( - url, downloaded_sha1, sha1)) - zip_io = _BytesIO(zip_bytes) - zip_file = zipfile.ZipFile(zip_io) + url, download_sha1, sha1)) + return byte_content + + +def splitall(path): + """Split a path into a list of components + + >>> splitall('nano-2.2.6/doc/Makefile.am') + ['nano-2.2.6', 'doc', 'Makefile.am'] + """ + parts = [] + while True: + head, tail = os.path.split(path) + if tail: + parts.insert(0, tail) + elif head: + parts.insert(0, head) + break + else: + break + path = head + return parts + + +def transform(tarinfo, strip_components=0): + """Transform TarInfo objects for extraction""" + path_components = splitall(tarinfo.name) + try: + tarinfo.name = os.path.join(*path_components[strip_components:]) + except TypeError: + if len(path_components) <= strip_components: + return None + raise + return tarinfo + + +def tar_install(url, sha1, install_directory, compression='*', + strip_components=0): + """Download and install a tar bundle""" + if not os.path.isdir(install_directory): + tar_bytes = download(url=url, sha1=sha1) + tar_io = _BytesIO(tar_bytes) + filename = os.path.basename(url) + mode = 'r:{}'.format(compression) + tar_file = tarfile.open(filename, mode, tar_io) + os.makedirs(install_directory) + members = [ + transform(tarinfo=tarinfo, strip_components=strip_components) + for tarinfo in tar_file] + tar_file.extractall( + path=install_directory, + members=[m for m in members if m is not None]) + + +def zip_install(url, sha1, install_directory): + """Download and install a zipped bundle""" if not os.path.isdir(install_directory): + zip_bytes = download(url=url, sha1=sha1) + zip_io = _BytesIO(zip_bytes) + zip_file = zipfile.ZipFile(zip_io) os.makedirs(install_directory) zip_file.extractall(install_directory) @@ -58,6 +116,23 @@ def install_nano(install_directory): install_directory=install_directory) +def install_nanorc(install_directory): + """Download and install nano syntax highlighting""" + tar_install( + url='http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz', + sha1='f2a628394f8dda1b9f28c7e7b89ccb9a6dbd302a', + install_directory=install_directory, + strip_components=1) + nanorc = os.path.join(os.path.expanduser('~'), '.nanorc') + if not os.path.isfile(nanorc): + syntax_dir = os.path.join(install_directory, 'doc', 'syntax') + with open(nanorc, 'w') as f: + for filename in os.listdir(syntax_dir): + if filename.endswith('.nanorc'): + path = os.path.join(syntax_dir, filename) + f.write('include {}\n'.format(path)) + + def create_nosetests_entry_point(python_scripts_directory): """Creates a terminal-based nosetests entry point for msysgit""" contents = '\n'.join([ @@ -108,9 +183,11 @@ def make_posix_path(windows_path): def main(): swc_dir = os.path.join(os.path.expanduser('~'), '.swc') bin_dir = os.path.join(swc_dir, 'bin') - create_nosetests_entry_point(python_scripts_directory=bin_dir) nano_dir = os.path.join(swc_dir, 'lib', 'nano') + nanorc_dir = os.path.join(swc_dir, 'share', 'nanorc') + create_nosetests_entry_point(python_scripts_directory=bin_dir) install_nano(install_directory=nano_dir) + install_nanorc(install_directory=nanorc_dir) update_bash_profile(extra_paths=(nano_dir, bin_dir)) -- 2.26.2