#!/usr/bin/env python """ The upgrade script downloads the latest IssueTrackerProduct from www.issuetrackerproduct.com and upgrades and installs the new files. Peter Bengtsson, mail@peterbe.com, (c) 2005 """ __changes__=''' 1.2 July 2005 Ability to create a new IssueTrackerProduct if not found 1.1 July 2005 First CVSed version ''' __version__='1.2' import os, sys, glob, gzip, tarfile from cStringIO import StringIO from urllib import urlopen import urllib2 latest_versionnr_url = "http://www.issuetrackerproduct.com/Download/getLatestVersionNumber" latest_versionurl_url = "http://www.issuetrackerproduct.com/Download/getLatestVersionURL" CVS_ANON_LOGIN = "cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/issuetracker login" CVS_ANON_CHECKOUT = "cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/issuetracker co IssueTrackerProduct" class VersionController: def __init__(self, home_path='.', verbose=False): self.home_path = home_path self.latest_version = _getLatestVersion() self.this_version = _getCurrentVersion(home_path) self.latest_version_url = _getLatestVersionURL() self.verbose = verbose def isUsingCVS(self): """ return true if in the home_path there is a CVS dir """ poss_path = os.path.join(self.home_path, 'CVS') return os.path.exists(poss_path) def cvsUpdate(self): """ try to do a CVS update """ _update = 1 if self.verbose: _update = raw_input("Upgrade %s [Y/n] " % shortname) if _update.lower().strip() not in ('y',''): _update = 0 if _update: _prev = os.path.abspath(os.curdir) os.chdir('..') os.system(CVS_ANON_LOGIN) os.system(CVS_ANON_CHECKOUT) os.chdir(_prev) def canUpgrade(self): """ return true if there is a newer version to download and install """ return self.this_version != self.latest_version def upgrade(self, pretend=False): return self._installURL(self.latest_version_url, pretend=pretend) def _installURL(self, URL, pretend=False): """ given a URL to a gzipped file, download it and replace the existing stuff """ assert URL.endswith('.tgz') or URL.endswith('.tar.gz') filename = URL.split('/')[-1] # download it downloadfile = open(filename, 'wb') req = urllib2.Request(URL) req.add_header('User-agent', 'Upgrade script (www.issuetrackerproduct.com)') furl = urllib2.urlopen(req) downloadfile.write(furl.read()) downloadfile.close() tar = tarfile.open(filename) _current_files = _listdir_fullpaths_filtered(self.home_path) _current_folders = _filter_whatispaths(_current_files) _current_files_copy = _current_files[:] for tarinfo in tar: assert tarinfo.name.startswith('IssueTrackerProduct'), \ "Incorrectly gzipped file" shortname = tarinfo.name.replace('IssueTrackerProduct/','') if not shortname: continue if shortname in _current_folders or \ shortname[:-1] in _current_folders: continue # directories aren't important elif shortname.find('mainbuttons') > -1 or \ shortname.find('actionbuttons') > -1: # old crap that might be in the tgz continue if shortname in _current_files: # the default value depends on if the file has changed shortname_path = os.path.abspath(os.path.join(self.home_path, shortname)) if tarinfo.size > 1000: if tarinfo.size == len(open(shortname_path).read()): _upgrade = 0 else: _upgrade = 1 else: # if the file is less than 1000 bytes, don't do a size comparison # because it can fail with really small files like 'version.txt' # whose content can change from "0.6.12" to "0.6.13" which is the same # length but different in content. Larger files and larger probability # that the changes also change the total file length. extracted_content = tar.extractfile(tarinfo).read() if extracted_content == open(shortname_path).read(): _upgrade = 0 else: _upgrade = 1 # if verbose, ask about each if self.verbose and _upgrade: _upgrade = raw_input("Upgrade %s [Y/n] " % shortname) if _upgrade.lower().strip() not in ('y',''): _upgrade = 0 if _upgrade: print "U %s" % shortname tar.extract(tarinfo, os.path.join(self.home_path, '..')) else: _install = 1 if self.verbose: _install = raw_input("Install %s [Y/n] " % shortname) if _install.lower().strip() not in ('y',''): _install = 0 if _install: print "I %s" % tarinfo.name.replace('IssueTrackerProduct','') tar.extract(tarinfo, os.path.join(self.home_path, '..')) if shortname in _current_files_copy: _current_files_copy.remove(shortname) this_script_filename = globals()['__file__'] if this_script_filename in _current_files_copy: _current_files_copy.remove(this_script_filename) elif this_script_filename.replace('./','') in _current_files_copy: _current_files_copy.remove(this_script_filename.replace('./','')) if self.verbose: if _current_files_copy: print >>sys.stderr, "The following files are not needed anymore" for f in _current_files_copy: print >>sys.stderr, f _delete = raw_input("\tDelete %s [y/N] " % f) if _delete.lower().strip() not in ('y',''): _delete = 1 if _delete: os.remove(f) def _filter_whatispaths(files): """ return a list of what is directories from a list of files and directories """ dirs = {} for v in files: splitted = os.path.split(v) if splitted[0]: dirs[splitted[0]] = 1 return dirs.keys() def _listdir_fullpaths_filtered(root, relpath=True): """ return a list of filepaths similar to os.path but open each directory. """ all = [] def _rejectFile(f): if f[-3:] in ('pyc','bak'): return True if f.endswith('~'): return True if f.startswith('#') or f.startswith('.#'): return True return False for base, dirs, files in os.walk(root): if base.endswith('CVS'): continue for file in files: if not _rejectFile(file): _path = os.path.join(base, file) if relpath: _path = _path.replace(root,'') if _path.startswith('/'): _path = _path[1:] all.append(_path) return all def _getCurrentVersion(home_path=None): if home_path: f = os.path.join(home_path, 'version.txt') else: f = 'version.txt' return open(f).read().strip() def _getLatestVersion(): return urlopen(latest_versionnr_url).read().strip() def _getLatestVersionURL(): return urlopen(latest_versionurl_url).read().strip() #------------------------------------------------------------------------------- def cli(): from optparse import OptionParser parser = OptionParser() parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Each step is confirmed by the user" ) # parser.add_option( options, args = parser.parse_args() verbose = not not options.verbose if os.path.abspath('.').endswith('IssueTrackerProduct'): home_path = os.path.abspath('.') elif 'IssueTrackerProduct' in os.listdir('.'): home_path = os.path.abspath(os.path.join('.','IssueTrackerProduct')) elif sys.argv[1:] and (sys.argv[1].endswith('IssueTrackerProduct') or sys.argv[1].endswith('IssueTrackerProduct/')): home_path = sys.argv[1] else: # perhaps they just want to download it! _mkdir = raw_input("IssueTrackerProduct folder can't be found. Create? [y/N] ") if _mkdir.lower().strip() in ('n',''): raise OSError, "IssueTrackerProduct can't be found. See(k) help." else: os.mkdir('IssueTrackerProduct') home_path = os.path.abspath(os.path.join('.','IssueTrackerProduct')) open(os.path.join(home_path, 'version.txt'),'w').write('0.0.0') vc = VersionController(home_path, verbose=verbose) if vc.isUsingCVS(): vc.cvsUpdate() elif vc.canUpgrade(): vc.upgrade() else: print >>sys.stderr, "Latest version (%s) already installed" % vc.latest_version return 0 # everything went fine if __name__=='__main__': sys.exit(cli())