swc-windows-installer.sh: Convert script from Python to POSIX shell
authorW. Trevor King <wking@tremily.us>
Mon, 13 Jan 2014 18:38:14 +0000 (10:38 -0800)
committerW. Trevor King <wking@tremily.us>
Mon, 13 Jan 2014 22:08:44 +0000 (14:08 -0800)
On Mon, Jan 13, 2014 at 05:49:51AM -0800, Aron Ahmadia wrote:
> We currently have an installer that handles the issue of installing
> `nano` into msysgit for use with Git: ...
>
> This currently doesn't help for bootcamps where Python is not
> installed, so it would be handy to have a version of this that
> doesn't rely on a Python install.

POSIX shell, because an interpreted language from 1977 [1] is more
widely supported than an interpreted language from 1991 [2].  It looks
like the default msysGit install sets up the right double-click magic
too:

On Mon, Jan 13, 2014 at 10:03:24AM -0800, Ethan White wrote:
> Will a POSIX version run by simply double clicking the file?

On Mon, Jan 13, 2014 at 10:25:33AM -0800, Ethan White wrote:
> Just checked this on my Windows machine and it actually seems to
> work automatically as long as GitBash is installed and the file has
> a .sh extension. So POSIX away.

[1]: http://en.wikipedia.org/wiki/Bourne_shell
[2]: http://en.wikipedia.org/wiki/Python_language

swc-windows-installer.py [deleted file]
swc-windows-installer.sh [new file with mode: 0755]

