diff --git a/pisi/build.py b/pisi/build.py index 0d55aea9..5ed949cd 100644 --- a/pisi/build.py +++ b/pisi/build.py @@ -16,6 +16,7 @@ # python standard library import os import sys +import glob import gettext __trans = gettext.translation('pisi', fallback=True) @@ -73,8 +74,8 @@ def check_path_collision(package, pkgList): # path.pathname: /usr/share/doc if util.subpath(pinfo.pathname, path.pathname): collisions.append(path.pathname) - ctx.ui.debug(_('Path %s belongs in multiple packages') % - path.pathname) + ctx.ui.error(_('Path %s belongs in multiple packages') % + path.pathname) return collisions # a dynamic build context @@ -356,27 +357,38 @@ class Builder: self.metadata = metadata def gen_files_xml(self, package): - """Generetes files.xml using the path definitions in specfile and - generated files by the build system.""" + """Generates files.xml using the path definitions in specfile and + the files produced by the build system.""" files = Files() install_dir = self.bctx.pkg_install_dir() + # FIXME: We need to expand globs before trying to calculate hashes + # Not on the fly like now. + # we'll exclude collisions in get_file_hashes. Having a # collisions list is not wrong, we must just handle it :). - collisions = check_path_collision(package, - self.spec.packages) + # sure -- exa + collisions = check_path_collision(package, self.spec.packages) + # FIXME: material collisions after expanding globs must be + # reported as errors, and an exception must be raised d = {} - for pinfo in package.paths: - path = install_dir + pinfo.pathname + def add_path(path): + # add the files under material path for fpath, fhash in util.get_file_hashes(path, collisions, install_dir): frpath = util.removepathprefix(install_dir, fpath) # relative path ftype = get_file_type(frpath, package.paths) - try: # broken links can cause problem + try: # broken links and empty dirs can cause problem fsize = str(os.path.getsize(fpath)) except OSError: fsize = None d[frpath] = FileInfo(frpath, ftype, fsize, fhash) + + for pinfo in package.paths: + wildcard_path = util.join_path(install_dir, pinfo.pathname) + for path in glob.glob(wildcard_path): + add_path(path) + for (p, fileinfo) in d.iteritems(): files.append(fileinfo) @@ -387,69 +399,29 @@ class Builder: def calc_build_no(self, package_name): """Calculate build number""" - def found_package(fn): - "did we find the filename we were looking for?" - if fn.startswith(package_name + '-'): - if fn.endswith(ctx.const.package_prefix): - # get version string, skip separator '-' - verstr = fn[len(package_name) + 1: - len(fn)-len(ctx.const.package_prefix)] - import string - for x in verstr.split('-'): - # weak rule: version components start with a digit - if x is '' or (not x[0] in string.digits): - return False - return True - return False + # find previous build in output dir and packages dir + found = [] + def locate_package_names(files): + for fn in files: + fn = fn.decode('utf-8') + if util.is_package_name(fn, package_name): + old_package_fn = os.path.join(root, fn) + ctx.ui.info('(found old version %s)' % old_package_fn) + old_pkg = Package(old_package_fn, 'r') + old_pkg.read(os.path.join(ctx.config.tmp_dir(), 'oldpkg')) + if str(old_pkg.metadata.package.name) != package_name: + ctx.ui.warning('Skipping %s with wrong pkg name ' % + old_package_fn) + continue + old_build = old_pkg.metadata.package.build + found.append( (old_package_fn, old_build) ) - # find previous build in ctx.config.options.output_dir - found = [] -# for root, dirs, files in os.walk(ctx.config.options.output_dir): -# for fn in files: -# fn = fn.decode('utf-8') -# if found_package(fn): -# old_package_fn = os.path.join(root, fn) -# ctx.ui.info('(found old version %s)' % old_package_fn) -# old_pkg = Package(old_package_fn, 'r') -# old_pkg.read(os.path.join(ctx.config.tmp_dir(), 'oldpkg')) -# if str(old_pkg.metadata.package.name) != package_name: -# ctx.ui.warning('Skipping %s with wrong pkg name ' % -# old_package_fn) -# continue -# old_build = old_pkg.metadata.package.build -# found.append( (old_package_fn, old_build) ) -# -# FIXME: Following dirty lines of code just search in the output_dir and -# packages dir for previous packages. But we should find a neat way -# for this... - files = [] - for f in os.listdir(ctx.config.options.output_dir): - fp = os.path.join(ctx.config.options.output_dir, f) - if os.path.isfile(fp): - files.append(fp) + for root, dirs, files in os.walk(ctx.config.options.output_dir): + dirs = [] # don't recurse + locate_package_names(files) + for root, dirs, files in os.walk(ctx.config.packages_dir()): + locate_package_names(files) - packages_dir = ctx.config.packages_dir() - # FIXME: packages_dir() should be there! - if not os.path.exists(packages_dir): - os.makedirs(packages_dir) - for f in os.listdir(packages_dir): - fp = os.path.join(packages_dir, f) - if os.path.isfile(fp): - files.append(fp) - - for fn in files: - fn = fn.decode('utf-8') - if found_package(os.path.basename(fn)): - old_package_fn = fn - ctx.ui.info(_('(found old version %s)') % old_package_fn) - old_pkg = Package(old_package_fn, 'r') - old_pkg.read(os.path.join(ctx.config.tmp_dir(), 'oldpkg')) - if str(old_pkg.metadata.package.name) != package_name: - ctx.ui.warning(_('Skipping %s with wrong pkg name ') % - old_package_fn) - continue - old_build = old_pkg.metadata.package.build - found.append( (old_package_fn, old_build) ) if not found: return 0 ctx.ui.warning(_('(no previous build found, setting build no to 0.)')) diff --git a/pisi/util.py b/pisi/util.py index 9017b0a4..1b2d0107 100644 --- a/pisi/util.py +++ b/pisi/util.py @@ -241,13 +241,11 @@ def dir_size(dir): # installed size. Gettin a sum of all files' sizes if far from # being true. Using 'du' command (like Debian does) can be a # better solution :(. - getsize = os.path.getsize + # Not really, du calculates size on disk, this is much better -- exa + from os.path import getsize, islink, isdir, exists join = join_path - islink = os.path.islink - isdir = os.path.isdir - exist = os.path.exists - if exist(dir) and (not isdir(dir) and not islink(dir)): + if exists(dir) and (not isdir(dir) and not islink(dir)): #so, this is not a directory but file.. return getsize(dir) @@ -262,7 +260,10 @@ def copy_file(src,dest): check_dir(os.path.dirname(dest)) shutil.copyfile(src, dest) -def get_file_hashes(top, exclude_prefix=None, removePrefix=None): +# FIXME: this should be done in a much much simpler way +# as it stands, it seems to be a kludge to solve +# an unrelated problem +def get_file_hashes(top, exclude_prefix=None, remove_prefix=None): """Generator function iterates over a toplevel path and returns the (filePath, sha1Hash) tuples for all files. If excludePrefixes list is given as a parameter, function will exclude the filePaths @@ -294,8 +295,8 @@ def get_file_hashes(top, exclude_prefix=None, removePrefix=None): return def has_excluded_prefix(filename): - if exclude_prefix and removePrefix: - tempfnam = remove_prefix(removePrefix, filename) + if exclude_prefix and remove_prefix: + tempfnam = remove_prefix(remove_prefix, filename) for p in exclude_prefix: if tempfnam.startswith(p): return 1 @@ -307,7 +308,7 @@ def get_file_hashes(top, exclude_prefix=None, removePrefix=None): #yield the symlink.. #bug 373 yield (root, sha1_sum(os.readlink(root), True)) - exclude_prefix.append(remove_prefix(removePrefix, root) + "/") + exclude_prefix.append(remove_prefix(remove_prefix, root) + "/") continue #bug 397 @@ -315,7 +316,7 @@ def get_file_hashes(top, exclude_prefix=None, removePrefix=None): d = join_path(root, dir) if os.path.islink(d) and not has_excluded_prefix(d): yield (d, sha1_sum(os.readlink(d), True)) - exclude_prefix.append(remove_prefix(removePrefix, d) + "/") + exclude_prefix.append(remove_prefix(remove_prefix, d) + "/") #bug 340 if os.path.isdir(root) and not has_excluded_prefix(root): @@ -355,7 +356,7 @@ def sha1_file(filename): m.update(line) return m.hexdigest() except IOError: - raise FileError(_("Cannot calculate SHA1 hash of %s") % filename) + raise FileError(_("I/O Error: Cannot calculate SHA1 hash of %s") % filename) def sha1_data(data): """calculate sha1 hash of given data""" @@ -478,6 +479,22 @@ def clean_locks(top = '.'): def package_name(name, version, release): return name + '-' + version + '-' + release + ctx.const.package_prefix +def is_package_name(fn, package_name = None): + "check if fn is a valid filename for given package_name" + "if not given a package name, see if fn fits the package name rules" + if (package_name==None) or fn.startswith(package_name + '-'): + if fn.endswith(ctx.const.package_prefix): + # get version string, skip separator '-' + verstr = fn[len(package_name) + 1: + len(fn)-len(ctx.const.package_prefix)] + import string + for x in verstr.split('-'): + # weak rule: version components after '-' start with a digit + if x is '' or (not x[0] in string.digits): + return False + return True + return False + def env_update(): env_dir = join_path(ctx.config.dest_dir(), "/etc/env.d")