* For every package the same task file might be re-read/written (if
entry changed/added) from disk.
That allows to replace easily original entry for 'source' package
- (listed as Ignore:) with actual first listed binary package.
+ (listed as Suggests:) with actual first listed binary package.
This should be taken into consideration if current per-package
handling gets changed
specified in ~/.blends-inject.cfg file, e.g.::
[debian-med]
- path = /home/yoh/deb/debian-med/
+ path = ~/deb/debian-med/
[debian-science]
- path = /home/yoh/deb/debian-science/
-
+ path = ~/deb/debian-science/
Definition of the fields for task files by default are looked up
-within debian/blends, or files provided in the command line.
+within debian/blends, or files provided in the command line. Also for "-a"
+mode of operation you should define list of globs to match your debian/blends
+files::
+
+ [paths]
+ all=~/deb/gits/pkg-exppsy/neurodebian/future/blends/*
+ ~/deb/gits/*/debian/blends
+ ~/deb/gits/pkg-exppsy/*/debian/blends
+ # Python regular expression on which files to skip
+ # Default is listed below
+ #skip=.*[~#]$
+
Format of debian/blends
-----------------------
"""
-import re, os, sys
+import re, os, sys, tempfile, glob
from os.path import join, exists, expanduser, dirname, basename
from ConfigParser import ConfigParser
__author__ = 'Yaroslav Halchenko'
__prog__ = os.path.basename(sys.argv[0])
-__version__ = '0.0.3'
+__version__ = '0.0.7'
__copyright__ = 'Copyright (c) 2010 Yaroslav Halchenko'
__license__ = 'GPL'
# Prefixes for "standard" blends/tasks fields. Others do not get embedded
# into tasks files
BLENDS_FIELDS_PREFIXES = ('depends', 'recommends', 'suggests', 'ignore',
- 'why', 'homepage', 'wnpp', 'responsible', 'license',
+ 'why', 'homepage', 'language', 'wnpp', 'responsible', 'license',
'vcs-', 'pkg-url', 'pkg-description',
'published-', 'x-', 'registration', 'remark')
# Additional fields which might come useful (e.g. for filing wnpp bugs)
# but are not "standard" thus should be in the trailer
-CUSTOM_FIELDS_PREFIXES = ('author', 'language', 'pkg-name', 'pkg-source',
+CUSTOM_FIELDS_PREFIXES = ('author', 'pkg-name', 'pkg-source',
'version', 'remove')
# Other fields should cause Error for consistency
def verbose(level, msg):
if level <= verbosity:
- print " "*level, msg
+ sys.stderr.write(" "*level + msg + '\n')
def parse_debian_blends(f='debian/blends'):
pkg = deepcopy(prev_pkg)
for k_ in PKG_FIELDS: # prune older depends
pkg.pop(k_, None)
- pkg['Pkg-Name'] = pkg[k] = bname
+ pkg['Pkg-Name'] = pkg[k] = bname.lower()
+ if sname is not None:
+ sname = sname.lower()
pkg['Pkg-Source'] = sname
pkgs.append(pkg)
pkg.tasks = dict( (t.strip(), deb822.Deb822Dict()) for t in tasks )
for k, v in items:
kl = k.lower()
+
if kl == 'source':
source = v.strip()
elif kl == 'format':
if format_clean:
format_ = format_[:-6]
elif kl == 'tasks':
- tasks = v.split(',')
- newtasks = True # either we need to provide tune-ups
+ tasks = [x.strip() for x in v.split(',')]
+ newtasks = pkg is not None # either we need to provide tune-ups
# for current package
elif kl in PKG_FIELDS: # new package
- if source is None:
+ if source is None and not format_ in ['extended']:
source = v
pkg = new_pkg(pkg, v, source, tasks)
newtasks = False
else:
+ if pkg is None:
+ # So we had just source?
+ if source is None:
+ error("No package or source is known where to add %s" % (k,), 1)
+ # TODO: just deduce source from DebianMaterials
+ pkg = new_pkg(pkg, source, source, tasks)
+ # Since only source is available, it should be only Suggest:-ed
+ pkg['Suggests'] = source.lower()
+ newtasks = False
+
if newtasks:
- if pkg is None:
- # So we had just source?
- if source is None:
- error("No package or source is known where to add %s" % (k,), 1)
- # TODO: just deduce source from DebianMaterials
- pkg = new_pkg(pkg, source, source, tasks)
- # Since only source is available, it should be Ignore:-ed
- pkg['Ignore'] = source
- newtasks = False
# Add customization
for t in tasks:
if not t in pkg.tasks:
else:
# just store the key in the pkg itself
pkg[k] = v
+
return pkgs
"""
verbose(4, "Expanding content for %d packages" % len(pkgs))
debianm = None
+
# Expand packages which format is extended
for pkg in pkgs:
if pkg.format == 'extended':
('Pkg-Description',
lambda: debianm.get_description(pkg['Pkg-Name'])),
('Responsible', debianm.get_responsible),
- ('Homepage', lambda: debianm.source.get('Homepage', None))):
+ ('Homepage', lambda: debianm.source.get('Homepage', None)),
+ ('Pkg-source', lambda: debianm.source.get('Source', None)),
+ ):
if pkg.get(k, None):
continue
v = m()
for task, pkgs in tasks.iteritems():
verbose(2, "Task %s with %d packages" % (task, len(pkgs)))
blend, puretask = task.split('/')
- taskfile = join(config.get(blend, 'path'), 'tasks', puretask)
+ taskfile = expanduser(join(config.get(blend, 'path'), 'tasks', puretask))
# Load the file
stats = dict(Added=[], Modified=[])
entries = open(taskfile).readlines()
known = False
# We need to search by name and by source
- # We need to search for every possible type of dependecy
- regexp = re.compile('^ *(%s) *: *(%s) *$' %
- ('|'.join(PKG_FIELDS),
- '|'.join((pkg.name, pkg.source))),
- re.I)
+ # We need to search for every possible type of dependency
+ regexp_str = '^ *(%s) *: *(%s) *$' \
+ % ('|'.join(PKG_FIELDS),
+ '|'.join((pkg.name, pkg.source)).replace('+', '\+'))
+ verbose(4, "Searching for presence in %s using regexp: '%s'"
+ % (taskfile, regexp_str))
+ regexp = re.compile(regexp_str, re.I)
for istart, e in enumerate(entries):
if regexp.search(e):
verbose(4, "Found %s in position %i: %s" %
entries_prior = entries[:istart]
entries_post = entries[istart+icount:]
elif not 'remove' == pkg.action: # or Append one
- if pkg.name == 'python-brian-doc':
- import pydb
- pydb.debugger()
msgs['Action'] = 'Added'
entries_prior = entries
entry = descr + entry
if v.get('Source', None):
self._source = v
else:
- self._binaries[v['Package']] = v
+ # Since it might be hash-commented out
+ if 'Package' in v:
+ self._binaries[v['Package']] = v
def get_license(self, package=None, first_only=True):
"""Return a license(s). Parsed out from debian/copyright if it is
% (pkg_name, self))
return self.binaries[pkg_name]['Description']
+def print_wnpp(pkgs, config, wnpp_type="ITP"):
+ """Little helper to spit out formatted entry for WNPP bugreport
+
+ TODO: It would puke atm if any field is missing
+ """
+
+ pkg = pkgs[0] # everything is based on the 1st one
+ opts = dict(pkg.items())
+ opts['WNPP-Type'] = wnpp_type.upper()
+ opts['Pkg-Description-Short'] = re.sub('\n.*', '', pkg['Pkg-Description'])
+
+ subject = "%(WNPP-Type)s: %(Pkg-Name)s -- %(Pkg-Description-Short)s" % opts
+ body = """*** Please type your report below this line ***
+
+* Package name : %(Pkg-Name)s
+ Version : %(Version)s
+ Upstream Author : %(Author)s
+* URL : %(Homepage)s
+* License : %(License)s
+ Programming Lang: %(Language)s
+ Description : %(Pkg-Description)s
+
+""" % opts
+
+ # Unfortunately could not figure out how to set the owner, so I will just print it out
+ if False:
+ tmpfile = tempfile.NamedTemporaryFile()
+ tmpfile.write(body)
+ tmpfile.flush()
+ cmd = "reportbug -b --paranoid --subject='%s' --severity=wishlist --body-file='%s' -o /tmp/o.txt wnpp" \
+ % (subject, tmpfile.name)
+ verbose(2, "Running %s" %cmd)
+ os.system(cmd)
+ else:
+ print "Subject: %s\n\n%s" % (subject, body)
+
+
+def is_template(p):
+ """Helper to return true if pkg definition looks like a template
+ and should not be processed
+ """
+ # We might want to skip some which define a skeleton
+ # (no source/homepage/etc although fields are there)
+ for f in ['vcs-browser', 'pkg-url', 'pkg-description',
+ 'published-Title', 'pkg-name', 'homepage',
+ 'author']:
+ if f in p and p[f] != "":
+ return False
+ return True
+
+
def main():
p = OptionParser(
Option("-v", "--verbosity", action="store", type="int",
dest="verbosity", default=1, help="Noise level."))
+ # We might like to create a separate 'group' of options for commands
+ p.add_option(
+ Option("-w", action="store_true",
+ dest="wnpp", default=False,
+ help="Operate in WNPP mode: dumps cut-paste-able entry for WNPP bugreport"))
+
+ p.add_option(
+ Option("--wnpp", action="store",
+ dest="wnpp_mode", default=None,
+ help="Operate in WNPP mode: dumps cut-paste-able entry for WNPP bugreport"))
+
+ p.add_option(
+ Option("-a", action="store_true",
+ dest="all_mode", default=False,
+ help="Process all files listed in paths.all"))
+
+
(options, infiles) = p.parse_args()
global verbosity; verbosity = options.verbosity
- if not len(infiles):
- infiles = [join(options.topdir or './', 'debian/blends')] # default one
+ if options.wnpp and options.wnpp_mode is None:
+ options.wnpp_mode = 'ITP'
# Load configuration
- config = ConfigParser()
+ config = ConfigParser(defaults={'skip': '.*[~#]$'})
config.read(options.config_file)
+ if options.all_mode:
+ if len(infiles):
+ raise ValueError("Do not specify any files in -a mode. Use configuration file, section paths, option all")
+ globs = config.get('paths', 'all', None).split()
+ infiles = reduce(list.__add__, (glob.glob(expanduser(f)) for f in globs))
+ verbose(1, "Found %d files in specified paths" % len(infiles))
+
+ if not len(infiles):
+ infiles = [join(options.topdir or './', 'debian/blends')] # default one
+
+ skip_re = re.compile(config.get('paths', 'skip', None))
+
for blends_file in infiles:
verbose(1, "Processing %s" % blends_file)
if not exists(blends_file):
error("Cannot find a file %s. Either provide a file or specify top "
"debian directory with -d." % blends_file, 1)
+ if skip_re.match(blends_file):
+ verbose(2, "W: Skipped since matches paths.skip regexp")
+ continue
pkgs = parse_debian_blends(blends_file)
if options.topdir is None:
if dirname(blends_file).endswith('/debian'):
topdir = '.' # and hope for the best ;)
else:
topdir = options.topdir
- expand_pkgs(pkgs, topdir=topdir)
- tasks = group_packages_into_tasks(pkgs)
- inject_tasks(tasks, config)
+
+ expand_pkgs(pkgs, topdir=topdir)
+
+ pkgs = [p for p in pkgs if not is_template(p)]
+ if not len(pkgs):
+ verbose(2, "W: Skipping since seems to contain templates only")
+ continue
+ if options.wnpp_mode is not None:
+ print_wnpp(pkgs, config, options.wnpp_mode)
+ else:
+ # by default -- operate on blends/tasks files
+ tasks = group_packages_into_tasks(pkgs)
+ inject_tasks(tasks, config)
if __name__ == '__main__':