diff --git a/swc-windows-installer.py b/swc-windows-installer.py
deleted file mode 100755 (executable)
index 041642a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-
-"""Software Carpentry Windows Installer
-
-Helps mimic a *nix environment on Windows with as little work as possible.
-
-The script:
-* Installs nano and makes it accessible from msysgit
-* Provides standard nosetests behavior for msysgit
-
-To use:
-
-1. Install Python, IPython, and Nose.  An easy way to do this is with
-   the Anaconda CE Python distribution
-   http://continuum.io/anacondace.html
-2. Install msysgit
-   http://code.google.com/p/msysgit/downloads/list?q=full+installer+official+git
-3. Run swc_windows_installer.py
-   You should be able to simply double click the file in Windows
-
-"""
-
-import hashlib
-try:  # Python 3
-    from io import BytesIO as _BytesIO
-except ImportError:  # Python 2
-    from StringIO import StringIO as _BytesIO
-import os
-import re
-try:  # Python 3
-    from urllib.request import urlopen as _urlopen
-except ImportError:  # Python 2
-    from urllib2 import urlopen as _urlopen
-import zipfile
-
-
-def zip_install(url, sha1, install_directory):
-    """Download and install a zipped bundle of compiled software"""
-    r = _urlopen(url)
-    zip_bytes = r.read()
-    download_sha1 = hashlib.sha1(zip_bytes).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)
-    if not os.path.isdir(install_directory):
-        os.makedirs(install_directory)
-        zip_file.extractall(install_directory)
-
-
-def install_nano(install_directory):
-    """Download and install the nano text editor"""
-    zip_install(
-        url='http://www.nano-editor.org/dist/v2.2/NT/nano-2.2.6.zip',
-        sha1='f5348208158157060de0a4df339401f36250fe5b',
-        install_directory=install_directory)
-
-
-def create_nosetests_entry_point(python_scripts_directory):
-    """Creates a terminal-based nosetests entry point for msysgit"""
-    contents = '\n'.join([
-            '#!/usr/bin/env/ python',
-            'import sys',
-            'import nose',
-            "if __name__ == '__main__':",
-            '    sys.exit(nose.core.main())',
-            '',
-            ])
-    if not os.path.isdir(python_scripts_directory):
-        os.makedirs(python_scripts_directory)
-    with open(os.path.join(python_scripts_directory, 'nosetests'), 'w') as f:
-        f.write(contents)
-
-
-def update_bash_profile(extra_paths=()):
-    """Create or append to a .bash_profile for Software Carpentry
-
-    Adds nano to the path, sets the default editor to nano, and adds
-    additional paths for other executables.
-    """
-    lines = [
-        '',
-        '# Add paths for Software-Carpentry-installed scripts and executables',
-        'export PATH=$PATH:{}'.format(':'.join(
-            make_posix_path(path) for path in extra_paths),),
-        '',
-        '# Make nano the default editor',
-        'export EDITOR=nano',
-        '',
-        ]
-    config_path = os.path.join(os.path.expanduser('~'), '.bash_profile')
-    with open(config_path, 'a') as f:
-        f.write('\n'.join(lines))
-
-
-def make_posix_path(windows_path):
-    """Convert a Windows path to a posix path"""
-    for regex, sub in [
-            (re.compile(r'\\'), '/'),
-            (re.compile('^[Cc]:'), '/c'),
-            ]:
-        windows_path = regex.sub(sub, windows_path)
-    return 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')
-    install_nano(install_directory=nano_dir)
-    update_bash_profile(extra_paths=(nano_dir, bin_dir))
-
-
-if __name__ == '__main__':
-    main()
diff --git a/swc-windows-installer.sh b/swc-windows-installer.sh
new file mode 100755 (executable)
index 0000000..8fc15f1
--- /dev/null
@@ -0,0 +1,127 @@
+#!/bin/sh
+#
+# Software Carpentry Windows Installer
+#
+# Helps mimic a *nix environment on Windows with as little work as possible.
+#
+# The script:
+# * Installs nano and makes it accessible from msysGit
+# * Provides standard nosetests behavior (if Python and the nose
+#   module are installed) for msysGit
+#
+# To use:
+#
+# 1. Install msysGit
+#    http://code.google.com/p/msysgit/downloads/list?q=full+installer+official+git
+# 2. Run swc_windows_installer.sh
+#    You should be able to simply double click the file in Windows
+
+msg()
+{
+       MESSAGE="${1}"
+       echo "${1}" >&2
+}
+
+die()
+{
+       msg "${@}"
+       exit 1
+}
+
+zip_install()
+{
+       URL="${1}"
+       EXPECTED_MD5="${2}"
+       INSTALL_DIRECTORY="${3}"
+       ZIP=$(basename "${URL}")
+       if test ! -d "${INSTALL_DIRECTORY}"
+       then
+               msg "download ${URL} and install into ${INSTALL_DIRECTORY}"
+               curl -o "${ZIP}" "${URL}" || die "couldn't download ${URL}"
+               MD5=$(md5sum "${ZIP}" | cut -d ' ' -f 1) || die "couldn't hash ${ZIP}"
+               if test "${MD5}" != "${EXPECTED_MD5}"
+               then
+                       die "downloaded ${URL} has the wrong MD5 hash: ${MD5} != ${EXPECTED_MD5}"
+               fi
+               mkdir -p "${INSTALL_DIRECTORY}" ||
+                       die "couldn't create ${INSTALL_DIRECTORY}"
+               unzip "${ZIP}" -d "${INSTALL_DIRECTORY}" ||
+                       die "couldn't unzip ${ZIP} into ${INSTALL_DIRECTORY}"
+       fi
+}
+
+install_nano()
+{
+       INSTALL_DIRECTORY="${1}"
+       zip_install 'http://www.nano-editor.org/dist/v2.2/NT/nano-2.2.6.zip' \
+               '4d8987b64a6be0f8de29d51ab5dc5a7a' \
+               "${INSTALL_DIRECTORY}"
+}
+
+# Creates a terminal-based nosetests entry point for msysGit
+create_nosetests_entry_point()
+{
+       INSTALL_DIRECTORY="${1}"
+       if python -c 'import nose' 2> /dev/null
+       then
+               msg "create nosetests entry point in ${INSTALL_DIRECTORY}"
+               if test ! -f "${INSTALL_DIRECTORY}"
+               then
+                       mkdir -p "${INSTALL_DIRECTORY}"
+               fi
+               cat > "${INSTALL_DIRECTORY}/nosetests" <<-EOF
+                       #!/usr/bin/env/ python
+                       import sys
+                       import nose
+
+                       if __name__ == '__main__':
+                           sys.exit(nose.core.main())
+                       EOF
+       fi
+}
+
+add_swc_paths()
+{
+       FIRST_PATH="${1}"
+       if ! grep "PATH.*:${FIRST_PATH}" ~/.bash_profile > /dev/null 2>&1
+       then
+               msg "add SWC paths to PATH in ~/.bash_profile"
+               _PATH="\${PATH}"
+               for EXTRA_PATH in "${@}"
+               do
+                       _PATH="${_PATH}:${EXTRA_PATH}"
+               done
+               cat >> ~/.bash_profile <<-EOF
+
+                       # Add paths for Software-Carpentry-installed scripts and executables
+                       export PATH="${_PATH}"
+                       EOF
+       fi
+}
+
+set_default_editor()
+{
+       EDITOR="${1}"
+       if ! grep EDITOR ~/.bash_profile > /dev/null
+       then
+               msg "set the default EDITOR to '${EDITOR}'"
+               cat >> ~/.bash_profile <<-EOF
+
+                       # Set the default editor
+                       export EDITOR='${EDITOR}'
+                       EOF
+       fi
+}
+
+main()
+{
+       SWC_DIR=~/.swc
+       BIN_DIR="${SWC_DIR}/bin"
+       NANO_DIR="${SWC_DIR}/lib/nano"
+       create_nosetests_entry_point "${BIN_DIR}" || die "couldn't create nosetests"
+       install_nano "${NANO_DIR}" || die "couldn't install nano"
+       add_swc_paths "${NANO_DIR}" "${BIN_DIR}" || die "couldn't add SWC paths"
+       set_default_editor nano || die "couldn't set EDITOR"
+}
+
+main