Wrote a templating system for initrd creation.
A lot of stuff got changed and rewritten. Using a different approach now, so no point of tracking changes to the older commits.
This commit is contained in:
parent
d3fd188841
commit
b0b696d66d
9
etc/templates/initrd
Normal file
9
etc/templates/initrd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# initrd template file
|
||||||
|
#
|
||||||
|
# supported variables: @initrd@
|
||||||
|
# @instroot@
|
||||||
|
|
||||||
|
:copy
|
||||||
|
# comment
|
||||||
|
@instroot@/bin/bash to @initrd@/bin
|
||||||
|
@instroot@/bin/mount to @initrd@/bin
|
@ -1,26 +1,5 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
|
||||||
# lorax
|
# lorax
|
||||||
# Install image and tree support data generation tool.
|
|
||||||
#
|
|
||||||
# Copyright (C) 2008, 2009 Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Author(s): David Cantrell <dcantrell@redhat.com>
|
|
||||||
# Martin Gracik <mgracik@redhat.com>
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@ -30,7 +9,7 @@ import pylorax
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
version = '%s 0.1' % (os.path.basename(sys.argv[0]),)
|
version = '%s 0.1' % os.path.basename(sys.argv[0])
|
||||||
usage = '%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUT REPOSITORY'
|
usage = '%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUT REPOSITORY'
|
||||||
|
|
||||||
parser = OptionParser(usage=usage)
|
parser = OptionParser(usage=usage)
|
||||||
@ -39,7 +18,8 @@ if __name__ == '__main__':
|
|||||||
if os.path.isdir(value):
|
if os.path.isdir(value):
|
||||||
setattr(parser.values, option.dest, value)
|
setattr(parser.values, option.dest, value)
|
||||||
else:
|
else:
|
||||||
parser.error('%s is not a directory' % (value,))
|
parser.error('%s is not a directory.' % value)
|
||||||
|
|
||||||
|
|
||||||
# XXX "options" should not be required
|
# XXX "options" should not be required
|
||||||
# required
|
# required
|
||||||
@ -65,7 +45,8 @@ if __name__ == '__main__':
|
|||||||
metavar='URL', default='your distribution provided bug reporting tool.')
|
metavar='URL', default='your distribution provided bug reporting tool.')
|
||||||
group.add_option('-u', '--updates', help='Path to find updated RPMS.',
|
group.add_option('-u', '--updates', help='Path to find updated RPMS.',
|
||||||
metavar='PATHSPEC')
|
metavar='PATHSPEC')
|
||||||
group.add_option('-m', '--mirrorlist', help='Mirror list repository, may be listed multiple times.',
|
group.add_option('-m', '--mirrorlist',
|
||||||
|
help='Mirror list repository, may be listed multiple times.',
|
||||||
metavar='REPOSITORY', action='append', default=[])
|
metavar='REPOSITORY', action='append', default=[])
|
||||||
group.add_option('-c', '--confdir', help='Path to config files (default: /etc/lorax).',
|
group.add_option('-c', '--confdir', help='Path to config files (default: /etc/lorax).',
|
||||||
metavar='PATHSPEC', action='callback', callback=check_dir,
|
metavar='PATHSPEC', action='callback', callback=check_dir,
|
||||||
@ -89,10 +70,27 @@ if __name__ == '__main__':
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if not opts.product or not opts.version or not opts.release or not opts.output:
|
if not opts.product or not opts.version or not opts.release or not opts.output:
|
||||||
parser.error('Missing a required argument.')
|
parser.error('Missing required argument.')
|
||||||
|
|
||||||
if not args:
|
if not args:
|
||||||
parser.error('Missing repository to use for image generation.')
|
parser.error('Missing repository to use for image generation.')
|
||||||
|
|
||||||
lorax = pylorax.Lorax(repos=args, options=opts)
|
config = pylorax.Config()
|
||||||
|
config.set(confdir=opts.confdir,
|
||||||
|
debug=opts.debug,
|
||||||
|
cleanup=opts.cleanup)
|
||||||
|
|
||||||
|
# required
|
||||||
|
config.set(product=opts.product,
|
||||||
|
version=opts.version,
|
||||||
|
release=opts.release,
|
||||||
|
outdir=opts.output,
|
||||||
|
repos=args)
|
||||||
|
# optional
|
||||||
|
config.set(variant=opts.variant,
|
||||||
|
bugurl=opts.bugurl,
|
||||||
|
updates=opts.updates,
|
||||||
|
mirrorlist=opts.mirrorlist)
|
||||||
|
|
||||||
|
lorax = pylorax.Lorax(config=config)
|
||||||
lorax.run()
|
lorax.run()
|
||||||
|
@ -1,25 +1,4 @@
|
|||||||
#
|
# __init__.py
|
||||||
# pylorax
|
|
||||||
# Install image and tree support data generation tool -- Python module.
|
|
||||||
#
|
|
||||||
# Copyright (C) 2008, 2009 Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
# Author(s): David Cantrell <dcantrell@redhat.com>
|
|
||||||
# Martin Gracik <mgracik@redhat.com>
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@ -27,134 +6,146 @@ import shutil
|
|||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
|
import re
|
||||||
|
|
||||||
import yum
|
from config import Container
|
||||||
import rpmUtils
|
import utils.rpmutil as rpmutil
|
||||||
|
|
||||||
import instroot
|
|
||||||
import images
|
import images
|
||||||
|
|
||||||
|
from exceptions import LoraxError
|
||||||
|
|
||||||
class Lorax:
|
|
||||||
def __init__(self, repos, options):
|
|
||||||
self.repos = repos
|
|
||||||
|
|
||||||
# required
|
class Config(Container):
|
||||||
self.product = options.product
|
def __init__(self):
|
||||||
self.version = options.version
|
config = ('confdir', 'datadir', 'tempdir', 'debug', 'cleanup')
|
||||||
self.release = options.release
|
|
||||||
self.output = options.output
|
|
||||||
|
|
||||||
# optional
|
# options
|
||||||
self.debug = options.debug
|
required = ('product', 'version', 'release', 'outdir', 'repos')
|
||||||
self.variant = options.variant
|
optional = ('variant', 'bugurl', 'updates', 'mirrorlist')
|
||||||
self.bugurl = options.bugurl
|
|
||||||
self.updates = options.updates
|
|
||||||
self.mirrorlist = options.mirrorlist
|
|
||||||
self.confdir = options.confdir
|
|
||||||
self.cleanup = options.cleanup
|
|
||||||
|
|
||||||
self.conf = {}
|
Container.__init__(self, config + required + optional)
|
||||||
if not self.confdir:
|
|
||||||
self.confdir = '/etc/lorax'
|
# set defaults
|
||||||
self.conf['confdir'] = self.confdir
|
self.set(confdir='/etc/lorax',
|
||||||
self.conf['datadir'] = '/usr/share/lorax'
|
datadir='/usr/share/lorax',
|
||||||
self.conf['tmpdir'] = tempfile.gettempdir()
|
tempdir=tempfile.mkdtemp(prefix='lorax.tmp.', dir=tempfile.gettempdir()),
|
||||||
|
debug=False,
|
||||||
|
cleanup=False)
|
||||||
|
|
||||||
|
self.set(product='',
|
||||||
|
version='',
|
||||||
|
release='',
|
||||||
|
outdir='',
|
||||||
|
repos=[])
|
||||||
|
|
||||||
|
self.set(variant='',
|
||||||
|
bugurl='',
|
||||||
|
updates='',
|
||||||
|
mirrorlist=[])
|
||||||
|
|
||||||
|
|
||||||
|
class Lorax(object):
|
||||||
|
def __init__(self, config):
|
||||||
|
assert isinstance(config, Config) == True
|
||||||
|
self.conf = config
|
||||||
|
|
||||||
|
# check if we have all required options
|
||||||
|
if not self.conf.repos:
|
||||||
|
raise LoraxError, 'missing repos'
|
||||||
|
if not self.conf.outdir:
|
||||||
|
raise LoraxError, 'missing outdir'
|
||||||
|
if not self.conf.product:
|
||||||
|
raise LoraxError, 'missing product'
|
||||||
|
if not self.conf.version:
|
||||||
|
raise LoraxError, 'missing version'
|
||||||
|
if not self.conf.release:
|
||||||
|
raise LoraxError, 'missing release'
|
||||||
|
|
||||||
|
self.yum = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""run()
|
|
||||||
|
|
||||||
Generate install images.
|
|
||||||
"""
|
|
||||||
|
|
||||||
print('Collecting repos...')
|
print('Collecting repos...')
|
||||||
self.repo, self.extrarepos = self.__collectRepos()
|
self.collectRepos()
|
||||||
|
|
||||||
if not self.repo:
|
# check if we have at least one valid repository
|
||||||
sys.stderr.write('No valid repository.\n')
|
if not self.conf.repo:
|
||||||
|
sys.stderr.write('ERROR: no valid repository\n')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print('Initializing directories...')
|
print('Initializing directories...')
|
||||||
self.buildinstdir, self.treedir, self.cachedir = self.__initializeDirs()
|
self.initDirs()
|
||||||
|
|
||||||
print('Writing yum configuration...')
|
print('Initializing yum...')
|
||||||
self.yumconf = self.__writeYumConf()
|
self.initYum()
|
||||||
|
|
||||||
print('Getting the build architecture...')
|
print('Setting build architecture...')
|
||||||
self.buildarch = self.__getBuildArch()
|
self.setBuildArch()
|
||||||
|
|
||||||
print('Creating install root tree...')
|
|
||||||
self.makeInstRoot()
|
|
||||||
|
|
||||||
print('Writing .treeinfo...')
|
print('Writing .treeinfo...')
|
||||||
self.__writeTreeInfo()
|
self.writeTreeInfo()
|
||||||
|
|
||||||
print('Writing .discinfo...')
|
print('Writing .discinfo...')
|
||||||
self.__writeDiscInfo()
|
self.writeDiscInfo()
|
||||||
|
|
||||||
print('Creating images...')
|
print('Preparing the install tree...')
|
||||||
|
self.prepareInstRoot()
|
||||||
|
|
||||||
|
print('Creating the images...')
|
||||||
self.makeImages()
|
self.makeImages()
|
||||||
|
|
||||||
if self.cleanup:
|
if self.conf.cleanup:
|
||||||
print('Cleaning up...')
|
print('Cleaning up...')
|
||||||
self.cleanUp()
|
self.cleanUp()
|
||||||
|
|
||||||
def __collectRepos(self):
|
def collectRepos(self):
|
||||||
"""_collectRepos()
|
|
||||||
|
|
||||||
Get the main repo (the first one) and then build a list of all remaining
|
|
||||||
repos in the list. Sanitize each repo URL for proper yum syntax.
|
|
||||||
"""
|
|
||||||
|
|
||||||
repolist = []
|
repolist = []
|
||||||
for repospec in self.repos:
|
for repospec in self.conf.repos:
|
||||||
if repospec.startswith('/'):
|
if repospec.startswith('/'):
|
||||||
repo = 'file://%s' % (repospec,)
|
repo = 'file://%s' % repospec
|
||||||
print('Adding local repo:\n %s' % (repo,))
|
print('Adding local repo: %s' % repo)
|
||||||
repolist.append(repo)
|
repolist.append(repo)
|
||||||
elif repospec.startswith('http://') or repospec.startswith('ftp://'):
|
elif repospec.startswith('http://') or repospec.startswith('ftp://'):
|
||||||
print('Adding remote repo:\n %s' % (repospec,))
|
print('Adding remote repo: %s' % repospec)
|
||||||
repolist.append(repospec)
|
repolist.append(repospec)
|
||||||
|
|
||||||
if not repolist:
|
if not repolist:
|
||||||
return None, []
|
repo, extrarepos = None, []
|
||||||
else:
|
else:
|
||||||
return repolist[0], repolist[1:]
|
repo, extrarepos = repolist[0], repolist[1:]
|
||||||
|
|
||||||
def __initializeDirs(self):
|
self.conf.addAttr(['repo', 'extrarepos'])
|
||||||
"""_initializeDirs()
|
self.conf.set(repo=repo, extrarepos=extrarepos)
|
||||||
|
|
||||||
Create directories used for image generation.
|
# remove repos attribute, to get a traceback, if we use it later
|
||||||
"""
|
self.conf.delAttr('repos')
|
||||||
|
|
||||||
if not os.path.isdir(self.output):
|
def initDirs(self):
|
||||||
os.makedirs(self.output, mode=0755)
|
if not os.path.isdir(self.conf.outdir):
|
||||||
|
os.makedirs(self.conf.outdir, mode=0755)
|
||||||
|
|
||||||
self.conf['tmpdir'] = tempfile.mkdtemp('XXXXXX', 'lorax.tmp.', self.conf['tmpdir'])
|
treedir = os.path.join(self.conf.tempdir, 'treedir', 'install')
|
||||||
buildinstdir = tempfile.mkdtemp('XXXXXX', 'buildinstall.tree.', self.conf['tmpdir'])
|
cachedir = os.path.join(self.conf.tempdir, 'yumcache')
|
||||||
treedir = tempfile.mkdtemp('XXXXXX', 'treedir.', self.conf['tmpdir'])
|
|
||||||
cachedir = tempfile.mkdtemp('XXXXXX', 'yumcache.', self.conf['tmpdir'])
|
|
||||||
|
|
||||||
print('Working directories:')
|
print('Working directories:')
|
||||||
print(' tmpdir = %s' % (self.conf['tmpdir'],))
|
print(' tempdir = %s' % self.conf.tempdir)
|
||||||
print(' buildinstdir = %s' % (buildinstdir,))
|
print(' treedir = %s' % treedir)
|
||||||
print(' treedir = %s' % (treedir,))
|
print(' cachedir = %s' % cachedir)
|
||||||
print(' cachedir = %s' % (cachedir,))
|
|
||||||
|
|
||||||
return buildinstdir, treedir, cachedir
|
self.conf.addAttr(['treedir', 'cachedir'])
|
||||||
|
self.conf.set(treedir=treedir, cachedir=cachedir)
|
||||||
|
|
||||||
def __writeYumConf(self):
|
def initYum(self):
|
||||||
"""_writeYumConf()
|
yumconf = os.path.join(self.conf.tempdir, 'yum.conf')
|
||||||
|
|
||||||
Generate a temporary yum.conf file for image generation. Returns the path
|
|
||||||
to the temporary yum.conf file on success, None of failure.
|
|
||||||
"""
|
|
||||||
|
|
||||||
(fd, yumconf) = tempfile.mkstemp(prefix='yum.conf', dir=self.conf['tmpdir'])
|
|
||||||
f = os.fdopen(fd, 'w')
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = open(yumconf, 'w')
|
||||||
|
except IOError:
|
||||||
|
sys.stderr.write('ERROR: Unable to write yum.conf file\n')
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
f.write('[main]\n')
|
f.write('[main]\n')
|
||||||
f.write('cachedir=%s\n' % (self.cachedir,))
|
f.write('cachedir=%s\n' % self.conf.cachedir)
|
||||||
f.write('keepcache=0\n')
|
f.write('keepcache=0\n')
|
||||||
f.write('gpgcheck=0\n')
|
f.write('gpgcheck=0\n')
|
||||||
f.write('plugins=0\n')
|
f.write('plugins=0\n')
|
||||||
@ -163,73 +154,63 @@ class Lorax:
|
|||||||
|
|
||||||
f.write('[loraxrepo]\n')
|
f.write('[loraxrepo]\n')
|
||||||
f.write('name=lorax repo\n')
|
f.write('name=lorax repo\n')
|
||||||
f.write('baseurl=%s\n' % (self.repo,))
|
f.write('baseurl=%s\n' % self.conf.repo)
|
||||||
f.write('enabled=1\n\n')
|
f.write('enabled=1\n\n')
|
||||||
|
|
||||||
for n, extra in enumerate(self.extrarepos, start=1):
|
for n, extra in enumerate(self.conf.extrarepos, start=1):
|
||||||
f.write('[lorax-extrarepo-%d]\n' % (n,))
|
f.write('[lorax-extrarepo-%d]\n' % n)
|
||||||
f.write('name=lorax extra repo %d\n' % (n,))
|
f.write('name=lorax extra repo %d\n' % n)
|
||||||
f.write('baseurl=%s\n' % (extra,))
|
f.write('baseurl=%s\n' % extra)
|
||||||
f.write('enabled=1\n')
|
f.write('enabled=1\n')
|
||||||
|
|
||||||
for n, mirror in enumerate(self.mirrorlist, start=1):
|
for n, mirror in enumerate(self.conf.mirrorlist, start=1):
|
||||||
f.write('[lorax-mirrorlistrepo-%d]\n' % (n,))
|
f.write('[lorax-mirrorlistrepo-%d]\n' % n)
|
||||||
f.write('name=lorax mirrorlist repo %d\n' % (n,))
|
f.write('name=lorax mirrorlist repo %d\n' % n)
|
||||||
f.write('mirrorlist=%s\n' % (mirror,))
|
f.write('mirrorlist=%s\n' % mirror)
|
||||||
f.write('enabled=1\n')
|
f.write('enabled=1\n')
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
print('Wrote lorax yum configuration to %s' % (yumconf,))
|
|
||||||
|
|
||||||
return yumconf
|
self.conf.addAttr('yumconf')
|
||||||
|
self.conf.set(yumconf=yumconf)
|
||||||
|
|
||||||
def __getBuildArch(self):
|
self.yum = rpmutil.Yum(yumconf=self.conf.yumconf, installroot=self.conf.treedir)
|
||||||
"""_getBuildArch()
|
|
||||||
|
|
||||||
Query the configured yum repositories to determine our build architecture,
|
# remove not needed options
|
||||||
which is the architecture of the anaconda package in the repositories.
|
self.conf.delAttr(['repo', 'extrarepos', 'mirrorlist'])
|
||||||
|
|
||||||
This function is based on a subset of what repoquery(1) does.
|
def setBuildArch(self):
|
||||||
"""
|
unamearch = os.uname()[4]
|
||||||
|
|
||||||
uname_arch = os.uname()[4]
|
self.conf.addAttr('buildarch')
|
||||||
|
self.conf.set(buildarch=unamearch)
|
||||||
if not self.yumconf or not os.path.isfile(self.yumconf):
|
|
||||||
sys.stderr.write('ERROR: yum.conf does not exist, defaulting to %s\n' % (uname_arch,))
|
|
||||||
return uname_arch
|
|
||||||
|
|
||||||
repoq = yum.YumBase()
|
|
||||||
repoq.doConfigSetup(self.yumconf)
|
|
||||||
|
|
||||||
|
anaconda = self.yum.find('anaconda')
|
||||||
try:
|
try:
|
||||||
repoq.doRepoSetup()
|
self.conf.set(buildarch=anaconda[0].arch)
|
||||||
except yum.Errors.RepoError:
|
except:
|
||||||
sys.stderr.write('ERROR: cannot query yum repo, defaulting to %s\n' % (uname_arch,))
|
pass
|
||||||
return uname_arch
|
|
||||||
|
|
||||||
repoq.doSackSetup(rpmUtils.arch.getArchList())
|
# set the libdir
|
||||||
repoq.doTsSetup()
|
self.conf.addAttr('libdir')
|
||||||
|
self.conf.set(libdir='lib')
|
||||||
|
# on 64-bit systems, make sure we use lib64 as the lib directory
|
||||||
|
if self.conf.buildarch.endswith('64') or self.conf.buildarch == 's390x':
|
||||||
|
self.conf.set(libdir='lib64')
|
||||||
|
|
||||||
ret_arch = None
|
def writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''):
|
||||||
for pkg in repoq.pkgSack.simplePkgList():
|
outfile = os.path.join(self.conf.outdir, '.treeinfo')
|
||||||
(n, a, e, v, r) = pkg
|
|
||||||
if n == 'anaconda':
|
|
||||||
ret_arch = a
|
|
||||||
break
|
|
||||||
|
|
||||||
if not ret_arch:
|
# don't print anything instead of None if variant is not specified
|
||||||
ret_arch = uname_arch
|
variant = ''
|
||||||
|
if self.conf.variant:
|
||||||
return ret_arch
|
variant = self.conf.variant
|
||||||
|
|
||||||
def __writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''):
|
|
||||||
outfile = os.path.join(self.output, '.treeinfo')
|
|
||||||
|
|
||||||
data = { 'timestamp': time.time(),
|
data = { 'timestamp': time.time(),
|
||||||
'family': self.product,
|
'family': self.conf.product,
|
||||||
'version': self.version,
|
'version': self.conf.version,
|
||||||
'arch': self.buildarch,
|
'arch': self.conf.buildarch,
|
||||||
'variant': self.variant,
|
'variant': variant,
|
||||||
'discnum': str(discnum),
|
'discnum': str(discnum),
|
||||||
'totaldiscs': str(totaldiscs),
|
'totaldiscs': str(totaldiscs),
|
||||||
'packagedir': packagedir }
|
'packagedir': packagedir }
|
||||||
@ -241,6 +222,17 @@ class Lorax:
|
|||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
c.set(section, key, value)
|
c.set(section, key, value)
|
||||||
|
|
||||||
|
section = 'images-%s' % self.conf.buildarch
|
||||||
|
c.add_section(section)
|
||||||
|
c.set(section, 'kernel', 'images/pxeboot/vmlinuz')
|
||||||
|
c.set(section, 'initrd', 'images/pxeboot/initrd.img')
|
||||||
|
|
||||||
|
# XXX actually create the boot iso somewhere, and set up this attribute
|
||||||
|
self.conf.addAttr('bootiso')
|
||||||
|
|
||||||
|
if self.conf.bootiso:
|
||||||
|
c.set(section, 'boot.iso', 'images/%s' % self.conf.bootiso)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = open(outfile, 'w')
|
f = open(outfile, 'w')
|
||||||
except IOError:
|
except IOError:
|
||||||
@ -250,47 +242,43 @@ class Lorax:
|
|||||||
f.close()
|
f.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __writeDiscInfo(self, discnum=0):
|
def writeDiscInfo(self, discnum=0):
|
||||||
outfile = os.path.join(self.output, '.discinfo')
|
outfile = os.path.join(self.conf.outdir, '.discinfo')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = open(outfile, 'w')
|
f = open(outfile, 'w')
|
||||||
except IOError:
|
except IOError:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
f.write('%f\n' % (time.time(),))
|
f.write('%f\n' % time.time())
|
||||||
f.write('%s\n' % (self.release,))
|
f.write('%s\n' % self.conf.release)
|
||||||
f.write('%s\n' % (self.buildarch,))
|
f.write('%s\n' % self.conf.buildarch)
|
||||||
f.write('%d\n' % (discnum,))
|
f.write('%d\n' % discnum)
|
||||||
f.close()
|
f.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def makeInstRoot(self):
|
def prepareInstRoot(self):
|
||||||
root = instroot.InstRoot(conf=self.conf,
|
# XXX why do we need this?
|
||||||
yumconf=self.yumconf,
|
os.symlink(os.path.join(os.path.sep, 'tmp'),
|
||||||
arch=self.buildarch,
|
os.path.join(self.conf.treedir, 'var', 'lib', 'xkb'))
|
||||||
treedir=self.treedir,
|
|
||||||
updates=self.updates)
|
|
||||||
root.run()
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
def makeImages(self):
|
def makeImages(self):
|
||||||
pass
|
i = images.Images(self.conf, self.yum)
|
||||||
|
i.run()
|
||||||
|
|
||||||
|
# XXX figure out where to put this
|
||||||
|
#def copyUpdates(self):
|
||||||
|
# if self.conf.updates and os.path.isdir(self.conf.updates):
|
||||||
|
# cp(os.path.join(self.conf.updates, '*'), self.conf.treedir)
|
||||||
|
# self.conf.delAttr('updates')
|
||||||
|
|
||||||
def cleanUp(self, trash=[]):
|
def cleanUp(self, trash=[]):
|
||||||
"""cleanup([trash])
|
|
||||||
|
|
||||||
Given a list of things to remove, cleanUp() will remove them if it can.
|
|
||||||
Never fails, just tries to remove things and returns regardless of
|
|
||||||
failures removing things.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for item in trash:
|
for item in trash:
|
||||||
if os.path.isdir(item):
|
if os.path.isdir(item):
|
||||||
shutil.rmtree(item, ignore_errors=True)
|
shutil.rmtree(item, ignore_errors=True)
|
||||||
else:
|
else:
|
||||||
os.unlink(item)
|
os.unlink(item)
|
||||||
|
|
||||||
if os.path.isdir(self.conf['tmpdir']):
|
# remove the whole lorax tempdir
|
||||||
shutil.rmtree(self.conf['tmpdir'], ignore_errors=True)
|
if os.path.isdir(self.conf.tempdir):
|
||||||
|
shutil.rmtree(self.conf.tempdir, ignore_errors=True)
|
||||||
|
@ -30,17 +30,18 @@ import fnmatch
|
|||||||
import re
|
import re
|
||||||
import fileinput
|
import fileinput
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import pwd
|
import pwd
|
||||||
import grp
|
import grp
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from fileutils import cp, mv
|
from fileutils import cp, mv, touch
|
||||||
|
from yumutils import extract_rpm
|
||||||
|
|
||||||
|
import utils
|
||||||
|
|
||||||
sys.path.insert(0, '/usr/share/yum-cli')
|
|
||||||
import yummain
|
|
||||||
|
|
||||||
class InstRoot:
|
class InstRoot:
|
||||||
"""InstRoot(conf, yumconf, arch, treedir, [updates=None])
|
"""InstRoot(config, options, yum)
|
||||||
|
|
||||||
Create a instroot tree for the specified architecture. The list of
|
Create a instroot tree for the specified architecture. The list of
|
||||||
packages to install are specified in the /etc/lorax/packages and
|
packages to install are specified in the /etc/lorax/packages and
|
||||||
@ -58,20 +59,12 @@ class InstRoot:
|
|||||||
returned or the program is aborted immediately.
|
returned or the program is aborted immediately.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, conf, yumconf, arch, treedir, updates=None):
|
def __init__(self, config, options, yum):
|
||||||
self.conf = conf
|
self.conf = config
|
||||||
self.yumconf = yumconf
|
self.opts = options
|
||||||
self.arch = arch
|
self.yum = yum
|
||||||
self.treedir = treedir
|
|
||||||
self.updates = updates
|
|
||||||
|
|
||||||
self.libdir = 'lib'
|
self.destdir = self.conf.treedir
|
||||||
# on 64-bit systems, make sure we use lib64 as the lib directory
|
|
||||||
if self.arch.endswith('64') or self.arch == 's390x':
|
|
||||||
self.libdir = 'lib64'
|
|
||||||
|
|
||||||
# the directory where the instroot will be created
|
|
||||||
self.destdir = os.path.join(self.treedir, 'install')
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""run()
|
"""run()
|
||||||
@ -79,24 +72,21 @@ class InstRoot:
|
|||||||
Generate the instroot tree and prepare it for building images.
|
Generate the instroot tree and prepare it for building images.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not os.path.isdir(self.destdir):
|
|
||||||
os.makedirs(self.destdir)
|
|
||||||
|
|
||||||
# build a list of packages to install
|
|
||||||
self.packages = self.__getPackageList()
|
self.packages = self.__getPackageList()
|
||||||
|
|
||||||
# install the packages to the instroot
|
|
||||||
self.__installPackages()
|
self.__installPackages()
|
||||||
|
|
||||||
# scrub instroot
|
if not self.__installKernel():
|
||||||
self.__scrubInstRoot()
|
sys.exit(1)
|
||||||
|
|
||||||
|
# XXX
|
||||||
|
#self.__scrubInstRoot()
|
||||||
|
|
||||||
def __getPackageList(self):
|
def __getPackageList(self):
|
||||||
packages = set()
|
packages = set()
|
||||||
|
|
||||||
packages_files = []
|
packages_files = []
|
||||||
packages_files.append(os.path.join(self.conf['confdir'], 'packages'))
|
packages_files.append(os.path.join(self.conf.confdir, 'packages'))
|
||||||
packages_files.append(os.path.join(self.conf['confdir'], self.arch, 'packages'))
|
packages_files.append(os.path.join(self.conf.confdir, self.opts.buildarch, 'packages'))
|
||||||
|
|
||||||
for pfile in packages_files:
|
for pfile in packages_files:
|
||||||
if os.path.isfile(pfile):
|
if os.path.isfile(pfile):
|
||||||
@ -120,29 +110,98 @@ class InstRoot:
|
|||||||
return packages
|
return packages
|
||||||
|
|
||||||
def __installPackages(self):
|
def __installPackages(self):
|
||||||
# build the list of arguments to pass to yum
|
# XXX i don't think this is needed
|
||||||
arglist = ['-c', self.yumconf]
|
|
||||||
arglist.append("--installroot=%s" % (self.destdir,))
|
|
||||||
arglist.extend(['install', '-y'])
|
|
||||||
arglist.extend(self.packages)
|
|
||||||
|
|
||||||
# do some prep work on the destdir before calling yum
|
# do some prep work on the destdir before calling yum
|
||||||
os.makedirs(os.path.join(self.destdir, 'boot'))
|
#os.makedirs(os.path.join(self.destdir, 'boot'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'usr', 'sbin'))
|
#os.makedirs(os.path.join(self.destdir, 'usr', 'sbin'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'usr', 'lib', 'debug'))
|
#os.makedirs(os.path.join(self.destdir, 'usr', 'lib', 'debug'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'usr', 'src', 'debug'))
|
#os.makedirs(os.path.join(self.destdir, 'usr', 'src', 'debug'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'tmp'))
|
#os.makedirs(os.path.join(self.destdir, 'tmp'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'var', 'log'))
|
#os.makedirs(os.path.join(self.destdir, 'var', 'log'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'var', 'lib'))
|
#os.makedirs(os.path.join(self.destdir, 'var', 'lib', 'yum'))
|
||||||
os.makedirs(os.path.join(self.destdir, 'var', 'lib', 'yum'))
|
|
||||||
|
# XXX maybe only this...
|
||||||
|
#os.makedirs(os.path.join(self.destdir, 'var', 'lib'))
|
||||||
os.symlink(os.path.join(os.path.sep, 'tmp'), os.path.join(self.destdir, 'var', 'lib', 'xkb'))
|
os.symlink(os.path.join(os.path.sep, 'tmp'), os.path.join(self.destdir, 'var', 'lib', 'xkb'))
|
||||||
|
|
||||||
# XXX sort through yum errcodes and return False for actual bad things we care about
|
self.yum.install(self.packages)
|
||||||
errcode = yummain.user_main(arglist, exit_code=False)
|
|
||||||
|
|
||||||
# copy updates to destdir
|
# copy updates to treedir
|
||||||
if self.updates and os.path.isdir(self.updates):
|
if self.opts.updates and os.path.isdir(self.opts.updates):
|
||||||
cp(os.path.join(self.updates, '*'), self.destdir)
|
cp(os.path.join(self.opts.updates, '*'), self.destdir)
|
||||||
|
|
||||||
|
# XXX
|
||||||
|
def __installKernel(self):
|
||||||
|
arches = [self.opts.buildarch]
|
||||||
|
efiarch = []
|
||||||
|
kerneltags = ['kernel']
|
||||||
|
kernelxen = []
|
||||||
|
|
||||||
|
if self.opts.buildarch == 'ppc':
|
||||||
|
arches = ['ppc64', 'ppc']
|
||||||
|
elif self.opts.buildarch == 'i386':
|
||||||
|
arches = ['i586']
|
||||||
|
efiarch = ['ia32']
|
||||||
|
kerneltags = ['kernel', 'kernel-PAE']
|
||||||
|
kernelxen = ['kernel-PAE']
|
||||||
|
elif self.opts.buildarch == 'x86_64':
|
||||||
|
efiarch = ['x64']
|
||||||
|
elif self.opts.buildarch == 'ia64':
|
||||||
|
efiarch = ['ia64']
|
||||||
|
|
||||||
|
kpackages = self.yum.find(kerneltags)
|
||||||
|
|
||||||
|
if not kpackages:
|
||||||
|
sys.stderr.write('ERROR: Unable to find any kernel package\n')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# create the modinfo file
|
||||||
|
(fd, modinfo) = tempfile.mkstemp(prefix='modinfo-%s.' % self.opts.buildarch,
|
||||||
|
dir=self.conf.tempdir)
|
||||||
|
self.conf.addAttr('modinfo')
|
||||||
|
self.conf.set(modinfo=modinfo)
|
||||||
|
|
||||||
|
for kernel in kpackages:
|
||||||
|
fn = self.yum.download(kernel)
|
||||||
|
kernelroot = os.path.join(self.conf.kernelbase, kernel.arch)
|
||||||
|
extract_rpm(fn, kernelroot)
|
||||||
|
os.unlink(fn)
|
||||||
|
|
||||||
|
# get vmlinuz and version
|
||||||
|
dir = os.path.join(kernelroot, 'boot')
|
||||||
|
if self.opts.buildarch == 'ia64':
|
||||||
|
dir = os.path.join(dir, 'efi', 'EFI', 'redhat')
|
||||||
|
|
||||||
|
vmlinuz = None
|
||||||
|
for file in os.listdir(dir):
|
||||||
|
if file.startswith('vmlinuz'):
|
||||||
|
vmlinuz = file
|
||||||
|
prefix, sep, version = file.partition('-')
|
||||||
|
|
||||||
|
if not vmlinuz:
|
||||||
|
sys.stderr.write('ERROR: vmlinuz file not found\n')
|
||||||
|
return False
|
||||||
|
|
||||||
|
modules_dir = os.path.join(kernelroot, 'lib', 'modules', version)
|
||||||
|
if not os.path.isdir(modules_dir):
|
||||||
|
sys.stderr.write('ERROR: modules directory not found\n')
|
||||||
|
return False
|
||||||
|
|
||||||
|
allmods = []
|
||||||
|
for file in os.listdir(modules_dir):
|
||||||
|
if file.endswith('.ko'):
|
||||||
|
allmods.append(os.path.join(modules_dir, file))
|
||||||
|
|
||||||
|
# install firmware
|
||||||
|
fpackages = self.yum.find('*firmware*')
|
||||||
|
for firmware in fpackages:
|
||||||
|
fn = self.yum.download(firmware)
|
||||||
|
extract_rpm(fn, kernelroot)
|
||||||
|
os.unlink(fn)
|
||||||
|
|
||||||
|
utils.genmodinfo(modules_dir, self.conf.modinfo)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def __scrubInstRoot(self):
|
def __scrubInstRoot(self):
|
||||||
self.__createConfigFiles()
|
self.__createConfigFiles()
|
||||||
@ -155,35 +214,34 @@ class InstRoot:
|
|||||||
self.__configureKmod()
|
self.__configureKmod()
|
||||||
self.__moveAnacondaFiles()
|
self.__moveAnacondaFiles()
|
||||||
self.__setShellLinks()
|
self.__setShellLinks()
|
||||||
self.__moveBins()
|
#self.__moveBins()
|
||||||
self.__removeUnwanted()
|
self.__removeUnwanted()
|
||||||
self.__changeDestDirPermissions()
|
self.__changeDestDirPermissions()
|
||||||
self.__createLDConfig()
|
self.__createLDConfig()
|
||||||
self.__setBusyboxLinks()
|
self.__setBusyboxLinks()
|
||||||
self.__strip()
|
self.__strip()
|
||||||
self.__fixBrokenLinks()
|
#self.__fixBrokenLinks()
|
||||||
|
|
||||||
def __createConfigFiles(self):
|
def __createConfigFiles(self):
|
||||||
# create %gconf.xml
|
# create %gconf.xml
|
||||||
dogtailconf = os.path.join(self.conf['datadir'], 'dogtail-%gconf.xml')
|
dogtailconf = os.path.join(self.conf.datadir, 'dogtail-%gconf.xml')
|
||||||
if os.path.isfile(dogtailconf):
|
if os.path.isfile(dogtailconf):
|
||||||
os.makedirs(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface'))
|
os.makedirs(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface'))
|
||||||
f = open(os.path.join(self.destdir, '.gconf', 'desktop', '%gconf.xml'), 'w')
|
touch(os.path.join(self.destdir, '.gconf', 'desktop', '%gconf.xml'))
|
||||||
f.close()
|
touch(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', '%gconf.xml'))
|
||||||
f = open(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', '%gconf.xml'), 'w')
|
|
||||||
f.close()
|
|
||||||
dst = os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml')
|
dst = os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml')
|
||||||
cp(dogtailconf, dst)
|
cp(dogtailconf, dst)
|
||||||
|
|
||||||
# create selinux config
|
# create selinux config
|
||||||
if os.path.isfile(os.path.join(self.destdir, 'etc', 'selinux', 'targeted')):
|
if os.path.isfile(os.path.join(self.destdir, 'etc', 'selinux', 'targeted')):
|
||||||
selinuxconf = os.path.join(self.conf['datadir'], 'selinux-config')
|
selinuxconf = os.path.join(self.conf.datadir, 'selinux-config')
|
||||||
if os.path.isfile(selinuxconf):
|
if os.path.isfile(selinuxconf):
|
||||||
dst = os.path.join(self.destdir, 'etc', 'selinux', 'config')
|
dst = os.path.join(self.destdir, 'etc', 'selinux', 'config')
|
||||||
cp(selinuxconf, dst)
|
cp(selinuxconf, dst)
|
||||||
|
|
||||||
# create libuser.conf
|
# create libuser.conf
|
||||||
libuserconf = os.path.join(self.conf['datadir'], 'libuser.conf')
|
libuserconf = os.path.join(self.conf.datadir, 'libuser.conf')
|
||||||
if os.path.isfile(libuserconf):
|
if os.path.isfile(libuserconf):
|
||||||
dst = os.path.join(self.destdir, 'etc', 'libuser.conf')
|
dst = os.path.join(self.destdir, 'etc', 'libuser.conf')
|
||||||
cp(libuserconf, dst)
|
cp(libuserconf, dst)
|
||||||
@ -265,7 +323,7 @@ class InstRoot:
|
|||||||
shutil.rmtree(icon, ignore_errors=True)
|
shutil.rmtree(icon, ignore_errors=True)
|
||||||
|
|
||||||
# remove engines we don't need
|
# remove engines we don't need
|
||||||
tmp_path = os.path.join(self.destdir, 'usr', self.libdir, 'gtk-2.0')
|
tmp_path = os.path.join(self.destdir, 'usr', self.opts.libdir, 'gtk-2.0')
|
||||||
if os.path.isdir(tmp_path):
|
if os.path.isdir(tmp_path):
|
||||||
fnames = map(lambda fname: os.path.join(tmp_path, fname, 'engines'), os.listdir(tmp_path))
|
fnames = map(lambda fname: os.path.join(tmp_path, fname, 'engines'), os.listdir(tmp_path))
|
||||||
dnames = filter(lambda fname: os.path.isdir(fname), fnames)
|
dnames = filter(lambda fname: os.path.isdir(fname), fnames)
|
||||||
@ -358,27 +416,27 @@ class InstRoot:
|
|||||||
if not os.path.isdir(bootpath):
|
if not os.path.isdir(bootpath):
|
||||||
os.makedirs(bootpath)
|
os.makedirs(bootpath)
|
||||||
|
|
||||||
if self.arch == 'i386' or self.arch == 'x86_64':
|
if self.opts.buildarch == 'i386' or self.opts.buildarch == 'x86_64':
|
||||||
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
|
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
|
||||||
if bootfile.startswith('memtest'):
|
if bootfile.startswith('memtest'):
|
||||||
src = os.path.join(self.destdir, 'boot', bootfile)
|
src = os.path.join(self.destdir, 'boot', bootfile)
|
||||||
dst = os.path.join(bootpath, bootfile)
|
dst = os.path.join(bootpath, bootfile)
|
||||||
cp(src, dst)
|
cp(src, dst)
|
||||||
elif self.arch.startswith('sparc'):
|
elif self.opts.buildarch.startswith('sparc'):
|
||||||
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
|
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
|
||||||
if bootfile.endswith('.b'):
|
if bootfile.endswith('.b'):
|
||||||
src = os.path.join(self.destdir, 'boot', bootfile)
|
src = os.path.join(self.destdir, 'boot', bootfile)
|
||||||
dst = os.path.join(bootpath, bootfile)
|
dst = os.path.join(bootpath, bootfile)
|
||||||
cp(src, dst)
|
cp(src, dst)
|
||||||
elif self.arch.startswith('ppc'):
|
elif self.opts.buildarch.startswith('ppc'):
|
||||||
src = os.path.join(self.destdir, 'boot', 'efika.forth')
|
src = os.path.join(self.destdir, 'boot', 'efika.forth')
|
||||||
dst = os.path.join(bootpath, 'efika.forth')
|
dst = os.path.join(bootpath, 'efika.forth')
|
||||||
cp(src, dst)
|
cp(src, dst)
|
||||||
elif self.arch == 'alpha':
|
elif self.opts.buildarch == 'alpha':
|
||||||
src = os.path.join(self.destdir, 'boot', 'bootlx')
|
src = os.path.join(self.destdir, 'boot', 'bootlx')
|
||||||
dst = os.path.join(bootpath, 'bootlx')
|
dst = os.path.join(bootpath, 'bootlx')
|
||||||
cp(src, dst)
|
cp(src, dst)
|
||||||
elif self.arch == 'ia64':
|
elif self.opts.buildarch == 'ia64':
|
||||||
src = os.path.join(self.destdir, 'boot', 'efi', 'EFI', 'redhat')
|
src = os.path.join(self.destdir, 'boot', 'efi', 'EFI', 'redhat')
|
||||||
shutil.rmtree(bootpath, ignore_errors=True)
|
shutil.rmtree(bootpath, ignore_errors=True)
|
||||||
cp(src, bootpath)
|
cp(src, bootpath)
|
||||||
@ -435,6 +493,7 @@ class InstRoot:
|
|||||||
os.symlink(busybox, sh)
|
os.symlink(busybox, sh)
|
||||||
|
|
||||||
def __moveBins(self):
|
def __moveBins(self):
|
||||||
|
# XXX why do we want to move everything to /usr when in mk-images we copy it back?
|
||||||
bin = os.path.join(self.destdir, 'bin')
|
bin = os.path.join(self.destdir, 'bin')
|
||||||
sbin = os.path.join(self.destdir, 'sbin')
|
sbin = os.path.join(self.destdir, 'sbin')
|
||||||
|
|
||||||
@ -518,49 +577,47 @@ class InstRoot:
|
|||||||
|
|
||||||
def __createLDConfig(self):
|
def __createLDConfig(self):
|
||||||
ldsoconf = os.path.join(self.destdir, 'etc', 'ld.so.conf')
|
ldsoconf = os.path.join(self.destdir, 'etc', 'ld.so.conf')
|
||||||
f = open(ldsoconf, 'w')
|
touch(ldsoconf)
|
||||||
f.close()
|
|
||||||
|
|
||||||
proc_dir = os.path.join(self.destdir, 'proc')
|
proc_dir = os.path.join(self.destdir, 'proc')
|
||||||
if not os.path.isdir(proc_dir):
|
if not os.path.isdir(proc_dir):
|
||||||
os.makedirs(proc_dir)
|
os.makedirs(proc_dir)
|
||||||
|
|
||||||
# XXX isn't there a better way?
|
os.system('mount -t proc proc %s' % proc_dir)
|
||||||
os.system('mount -t proc proc %s' % (proc_dir,))
|
|
||||||
|
|
||||||
f = open(ldsoconf, 'w')
|
f = open(ldsoconf, 'w')
|
||||||
x11_libdir = os.path.join(self.destdir, 'usr', 'X11R6', self.libdir)
|
|
||||||
|
x11_libdir = os.path.join(self.destdir, 'usr', 'X11R6', self.opts.libdir)
|
||||||
if os.path.exists(x11_libdir):
|
if os.path.exists(x11_libdir):
|
||||||
f.write('/usr/X11R6/%s\n' % (self.libdir,))
|
f.write('/usr/X11R6/%s\n' % self.opts.libdir)
|
||||||
f.write('/usr/kerberos/%s\n' % (self.libdir,))
|
|
||||||
|
f.write('/usr/kerberos/%s\n' % self.opts.libdir)
|
||||||
|
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
os.chdir(self.destdir)
|
os.chdir(self.destdir)
|
||||||
# XXX can't exit from os.chroot() :(
|
os.system('/usr/sbin/chroot %s /sbin/ldconfig' % self.destdir)
|
||||||
os.system('/usr/sbin/chroot %s /usr/sbin/ldconfig' % (self.destdir,))
|
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
if self.arch not in ('s390', 's390x'):
|
if self.opts.buildarch not in ('s390', 's390x'):
|
||||||
os.unlink(os.path.join(self.destdir, 'usr', 'sbin', 'ldconfig'))
|
os.unlink(os.path.join(self.destdir, 'sbin', 'ldconfig'))
|
||||||
|
|
||||||
os.unlink(os.path.join(self.destdir, 'etc', 'ld.so.conf'))
|
os.unlink(os.path.join(self.destdir, 'etc', 'ld.so.conf'))
|
||||||
|
|
||||||
# XXX isn't there a better way?
|
os.system('umount %s' % proc_dir)
|
||||||
os.system('umount %s' % (proc_dir,))
|
|
||||||
|
|
||||||
def __setBusyboxLinks(self):
|
def __setBusyboxLinks(self):
|
||||||
src = os.path.join(self.destdir, 'usr', 'sbin', 'busybox.anaconda')
|
src = os.path.join(self.destdir, 'sbin', 'busybox.anaconda')
|
||||||
dst = os.path.join(self.destdir, 'usr', 'bin', 'busybox')
|
dst = os.path.join(self.destdir, 'bin', 'busybox')
|
||||||
mv(src, dst)
|
mv(src, dst)
|
||||||
|
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
os.chdir(os.path.join(self.destdir, 'usr', 'bin'))
|
os.chdir(os.path.join(self.destdir, 'bin'))
|
||||||
|
|
||||||
busybox_process = subprocess.Popen(['./busybox'], stdout=subprocess.PIPE)
|
busybox_process = subprocess.Popen(['./busybox'], stdout=subprocess.PIPE)
|
||||||
busybox_process.wait()
|
busybox_process.wait()
|
||||||
|
|
||||||
if busybox_process.returncode:
|
if busybox_process.returncode:
|
||||||
raise LoraxError, 'cannot run busybox'
|
raise Error, 'busybox error'
|
||||||
|
|
||||||
busybox_output = busybox_process.stdout.readlines()
|
busybox_output = busybox_process.stdout.readlines()
|
||||||
busybox_output = map(lambda line: line.strip(), busybox_output)
|
busybox_output = map(lambda line: line.strip(), busybox_output)
|
||||||
@ -641,3 +698,10 @@ class InstRoot:
|
|||||||
newtarget = re.sub(r'^\.\./\.\./%s/\(.*\)' % dir, r'\.\./%s/\1' % dir, target)
|
newtarget = re.sub(r'^\.\./\.\./%s/\(.*\)' % dir, r'\.\./%s/\1' % dir, target)
|
||||||
if newtarget != target:
|
if newtarget != target:
|
||||||
os.symlink(newtarget, link)
|
os.symlink(newtarget, link)
|
||||||
|
|
||||||
|
def __makeAdditionalDirs(self):
|
||||||
|
os.makedirs(os.path.join(self.destdir, 'modules'))
|
||||||
|
os.makedirs(os.path.join(self.destdir, 'tmp'))
|
||||||
|
for dir in ('a', 'b', 'd', 'l', 's', 'v', 'x'):
|
||||||
|
os.makedirs(os.path.join(self.destdir, 'etc', 'terminfo', dir))
|
||||||
|
os.makedirs(os.path.join(self.destdir, 'var', 'lock', 'rpm'))
|
@ -9,11 +9,7 @@ logging.basicConfig(level=logging.DEBUG)
|
|||||||
logger = logging.getLogger('pylorax')
|
logger = logging.getLogger('pylorax')
|
||||||
|
|
||||||
|
|
||||||
def genmodinfo(path=None):
|
def genmodinfo(path, output):
|
||||||
if not path:
|
|
||||||
release = os.uname()[2]
|
|
||||||
path = os.path.join('/lib/modules', release)
|
|
||||||
|
|
||||||
mods = {}
|
mods = {}
|
||||||
for root, dirs, files in os.walk(path):
|
for root, dirs, files in os.walk(path):
|
||||||
for file in files:
|
for file in files:
|
||||||
@ -56,13 +52,14 @@ def genmodinfo(path=None):
|
|||||||
modinfo = '%s\n\t%s\n\t"%s"\n' % (modname, modtype, desc)
|
modinfo = '%s\n\t%s\n\t"%s"\n' % (modname, modtype, desc)
|
||||||
list[modtype][modname] = modinfo
|
list[modtype][modname] = modinfo
|
||||||
|
|
||||||
# XXX i don't think we want to print it out now
|
f = open(output, 'a')
|
||||||
print 'Version 0'
|
f.write('Version 0\n')
|
||||||
for type in list:
|
for type in list:
|
||||||
modlist = list[type].keys()
|
modlist = list[type].keys()
|
||||||
modlist.sort()
|
modlist.sort()
|
||||||
for m in modlist:
|
for m in modlist:
|
||||||
print list[type][m]
|
f.write('%s\n' %list[type][m])
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
# XXX is the input a path to a file?
|
# XXX is the input a path to a file?
|
28
src/pylorax/actions/__init__.py
Normal file
28
src/pylorax/actions/__init__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# pylorax/actions/__init__.py
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def getActions():
|
||||||
|
actions = {}
|
||||||
|
root, actions_dir = os.path.split(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
modules = set()
|
||||||
|
for filename in os.listdir(os.path.join(root, actions_dir)):
|
||||||
|
if filename.endswith('.py') and filename != '__init__.py':
|
||||||
|
basename, extension = os.path.splitext(filename)
|
||||||
|
modules.add(os.path.join('pylorax', actions_dir, basename).replace('/', '.'))
|
||||||
|
|
||||||
|
for module in modules:
|
||||||
|
print('Loading actions from %s' % module)
|
||||||
|
imported = __import__(module, globals(), locals(), [module], -1)
|
||||||
|
try:
|
||||||
|
commands = getattr(imported, 'COMMANDS')
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
for command, classname in commands.items():
|
||||||
|
print('Loaded: %s' % classname)
|
||||||
|
actions[command] = getattr(imported, classname)
|
||||||
|
|
||||||
|
return actions
|
179
src/pylorax/actions/fileactions.py
Normal file
179
src/pylorax/actions/fileactions.py
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
# pylorax/actions/fileactions.py
|
||||||
|
|
||||||
|
from pylorax.base import LoraxAction
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from pylorax.utils.fileutil import cp, mv, touch, edit, replace
|
||||||
|
|
||||||
|
|
||||||
|
COMMANDS = { 'copy': 'Copy',
|
||||||
|
'move': 'Move',
|
||||||
|
'link': 'Link',
|
||||||
|
'touch': 'Touch',
|
||||||
|
'edit': 'Edit',
|
||||||
|
'replace': 'Replace' }
|
||||||
|
|
||||||
|
|
||||||
|
def getFileName(string):
|
||||||
|
m = re.match(r'@instroot@(?P<file>.*)', string)
|
||||||
|
if m:
|
||||||
|
return m.group('file')
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Copy(LoraxAction):
|
||||||
|
|
||||||
|
REGEX = r'^(?P<src>.*?)\sto\s(?P<dst>.*?)(\smode\s(?P<mode>.*?))?$'
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
LoraxAction.__init__(self)
|
||||||
|
self._attrs['src'] = kwargs.get('src')
|
||||||
|
self._attrs['dst'] = kwargs.get('dst')
|
||||||
|
self._attrs['mode'] = kwargs.get('mode')
|
||||||
|
|
||||||
|
file = getFileName(self._attrs['src'])
|
||||||
|
if file:
|
||||||
|
self._attrs['install'] = file
|
||||||
|
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
cp(src=self.src, dst=self.dst, mode=self.mode, verbose=verbose)
|
||||||
|
self._attrs['success'] = True
|
||||||
|
|
||||||
|
def getDeps(self):
|
||||||
|
return self._attrs['src']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def src(self):
|
||||||
|
return self._attrs['src']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dst(self):
|
||||||
|
return self._attrs['dst']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mode(self):
|
||||||
|
return self._attrs['mode']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def install(self):
|
||||||
|
return self._attrs.get('install')
|
||||||
|
|
||||||
|
|
||||||
|
class Move(Copy):
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
mv(src=self.src, dst=self.dst, mode=self.mode, verbose=verbose)
|
||||||
|
self._attrs['success'] = True
|
||||||
|
|
||||||
|
|
||||||
|
class Link(LoraxAction):
|
||||||
|
|
||||||
|
REGEX = r'^(?P<name>.*?)\sto\s(?P<target>.*?)$'
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
LoraxAction.__init__(self)
|
||||||
|
self._attrs['name'] = kwargs.get('name')
|
||||||
|
self._attrs['target'] = kwargs.get('target')
|
||||||
|
|
||||||
|
file = getFileName(self._attrs['name'])
|
||||||
|
if file:
|
||||||
|
self._attrs['install'] = file
|
||||||
|
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
os.symlink(self.name, self.target)
|
||||||
|
self._attrs['success'] = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._attrs['name']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target(self):
|
||||||
|
return self._attrs['target']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def install(self):
|
||||||
|
return self._attrs['install']
|
||||||
|
|
||||||
|
|
||||||
|
class Touch(LoraxAction):
|
||||||
|
|
||||||
|
REGEX = r'^(?P<filename>.*?)$'
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
LoraxAction.__init__(self)
|
||||||
|
self._attrs['filename'] = kwargs.get('filename')
|
||||||
|
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
touch(filename=self.filename, verbose=verbose)
|
||||||
|
self._attrs['success'] = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filename(self):
|
||||||
|
return self._attrs['filename']
|
||||||
|
|
||||||
|
|
||||||
|
class Edit(Touch):
|
||||||
|
|
||||||
|
REGEX = r'^(?P<filename>.*?)\stext\s"(?P<text>.*?)"((?P<append>\sappend?))?$'
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
Touch.__init__(self, **kwargs)
|
||||||
|
self._attrs['text'] = kwargs.get('text')
|
||||||
|
|
||||||
|
append = kwargs.get('append', False)
|
||||||
|
if append:
|
||||||
|
self._attrs['append'] = True
|
||||||
|
else:
|
||||||
|
self._attrs['append'] = False
|
||||||
|
|
||||||
|
file = getFileName(self._attrs['filename'])
|
||||||
|
if file:
|
||||||
|
self._attrs['install'] = file
|
||||||
|
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
edit(filename=self.filename, text=self.text, append=self.append, verbose=verbose)
|
||||||
|
self._attrs['success'] = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return self._attrs['text']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def append(self):
|
||||||
|
return self._attrs['append']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def install(self):
|
||||||
|
return self._attrs['install']
|
||||||
|
|
||||||
|
|
||||||
|
class Replace(Touch):
|
||||||
|
|
||||||
|
REGEX = r'^(?P<filename>.*?)\sfind\s"(?P<find>.*?)"\sreplace\s"(?P<replace>.*?)"$'
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
Touch.__init__(self, **kwargs)
|
||||||
|
self._attrs['find'] = kwargs.get('find')
|
||||||
|
self._attrs['replace'] = kwargs.get('replace')
|
||||||
|
|
||||||
|
file = getFileName(self._attrs['filename'])
|
||||||
|
if file:
|
||||||
|
self._attrs['install'] = file
|
||||||
|
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
replace(filename=self.filename, find=self.find, replace=self.replace, verbose=verbose)
|
||||||
|
self._attrs['success'] = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def find(self):
|
||||||
|
return self._attrs['find']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def replace(self):
|
||||||
|
return self._attrs['replace']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def install(self):
|
||||||
|
return self._attrs['install']
|
43
src/pylorax/base.py
Normal file
43
src/pylorax/base.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# pylorax/base.py
|
||||||
|
|
||||||
|
import commands
|
||||||
|
|
||||||
|
|
||||||
|
class LoraxAction(object):
|
||||||
|
|
||||||
|
REGEX = r'.*'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
if self.__class__ is LoraxAction:
|
||||||
|
raise TypeError, 'LoraxAction is an abstract class'
|
||||||
|
|
||||||
|
self._attrs = {}
|
||||||
|
self._attrs['success'] = None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s: %s' % (self.__class__.__name__, self._attrs)
|
||||||
|
|
||||||
|
def execute(self, verbose=False):
|
||||||
|
raise NotImplementedError, 'execute method not implemented for LoraxAction class'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def success(self):
|
||||||
|
return self._attrs['success']
|
||||||
|
|
||||||
|
|
||||||
|
def seq(arg):
|
||||||
|
if type(arg) not in (type([]), type(())):
|
||||||
|
return [arg]
|
||||||
|
else:
|
||||||
|
return arg
|
||||||
|
|
||||||
|
|
||||||
|
def getConsoleSize():
|
||||||
|
err, output = commands.getstatusoutput('stty size')
|
||||||
|
if not err:
|
||||||
|
height, width = output.split()
|
||||||
|
else:
|
||||||
|
# set defaults
|
||||||
|
height, width = 24, 80
|
||||||
|
|
||||||
|
return int(height), int(width)
|
125
src/pylorax/config.py
Normal file
125
src/pylorax/config.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# pylorax/config.py
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from base import seq
|
||||||
|
import re
|
||||||
|
|
||||||
|
from exceptions import TemplateError
|
||||||
|
|
||||||
|
|
||||||
|
class Container(object):
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
self.__dict__['__internal'] = {}
|
||||||
|
self.__dict__['__internal']['attrs'] = set()
|
||||||
|
|
||||||
|
if attrs:
|
||||||
|
self.addAttr(attrs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.__makeDict())
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.__makeDict())
|
||||||
|
|
||||||
|
def __getitem__(self, attr):
|
||||||
|
self.__checkInternal(attr)
|
||||||
|
if attr not in self.__dict__:
|
||||||
|
raise AttributeError, "'Container' object has no attribute '%s'" % attr
|
||||||
|
|
||||||
|
return self.__dict__[attr]
|
||||||
|
|
||||||
|
def __setattr__(self, attr, value):
|
||||||
|
raise AttributeError, 'you cannot do that, use addAttr() and set() instead'
|
||||||
|
|
||||||
|
def __delattr__(self, attr):
|
||||||
|
raise AttributeError, 'you cannot do that, use delAttr() instead'
|
||||||
|
|
||||||
|
def addAttr(self, attrs):
|
||||||
|
for attr in filter(lambda attr: attr not in self.__dict__, seq(attrs)):
|
||||||
|
self.__checkInternal(attr)
|
||||||
|
|
||||||
|
self.__dict__[attr] = None
|
||||||
|
self.__dict__['__internal']['attrs'].add(attr)
|
||||||
|
|
||||||
|
def delAttr(self, attrs):
|
||||||
|
for attr in filter(lambda attr: attr in self.__dict__, seq(attrs)):
|
||||||
|
self.__checkInternal(attr)
|
||||||
|
|
||||||
|
del self.__dict__[attr]
|
||||||
|
self.__dict__['__internal']['attrs'].discard(attr)
|
||||||
|
|
||||||
|
def set(self, **kwargs):
|
||||||
|
unknown = set()
|
||||||
|
for attr, value in kwargs.items():
|
||||||
|
self.__checkInternal(attr)
|
||||||
|
|
||||||
|
if attr in self.__dict__:
|
||||||
|
self.__dict__[attr] = value
|
||||||
|
else:
|
||||||
|
unknown.add(attr)
|
||||||
|
|
||||||
|
return unknown
|
||||||
|
|
||||||
|
def __makeDict(self):
|
||||||
|
d = {}
|
||||||
|
for attr in self.__dict__['__internal']['attrs']:
|
||||||
|
d[attr] = self.__dict__[attr]
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
def __checkInternal(self, attr):
|
||||||
|
if attr.startswith('__'):
|
||||||
|
raise AttributeError, 'do not mess with internal stuff'
|
||||||
|
|
||||||
|
|
||||||
|
class Template(object):
|
||||||
|
def __init__(self):
|
||||||
|
self._actions = []
|
||||||
|
|
||||||
|
def parse(self, filename, supported_actions):
|
||||||
|
try:
|
||||||
|
f = open(filename, 'r')
|
||||||
|
except IOError:
|
||||||
|
sys.stdout.write('ERROR: Unable to open the template file\n')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
lines = f.readlines()
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
active_action = ''
|
||||||
|
in_action = False
|
||||||
|
for lineno, line in enumerate(lines, start=1):
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if not line or line.startswith('#'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if in_action and not line.startswith(':'):
|
||||||
|
# create the action object
|
||||||
|
regex = supported_actions[active_action].REGEX
|
||||||
|
m = re.match(regex, line)
|
||||||
|
if m:
|
||||||
|
new_action = supported_actions[active_action](**m.groupdict())
|
||||||
|
self._actions.append(new_action)
|
||||||
|
else:
|
||||||
|
# didn't match the regex
|
||||||
|
raise TemplateError, 'invalid action format "%s" on line %d' % (line, lineno)
|
||||||
|
|
||||||
|
if in_action and line.startswith(':'):
|
||||||
|
in_action = False
|
||||||
|
|
||||||
|
if not in_action and line.startswith(':'):
|
||||||
|
active_action = line[1:]
|
||||||
|
|
||||||
|
if active_action not in supported_actions:
|
||||||
|
raise TemplateError, 'unknown action "%s" on line %d' % (active_action, lineno)
|
||||||
|
else:
|
||||||
|
in_action = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def actions(self):
|
||||||
|
return self._actions
|
7
src/pylorax/exceptions.py
Normal file
7
src/pylorax/exceptions.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# pylorax/exceptions.py
|
||||||
|
|
||||||
|
class LoraxError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TemplateError(Exception):
|
||||||
|
pass
|
@ -1,50 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
import glob
|
|
||||||
|
|
||||||
|
|
||||||
def cp(src, dst, verbose=False):
|
|
||||||
for name in glob.iglob(src):
|
|
||||||
__copy(name, dst, verbose=verbose)
|
|
||||||
|
|
||||||
def mv(src, dst, verbose=False):
|
|
||||||
for name in glob.iglob(src):
|
|
||||||
__copy(name, dst, verbose=verbose, remove=True)
|
|
||||||
|
|
||||||
|
|
||||||
def __copy(src, dst, verbose=False, remove=False):
|
|
||||||
if not os.path.exists(src):
|
|
||||||
print('cannot stat "%s": No such file or directory' % (src,))
|
|
||||||
return
|
|
||||||
|
|
||||||
if os.path.isdir(dst):
|
|
||||||
basename = os.path.basename(src)
|
|
||||||
dst = os.path.join(dst, basename)
|
|
||||||
|
|
||||||
if os.path.isdir(src):
|
|
||||||
if os.path.isfile(dst):
|
|
||||||
print('omitting directory "%s"' % (src,))
|
|
||||||
return
|
|
||||||
|
|
||||||
if not os.path.isdir(dst):
|
|
||||||
os.makedirs(dst)
|
|
||||||
|
|
||||||
names = map(lambda name: os.path.join(src, name), os.listdir(src))
|
|
||||||
for name in names:
|
|
||||||
__copy(name, dst, verbose=verbose, remove=remove)
|
|
||||||
else:
|
|
||||||
if os.path.isdir(dst):
|
|
||||||
print('cannot overwrite directory "%s" with non-directory' % (dst,))
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
if verbose:
|
|
||||||
print('copying "%s" to "%s"' % (src, dst))
|
|
||||||
shutil.copy2(src, dst)
|
|
||||||
except shutil.Error, IOError:
|
|
||||||
print('cannot copy "%s" to "%s"' % (src, dst))
|
|
||||||
else:
|
|
||||||
if remove:
|
|
||||||
if verbose:
|
|
||||||
print('removing "%s"' % (src,))
|
|
||||||
os.unlink(src)
|
|
@ -1,102 +1,140 @@
|
|||||||
#
|
# pylorax/images.py
|
||||||
# pylorax images module
|
|
||||||
# Install image and tree support data generation tool -- Python module
|
|
||||||
#
|
|
||||||
|
|
||||||
import datetime
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
from utils.fileutil import cp, mv, rm, touch, replace
|
||||||
|
|
||||||
|
import initrd
|
||||||
|
|
||||||
|
|
||||||
class Images():
|
class Images(object):
|
||||||
|
def __init__(self, config, yum):
|
||||||
|
self.conf = config
|
||||||
|
self.yum = yum
|
||||||
|
|
||||||
def __init__(self, conf, yumconf, arch, imgdir, product, version, bugurl, output, noiso=False):
|
# XXX don't see this used anywhere... maybe in some other script, have to check...
|
||||||
self.conf = conf
|
#syslinux = os.path.join(self.conf.treedir, 'usr', 'lib', 'syslinux', 'syslinux-nomtools')
|
||||||
self.yumconf = yumconf
|
#if not os.path.isfile(syslinux):
|
||||||
|
# print('WARNING: %s does not exist' % syslinux)
|
||||||
|
# syslinux = os.path.join(self.conf.treedir, 'usr', 'bin', 'syslinux')
|
||||||
|
# if not os.path.isfile(syslinux):
|
||||||
|
# print('ERROR: %s does not exist' % syslinux)
|
||||||
|
# sys.exit(1)
|
||||||
|
|
||||||
self.arch = arch
|
def run(self):
|
||||||
self.imgdir = imgdir
|
self.prepareBootTree()
|
||||||
self.product = product
|
|
||||||
self.version = version
|
|
||||||
self.bugurl = bugurl
|
|
||||||
|
|
||||||
self.output = output
|
def __makeinitrd(self, dst, size=8192, loader='loader'):
|
||||||
self.noiso = noiso
|
i = initrd.InitRD(self.conf, self.yum)
|
||||||
|
i.prepare()
|
||||||
|
i.processActions()
|
||||||
|
i.create(dst)
|
||||||
|
i.cleanUp()
|
||||||
|
|
||||||
now = datetime.datetime.now()
|
def prepareBootTree(self):
|
||||||
self.imageuuid = now.strftime('%Y%m%d%H%M') + '.' + os.uname()[4]
|
# install needed packages
|
||||||
|
self.yum.addPackages(['anaconda', 'anaconda-runtime', 'kernel', 'syslinux', 'memtest'])
|
||||||
|
self.yum.install()
|
||||||
|
|
||||||
self.initrdmods = self.__getModulesList()
|
# create the destination directories
|
||||||
|
self.imgdir = os.path.join(self.conf.outdir, 'images')
|
||||||
if self.arch == 'sparc64':
|
if os.path.exists(self.imgdir):
|
||||||
self.basearch = 'sparc'
|
rm(self.imgdir)
|
||||||
else:
|
self.pxedir = os.path.join(self.imgdir, 'pxeboot')
|
||||||
self.basearch = self.arch
|
os.makedirs(self.imgdir)
|
||||||
|
os.makedirs(self.pxedir)
|
||||||
self.libdir = 'lib'
|
|
||||||
if self.arch == 'x86_64' or self.arch =='s390x':
|
|
||||||
self.libdir = 'lib64'
|
|
||||||
|
|
||||||
# explicit block size setting for some arches
|
|
||||||
# FIXME we compose ppc64-ish trees as ppc, so we have to set the "wrong" block size
|
|
||||||
# XXX i don't get this :)
|
|
||||||
self.crambs = []
|
|
||||||
if self.arch == 'sparc64':
|
|
||||||
self.crambs = ['--blocksize', '8192']
|
|
||||||
elif self.arch == 'sparc':
|
|
||||||
self.crambs = ['--blocksize', '4096']
|
|
||||||
|
|
||||||
self.__setUpDirectories()
|
|
||||||
|
|
||||||
def __getModulesList(self):
|
|
||||||
modules = set()
|
|
||||||
|
|
||||||
modules_files = []
|
|
||||||
modules_files.append(os.path.join(self.conf['confdir'], 'modules'))
|
|
||||||
modules_files.append(os.path.join(self.conf['confdir'], self.arch, 'modules'))
|
|
||||||
|
|
||||||
for pfile in modules_files:
|
|
||||||
if os.path.isfile(pfile):
|
|
||||||
f = open(pfile, 'r')
|
|
||||||
for line in f.readlines():
|
|
||||||
line = line.strip()
|
|
||||||
|
|
||||||
if not line or line.startswith('#'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if line.startswith('-'):
|
|
||||||
modules.discard(line[1:])
|
|
||||||
else:
|
|
||||||
modules.add(line)
|
|
||||||
|
|
||||||
|
# write the images/README
|
||||||
|
f = open(os.path.join(self.imgdir, 'README'), 'w')
|
||||||
|
f.write('This directory contains image files that can be used to create media\n'
|
||||||
|
'capable of starting the %s installation process.\n\n' % self.conf.product)
|
||||||
|
f.write('The boot.iso file is an ISO 9660 image of a bootable CD-ROM. It is useful\n'
|
||||||
|
'in cases where the CD-ROM installation method is not desired, but the\n'
|
||||||
|
'CD-ROM\'s boot speed would be an advantage.\n\n')
|
||||||
|
f.write('To use this image file, burn the file onto CD-R (or CD-RW) media as you\n'
|
||||||
|
'normally would.\n')
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
modules = list(modules)
|
# write the images/pxeboot/README
|
||||||
modules.sort()
|
f = open(os.path.join(self.pxedir, 'README'), 'w')
|
||||||
|
f.write('The files in this directory are useful for booting a machine via PXE.\n\n')
|
||||||
|
f.write('The following files are available:\n')
|
||||||
|
f.write('vmlinuz - the kernel used for the installer\n')
|
||||||
|
f.write('initrd.img - an initrd with support for all install methods and\n')
|
||||||
|
f.write(' drivers supported for installation of %s\n' % self.conf.product)
|
||||||
|
f.close()
|
||||||
|
|
||||||
return modules
|
# set up some dir variables for further use
|
||||||
|
anacondadir = os.path.join(self.conf.treedir, 'usr', 'lib', 'anaconda-runtime')
|
||||||
|
bootdiskdir = os.path.join(anacondadir, 'boot')
|
||||||
|
syslinuxdir = os.path.join(self.conf.treedir, 'usr', 'lib', 'syslinux')
|
||||||
|
|
||||||
def __setUpDirectories(self):
|
isolinuxbin = os.path.join(syslinuxdir, 'isolinux.bin')
|
||||||
imagepath = os.path.join(self.output, 'images')
|
if os.path.isfile(isolinuxbin):
|
||||||
fullmodpath = tempfile.mkdtemp('XXXXXX', 'instimagemods.', self.conf['tmpdir'])
|
print('Creating the isolinux directory...')
|
||||||
finalfullmodpath = os.path.join(self.output, 'modules')
|
self.isodir = os.path.join(self.conf.outdir, 'isolinux')
|
||||||
|
if os.path.exists(self.isodir):
|
||||||
|
rm(self.isodir)
|
||||||
|
os.makedirs(self.isodir)
|
||||||
|
|
||||||
kernelbase = tempfile.mkdtemp('XXXXXX', 'updboot.kernel.', self.conf['tmpdir'])
|
# copy the isolinux.bin to isolinux dir
|
||||||
kernelname = 'vmlinuz'
|
cp(isolinuxbin, self.isodir)
|
||||||
|
|
||||||
kerneldir = '/boot'
|
# copy the syslinux.cfg to isolinux/isolinux.cfg
|
||||||
if self.arch == 'ia64':
|
isolinuxcfg = os.path.join(self.isodir, 'isolinux.cfg')
|
||||||
kerneldir = os.path.join(kerneldir, 'efi', 'EFI', 'redhat')
|
cp(os.path.join(bootdiskdir, 'syslinux.cfg'), isolinuxcfg)
|
||||||
|
|
||||||
for dir in [imagepath, fullmodpath, finalfullmodpath, kernelbase]:
|
# set the product and version in isolinux.cfg
|
||||||
if os.path.isdir(dir):
|
replace(isolinuxcfg, r'@PRODUCT@', self.conf.product)
|
||||||
shutil.rmtree(dir)
|
replace(isolinuxcfg, r'@VERSION@', self.conf.version)
|
||||||
os.makedirs(dir)
|
|
||||||
|
|
||||||
self.imagepath = imagepath
|
# copy the grub.conf to isolinux dir
|
||||||
self.fullmodpath = fullmodpath
|
cp(os.path.join(bootdiskdir, 'grub.conf'), self.isodir)
|
||||||
self.finalfullmodpath = finalfullmodpath
|
|
||||||
|
|
||||||
self.kernelbase = kernelbase
|
# create the initrd in isolinux dir
|
||||||
self.kernelname = kernelname
|
initrd = os.path.join(self.isodir, 'initrd.img')
|
||||||
self.kerneldir = kerneldir
|
self.__makeinitrd(initrd)
|
||||||
|
|
||||||
|
# copy the vmlinuz to isolinux dir
|
||||||
|
vmlinuz = os.path.join(self.conf.treedir, 'boot', 'vmlinuz-*')
|
||||||
|
cp(vmlinuz, os.path.join(self.isodir, 'vmlinuz'))
|
||||||
|
|
||||||
|
# copy the splash files to isolinux dir
|
||||||
|
vesasplash = os.path.join(anacondadir, 'syslinux-vesa-splash.jpg')
|
||||||
|
if os.path.isfile(vesasplash):
|
||||||
|
cp(vesasplash, os.path.join(self.isodir, 'splash.jpg'))
|
||||||
|
vesamenu = os.path.join(syslinuxdir, 'vesamenu.c32')
|
||||||
|
cp(vesamenu, self.isodir)
|
||||||
|
replace(isolinuxcfg, r'default linux', r'default vesamenu.c32')
|
||||||
|
replace(isolinuxcfg, r'prompt 1', r'#prompt 1')
|
||||||
|
else:
|
||||||
|
splashtools = os.path.join(anacondadir, 'splashtools.sh')
|
||||||
|
splashlss = os.path.join(bootdiskdir, 'splash.lss')
|
||||||
|
if os.path.isfile(splashtools):
|
||||||
|
os.system('%s %s %s' % (splashtools,
|
||||||
|
os.path.join(bootdiskdir, 'syslinux-splash.jpg'),
|
||||||
|
splashlss))
|
||||||
|
if os.path.isfile(splashlss):
|
||||||
|
cp(splashlss, self.isodir)
|
||||||
|
|
||||||
|
# copy the .msg files to isolinux dir
|
||||||
|
for file in os.listdir(bootdiskdir):
|
||||||
|
if file.endswith('.msg'):
|
||||||
|
cp(os.path.join(bootdiskdir, file), self.isodir)
|
||||||
|
replace(os.path.join(self.isodir, file), r'@VERSION@', self.conf.version)
|
||||||
|
|
||||||
|
# if present, copy the memtest to isolinux dir
|
||||||
|
# XXX search for it in bootdiskdir or treedir/install/boot ?
|
||||||
|
#cp(os.path.join(bootdiskdir, 'memtest*'), os.path.join(self.isodir, 'memtest'))
|
||||||
|
cp(os.path.join(self.conf.treedir, 'boot', 'memtest*'),
|
||||||
|
os.path.join(self.isodir, 'memtest'))
|
||||||
|
if os.path.isfile(os.path.join(self.isodir, 'memtest')):
|
||||||
|
f = open(isolinuxcfg, 'a')
|
||||||
|
f.write('label memtest86\n')
|
||||||
|
f.write(' menu label ^Memory test\n')
|
||||||
|
f.write(' kernel memtest\n')
|
||||||
|
f.write(' append -\n')
|
||||||
|
f.close()
|
||||||
|
else:
|
||||||
|
print('No isolinux binary found, skipping isolinux creation')
|
||||||
|
74
src/pylorax/initrd.py
Normal file
74
src/pylorax/initrd.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# pylorax/initrd.py
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
import actions
|
||||||
|
from config import Template
|
||||||
|
from utils.libutil import LDD
|
||||||
|
from utils.fileutil import rm
|
||||||
|
|
||||||
|
|
||||||
|
class InitRD(object):
|
||||||
|
def __init__(self, config, yum):
|
||||||
|
self.conf = config
|
||||||
|
self.yum = yum
|
||||||
|
|
||||||
|
self.initrddir = os.path.join(self.conf.tempdir, 'initrd')
|
||||||
|
os.makedirs(self.initrddir)
|
||||||
|
|
||||||
|
# get supported actions
|
||||||
|
supported_actions = actions.getActions()
|
||||||
|
|
||||||
|
initrd_templates = []
|
||||||
|
initrd_templates.append(os.path.join(self.conf.confdir, 'templates', 'initrd'))
|
||||||
|
initrd_templates.append(os.path.join(self.conf.confdir, 'templates', self.conf.buildarch,
|
||||||
|
'initrd'))
|
||||||
|
|
||||||
|
self.template = Template()
|
||||||
|
for file in initrd_templates:
|
||||||
|
if os.path.isfile(file):
|
||||||
|
self.template.parse(file, supported_actions)
|
||||||
|
|
||||||
|
self.actions = []
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
# install needed packages
|
||||||
|
for action in filter(lambda action: hasattr(action, 'install'), self.template.actions):
|
||||||
|
self.yum.addPackages(action.install)
|
||||||
|
|
||||||
|
self.yum.install()
|
||||||
|
|
||||||
|
# get needed dependencies
|
||||||
|
ldd = LDD(libroot=os.path.join(self.conf.treedir, self.conf.libdir))
|
||||||
|
for action in filter(lambda action: hasattr(action, 'getDeps'), self.template.actions):
|
||||||
|
file = re.sub(r'@instroot@(?P<file>.*)', '%s\g<file>' % self.conf.treedir,
|
||||||
|
action.getDeps())
|
||||||
|
ldd.getDeps(file)
|
||||||
|
|
||||||
|
# resolve symlinks
|
||||||
|
ldd.getLinks()
|
||||||
|
|
||||||
|
# add dependencies to actions
|
||||||
|
for dep in ldd.deps:
|
||||||
|
kwargs = {}
|
||||||
|
kwargs['src'] = dep
|
||||||
|
kwargs['dst'] = re.sub(r'%s(?P<file>.*)' % self.conf.treedir,
|
||||||
|
'%s\g<file>' % self.initrddir,
|
||||||
|
dep)
|
||||||
|
|
||||||
|
new_action = actions.fileactions.Copy(**kwargs)
|
||||||
|
self.actions.append(new_action)
|
||||||
|
|
||||||
|
def processActions(self):
|
||||||
|
for action in self.template.actions:
|
||||||
|
action.execute()
|
||||||
|
|
||||||
|
for action in self.actions:
|
||||||
|
action.execute()
|
||||||
|
|
||||||
|
def create(self, dst):
|
||||||
|
os.system('find %s | cpio --quiet -c -o | gzip -9 > %s' % (self.initrddir, dst))
|
||||||
|
|
||||||
|
def cleanUp(self):
|
||||||
|
rm(self.initrddir)
|
0
src/pylorax/utils/__init__.py
Normal file
0
src/pylorax/utils/__init__.py
Normal file
104
src/pylorax/utils/fileutil.py
Normal file
104
src/pylorax/utils/fileutil.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# pylorax/utils/fileutil.py
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import glob
|
||||||
|
import fileinput
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def cp(src, dst, mode=None, verbose=False):
|
||||||
|
for name in glob.iglob(src):
|
||||||
|
__copy(name, dst, verbose=verbose)
|
||||||
|
if mode:
|
||||||
|
os.chmod(dst, mode)
|
||||||
|
|
||||||
|
def mv(src, dst, mode=None, verbose=False):
|
||||||
|
for name in glob.iglob(src):
|
||||||
|
__copy(name, dst, verbose=verbose, remove=True)
|
||||||
|
if mode:
|
||||||
|
os.chmod(dst, mode)
|
||||||
|
|
||||||
|
def rm(target, verbose=False):
|
||||||
|
if os.path.isdir(target):
|
||||||
|
if verbose:
|
||||||
|
print('removing directory "%s"' % target)
|
||||||
|
shutil.rmtree(target, ignore_errors=True)
|
||||||
|
else:
|
||||||
|
if verbose:
|
||||||
|
print('removing file "%s"' % target)
|
||||||
|
os.unlink(target)
|
||||||
|
|
||||||
|
def __copy(src, dst, verbose=False, remove=False):
|
||||||
|
if not os.path.exists(src):
|
||||||
|
sys.stderr.write('cannot stat "%s": No such file or directory\n' % src)
|
||||||
|
return
|
||||||
|
|
||||||
|
if os.path.isdir(dst):
|
||||||
|
basename = os.path.basename(src)
|
||||||
|
dst = os.path.join(dst, basename)
|
||||||
|
|
||||||
|
if os.path.isdir(src):
|
||||||
|
if os.path.isfile(dst):
|
||||||
|
sys.stderr.write('omitting directory "%s"\n' % src)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.isdir(dst):
|
||||||
|
os.makedirs(dst)
|
||||||
|
|
||||||
|
names = map(lambda name: os.path.join(src, name), os.listdir(src))
|
||||||
|
for name in names:
|
||||||
|
__copy(name, dst, verbose=verbose, remove=remove)
|
||||||
|
else:
|
||||||
|
if os.path.isdir(dst):
|
||||||
|
sys.stderr.write('cannot overwrite directory "%s" with non-directory\n' % dst)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
if verbose:
|
||||||
|
print('copying "%s" to "%s"' % (src, dst))
|
||||||
|
shutil.copy2(src, dst)
|
||||||
|
except (shutil.Error, IOError) as why:
|
||||||
|
sys.stderr.write('cannot copy "%s" to "%s": %s\n' % (src, dst, why))
|
||||||
|
else:
|
||||||
|
if remove:
|
||||||
|
if verbose:
|
||||||
|
print('removing "%s"' % src)
|
||||||
|
os.unlink(src)
|
||||||
|
|
||||||
|
|
||||||
|
def touch(filename, verbose=False):
|
||||||
|
if os.path.exists(filename):
|
||||||
|
os.utime(filename, None)
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = open(filename, 'w')
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
f.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def edit(filename, text, append=False, verbose=False):
|
||||||
|
mode = 'w'
|
||||||
|
if append:
|
||||||
|
mode = 'a'
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = open(filename, mode)
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
f.write(text)
|
||||||
|
f.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def replace(filename, find, replace, verbose=False):
|
||||||
|
fin = fileinput.input(filename, inplace=1)
|
||||||
|
for line in fin:
|
||||||
|
line = re.sub(find, replace, line)
|
||||||
|
sys.stdout.write(line)
|
||||||
|
fin.close()
|
||||||
|
return True
|
57
src/pylorax/utils/libutil.py
Normal file
57
src/pylorax/utils/libutil.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
import os
|
||||||
|
import commands
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class LDD(object):
|
||||||
|
def __init__(self, libroot='/'):
|
||||||
|
f = open('/usr/bin/ldd', 'r')
|
||||||
|
for line in f.readlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith('RTLDLIST='):
|
||||||
|
rtldlist, sep, ld_linux = line.partition('=')
|
||||||
|
break
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
self._ldd = '%s --list --library-path %s' % (ld_linux, libroot)
|
||||||
|
self._deps = set()
|
||||||
|
|
||||||
|
def getDeps(self, filename):
|
||||||
|
rc, output = commands.getstatusoutput('%s %s' % (self._ldd, filename))
|
||||||
|
|
||||||
|
if rc:
|
||||||
|
return
|
||||||
|
|
||||||
|
lines = output.splitlines()
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
m = re.match(r'^[a-zA-Z0-9.]*\s=>\s(?P<lib>[a-zA-Z0-9./]*)\s\(0x[0-9a-f]*\)$', line)
|
||||||
|
if m:
|
||||||
|
lib = m.group('lib')
|
||||||
|
if lib not in self._deps:
|
||||||
|
self._deps.add(lib)
|
||||||
|
self.getDeps(lib)
|
||||||
|
|
||||||
|
def getLinks(self):
|
||||||
|
targets = set()
|
||||||
|
for lib in self._deps:
|
||||||
|
if os.path.islink(lib):
|
||||||
|
targets.add(os.path.realpath(lib))
|
||||||
|
|
||||||
|
self._deps.update(targets)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def deps(self):
|
||||||
|
return self._deps
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ldd = LDD(libroot=sys.argv[2])
|
||||||
|
ldd.getDeps(sys.argv[1])
|
||||||
|
ldd.getLinks()
|
||||||
|
|
||||||
|
for dep in ldd.deps:
|
||||||
|
print dep
|
158
src/pylorax/utils/rpmutil.py
Normal file
158
src/pylorax/utils/rpmutil.py
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
# pylorax/utils/rpmutil.py
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import yum
|
||||||
|
import urlgrabber
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import yum.callbacks
|
||||||
|
import yum.rpmtrans
|
||||||
|
|
||||||
|
from rpmUtils.miscutils import rpm2cpio
|
||||||
|
from cpioarchive import CpioArchive
|
||||||
|
|
||||||
|
from pylorax.base import seq, getConsoleSize
|
||||||
|
|
||||||
|
|
||||||
|
class Callback(yum.rpmtrans.SimpleCliCallBack):
|
||||||
|
def __init__(self):
|
||||||
|
yum.rpmtrans.SimpleCliCallBack.__init__(self)
|
||||||
|
self.height, self.width = getConsoleSize()
|
||||||
|
|
||||||
|
def event(self, package, action, te_current, te_total, ts_current, ts_total):
|
||||||
|
# XXX crazy output stuff
|
||||||
|
progress = float(te_current) / float(te_total)
|
||||||
|
|
||||||
|
percentage = int(progress * 100)
|
||||||
|
|
||||||
|
bar_length = 20
|
||||||
|
bar = int(percentage / (100/bar_length))
|
||||||
|
|
||||||
|
total_progress_str = '[%s/%s] ' % (ts_current, ts_total)
|
||||||
|
package_progress_str = ' [%s%s] %3d%%' % ('#' * bar, '-' * (bar_length - bar), percentage)
|
||||||
|
|
||||||
|
action_str = '%s %s' % (self.action[action], package)
|
||||||
|
chars_left = self.width - len(total_progress_str) - len(package_progress_str)
|
||||||
|
|
||||||
|
if len(action_str) > chars_left:
|
||||||
|
action_str = action_str[:chars_left-3]
|
||||||
|
action_str = action_str + '...'
|
||||||
|
else:
|
||||||
|
action_str = action_str + ' ' * (chars_left - len(action_str))
|
||||||
|
|
||||||
|
msg = total_progress_str + action_str + package_progress_str
|
||||||
|
|
||||||
|
sys.stdout.write(msg)
|
||||||
|
sys.stdout.write('\b' * len(msg))
|
||||||
|
|
||||||
|
if percentage == 100:
|
||||||
|
sys.stdout.write('\n')
|
||||||
|
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
class Yum(object):
|
||||||
|
def __init__(self, yumconf='/etc/yum/yum.conf', installroot='/'):
|
||||||
|
self.yb = yum.YumBase()
|
||||||
|
|
||||||
|
self.yumconf = os.path.abspath(yumconf)
|
||||||
|
self.installroot = os.path.abspath(installroot)
|
||||||
|
|
||||||
|
self.yb.preconf.fn = self.yumconf
|
||||||
|
self.yb.preconf.root = self.installroot
|
||||||
|
self.yb._getConfig()
|
||||||
|
|
||||||
|
self.yb._getRpmDB()
|
||||||
|
self.yb._getRepos()
|
||||||
|
self.yb._getSacks()
|
||||||
|
|
||||||
|
def find(self, patterns):
|
||||||
|
pl = self.yb.doPackageLists(patterns=seq(patterns))
|
||||||
|
return pl.installed, pl.available
|
||||||
|
|
||||||
|
def isInstalled(self, pattern):
|
||||||
|
print('searching for package matching %s' % pattern)
|
||||||
|
pl = self.yb.doPackageLists(pkgnarrow='installed', patterns=[pattern])
|
||||||
|
print('found %s' % pl.installed)
|
||||||
|
return pl.installed
|
||||||
|
|
||||||
|
def download(self, packages):
|
||||||
|
for package in seq(packages):
|
||||||
|
print('Downloading package %s...' % package)
|
||||||
|
fn = urlgrabber.urlgrab(package.remote_url)
|
||||||
|
shutil.copy(fn, self.installroot)
|
||||||
|
|
||||||
|
return os.path.join(self.installroot, os.path.basename(fn))
|
||||||
|
|
||||||
|
def addPackages(self, patterns):
|
||||||
|
# FIXME don't add packages already installed
|
||||||
|
for pattern in seq(patterns):
|
||||||
|
installed = self.isInstalled(pattern)
|
||||||
|
if installed:
|
||||||
|
print 'Package %s already installed' % installed
|
||||||
|
return
|
||||||
|
|
||||||
|
print('Adding package matching %s...' % pattern)
|
||||||
|
try:
|
||||||
|
self.yb.install(name=pattern)
|
||||||
|
except yum.Errors.InstallError:
|
||||||
|
try:
|
||||||
|
self.yb.install(pattern=pattern)
|
||||||
|
except yum.Errors.InstallError:
|
||||||
|
sys.stderr.write('ERROR: No package matching %s available\n' % pattern)
|
||||||
|
|
||||||
|
def install(self):
|
||||||
|
self.yb.resolveDeps()
|
||||||
|
self.yb.buildTransaction()
|
||||||
|
|
||||||
|
cb = yum.callbacks.ProcessTransBaseCallback()
|
||||||
|
rpmcb = Callback()
|
||||||
|
self.yb.processTransaction(callback=cb, rpmDisplay=rpmcb)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_rpm(rpmfile, destdir):
|
||||||
|
if not os.path.isdir(destdir):
|
||||||
|
os.makedirs(destdir)
|
||||||
|
|
||||||
|
rpm = os.open(rpmfile, os.O_RDONLY)
|
||||||
|
output = open(os.path.join(destdir, 'CONTENT.cpio'), 'w')
|
||||||
|
|
||||||
|
rpm2cpio(rpm, output)
|
||||||
|
output.close()
|
||||||
|
|
||||||
|
cwd = os.getcwd()
|
||||||
|
os.chdir(destdir)
|
||||||
|
|
||||||
|
cpio = CpioArchive(name=output.name)
|
||||||
|
for entry in cpio:
|
||||||
|
path = os.path.abspath(entry.name)
|
||||||
|
isdir = stat.S_ISDIR(entry.mode)
|
||||||
|
|
||||||
|
if isdir:
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
else:
|
||||||
|
print('Extracting %s...' % entry.name)
|
||||||
|
dir = os.path.dirname(path)
|
||||||
|
if not os.path.isdir(dir):
|
||||||
|
os.makedirs(dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = open(path, 'w')
|
||||||
|
except IOError:
|
||||||
|
sys.stderr.write('ERROR: Unable to extract file %s\n' % path)
|
||||||
|
else:
|
||||||
|
f.write(entry.read())
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
os.chmod(path, entry.mode)
|
||||||
|
os.chown(path, entry.uid, entry.gid)
|
||||||
|
|
||||||
|
cpio.close()
|
||||||
|
os.unlink(output.name)
|
||||||
|
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
return True
|
Loading…
Reference in New Issue
Block a user