home *** CD-ROM | disk | FTP | other *** search
- # Copyright 2001 (C) ActiveState Tool Corp., All Rights Reserved.
- #
- import sys, os, urllib, urlparse, string
- import soaptalk
- import ppmconfig
- import xml.dom.minidom
- import shutil
- import re
- import tempfile
-
- from types import *
- from ppmerrors import *
- from distutils import dir_util
- from distutils.errors import DistutilsExecError
- from distutils.spawn import spawn
- from distutils.dir_util import mkpath
-
- def filenameFromURL(url):
- return os.path.split(urlparse.urlparse(url)[2])[1]
-
- def find_loco_type(loco):
- if string.find(loco.lower() , 'file:')>=0:
- return 'file'
- if string.find(loco.lower(), 'ftp:')>=0:
- return 'ftp'
- if string.find(loco.lower(), 'http:')>=0:
- return 'http'
- if os.path.isfile(loco) or\
- os.path.isfile(loco+'.ppd') or\
- os.path.isfile(loco+'.PPD'):
- return 'file'
- # error checking ???? - this is a hack to enable relative paths
- # but a check is needed for bad files
- return ''
-
-
- def isurl(url):
- if find_loco_type(url) != 'file':
- if string.find(url,'://')>=0:
- return 1
- return 0
-
- def isfile(file):
- if find_loco_type(file) == 'file' or\
- re.match(r'[A-z]:(/|\\)\w+',file):
- return 1
- return 0
-
- def isdir(location):
- if os.path.isdir(location):
- return 1
- return 0
-
- def CheckOs(ValidOsList):
- for myos in ValidOsList:
- if (myos.lower() == 'nt') and (os.name=='nt' or os.name =='dos'):
- return 1
- elif myos.lower() == 'linux' and string.find(sys.platform,'linux')>=0:
- return 1
- elif myos.lower() == 'sun' and string.find(sys.platform,'sun')>=0:
- return 1
- #XXX
- elif myos=='':
- return 1
- return 0
-
- def get_repository_location(ImplementationObj):
- try:
- loco = ImplementationObj.codebase['href']
- # if loco is None we get ride of the key
- if loco is None:
- del ImplementationObj.codebase['href']
- raise KeyError('HREF attr not found')
- return str(loco)
- except KeyError:
- try:
- loco = ImplementationObj.codebase['filename']
- if loco is None:
- del ImplementationObj.codebase['filename']
- raise KeyError('FILENAME or HREF attr not found')
- return str(loco)
- except KeyError, e:
- raise FailInstall('Codebase is not valid: %s' % e)
-
- def switchdir(newdir):
- olddir = os.getcwd()
- os.chdir(newdir)
- return olddir
-
- def decompress_zipfile(build_dir,zip_filename,
- verbose=0,dry_run=0):
- mkpath(build_dir, verbose=verbose)
- curdir = switchdir(build_dir)
- #XXX this is one disadvantage of using distutil. If
- #you don't reset this hash, Distutils would be deceived
- #and does not recreate a path which has been visited before,
- #even if the path is not valid anymore.
- dir_util._path_created = {}
- errorreporter.Msg("Inflating '%s'..." % zip_filename)
- try:
- import zipfile
- except ImportError:
- try:
- spawn(["unzip", zip_filename],
- verbose=verbose, dry_run=dry_run)
- switchdir(curdir)
- return zip_filename
- except DistutilsExecError:
- raise DistutilsExecError, \
- ("unable to create zip file '%s': " +
- "could neither find a standalone zip utility nor " +
- "import the 'zipfile' module") % zip_filename
-
- if not zipfile.is_zipfile(zip_filename):
- raise FailInstall("Invalid ZIP file: format not recognized")
-
- def WriteFile(filename,bytes,verbose=0):
- dirname , fname = os.path.split(filename)
- mkpath(dirname , verbose=verbose)
- file = open(filename, 'wb')
- file.write(bytes)
- file.close()
-
- z = zipfile.ZipFile(zip_filename,'r')
- try:
- for filename in z.namelist():
- bytes = z.read(filename)
- WriteFile(filename , bytes, verbose=verbose)
- except zipfile.error, e:
- raise FailInstall('An error occured while decompressing '+\
- 'the archive: ' % e)
-
- switchdir(curdir)
- return zip_filename
-
- def decompress_tarball(build_dir,archive_name,decompress="gunzip",
- verbose=0,dry_run=0):
- decompress_ext = { 'gunzip': ".gz",
- 'bunzip2': '.bz2',
- 'decompress': ".Z" }
-
- if decompress is not None and decompress not in decompress_ext.keys():
- raise ValueError, \
- "bad value for 'decompress': %s: must be "+\
- "None, 'gunzip', or 'decompress'" % decompress
-
- if decompress:
- errorreporter.Msg(decompress+' '+ os.path.join(build_dir,archive_name))
- if os.system(decompress +' '+ os.path.join(build_dir,archive_name))!=0:
- raise FailInstall('Command %s returned a negative '+\
- 'value' % decompress)
- archive_name = archive_name[0:string.rfind(archive_name , \
- decompress_ext[decompress])]
-
- dnld_dir = os.path.dirname(build_dir)
- mkpath(build_dir, verbose=verbose)
- curdir = switchdir(build_dir)
- if verbose:
- cmd = "tar -xvf " + archive_name
- else:
- cmd = "tar -xf " + archive_name
- errorreporter.Msg("Inflating '%s'..." % cmd)
- if os.system(cmd)!=0:
- raise FailInstall("Command %s returned a negative value" % cmd)
- switchdir(build_dir)
- return archive_name
-
- # known archive formats
- ARCHIVE_FORMATS = {
- 'tar.gz': (decompress_tarball, [('decompress', 'gunzip')], \
- "gzip'ed tar-file"),
- 'tar.bz2': (decompress_tarball, [('decompress', 'bunzip2')], \
- "bzip2'ed tar-file"),
- 'tar.Z': (decompress_tarball, [('decompress', 'decompress')], \
- "compressed tar file"),
- 'tar': (decompress_tarball, [('decompress', None)], \
- "uncompressed tar file"),
- 'zip': (decompress_zipfile, [],"ZIP file")
- }
-
- def get_archive_type(fullfilename):
- name , ext = (None, None)
- (head , tail) = os.path.split(fullfilename)
- if not tail:
- raise ValueError
- for formats in ARCHIVE_FORMATS.keys():
- index = string.rfind(tail,formats)
- if index>0:
- ext = tail[index:]
- name = tail[0:index-1]
- if not name or not ext:
- raise ValueError
- return (name , ext)
-
-
- def decompress_archive(fullfilename, Build_dir,verbose=0,dry_run=0):
- #get the name and the type of the compressed file
- errorreporter.Msg('Decompressing the archive %s...' % fullfilename)
- try:
- (filename , ext) = get_archive_type(fullfilename)
- except ValueError, e:
- errorreporter.LowError("Archive type not recognized: %s" % e)
- return
-
- kwargs = { 'verbose': verbose,
- 'dry_run': dry_run }
- try:
- format_info = ARCHIVE_FORMATS[ext]
- except KeyError:
- raise ValueError, "unknown archive format '%s'" % ext
-
- errorreporter.Msg('Archive format recognized as: %s' % format_info[2])
- func = format_info[0]
- for (arg,val) in format_info[1]:
- kwargs[arg] = val
-
- return apply(func,(Build_dir,fullfilename),kwargs)
-
-
- def CheckInstallation(pkg,instpkgs):
- return pkg.name in [p.name for p in instpkgs]
-
- FancyStatus = '[ %d, %d ] ************************************* [ %s ]'
- class Installer:
- def __init__(self, verbose, printfunc):
- #XXX
- self.verbose = verbose
- self.TotalDownload = 0
- self.printfunc = printfunc
-
- def init(self, package_name, ppd_loco = None, bin_loco = None):
- self.pn = package_name
- self.ppd_loco = ppd_loco
- self.bin_loco = bin_loco
-
- def fetch_ppd(self, locos, pac_name):
- if 1: # XXX remove this silly thing later
- #if it is a file or url just fetch it right here and do not
- #use SOAP calls to PPM server
- rc = find_loco_type(pac_name)
- if rc == 'file':
- self.printfunc( "Opening PPD file on local file system...")
- if string.find(pac_name,'.ppd')<1:
- pac_name += '.ppd'
- try:
- fobj = open(pac_name, 'r')
- self.ppd_path = os.path.abspath(pac_name)
- ppd = fobj.read()
- fobj.close()
- except IOError, e:
- errorreporter.Fatal('can not open ppd file: %s' % e)
- return None
- #XXX
- #XXX
- return ppd
- if rc =='http':
- return self.fetch_ppd_fromURL(pac_name)
- self.init(pac_name, locos.uri)
- if not self.ppd_loco:
- errorreporter.Fatal("Can not fetch the package info."+\
- "No location has been specified.")
- return
- if not self.pn:
- errorreporter.Fatal("No package name has been specified")
- return
- #if locos is a repository url then we have to deal with it using SOAP
- rc = find_loco_type(locos.uri)
- if rc != 'http':
- raise ProtocolError('Sorry, The SOAP server can not bind to this protocol: %s' \
- % rc)
- return
- try:
- soap_server = soaptalk.soaptalk(locos.uri,namespace=locos.namespace)
- except Exception, e:
- errorreporter.Error("Can not access the specified server: %s" % e)
- return ''
- return soap_server.fetch_ppd(self.pn)
-
- def status_hook(self,blocks,blockSize,FileSize):
- size = blocks*blockSize
- if self.DownloadStatus and \
- int(size/self.DownloadStatus)>self.TotalDownload:
- self.TotalDownload += 1
- if FileSize:
- self.printfunc(FancyStatus % (int(size/1000),
- int(FileSize/1000), str(int((size*100)/FileSize))))
- else:
- self.printfunc(FancyStatus % (str(size/1000), 'UNKNOWN'))
-
- def fetch_binary(self, location, builddir=os.curdir):
- self.bin_loco = location
- self.build_dir = str(builddir)
-
- if self.build_dir[-1] != '/':
- self.build_dir += '/'
- mkpath(self.build_dir,verbose=self.verbose)
- if isurl(self.bin_loco):
- filename = filenameFromURL(self.bin_loco)
- (dummy, _) = get_archive_type(filename)
- build_dir = os.path.join(self.build_dir,dummy)
- mkpath(build_dir)
- fullfilename = os.path.join(build_dir,filename)
- if os.path.exists(fullfilename):
- self.printfunc("(Path already exists -> Deleting %s)" % fullfilename)
- try:
- if(os.path.isdir(fullfilename)):
- shutil.rmtree(fullfilename,1)
- if(os.path.isfile(fullfilename)):
- os.unlink(fullfilename)
- except Exception, e:
- errorreporter.Error("can not download the package: %s" % e)
- return ''
-
- self.printfunc("(fetching %s)"% filename)
- try:
- urllib.urlretrieve(self.bin_loco, fullfilename,
- self.status_hook)
- return filename
- except IOError, e:
- errorreporter.Error("can not access the specified URL: %s" % e)
- raise ProtocolError('')
-
- else:
- # check for paths relative to the PPD location
- ppd_dir = os.path.dirname(self.ppd_path)
- bin_loco_path = os.path.join(ppd_dir,self.bin_loco)
- if isfile(bin_loco_path):
- # url name machinery to make urllib happy
- bin_loco_path = string.translate(bin_loco_path,string.maketrans(':','|'))
- self.bin_loco = 'file:///' + bin_loco_path
- self.printfunc("self.bin_loco %s" % self.bin_loco)
- filename = filenameFromURL(self.bin_loco)
- (dummy, _) = get_archive_type(filename)
- build_dir = os.path.join(self.build_dir,dummy)
- mkpath(build_dir)
- fullfilename = os.path.join(build_dir,filename)
- if os.path.exists(fullfilename):
- self.printfunc("(Path already exists -> Deleting %s)" % fullfilename)
- try:
- if(os.path.isdir(fullfilename)):
- shutil.rmtree(fullfilename,1)
- if(os.path.isfile(fullfilename)):
- os.unlink(fullfilename)
- except Exception, e:
- errorreporter.Error("can not fetch the package: %s" % e)
- return ''
-
- self.printfunc("(fetching %s)"% filename)
- try:
- urllib.urlretrieve(self.bin_loco, fullfilename,
- self.status_hook)
- return filename
- except IOError, e:
- errorreporter.Error("can not access the specified URL: %s" % e)
- raise ProtocolError('')
- else:
- return ''
-
- def fetch_ppd_fromURL(self,url):
- if not string.rfind(url,'.ppd')>0:
- url += '.ppd'
- if isurl(url):
- try:
- file = urllib.urlopen(url)
- ppd = file.read()
- ppd = str(ppd)
- ppd.strip()
- file.close()
- return ppd
- except IOError, e:
- errorreporter.Error("can not read the socket: %s" % e)
- return ''
- else:
- return ''
-
- def InstallPackage(self,ppd,cnfs,clean=0,upgrade=0):
- if type(ppd) is TupleType:
- raise BadPPD(str(ppd))
- if not ppd:
- raise PackageNotFound
- return
- elif string.find(ppd,'404')>=0 or \
- string.find(ppd,'Not Found')>=0:
- raise PackageNotFound
- else:
- ppd = str(ppd)
-
- self.TotalSize = 0
- self.DownloadStatus = cnfs.options['downloadstatus']
- try:
- domdom = xml.dom.minidom.parseString(ppd)
- except Exception, e:
- raise BadPPD(e)
- try:
- self.softpkg = ppmconfig.Package(domdom.getElementsByTagName\
- ("SOFTPKG")[0])
- except:
- raise FailInstall("Defective PPD")
-
- # checks to see if this package has been installed before
- if CheckInstallation(self.softpkg,cnfs.InstPackages) and \
- not upgrade:
- raise AlreadyInstalled
-
- for imp in self.softpkg.implementations:
- #checks to see if our OS is among the OS tags listed in the PPD
- if not imp.python_version:
- filename = tempfile.mktemp(".ppd")
- self.printfunc("tempfile %s" % filename)
- open(filename, "w").write(ppd)
- os.system("ppm install %s" % filename )
- #os.remove(tempfile)
- return
-
- if CheckOs(imp.oss):
- location = get_repository_location(imp)
- InstallerApp = imp.installer
- try:
- self.binary_name = self.fetch_binary(location,cnfs.builddir)
- except ProtocolError:
- raise FailInstall('URL inaccessible')
- try:
- self.InstallBinary(cnfs.options['root'],
- clean=clean,
- verbose=self.verbose,
- InstallerApp=InstallerApp)
- display = errorreporter.tracer.displayer.display
- display("Package %s was successfully installed" % \
- self.softpkg.name, 4)
- return self.softpkg
- except Exception, e:
- raise FailInstall(e)
-
- raise FailInstall('Package %s has not been implemented on your platform.' \
- % self.softpkg.name)
-
- def execute(self, arg,dirname,names):
- if arg[1]:
- if not arg[1] in names:
- raise FailInstall("Setup script '%s' not found!" % arg[1])
- curdir = switchdir(dirname)
- rc = os.system(arg[1])
- switchdir(curdir)
- if rc==0:
- return
- else:
- raise FailInstall("Can not execute the setup script")
- elif 'setup.py' in names:
- curdir = switchdir(dirname)
-
- if sys.platform.startswith("win") and \
- ppmconfig.using_gui():
- nul = "> nul:"
- else:
- nul=""
-
- if arg[0]:
- root = "--root"
- else:
- root = ""
-
- SPACE=" "
- command = SPACE.join(['"'+sys.executable+'"',
- "setup.py install --skip-build",
- root, nul] )
-
- rc = os.system(command)
- switchdir(curdir)
- if rc==0:
- arg[2][0]=1 #XXX
- return
- else:
- raise FailInstall("Can not execute the setup script")
-
- def InstallBinary(self,root,clean=0,verbose=0,InstallerApp=''):
- # Python!!!
-
- self.printfunc("entering install binary... %s" % (self.binary_name))
- (dummy, _) = get_archive_type(self.binary_name)
-
- build_dir = os.path.join(self.build_dir, dummy)
- errorreporter.Msg('Trying to inflate and install '+ \
- 'downloaded binary %s in directory %s' % \
- (self.binary_name, build_dir))
-
- archive_name = decompress_archive(self.binary_name , build_dir,\
- verbose=self.verbose)
-
- if not InstallerApp:
- errorreporter.Msg('installing the package using ''setup.py'' script')
- else:
- errorreporter.Msg('installing the package using %s' % InstallerApp)
- IsItInstalled = [0]
- try:
- os.path.walk(build_dir, self.execute,[root,InstallerApp,IsItInstalled])
- except Exception, e:
- raise FailInstall(e)
- if not IsItInstalled[0]:
- raise FailInstall('')
-
- def deletem(arg,dirname,names):
- if arg:
- os.remove(os.path.join(dirname,arg))
- elif 'setup.py' in names or\
- 'Setup.py' in names:
- names = []
- shutil.rmtree(dirname,1)
-
- if clean:
- errorreporter.Msg('Removing downloaded files...')
- try:
- shutil.rmtree(build_dir)
- except Exception, e:
- errorreporter.Error("Error removing build dir. Some \
- files may not be removed: %s" % e)
-