# # urlinstall.py - URL based install source method # # Erik Troan # # Copyright 1999-2002 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # library public license. # # You should have received a copy of the GNU Library Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # from hdrlist import groupSetFromCompsFile, HeaderList from installmethod import InstallMethod, FileCopyException import os import rpm import time import urllib2 import string import struct import socket # we import these explicitly because urllib loads them dynamically, which # stinks -- and we need to have them imported for the --traceonly option import ftplib import httplib import StringIO from rhpl.log import log import product FILENAME = 1000000 DISCNUM = 1000002 def urlretrieve(location, file): """Downloads from location and saves to file.""" try: url = urllib2.urlopen(location) except urllib2.HTTPError, e: raise IOError(e.code, e.msg) except urllib2.URLError, e: raise IOError(-1, e.reason) f = open(file, 'w+') f.write(url.read()) f.close() url.close() class UrlInstallMethod(InstallMethod): def readCompsViaMethod(self, hdlist): fname = self.findBestFileMatch(None, 'comps.xml') # if not local then assume its on host if fname is None: if (product.productDefault == product.productSite) : fname = self.baseUrl + "/" + product.productDefault + "/base/comps.xml" else: fname = self.baseUrl + "/" + product.productSite + "/base/comps.xml" log("Comps not in update dirs, using %s",fname) return groupSetFromCompsFile(fname, hdlist) def getFilename(self, h, timer): tmppath = self.getTempPath() # h doubles as a filename -- gross if type("/") == type(h): fullPath = self.baseUrl + "/" + h else: if self.multiDiscs: base = "%s/disc%d" % (self.pkgUrl, h[DISCNUM]) else: base = self.pkgUrl if self.isUpdateRPM(h): # path = "/RedHat/Updates/" path = "/" + product.productSite + "/Updates/" else: # path = "/RedHat/RPMS/" path = "/" + product.productDefault + "/RPMS/" fullPath = base + path + h[FILENAME] file = tmppath + os.path.basename(fullPath) tries = 0 while tries < 5: try: urlretrieve(fullPath, file) except IOError, (errnum, msg): log("IOError %s occurred getting %s: %s" %(errnum, fullPath, str(msg))) time.sleep(5) else: break tries = tries + 1 if tries >= 5: raise FileCopyException return file def copyFileToTemp(self, filename): tmppath = self.getTempPath() if self.multiDiscs: base = "%s/disc1" % (self.pkgUrl,) else: base = self.pkgUrl fullPath = base + "/" + filename file = tmppath + "/" + os.path.basename(fullPath) tries = 0 while tries < 5: try: urlretrieve(fullPath, file) except IOError, (errnum, msg): log("IOError %s occurred getting %s: %s", errnum, fullPath, str(msg)) time.sleep(5) else: break tries = tries + 1 if tries >= 5: raise FileCopyException return file def unlinkFilename(self, fullName): os.remove(fullName) def readHeaders(self): tries = 0 while tries < 5: if (product.productDefault == product.productSite) : hdurl = self.baseUrl + "/" + product.productDefault + "/base/hdlist" else: log("product.productSiteDir is %s", product.productSiteDir) log("product.productSite is %s ", product.productSite) hdurl = self.baseUrl + "/" + product.productSite + "/base/hdlist" try: url = urllib2.urlopen(hdurl) except urllib2.HTTPError, e: log("HTTPError: %s occurred getting %s", hdurl, e) except urllib2.URLError, e: log("URLError: %s occurred getting %s", hdurl, e) except IOError, (errnum, msg): log("IOError %s occurred getting %s: %s", errnum, hdurl, msg) else: break time.sleep(5) tries = tries + 1 if tries >= 5: raise FileCopyException raw = url.read(16) if raw is None or len(raw) < 1: raise TypeError, "header list is empty!" hl = [] while (raw and len(raw)>0): info = struct.unpack("iiii", raw) magic1 = socket.ntohl(info[0]) & 0xffffffff if (magic1 != 0x8eade801 or info[1]): raise TypeError, "bad magic in header" il = socket.ntohl(info[2]) dl = socket.ntohl(info[3]) totalSize = il * 16 + dl; hdrString = raw[8:] + url.read(totalSize) hdr = rpm.headerLoad(hdrString) hl.append(hdr) raw = url.read(16) return HeaderList(hl) def mergeFullHeaders(self, hdlist): if (product.productDefault == product.productSite) : fn = self.getFilename("/" + product.productDefault + "/base/hdlist2", None) else: fn = self.getFilename("/" + product.productSite + "/base/hdlist2", None) hdlist.mergeFullHeaders(fn) os.unlink(fn) def __init__(self, url, rootPath): InstallMethod.__init__(self, rootPath) if url.startswith("ftp"): isFtp = 1 else: isFtp = 0 # build up the url. this is tricky so that we can replace # the first instance of // with /%3F to do absolute URLs right i = string.index(url, '://') + 3 self.baseUrl = url[:i] rem = url[i:] i = string.index(rem, '/') + 1 self.baseUrl = self.baseUrl + rem[:i] rem = rem[i:] # encoding fun so that we can handle absolute paths if rem.startswith("/") and isFtp: rem = "%2F" + rem[1:] self.baseUrl = self.baseUrl + rem if self.baseUrl[-1] == "/": self.baseUrl = self.baseUrl[:-1] # self.baseUrl points at the path which contains the 'RedHat' # directory with the hdlist. if self.baseUrl[-6:] == "/disc1": self.multiDiscs = 1 self.pkgUrl = self.baseUrl[:-6] else: self.multiDiscs = 0 self.pkgUrl = self.baseUrl