]> git.donarmstrong.com Git - neurodebian.git/blobdiff - tools/blends-inject
Also for stats report which repo and which job number use our setup
[neurodebian.git] / tools / blends-inject
index 11f7572ed6e2ac2753aa8d510b0e03a47109a217..d62d3ba7dee23e06f5228b3fa5d6123479e58f11 100755 (executable)
@@ -19,7 +19,7 @@ Possible TODOs:
 * 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
 * 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
 
   This should be taken into consideration if current per-package
   handling gets changed
 
@@ -33,14 +33,24 @@ Paths to the blends top directories, containing tasks directories are
 specified in ~/.blends-inject.cfg file, e.g.::
 
  [debian-med]
 specified in ~/.blends-inject.cfg file, e.g.::
 
  [debian-med]
- path = /home/yoh/deb/debian-med/
+ path = ~/deb/debian-med/
 
  [debian-science]
 
  [debian-science]
- path = /home/yoh/deb/debian-science/
-
+ path = ~/deb/debian-science/
 
 Definition of the fields for task files by default are looked up
 
 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
 -----------------------
 
 Format of debian/blends
 -----------------------
@@ -85,7 +95,7 @@ Published-Year: 2008
 Published-DOI: 10.3389/neuro.11.005.2008
 
  ; May be some previous entry should be removed, thus say so
 Published-DOI: 10.3389/neuro.11.005.2008
 
  ; May be some previous entry should be removed, thus say so
-Removed: python-brian-doc
+Remove: python-brian-doc
 
  ;Tasks: debian-med/imaging-dev
  ;Why: Allows interactive development/scripting
 
  ;Tasks: debian-med/imaging-dev
  ;Why: Allows interactive development/scripting
@@ -104,7 +114,7 @@ Removed: python-brian-doc
 """
 
 
 """
 
 
-import re, os, sys
+import re, os, sys, tempfile, glob
 from os.path import join, exists, expanduser, dirname, basename
 
 from ConfigParser import ConfigParser
 from os.path import join, exists, expanduser, dirname, basename
 
 from ConfigParser import ConfigParser
@@ -125,28 +135,37 @@ def open(f, *args):
 
 __author__ = 'Yaroslav Halchenko'
 __prog__ = os.path.basename(sys.argv[0])
 
 __author__ = 'Yaroslav Halchenko'
 __prog__ = os.path.basename(sys.argv[0])
-__version__ = '0.0.2'
+__version__ = '0.0.7'
 __copyright__ = 'Copyright (c) 2010 Yaroslav Halchenko'
 __license__ = 'GPL'
 
 # What fields initiate new package description
 __copyright__ = 'Copyright (c) 2010 Yaroslav Halchenko'
 __license__ = 'GPL'
 
 # What fields initiate new package description
-PKG_FIELDS = ('depends', 'recommends', 'suggests', 'ignore', 'removed')
+PKG_FIELDS = ('depends', 'recommends', 'suggests', 'ignore', 'remove')
 
 # We might need to resort to assure some what a canonical order
 
 # We might need to resort to assure some what a canonical order
-FIELDS_ORDER = ('depends', 'recommends', 'suggests', 'ignore',
-                'homepage', 'language', 'wnpp', 'responsible', 'license',
+# Prefixes for "standard" blends/tasks fields.  Others do not get embedded
+# into tasks files
+BLENDS_FIELDS_PREFIXES = ('depends', 'recommends', 'suggests', 'ignore',
+                'why', 'homepage', 'language', 'wnpp', 'responsible', 'license',
                 'vcs-', 'pkg-url', 'pkg-description',
                 'published-', 'x-', 'registration', 'remark')
                 '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', 'pkg-name', 'pkg-source',
+                          'version', 'remove')
+# Other fields should cause Error for consistency
+
+FIELDS_ORDER = BLENDS_FIELDS_PREFIXES + CUSTOM_FIELDS_PREFIXES
 
 verbosity = None
 
 
 verbosity = None
 
