#
# urlinstall.py - URL based install source method
#
# Erik Troan <
[email protected]>
#
# 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