From 2e9cad42c8d999ad8c763b3dd99bd5aa633e8ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eray=20=C3=96zkural?= Date: Wed, 12 Oct 2005 10:19:11 +0000 Subject: [PATCH] * fix: require build dependencies in Builder * make ignore-dependency work with Build commands * fix: all Build subcommands must derive from Build * new option: ignore-action-errors, try it, you will love it! * fix: proper error handling in actionsapi (see #460) * rename: PisiBuild -> Builder * cosmetic changes: - eliminate unnecessary use of punctuation - when we have colors, do not print Error:, Warning: prefixes * fix some typos --- pisi/actionsapi/__init__.py | 8 +++++++ pisi/actionsapi/kde.py | 10 ++++----- pisi/actionsapi/libtools.py | 4 ++-- pisi/actionsapi/perlmodules.py | 12 +++++------ pisi/actionsapi/pisitools.py | 18 ++++++++-------- pisi/actionsapi/pisitoolsfunctions.py | 6 +++--- pisi/actionsapi/pythonmodules.py | 6 +++--- pisi/actionsapi/scons.py | 4 ++-- pisi/actionsapi/shelltools.py | 24 +++++++++++---------- pisi/api.py | 22 ++------------------ pisi/build.py | 30 ++++++++++++++++++++------- pisi/cli/__init__.py | 10 +++++++-- pisi/cli/commands.py | 27 ++++++++++++++++++------ 13 files changed, 104 insertions(+), 77 deletions(-) diff --git a/pisi/actionsapi/__init__.py b/pisi/actionsapi/__init__.py index f9b9d9c1..a8e30068 100644 --- a/pisi/actionsapi/__init__.py +++ b/pisi/actionsapi/__init__.py @@ -20,3 +20,11 @@ class Error(pisi.Error): class Exception(pisi.Exception): pass + +import pisi.context as ctx + +def error(msg): + if ctx.config.get_option('ignore_action_errors'): + ctx.ui.error(msg) + else: + raise Error(msg) diff --git a/pisi/actionsapi/kde.py b/pisi/actionsapi/kde.py index d394167a..bc652b61 100644 --- a/pisi/actionsapi/kde.py +++ b/pisi/actionsapi/kde.py @@ -64,20 +64,20 @@ def configure(parameters = ''): %s' % (get.kdeDIR(), get.HOST(), get.qtDIR(), get.qtLIBDIR(), parameters) if system(args): - raise ConfigureError(_('!!! Configure failed...\n')) + raise ConfigureError(_('Configure failed.')) else: - raise ConfigureError(_('!!! No configure script found...\n')) + raise ConfigureError(_('No configure script found.')) def make(parameters = ''): '''make source with given parameters = "all" || "doc" etc.''' if system('make %s' % parameters): - raise MakeError(_('!!! Make failed...\n')) + raise MakeError(_('Make failed.')) def install(parameters = 'install'): if can_access_file('Makefile'): args = 'make DESTDIR=%s destdir=%s %s' % (get.installDIR(), get.installDIR(), parameters) if system(args): - raise InstallError(_('!!! Install failed...\n')) + raise InstallError(_('Install failed.')) else: - raise InstallError(_('!!! No Makefile found...\n')) + raise InstallError(_('No Makefile found.')) diff --git a/pisi/actionsapi/libtools.py b/pisi/actionsapi/libtools.py index fa7c83a8..26cb2fdd 100644 --- a/pisi/actionsapi/libtools.py +++ b/pisi/actionsapi/libtools.py @@ -35,7 +35,7 @@ def preplib(sourceDirectory = '/usr/lib'): sourceDirectory = get.installDIR() + sourceDirectory if can_access_directory(sourceDirectory): if system('/sbin/ldconfig -n -N %s' % sourceDirectory): - raise RunTimeError(_('!!! Running ldconfig failed...')) + raise RunTimeError(_('Running ldconfig failed.')) def gnuconfig_update(): ''' copy newest config.* onto source\'s ''' @@ -47,7 +47,7 @@ def gnuconfig_update(): def libtoolize(parameters = ''): if system('/usr/bin/libtoolize %s' % parameters): - raise RunTimeError(_('Running libtoolize failed...')) + raise RunTimeError(_('Running libtoolize failed.')) def gen_usr_ldscript(dynamicLib): diff --git a/pisi/actionsapi/perlmodules.py b/pisi/actionsapi/perlmodules.py index c2766be1..06925b3b 100644 --- a/pisi/actionsapi/perlmodules.py +++ b/pisi/actionsapi/perlmodules.py @@ -50,27 +50,27 @@ def configure(parameters = ''): export('PERL_MM_USE_DEFAULT', '1') if can_access_file('Build.PL'): if system('perl Build.PL installdirs=vendor destdir=%s' % get.installDIR()): - raise CompileError, _('!!! Configure failed...\n') + raise CompileError, _('Configure failed.') else: if system('perl Makefile.PL %s PREFIX=/usr INSTALLDIRS=vendor DESTDIR=%s' % (parameters, get.installDIR())): - raise CompileError, _('!!! Configure failed...\n') + raise CompileError, _('Configure failed.') def make(parameters = ''): '''make source with given parameters.''' if can_access_file('Makefile'): if system('make %s' % parameters): - raise MakeError, _('!!! Make failed...\n') + raise MakeError, _('Make failed.') else: if system('perl Build build'): - raise MakeError, _('!!! Make failed...\n') + raise MakeError, _('perl build failed.') def install(parameters = 'install'): '''install source with given parameters.''' if can_access_file('Makefile'): if system('make %s' % parameters): - raise InstallError, _('!!! Install failed...\n') + raise InstallError, _('Make failed.') else: if system('perl Build install'): - raise MakeError, _('!!! Install failed...\n') + raise MakeError, _('perl install failed.') # FIXME: fix_local_pod % update_pod diff --git a/pisi/actionsapi/pisitools.py b/pisi/actionsapi/pisitools.py index 59730995..e6fc297d 100644 --- a/pisi/actionsapi/pisitools.py +++ b/pisi/actionsapi/pisitools.py @@ -30,6 +30,8 @@ import pisi.actionsapi.get as get from pisi.actionsapi.pisitoolsfunctions import * from pisi.actionsapi.shelltools import * +from pisi.actionsapi import error + def dobin(sourceFile, destinationDirectory = '/usr/bin'): '''insert a executable file into /bin or /usr/bin''' @@ -124,7 +126,7 @@ def doman(*sourceFiles): pageName, pageDirectory = source[:source.rindex('.')], \ source[source.rindex('.')+1:] except ValueError: - ctx.ui.warning(_('ActionsAPI [doman]: Wrong man page file: %s') % (source)) + error(_('ActionsAPI [doman]: Wrong man page file: %s') % (source)) makedirs(manDIR + '/man%s' % pageDirectory) system('install -m0644 %s %s' % (source, manDIR + '/man%s' % pageDirectory)) @@ -162,7 +164,7 @@ def rename(sourceFile, destinationFile): try: os.rename(get.installDIR() + sourceFile, get.installDIR() + baseDir + "/" + destinationFile) except OSError: - ctx.ui.warning(_('ActionsAPI [rename]: No such file or directory: %s') % (sourceFile)) + error(_('ActionsAPI [rename]: No such file or directory: %s') % (sourceFile)) def dosed(sourceFiles, findPattern, replacePattern = ''): '''replaces patterns in sourceFiles''' @@ -179,7 +181,7 @@ def dosed(sourceFiles, findPattern, replacePattern = ''): line = re.sub(findPattern, replacePattern, line) sys.stdout.write(line) else: - raise FileError(_('File doesn\'t exists or permission denied: %s') % sourceFile) + raise FileError(_('File does not exist or permission denied: %s') % sourceFile) def dosbin(sourceFile, destinationDirectory = '/usr/sbin'): '''insert a executable file into /sbin or /usr/sbin''' @@ -196,7 +198,7 @@ def dosym(sourceFile, destinationFile): try: os.symlink(sourceFile, get.installDIR() + destinationFile) except OSError: - ctx.ui.warning(_('ActionsAPI [dosym]: File exists: %s') % (sourceFile)) + error(_('ActionsAPI [dosym]: File exists: %s') % (sourceFile)) def insinto(destinationDirectory, sourceFile, destinationFile = ''): '''insert a sourceFile into destinationDirectory as a destinationFile with same uid/guid/permissions''' @@ -212,11 +214,9 @@ def insinto(destinationDirectory, sourceFile, destinationFile = ''): def newdoc(sourceFile, destinationFile): '''inserts a sourceFile into /usr/share/doc/PACKAGE/ directory as a destinationFile''' destinationDirectory = '' #490 - try: - destinationDirectory = destinationFile[:destinationFile.rindex('/')] - destinationFile = destinationFile[destinationFile.rindex('/') + 1:] - except: - pass + import os.path + destinationDirectory = os.path.dirname(destinationFile) + destinationFile = os.path.basename(destinationFile) move(sourceFile, destinationFile) readable_insinto(os.path.join(get.installDIR(), 'usr/share/doc', get.srcTAG(), destinationDirectory), destinationFile) diff --git a/pisi/actionsapi/pisitoolsfunctions.py b/pisi/actionsapi/pisitoolsfunctions.py index 2b850e1c..857846f7 100644 --- a/pisi/actionsapi/pisitoolsfunctions.py +++ b/pisi/actionsapi/pisitoolsfunctions.py @@ -43,7 +43,7 @@ def executable_insinto(destinationDirectory, *sourceFiles): '''insert a executable file into destinationDirectory''' if not sourceFiles or not destinationDirectory: - raise ArgumentError(_('Insufficient arguments...')) + raise ArgumentError(_('Insufficient arguments.')) if not can_access_directory(destinationDirectory): makedirs(destinationDirectory) @@ -56,7 +56,7 @@ def readable_insinto(destinationDirectory, *sourceFiles): '''inserts file list into destinationDirectory''' if not sourceFiles or not destinationDirectory: - raise ArgumentError(_('Insufficient arguments...')) + raise ArgumentError(_('Insufficient arguments.')) if not can_access_directory(destinationDirectory): makedirs(destinationDirectory) @@ -69,7 +69,7 @@ def lib_insinto(sourceFile, destinationDirectory, permission = 0644): '''inserts a library fileinto destinationDirectory with given permission''' if not sourceFile or not destinationDirectory: - raise ArgumentError(_(' Insufficient arguments...')) + raise ArgumentError(_(' Insufficient arguments.')) if not can_access_directory(destinationDirectory): makedirs(destinationDirectory) diff --git a/pisi/actionsapi/pythonmodules.py b/pisi/actionsapi/pythonmodules.py index b7decb85..d8fb1897 100644 --- a/pisi/actionsapi/pythonmodules.py +++ b/pisi/actionsapi/pythonmodules.py @@ -47,12 +47,12 @@ class RunTimeError(pisi.actionsapi.Error): def compile(parameters = ''): '''compile source with given parameters.''' if system('python setup.py build %s' % (get.installDIR(), parameters)): - raise CompileError, _('!!! Make failed...\n') + raise CompileError, _('Make failed.') def install(parameters = ''): '''does python setup.py install''' if system('python setup.py install --root=%s --no-compile %s' % (get.installDIR(), parameters)): - raise InstallError, _('!!! Install failed...\n') + raise InstallError, _('Install failed.') DDOCS = 'CHANGELOG COPYRIGHT KNOWN_BUGS MAINTAINERS PKG-INFO \ CONTRIBUTORS LICENSE COPYING* Change* MANIFEST* README*' @@ -64,4 +64,4 @@ def install(parameters = ''): def run(parameters = ''): '''executes parameters with python''' if system('python %s' % (parameters)): - raise RunTimeError, _('!!! Running %s failed...\n') % parameters + raise RunTimeError, _('Running %s failed.') % parameters diff --git a/pisi/actionsapi/scons.py b/pisi/actionsapi/scons.py index 9c3e75db..c992986f 100644 --- a/pisi/actionsapi/scons.py +++ b/pisi/actionsapi/scons.py @@ -37,8 +37,8 @@ class InstallError(pisi.actionsapi.Error): def make(parameters = ''): if system("scons %s" % parameters): - raise MakeError(_('!!! Make failed...\n')) + raise MakeError(_('Make failed.')) def install(parameters = 'install'): if system("scons prefix=%s %s" % (get.installDIR(), parameters)): - raise InstallError(_('!!! Install failed...\n')) + raise InstallError(_('Install failed.')) diff --git a/pisi/actionsapi/shelltools.py b/pisi/actionsapi/shelltools.py index f3ac3144..43846671 100644 --- a/pisi/actionsapi/shelltools.py +++ b/pisi/actionsapi/shelltools.py @@ -27,6 +27,8 @@ import pisi.context as ctx import pisi.actionsapi import pisi.actionsapi.get +from pisi.actionsapi import error + def can_access_file(sourceFile): '''test the existence of file''' return os.access(sourceFile, os.F_OK) @@ -40,7 +42,7 @@ def makedirs(destinationDirectory): try: os.makedirs(destinationDirectory) except OSError: - pass + error(_('Cannot create directory %s' % destinationDirectory)) def echo(destionationFile, content): try: @@ -48,7 +50,7 @@ def echo(destionationFile, content): f.write("%s\n" % content) f.close() except IOError: - ctx.ui.error(_(' ActionsAPI [echo]: Can\'t append to file %s...') % (destionationFile)) + error(_('ActionsAPI [echo]: Can\'t append to file %s.') % (destionationFile)) def chmod(sourceFile, mode = 0755): '''change the mode of sourceFile to the mode''' @@ -98,11 +100,11 @@ def unlinkDir(sourceDirectory): try: shutil.rmtree(sourceDirectory) except OSError: - ctx.ui.error(_(' ActionsAPI [unlinkDir]: Operation not permitted: %s') % (sourceDirectory)) + error(_(' ActionsAPI [unlinkDir]: Operation not permitted: %s') % (sourceDirectory)) elif isFile(sourceDirectory): pass else: - ctx.ui.error(_(' ActionsAPI [unlinkDir]: Directory %s doesn\'t exists.') % (sourceDirectory)) + error(_(' ActionsAPI [unlinkDir]: Directory %s doesn\'t exists.') % (sourceDirectory)) def move(sourceFile, destinationFile): '''recursively move a sourceFile or directory to destinationFile''' @@ -111,9 +113,9 @@ def move(sourceFile, destinationFile): try: shutil.move(file, destinationFile) except OSError: - ctx.ui.error(_(' ActionsAPI [move]: Permission denied: %s to %s') % (file, destinationFile)) + error(_(' ActionsAPI [move]: Permission denied: %s to %s') % (file, destinationFile)) else: - ctx.ui.error(_(' ActionsAPI [move]: File %s doesn\'t exists.') % (file)) + error(_(' ActionsAPI [move]: File %s doesn\'t exists.') % (file)) def copy(sourceFile, destinationFile): '''recursively copy a sourceFile or directory to destinationFile''' @@ -122,11 +124,11 @@ def copy(sourceFile, destinationFile): try: shutil.copy(file, destinationFile) except IOError: - ctx.ui.error(_('ActionsAPI [copy]: Permission denied: %s to %s') % (file, destinationFile)) + error(_('ActionsAPI [copy]: Permission denied: %s to %s') % (file, destinationFile)) elif isDirectory(file): copytree(file, destinationFile) else: - ctx.ui.error(_('ActionsAPI [copy]: File %s does not exist.') % file) + error(_('ActionsAPI [copy]: File %s does not exist.') % file) def copytree(source, destination, sym = False): '''recursively copy an entire directory tree rooted at source''' @@ -134,9 +136,9 @@ def copytree(source, destination, sym = False): try: shutil.copytree(source, destination, sym) except OSError: - ctx.ui.error(_(' ActionsAPI [copytree]: Permission denied: %s to %s') % (source, destination)) + error(_(' ActionsAPI [copytree]: Permission denied: %s to %s') % (source, destination)) else: - ctx.ui.error(_(' ActionsAPI [copytree]: Directory %s doesn\'t exists.') % (source)) + error(_(' ActionsAPI [copytree]: Directory %s doesn\'t exists.') % (source)) def touch(sourceFile): '''changes the access time of the 'sourceFile', or creates it if it is not exist''' @@ -148,7 +150,7 @@ def touch(sourceFile): f = open(sourceFile, 'w') f.close() except IOError: - ctx.ui.error(_(' ActionsAPI [touch]: Permission denied: %s') % (sourceFile)) + error(_(' ActionsAPI [touch]: Permission denied: %s') % (sourceFile)) def cd(directoryName = ''): '''change directory''' diff --git a/pisi/api.py b/pisi/api.py index 22469653..fa286db8 100644 --- a/pisi/api.py +++ b/pisi/api.py @@ -550,31 +550,14 @@ def update_repo(repo): # build functions... def prepare_for_build(pspecfile, authInfo=None): - # FIXME: there is a function named "build" in this module which - # makes it impossible to use build module directly. - from build import PisiBuild - url = URI(pspecfile) if url.is_remote_file(): from sourcefetcher import SourceFetcher fs = SourceFetcher(url, authInfo) url.uri = fs.fetch_all() - pb = PisiBuild(url.uri) - - # find out the build dependencies that are not satisfied... - dep_unsatis = [] - for dep in pb.spec.source.buildDeps: - if not dependency.installed_satisfies_dep(dep): - dep_unsatis.append(dep) - - # FIXME: take care of the required buildDeps... - # For now just report an error! - if dep_unsatis: - ctx.ui.error(_("Unsatisfied Build Dependencies:")) - for dep in dep_unsatis: - ctx.ui.warning(dep.package) - # FIXME: raise an exception if ignore-depends not given + import pisi.build + pb = pisi.build.Builder(url.uri) return pb @@ -582,7 +565,6 @@ def build(pspecfile, authInfo=None): pb = prepare_for_build(pspecfile, authInfo) pb.build() - order = {"none": 0, "unpack": 1, "setupaction": 2, diff --git a/pisi/build.py b/pisi/build.py index f26dc50a..2989119c 100644 --- a/pisi/build.py +++ b/pisi/build.py @@ -24,6 +24,7 @@ _ = __trans.ugettext import pisi import pisi.util as util import pisi.context as ctx +import pisi.dependency as dependency from pisi.sourcearchive import SourceArchive from pisi.files import Files, FileInfo from pisi.metadata import MetaData @@ -114,8 +115,8 @@ class BuildContext(object): return self.pkg_dir() + ctx.const.install_dir_suffix -class PisiBuild: - """PisiBuild class, provides the package build and creation routines""" +class Builder: + """Provides the package build and creation routines""" def __init__(self, pspec): self.bctx = BuildContext(pspec) self.pspecDir = os.path.dirname(os.path.realpath(self.bctx.pspecfile)) @@ -148,13 +149,12 @@ class PisiBuild: # check if all patch files exists, if there are missing no need to unpack! self.patch_exists() - + + self.check_build_dependencies() + self.fetch_source_archive() - self.unpack_source_archive() - self.solve_build_dependencies() - # apply the patches and prepare a source directory for build. self.apply_patches() @@ -256,10 +256,24 @@ class PisiBuild: os.chdir(curDir) - def solve_build_dependencies(self): + def check_build_dependencies(self): """fail if dependencies not satisfied""" #TODO: we'll have to do better than plugging a fxn here - pass + # find out the build dependencies that are not satisfied... + dep_unsatis = [] + for dep in self.spec.source.buildDeps: + if not dependency.installed_satisfies_dep(dep): + dep_unsatis.append(dep) + + # FIXME: take care of the required buildDeps... + # For now just report an error! + if dep_unsatis: + ctx.ui.error(_("Unsatisfied Build Dependencies:")) + for dep in dep_unsatis: + ctx.ui.warning(dep.package) + # FIXME: raise an exception if ignore-depends not given + if not ctx.config.get_option('ignore_dependency'): + raise Error(_('Cannot build package due to unsatisfied build dependencies')) def patch_exists(self): """check existence of patch files declared in PSPEC""" diff --git a/pisi/cli/__init__.py b/pisi/cli/__init__.py index b90b9a36..16bbc7e4 100644 --- a/pisi/cli/__init__.py +++ b/pisi/cli/__init__.py @@ -72,10 +72,16 @@ class CLI(UI): self.output(msg + msgend) def warning(self,msg): - self.output(colorize(_('Warning: ') + msg + '\n', 'purple'), err=True) + if ctx.config.get_option('no_color'): + self.output(_('Warning: ') + msg + '\n', err=True) + else: + self.output(colorize(msg + '\n', 'purple'), err=True) def error(self,msg): - self.output(colorize(_('Error: ') + msg + '\n', 'red'), err=True) + if ctx.config.get_option('no_color'): + self.output(_('Error: ') + msg + '\n', err=True) + else: + self.output(colorize(msg + '\n', 'red'), err=True) def action(self,msg): #TODO: this seems quite redundant? diff --git a/pisi/cli/commands.py b/pisi/cli/commands.py index 71748eea..dc32db5b 100644 --- a/pisi/cli/commands.py +++ b/pisi/cli/commands.py @@ -219,6 +219,7 @@ If run without parameters, it prints the general help.""" self.finalize() + class Clean(Command): """Clean stale locks.""" @@ -233,7 +234,8 @@ class Clean(Command): self.init() pisi.util.clean_locks() self.finalize() - + + class DeleteCache(Command): """Delete cache files""" @@ -248,6 +250,7 @@ class DeleteCache(Command): self.init(database=False) pisi.api.delete_cache() + class Graph(Command): """Graph package relations. Usage: graph ... @@ -270,12 +273,19 @@ conflicts relations starting from given packages. g.write_graphviz(file('pgraph.dot', 'w')) self.finalize() +# option mixins def buildno_opts(self): self.parser.add_option("", "--ignore-build-no", action="store_true", default=False, help=_("do not take build no into account.")) +def ignoredep_opt(self): + p = self.parser + p.add_option("-E", "--ignore-dependency", action="store_true", + default=False, + help=_("do not take dependency information into account")) + class Build(Command): """Build a PISI package using a pspec.xml file @@ -294,8 +304,13 @@ fetch all necessary files and build the package for you. def options(self): buildno_opts(self) + ignoredep_opt(self) self.parser.add_option("-O", "--output-dir", action="store", default=".", help=_("output directory for produced packages")) + self.parser.add_option("-A", "--ignore-action-errors", + action="store_true", default=False, + help=_("bypass errors from ActionsAPI")) + def run(self): if not self.args: @@ -320,9 +335,7 @@ class PackageOp(Command): p = self.parser p.add_option("-B", "--ignore-comar", action="store_true", default=False, help=_("bypass comar configuration agent")) - p.add_option("", "--ignore-dependency", action="store_true", - default=False, - help=_("do not take dependency information into account")) + ignoredep_opt(self) def init(self): super(PackageOp, self).init(True) @@ -331,6 +344,7 @@ class PackageOp(Command): #self.finalize_db() pass + class Install(PackageOp): """Install PISI packages @@ -359,6 +373,7 @@ specified a package name, it should exist in a specified repository. pisi.api.install(self.args) self.finalize() + class Upgrade(PackageOp): """Upgrade PISI packages @@ -864,9 +879,9 @@ Finds the installed package which contains the specified file. self.finalize() - # Partial build commands + class BuildUntil(Build): """Run the build process partially @@ -955,7 +970,7 @@ TODO: desc. self.finalize() -class BuildBuild(Command): +class BuildBuild(Build): """Setup the source Usage: build-build