-def error(msg, exit_code):
+def error(msg, exit_code=1):
     sys.stderr.write(msg + '\n')
     sys.exit(exit_code)
 
 def verbose(level, msg):
     if level <= verbosity:
     sys.stderr.write(msg + '\n')
     sys.exit(exit_code)
 
 def verbose(level, msg):
     if level <= verbosity:
-        print " "*level, msg
+        sys.stderr.write(" "*level + msg + '\n')
 
 
 def parse_debian_blends(f='debian/blends'):
 
 
 def parse_debian_blends(f='debian/blends'):
@@ -176,7 +195,9 @@ def parse_debian_blends(f='debian/blends'):
             pkg = deepcopy(prev_pkg)
             for k_ in PKG_FIELDS:   # prune older depends
                 pkg.pop(k_, None)
             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 )
         pkg['Pkg-Source'] = sname
         pkgs.append(pkg)
         pkg.tasks = dict( (t.strip(), deb822.Deb822Dict()) for t in tasks )
@@ -186,6 +207,7 @@ def parse_debian_blends(f='debian/blends'):
     for k, v in items:
 
         kl = k.lower()
     for k, v in items:
 
         kl = k.lower()
+
         if kl == 'source':
             source = v.strip()
         elif kl == 'format':
         if kl == 'source':
             source = v.strip()
         elif kl == 'format':
@@ -194,24 +216,26 @@ def parse_debian_blends(f='debian/blends'):
             if format_clean:
                 format_ = format_[:-6]
         elif kl == 'tasks':
             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
                                             # 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:
                 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 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)
-                    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:
                 # Add customization
                 for t in tasks:
                     if not t in pkg.tasks:
@@ -220,6 +244,7 @@ def parse_debian_blends(f='debian/blends'):
             else:
                 # just store the key in the pkg itself
                 pkg[k] = v
             else:
                 # just store the key in the pkg itself
                 pkg[k] = v
+
     return pkgs
 
 
     return pkgs
 
 
@@ -229,6 +254,7 @@ def expand_pkgs(pkgs, topdir='.'):
     """
     verbose(4, "Expanding content for %d packages" % len(pkgs))
     debianm = None
     """
     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':
     # Expand packages which format is extended
     for pkg in pkgs:
         if pkg.format == 'extended':
