#!/usr/bin/env python from __future__ import division import os import shutil import sys import stat import subprocess import tempfile import urllib2 import signal import tarfile from collections import namedtuple 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 class Ureka(object): def __init__(self, basepath): self.path = basepath self.path_data = os.path.abspath(os.path.join(self.path, 'misc')) self._files = ['os', 'bits', 'version', 'name'] if os.path.exists(self.path_data): self.info = self._info() else: self.info = {} def _info(self): data = [] for key in self._files: path = os.path.join(self.path_data, key) item = open(path, 'r').readline().strip() data.append(item) ureka_info = namedtuple('ureka_info', self._files) return ureka_info._make(data) def __getitem__(self, key): info = self.info._asdict() if key not in info: return None return info[key] def __iter__(self): for item in self.info._asdict().iteritems(): yield item UPGRADE_TEMP = tempfile.mkdtemp(prefix="upgrade") ORIGINAL = os.path.abspath('/home/jhunk/Ureka') def cleanup(): print('cleaning up') if __name__ == "__main__": signal.signal(signal.SIGINT, cleanup) #signal.signal(signal.SIGKILL, cleanup) signal.signal(signal.SIGTERM, cleanup) if not which('rsync'): print('rsync not found in PATH. Please install it.') exit(1) u = Ureka(ORIGINAL) INSTALL_PATH = os.path.join(UPGRADE_TEMP, '1.4.1') UREKA_TARBALL = "Ureka_{}_{}_{}.tar.gz".format(u['os'], u['bits'], '1.4.1') ''' http://ssb.stsci.edu/ureka/1.0/Ureka_linux-rhe5_64_1.4.1.tar.gz ''' #url = "http://ssb.stsci.edu/ureka/{}/Ureka_{}_{}_{}.tar.gz".format('1.4.1', u['os'], u['bits'], '1.4.1') url = "http://localhost/ureka/{}/{}".format('1.4.1', UREKA_TARBALL) print("Downloading update... {}".format(url)) req_data = urllib2.urlopen(url) 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...") files_total = 74690 #len(tarball.getmembers()) print("Unpacking update...") for index, member in enumerate(tarball, start=0): print("\r{:.2f}% [{}/{}]".format((index / files_total * 100), index, files_total)), tarball.extract(member, path=INSTALL_PATH) print("") open(os.path.join(INSTALL_PATH, 'Ureka', 'misc', 'name'), 'w+').write(u['name'] + os.linesep) n = Ureka(os.path.join(INSTALL_PATH, 'Ureka')) print("Updating distribution from {} to {}...".format(u['version'], n['version'])) proc = subprocess.Popen('rsync -a -u {} {}'.format(n.path, os.path.dirname(u.path)).split()) proc.wait() # Regenerate Ureka object u = Ureka(ORIGINAL) print("Normalizing...") proc = subprocess.Popen('{}/bin/ur-setup-real -sh'.format(u.path).split()) proc = subprocess.Popen('ur_normalize'.split()) shutil.rmtree(UPGRADE_TEMP)