#coding:utf-8
import os
import sunhpc
import xml.sax
class DistError(Exception):
    pass
    
class DistRPMList(DistError):
    def __init__(self, list):
        Exception.__init__(self, list)
        self.list = list

class Arch:
    """Base class that understands Linux architecture strings and nothing
    else.  All distributions needs this information as do other code
    that handles rpms"""
    
    def __init__(self):
        self.arch   = ''
        self.distArch   = ''
        self.cpus   = []
        self.i86cpus    = [ 'athlon', 'i686', 'i586', 'i486', 'i386' ]
        
    def getCPUs(self):
        return self.cpus
        
    def getArch(self):
        return self.arch
        
    def getDistArch(self):
        return self.distArch

    def setArch(self, arch, distArch=None):
        """The two architectures are to handle trends like
        the AMD64 dist arch, where the true arch is x86_64.
        NOTE: This trend does not exist with RHEL."""
        
        self.arch = arch
        if arch in self.i86cpus:
            self.cpus = self.i86cpus
            self.arch = 'i386'
        elif arch == 'x86_64':
            self.cpus = [ arch ]
            self.cpus.extend([ 'ia32e' ])
            self.cpus.extend(self.i86cpus)
        else:
            self.cpus = [ arch ]

        self.cpus.extend([ 'src', 'noarch' ])
        
        if distArch:
            self.distArch = distArch
        else:
            self.distArch = arch
        
class Base(Arch):
    """Understands how to navigate the sometimes arcane 
    RedHat linux distribution directory paths. Used to build
    and manipulate custom RedHat-compatible distributions."""

    def __init__(self):
        Arch.__init__(self)
        self.root       = ''
        self.distdir    = ''
        self.trees  = {}

    def isBuilt(self):
        if self.trees != {}:
            return 1
        else:
            return 0

    def build(self):
        self.trees['release'] = sunhpc.core.files.Tree(self.getReleasePath())

    def setRoot(self, s):
        self.root = s
        
    def setDist(self, d):
        self.distdir = d
        
    def getDist(self):
        return self.distdir

    def getRootPath(self):
        return self.root

    def getHomePath(self):
        return os.path.join(self.root, self.distdir)

    def getReleasePath(self):
        return os.path.join(self.getHomePath(), self.getDistArch())

    def getWANReleasePath(self, client='all'):
        return os.path.join(self.getHomePath(), client, 
            self.getDistArch())

    def getRPMSPath(self):
        return os.path.join(self.getReleasePath(), 'RedHat', 'RPMS')

    def getSRPMSPath(self):
        return os.path.join(self.getReleasePath(), 'SRPMS')
    
    def getBasePath(self):
        return os.path.join(self.getReleasePath(), 'RedHat', 'base')
        
    def getRollCentralPath(self):
        return str(os.path.join(self.getHomePath(), 'rolls'))
        
    def getBaseFile(self, name):
        for file in self.getFiles('release',
                      os.path.join('RedHat', 'base')):
            if file.getName() == name:
                return file
        return None

    def getTreeNames(self):
        return self.trees.keys()

    def getTree(self, name):
        if name in self.trees.keys():
            return self.trees[name]
        else:
            return None

    def setFiles(self, name, path, list):
        self.trees[name].setFiles(path, list)

    def getFiles(self, name, path):
        try:
            value = self.trees[name]
        except KeyError:
            return []
        list = [] 
        if type(value) == type([]):
            for tree in value:
                list.extend(tree.getFiles(path))
            return list
        else:
            return value.getFiles(path)

    def setBaseFiles(self, list):
        self.setFiles('release', os.path.join('RedHat', 'base'), list)

    def setRPMS(self, list):
        self.setFiles('release', os.path.join('RedHat', 'RPMS'), list)
        
    def setSRPMS(self, list):
        self.setFiles('release', 'SRPMS', list)

    def getPackage(self, name, list):
        matches = []
        for file in list:
            if file.getBaseName() == name:
                matches.append(file)
        
        if not matches:
            return None
        elif len(matches) == 1:
            return matches[0]
        else:
            raise DistRPMList(matches)

    def getRPM(self, name):
        return self.getPackage(name, self.getRPMS())
        
    def getSRPM(self, name):
        return self.getPackage(name, self.getSRPMS())
        
    def getRPMS(self):
        return self.getFiles('release', os.path.join('RedHat', 'RPMS'))

    def getSRPMS(self):
        return self.getFiles('release', os.path.join('SRPMS'))

    def getReleaseTree(self):
        return self.getTree('release')

    def dumpDirNames(self):
        for key in self.trees.keys():
            value = self.trees[key]
            if type(value) == types.ListType:
                for e in value:
                    e.dumpDirNames()
            else:
                value.dumpDirNames()
        
    def dump(self):
        for key in self.trees.keys():
            value = self.trees[key]
            if type(value) == types.ListType:
                for e in value:
                    e.dump()
            else:
                value.dump()
        
