aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2014-08-06 17:09:29 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2014-08-06 17:09:29 -0400
commitfd2b72e3d729cd7768db88531833c4fbcd9f2b7a (patch)
tree20f585a09d221dc8c914a0a28a02682ec6080863
parent6e3423392ecba1392ad1ae090b81426f0a0954f8 (diff)
downloadur_upgrade-fd2b72e3d729cd7768db88531833c4fbcd9f2b7a.tar.gz
Add BSD license. Code consolidation in progress.
-rwxr-xr-xur_upgrade.py209
1 files changed, 95 insertions, 114 deletions
diff --git a/ur_upgrade.py b/ur_upgrade.py
index a22ae95..f0e3879 100755
--- a/ur_upgrade.py
+++ b/ur_upgrade.py
@@ -1,81 +1,43 @@
#!/usr/bin/env python
+#Copyright (c) 2014, Joseph Hunkeler <jhunkeler at gmail.com>
+#All rights reserved.
+#
+#Redistribution and use in source and binary forms, with or without
+#modification, are permitted provided that the following conditions are met:
+#
+#1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import division
import argparse
import os
import shutil
-import sys
import subprocess
import tempfile
import urllib2
import signal
import tarfile
from distutils.version import StrictVersion
+from distutils.spawn import find_executable as which
from collections import namedtuple
from string import Template
from itertools import chain
-def which(cmd, mode=os.F_OK | os.X_OK, path=None):
- """Given a command, mode, and a PATH string, return the path which
- conforms to the given mode on the PATH, or None if there is no such
- file.
-
- `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
- of os.environ.get("PATH"), or can be overridden with a custom search
- path.
-
- """
- # Check that a given file can be accessed with the correct mode.
- # Additionally check that `file` is not a directory, as on Windows
- # directories pass the os.access check.
- def _access_check(fn, mode):
- return (os.path.exists(fn) and os.access(fn, mode)
- and not os.path.isdir(fn))
-
- # If we're given a path with a directory part, look it up directly rather
- # than referring to PATH directories. This includes checking relative to the
- # current directory, e.g. ./script
- if os.path.dirname(cmd):
- if _access_check(cmd, mode):
- return cmd
- return None
-
- if path is None:
- path = os.environ.get("PATH", os.defpath)
- if not path:
- return None
- path = path.split(os.pathsep)
-
- if sys.platform == "win32":
- # The current directory takes precedence on Windows.
- if not os.curdir in path:
- path.insert(0, os.curdir)
-
- # PATHEXT is necessary to check on Windows.
- pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
- # See if the given file matches any of the expected path extensions.
- # This will allow us to short circuit when given "python.exe".
- # If it does match, only test that one, otherwise we have to try
- # others.
- if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
- files = [cmd]
- else:
- files = [cmd + ext for ext in pathext]
- else:
- # On other platforms you don't have things like PATHEXT to tell you
- # what file suffixes are executable, so just pass on cmd as-is.
- files = [cmd]
-
- seen = set()
- for di in path:
- normdir = os.path.normcase(di)
- if not normdir in seen:
- seen.add(normdir)
- for thefile in files:
- name = os.path.join(di, thefile)
- if _access_check(name, mode):
- return name
- return None
+DEFAULT_MIRROR = "http://ssb.stsci.edu/ureka"
class Ureka(object):
'''
@@ -156,6 +118,53 @@ def ur_check_version(urobj, vers):
return False
return True
+def get_archive(url):
+ print("Downloading archive... {}".format(url))
+ try:
+ req_data = urllib2.urlopen(url)
+ except Exception as ex:
+ print("Error {}, {}: {}".format(ex.code, ex.msg, url))
+ exit(1)
+
+ remote_size = float(req_data.headers['content-length'])
+ total = 0
+ with open(os.path.join(UPGRADE_TEMP, UREKA_TARBALL), 'wb') as installer:
+ for chunk in iter(lambda: req_data.read(16*1024), ''):
+ print("\r{:.2f}% [{:.2f}/{:.2f} MB]".format((total / remote_size * 100), (total / 1024 ** 2), (remote_size / 1024 ** 2))),
+ total += float(len(chunk))
+ installer.write(chunk)
+ print("")
+
+def upgrade(srcobj, destobj):
+ print("Upgrading distribution from {} to {}...".format(srcobj['version'], destobj['version']))
+ proc = subprocess.Popen('rsync -a -ureka_dist_original {} {}'.format(destobj.path, os.path.dirname(srcobj.path)).split())
+ proc.wait()
+
+def unpack_archive():
+ installer = tarfile.open(os.path.join(UPGRADE_TEMP, UREKA_TARBALL), 'r')
+ print("Preparing to unpack upgrade... (please wait)")
+ files_total = len(installer.getmembers())
+
+ print("Unpacking upgrade...")
+ for index, member in enumerate(installer, start=1):
+ print("\r{:.2f}% [{}/{}]".format((index / files_total * 100), index, files_total)),
+ installer.extract(member, path=TEMP_INSTALL_PATH)
+ print("")
+
+def pre_upgrade():
+ with open(os.path.join(TEMP_INSTALL_PATH, 'Ureka', 'misc', 'name'), 'w+') as fp:
+ fp.write(ureka_dist_original['name'] + os.linesep)
+
+def post_upgrade(urobj):
+ print("Performing upgrade maintenance tasks...")
+ ur_env = ur_getenv(urobj.path)
+ proc = subprocess.Popen('ur_normalize -n -i -x'.split(), env=ur_env)
+ proc.wait()
+
+ print("Purging temporary data...")
+ shutil.rmtree(UPGRADE_TEMP)
+
+
def cleanup(sig, stack):
print('')
print('Received signal {}!'.format(sig))
@@ -177,6 +186,8 @@ if __name__ == "__main__":
exit(1)
if args.latest:
+ # Need to work out a deal with SSB.
+ # "LATEST-STABLE" and "LATEST-DEVEL" links could be useful
print("--latest is not implemented yet.")
exit(1)
@@ -185,7 +196,7 @@ if __name__ == "__main__":
exit(1)
UPGRADE_TEMP = tempfile.mkdtemp(prefix="upgrade")
- ORIGINAL = args.UR_DIR
+ CURRENT = args.UR_DIR
# Register signal handlers AFTER temporary directory is created
signal.signal(signal.SIGINT, cleanup)
@@ -195,67 +206,37 @@ if __name__ == "__main__":
print('rsync not found in PATH. Please install it.')
exit(1)
- u = Ureka(ORIGINAL)
+ ureka_dist_original = Ureka(CURRENT)
- if not ur_check_version(u, args.request):
- print("Refusing to downgrade from {} to {}".format(u['version'], args.request))
+ if not ur_check_version(ureka_dist_original, args.request):
+ print("Refusing to downgrade from {} to {}".format(ureka_dist_original['version'], args.request))
exit(1)
- INSTALL_PATH = os.path.join(UPGRADE_TEMP, args.request)
- UREKA_TARBALL = "Ureka_{}_{}_{}.tar.gz".format(u['os'], u['bits'], args.request)
- ''' http://ssb.stsci.edu/ureka/1.0/Ureka_linux-rhe5_64_1.4.1.tar.gz '''
+ TEMP_INSTALL_PATH = os.path.join(UPGRADE_TEMP, args.request)
+ UREKA_TARBALL = "Ureka_{}_{}_{}.tar.gz".format(ureka_dist_original['os'], ureka_dist_original['bits'], args.request)
- #url = "http://ssb.stsci.edu/ureka/{}/{}".format(args.version, UREKA_TARBALL)
- url = "http://localhost/ureka/{}/{}".format(args.request, UREKA_TARBALL)
-
+ url = "{}/{}/{}".format(DEFAULT_MIRROR, args.request, UREKA_TARBALL)
if args.mirror:
url = "{}/{}/{}".format(args.mirror, args.request, UREKA_TARBALL)
+
+ # Download requested archive
+ get_archive(url)
- print("Downloading archive... {}".format(url))
- try:
- req_data = urllib2.urlopen(url)
- except Exception as ex:
- print("Error {}, {}: {}".format(ex.code, ex.msg, url))
- exit(1)
-
- remote_size = float(req_data.headers['content-length'])
- total = 0
- with open(os.path.join(UPGRADE_TEMP, UREKA_TARBALL), 'wb') as installer:
- for chunk in iter(lambda: req_data.read(16*1024), ''):
- print("\r{:.2f}% [{:.2f}/{:.2f} MB]".format((total / remote_size * 100), (total / 1024 ** 2), (remote_size / 1024 ** 2))),
- total += float(len(chunk))
- installer.write(chunk)
- print("")
-
- os.mkdir(INSTALL_PATH)
- tarball = tarfile.open(os.path.join(UPGRADE_TEMP, UREKA_TARBALL), 'r')
- print("Preparing to unpack upgrade... (please wait)")
- files_total = len(tarball.getmembers())
+ # Unpack archive to temporary storage
+ unpack_archive()
- print("Unpacking upgrade...")
- for index, member in enumerate(tarball, start=1):
- print("\r{:.2f}% [{}/{}]".format((index / files_total * 100), index, files_total)),
- tarball.extract(member, path=INSTALL_PATH)
- print("")
+ # Generate upgrade Ureka object
+ ureka_dist_new = Ureka(os.path.join(TEMP_INSTALL_PATH, 'Ureka'))
- open(os.path.join(INSTALL_PATH, 'Ureka', 'misc', 'name'), 'w+').write(u['name'] + os.linesep)
- n = Ureka(os.path.join(INSTALL_PATH, 'Ureka'))
+ # Perform tasks required before upgrading
+ pre_upgrade()
- print("Upgrading distribution {} to {}...".format(u['version'], n['version']))
- proc = subprocess.Popen('rsync -a -u {} {}'.format(n.path, os.path.dirname(u.path)).split())
- proc.wait()
+ # Perform upgrade
+ upgrade(ureka_dist_original, ureka_dist_new)
- # Regenerate upgraded ureka installation object
- u = Ureka(ORIGINAL)
+ # Regenerate upgraded ureka installation target
+ ureka_dist_original = Ureka(CURRENT)
- print("Performing upgrade maintenance tasks...")
- ur_env = ur_getenv(u.path)
-
- proc = subprocess.Popen('ur_normalize -n -i -x'.split(), env=ur_env)
- proc.wait()
+ # Perform tasks required after upgrade is completed
+ post_upgrade(ureka_dist_original)
- print("Purging temporary data...")
- shutil.rmtree(UPGRADE_TEMP)
-
- print("Upgrade complete!")
-