@@ -240,7 +266,9 @@ def expand_pkgs(pkgs, topdir='.'):
                          ('Pkg-Description',
                           lambda: debianm.get_description(pkg['Pkg-Name'])),
                          ('Responsible', debianm.get_responsible),
                          ('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()
                 if pkg.get(k, None):
                     continue
                 v = m()
@@ -249,7 +277,24 @@ def expand_pkgs(pkgs, topdir='.'):
             # VCS fields
             pkg.update(debianm.get_vcsfields())
 
             # VCS fields
             pkg.update(debianm.get_vcsfields())
 
-def key_prefix_compare(x, y, order, strict=False, case=False):
+
+def prefix_index(x, entries, strict=True, case=False, default=10000):
+    """Returns an index for the x in entries
+    """
+    if not case:
+        x = x.lower()
+    for i, v in enumerate(entries):
+        if x.startswith(v):
+            return i
+
+    if strict:
+        raise IndexError(
+            "Could not find location for %s as specified by %s" %
+            (x, entries))
+    return default
+
+
+def key_prefix_compare(x, y, order, strict=True, case=False):
     """Little helper to help with sorting
 
     Sorts according to the order of string prefixes as given by
     """Little helper to help with sorting
 
     Sorts according to the order of string prefixes as given by
@@ -260,22 +305,8 @@ def key_prefix_compare(x, y, order, strict=False, case=False):
     if not case:
         order = [v.lower() for v in order]
 
     if not case:
         order = [v.lower() for v in order]
 
-    def prefix_index(t, order, strict=True, case=False):
-        x = t[0]
-        if not case:
-            x = x.lower()
-        for i, v in enumerate(order):
-            if x.startswith(v):
-                return i
-
-        if strict:
-            raise IndexError(
-                "Could not find location for %s as specified by %s" %
-                (x, order))
-        return 10000                    #  some large number ;)
-
-    cmp_res =  cmp(prefix_index(x, order, strict, case),
-                   prefix_index(y, order, strict, case))
+    cmp_res =  cmp(prefix_index(x[0], order, strict, case),
+                   prefix_index(y[0], order, strict, case))
     if not cmp_res:                     # still unknown
         return cmp(x, y)
     return cmp_res
     if not cmp_res:                     # still unknown
         return cmp(x, y)
     return cmp_res
@@ -311,7 +342,12 @@ def group_packages_into_tasks(pkgs):
 
             # Move Pkg-source/name into attributes
             pkg__.source = pkg__.pop('Pkg-Source')
 
             # Move Pkg-source/name into attributes
             pkg__.source = pkg__.pop('Pkg-Source')
-            pkg__.name = pkg__.pop('Pkg-name')
+            pkg__.name = pkg__.pop('Pkg-Name')
+            # Store the action taken on the package for later on actions
+            for f in PKG_FIELDS:
+                if f in pkg__:
+                    pkg__.action = f
+                    break
 
             tasks[task] = tasks.get(task, []) + [pkg__]
     verbose(4, "Grouped %d packages into %d tasks: %s" %
 
             tasks[task] = tasks.get(task, []) + [pkg__]
     verbose(4, "Grouped %d packages into %d tasks: %s" %
@@ -323,23 +359,36 @@ def inject_tasks(tasks, config):
     for task, pkgs in tasks.iteritems():
         verbose(2, "Task %s with %d packages" % (task, len(pkgs)))
         blend, puretask = task.split('/')
     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=[])
         for pkg in pkgs:
             msgs = {'Name': pkg.name.strip(), 'Action': None}
 
         # Load the file
         stats = dict(Added=[], Modified=[])
         for pkg in pkgs:
             msgs = {'Name': pkg.name.strip(), 'Action': None}
+
+            # Create a copy of the pkg with only valid tasks
+            # fields:
+            # TODO: make it configurable?
+            pkg = deepcopy(pkg)
+            for k in pkg:
+                if prefix_index(k, BLENDS_FIELDS_PREFIXES,
+                                strict=False, default=None) is None:
+                    pkg.pop(k) # remove it from becoming present in
+                               # the taskfile
+
             # Find either it is known to the task file already
 
             # Load entirely so we could simply manipulate
             entries = open(taskfile).readlines()
             known = False
             # We need to search by name and by source
             # Find either it is known to the task file already
 
             # Load entirely so we could simply manipulate
             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" %
             for istart, e in enumerate(entries):
                 if regexp.search(e):
                     verbose(4, "Found %s in position %i: %s" %
@@ -349,7 +398,9 @@ def inject_tasks(tasks, config):
 
             descr = ' ; Added by %s %s. [Please note here if modified manually]\n' % \
                     (__prog__,  __version__)
 
             descr = ' ; Added by %s %s. [Please note here if modified manually]\n' % \
                     (__prog__,  __version__)
-            # Replace existing entry
+
+            entry = pkg.dump()
+            # Replace existing entry?
             if known:
                 # TODO: Check if previous copy does not have our preceding comment
                 # Find the previous end
             if known:
                 # TODO: Check if previous copy does not have our preceding comment
                 # Find the previous end
@@ -362,33 +413,53 @@ def inject_tasks(tasks, config):
 
                 # Lets not change file without necessity, if entry is identical --
                 # do nothing
 
                 # Lets not change file without necessity, if entry is identical --
                 # do nothing
-                entry = pkg.dump()
                 old_entry = entries[istart:istart+icount]
 
                 if u''.join(old_entry) == entry:
                 old_entry = entries[istart:istart+icount]
 
                 if u''.join(old_entry) == entry:
-                   pass
+                    # no changes -- just go to the next one
+                    continue
                 else: # Rewrite the entry
                    if __prog__ in entries[istart-1]:
                        istart -= 1
                        icount += 2
                 else: # Rewrite the entry
                    if __prog__ in entries[istart-1]:
                        istart -= 1
                        icount += 2
-                   if not 'Removed' in pkg.keys():
-                       entries = entries[:istart] + [descr + entry] + entries[istart+icount:]
+                   if 'remove' != pkg.action:
+                       entry = descr + entry
                        msgs['Action'] = 'Changed'
                    else:
                        while entries[istart-1].strip() == '':
                            istart -=1
                            icount +=2
                        msgs['Action'] = 'Changed'
                    else:
                        while entries[istart-1].strip() == '':
                            istart -=1
                            icount +=2
-                       entries = entries[:istart] + entries[istart+icount:]
+                       entry = ''
                        msgs['Action'] = 'Removed'
                        msgs['Action'] = 'Removed'
-                   output = ''.join(entries)         # 'compute' first
-                   open(taskfile, 'w').write(output) # then only overwrite
-            elif not 'removed' in pkg:  # or Append one
+                   entries_prior = entries[:istart]
+                   entries_post = entries[istart+icount:]
+            elif not 'remove' == pkg.action:  # or Append one
                 msgs['Action'] = 'Added'
                 msgs['Action'] = 'Added'
+                entries_prior = entries
+                entry = descr + entry
+                entries_post = []
                 # could be as simple as
                 # could be as simple as
-                output = '\n%s%s' % (descr, pkg.dump(),)
-                open(taskfile, 'a').write(output)
+                # Lets do 'in full' for consistent handling of empty lines
+                # around
+                #output = '\n%s%s' % (descr, pkg.dump(),)
+                #open(taskfile, 'a').write(output)
 
             if msgs['Action']:
 
             if msgs['Action']:
+                # Prepare for dumping
+                # Prune spaces before
+                while len(entries_prior) and entries_prior[-1].strip() == '':
+                    entries_prior = entries_prior[:-1]
+                if len(entries_prior) and not entries_prior[-1].endswith('\n'):
+                    entries_prior[-1] += '\n' # assure present trailing newline
+                # Prune spaces after
+                while len(entries_post) and entries_post[0].strip() == '':
+                    entries_post = entries_post[1:]
+                if len(entries_post) and len(entry):
+                    # only then trailing empty line
+                    entry += '\n'
+                output = ''.join(entries_prior + [ '\n' + entry ] + entries_post)
+                open(taskfile, 'w').write(output) # then only overwrite
+
                 verbose(3, "%(Action)s %(Name)s" % msgs)
 
 
                 verbose(3, "%(Action)s %(Name)s" % msgs)
 
 
@@ -432,7 +503,9 @@ class DebianMaterials(object):
             if v.get('Source', None):
                 self._source = v
             else:
             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
 
     def get_license(self, package=None, first_only=True):
         """Return a license(s). Parsed out from debian/copyright if it is
@@ -501,6 +574,57 @@ class DebianMaterials(object):
                   % (pkg_name, self))
         return self.binaries[pkg_name]['Description']
 
                   % (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(
 def main():
 
     p = OptionParser(
@@ -523,21 +647,53 @@ def main():
         Option("-v", "--verbosity", action="store", type="int",
                dest="verbosity", default=1, help="Noise level."))
 
         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
 
     (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
 
     # Load configuration
-    config = ConfigParser()
+    config = ConfigParser(defaults={'skip': '.*[~#]$'})
     config.read(options.config_file)
 
     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)
     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'):
         pkgs = parse_debian_blends(blends_file)
         if options.topdir is None:
             if dirname(blends_file).endswith('/debian'):
@@ -546,9 +702,19 @@ def main():
                 topdir = '.'            # and hope for the best ;)
         else:
             topdir = options.topdir
                 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__':
 
 
 if __name__ == '__main__':