class Mirror(Base):

    def __init__(self, mirror=None):
        Base.__init__(self)
        if mirror:
            self.setHost(mirror.host)
            self.setPath(mirror.dir)
            self.setRoot(mirror.root)
            self.setArch(mirror.arch, mirror.distArch)
        else:
            self.host   = ''
            self.dir    = ''
        self.getRelease = 1

    def __str__(self):
        s = "SunHPC Mirror Distribution\n"
        s += "Host: %s\n" % self.getHost()
        s += "Path: %s\n" % self.getPath()
        return s

    def __cmp__(self, other):
        if not other:
            return -1
        elif other.getHost() == self.getHost() and \
            other.getPath() == self.getPath():
            return 0
        else:
            return -1

    def build(self):
        Base.build(self)
        self.trees['rolls'] = sunhpc.core.files.Tree(self.getRollsPath())

    def getRootPath(self):
        return self.root

    def setHost(self, s):
        self.host = s

    def setPath(self, s):
        self.dir = s

    def getHost(self):
        return self.host

    def getPath(self):
        return self.dir
    
    def getHomePath(self):
        return os.path.join(self.root, self.host, self.dir)

    def getRemoteReleasePath(self):
        return os.path.join(self.dir, self.getDistArch())

    def getRollsPath(self):
        return os.path.join(self.getRootPath(), 'rolls')

    def getRollRPMS(self, roll, version, arch):
        path = os.path.join(roll, version, arch, 'RedHat', 'RPMS')
        return self.getFiles('rolls', path)

    def getRollBaseFiles(self, roll, version, arch):
        path = os.path.join(roll, version, arch, 'RedHat', 'base')
        return self.getFiles('rolls', path)
        
    def getRollSRPMS(self, roll, version, arch):
        path = os.path.join(roll, version, arch, 'SRPMS')
        return self.getFiles('rolls', path)
        
    def getRolls(self):
        rolls = {}
        rollsPath = self.getRollsPath()
        if not os.path.exists(rollsPath):
            return rolls
        for r in os.listdir(rollsPath):
            rolls[r] = []
            rdir = os.path.join(self.getRollsPath(), r)
            if not os.path.isdir(rdir):
                continue
            for v in os.listdir(rdir):
                vdir = os.path.join(rdir, v)
                if not os.path.isdir(vdir):
                    continue
                for a in os.listdir(vdir):
                    adir = os.path.join(vdir, a)
                    if not os.path.isdir(adir):
                        continue
                    rolls[r].append((a, v))
        return rolls

class Distribution(Base):

    def __init__(self, m, v):
        Base.__init__(self)
        self.contrib    = ''
        self.local      = ''
        self.mirrors    = m
        self.root       = self.mirrors[0].root
        self.arch       = self.mirrors[0].arch
        self.distArch   = self.mirrors[0].distArch
        self.cpus       = self.mirrors[0].cpus
        self.version    = v

    def build(self):
        Base.build(self)
        
        self.trees['contrib']       = sunhpc.core.files.Tree(self.contrib)
        self.trees['force']         = sunhpc.core.files.Tree(self.getForceRPMSPath())
        self.trees['site-profiles'] = sunhpc.core.files.Tree(self.getSiteProfilesPath())
        self.trees['local_srpms']   = []
        self.trees['local']         = []
        self.trees['cdrom']         = []
        self.trees['rolls']         = []
        for e in self.getSiteRPMSPath():
            self.trees['local'].append(sunhpc.core.files.Tree(e))
        for e in self.getSiteSRPMSPath():
            self.trees['local_srpms'].append(sunhpc.core.files.Tree(e))
        for f in self.trees['force'].getFiles(''):
            f.setImortal()
  
    def setContrib(self, s):
        self.contrib = s

    def setLocal(self, s):
        self.local = s
        
    def getSunhpcRelease(self):
        return self.version
    
    def getBuildPath(self):
        return os.path.join(self.getReleasePath(), 'build')
    
    def getSiteRPMSPath(self):
        l = []
        if self.local:
            for cpu in self.cpus:
                l.append(os.path.join(self.local, 'RPMS', cpu))
        if 'RPMHOME' in os.environ:
            for cpu in self.cpus:
                l.append(os.path.join(os.environ['RPMHOME'],
                              'RPMS', cpu))
        return l

    def getSiteSRPMSPath(self):
        l = []
        if self.local:
            l.append(os.path.join(self.local, 'SRPMS'))
        if 'RPMHOME' in os.environ:
            l.append(os.path.join(os.environ['RPMHOME'], 'SRPMS'))
        return l

    def getForceRPMSPath(self):
        return os.path.join(self.getReleasePath(), 'force', 'RPMS')

    def getRollsPath(self):
        return os.path.join(self.getReleasePath(), 'rolls')

    def getContribRPMSPath(self):
        return os.path.join(self.contrib, self.arch, 'RPMS')

    def getContribSRPMSPath(self):
        return os.path.join(self.contrib, self.arch, 'SRPMS')

    def getSiteProfilesPath(self):
        return os.path.join(self.getRootPath(), 'site-profiles',
                    self.getSunhpcRelease())

    def getMirrors(self):
        return self.mirrors

    def getContribRPMS(self):
        return self.getFiles('contrib', os.path.join(self.arch, 'RPMS'))

    def getContribSRPMS(self):
        return self.getFiles('contrib', os.path.join(self.arch, 'SRPMS'))

    def getLocalRPMS(self):
        return self.getFiles('local', '')

    def getLocalSRPMS(self):
        return self.getFiles('local_srpms', '')

    def getForceRPMS(self):
        return self.getFiles('force', '')

    def getSiteProfilesTree(self):
        return self.getTree('site-profiles')

    def syncMirror(self):
        for mirror in self.mirrors:
            tree = mirror.getTree('release')
            for key in tree.getDirs():
                self.getTree('release').\
                setFiles(key, tree.getFiles(key))

