]> git.donarmstrong.com Git - neurodebian.git/blobdiff - neurodebian/dde.py
New repository setup instruction.
[neurodebian.git] / neurodebian / dde.py
old mode 100644 (file)
new mode 100755 (executable)
index 927988f..c80ab18
@@ -5,16 +5,25 @@
 import pysvn
 import json
 from debian_bundle import deb822
+
+# Lets first assure no guarding (but annoying) warnings
+import warnings
+warnings.simplefilter('ignore', FutureWarning)
+warnings.filterwarnings('ignore', 'Module debian_bundle was already imported.*', UserWarning)
+
 import apt
 from ConfigParser import SafeConfigParser
 from optparse import OptionParser, Option, OptionGroup, OptionConflictError
 import sys
 import os
+import copy
 import shutil
 import urllib2
 import urllib
 import codecs
 import subprocess
+import time
+import re
 # templating
 from jinja2 import Environment, PackageLoader
 
@@ -127,6 +136,8 @@ def add_pkgfromtaskfile(db, urls):
         for stanza in deb822.Packages.iter_paragraphs(fh):
             if stanza.has_key('Depends'):
                 pkg = stanza['Depends']
+            elif stanza.has_key('Recommends'):
+                pkg = stanza['Recommends']
             elif stanza.has_key('Suggests'):
                 pkg = stanza['Suggests']
             else:
@@ -147,7 +158,7 @@ def add_pkgfromtaskfile(db, urls):
 def get_emptydbentry():
     return {'main': {}}
 
-def import_blendstask(db, url):
+def import_blendstask(cfg, db, url):
     cache = AptListsCache()
     fh = cache.get(url)
     task_name = None
@@ -170,6 +181,8 @@ def import_blendstask(db, url):
 
         if st.has_key('Depends'):
             pkg = st['Depends']
+        elif st.has_key('Recommends'):
+            pkg = st['Recommends']
         elif st.has_key('Suggests'):
             pkg = st['Suggests']
         else:
@@ -212,7 +225,12 @@ def import_blendstask(db, url):
 
             # Publications
             if st.has_key('Published-Title'):
-                pub = {'title': st['Published-Title']}
+                title = st['Published-Title']
+                if title[-1] == '.':
+                    # trip trailing dot -- added later
+                    pub = {'title': title[:-1]}
+                else:
+                    pub = {'title': title}
                 if st.has_key('Published-Authors'):
                     pub['authors'] = st['Published-Authors']
                 if st.has_key('Published-Year'):
@@ -225,7 +243,7 @@ def import_blendstask(db, url):
                     pub['doi'] = st['Published-DOI']
                     # need at least one URL
                     if not pub.has_key('url'):
-                        pub['url'] = st['Published-DOI']
+                        pub['url'] = "http://dx.doi.org/%s" % st['Published-DOI']
 
                 db[p]['main']['publication'] = pub
 
@@ -245,6 +263,16 @@ def import_blendstask(db, url):
                 # just add this tasks name and id
                 db[p]['blends']['tasks'].append(task)
 
+            # handle pkg name aliases
+            if p in cfg.options('blend package aliases'):
+                src_entry = db[p].copy()
+                # remove original entry
+                del db[p]
+                # copy the entry into all aliases
+                for alias in cfg.get('blend package aliases', p).split():
+                    print "Aliasing %s to %s" % (p, alias)
+                    db[alias] = copy.deepcopy(src_entry)
+
     return db
 
 
@@ -385,14 +413,79 @@ def create_dir(path):
             os.mkdir(p)
 
 
-def dde_get(url):
+def dde_get(url, fail=False):
+    # enforce delay to be friendly to DDE
+    time.sleep(3)
     try:
-        return json.read(urllib2.urlopen(url+"?t=json").read())['r']
-    except (urllib2.HTTPError, StopIteration, urllib2.URLError):
-        print "NO PKG INFO AT:", url
+        data = json.read(urllib2.urlopen(url+"?t=json").read())['r']
+        print "SUCCESS:", url
+        return data
+    except urllib2.HTTPError, e:
+        print "NOINFO:", url, type(e)
+        return False
+    except urllib2.URLError, e:
+        print "URLERROR:", url, type(e)
+        if fail:
+            print "Permanant failure"
+            return False
+        print "Try again after 30 seconds..."
+        time.sleep(30)
+        return dde_get(url, fail=True)
+    except (StopIteration):
+        print "NOINFO:", url
+        return False
+    except json.ReadException, e:
+        print "UDD-DOWN?:", url, type(e)
         return False
 
 
+def nitrc_get(spec, fail=False):
+    nitrc_url = 'http://www.nitrc.org/export/site/projects.json.php'
+    try:
+        # change into this from python 2.6 on
+        #data = json.loads(urllib2.urlopen(nitrc_url + '?spec=%s' % spec).read())
+        data = json.read(urllib2.urlopen(nitrc_url + '?spec=%s' % spec).read())
+        print "NITRC-SUCCESS:", spec
+    except urllib2.HTTPError, e:
+        print "NITRC-NOINFO:", spec, type(e)
+        return False
+    except urllib2.URLError, e:
+        print "NITRC-URLERROR:", spec, type(e)
+        if fail:
+            print "Permanant failure"
+            return False
+        print "Try again after 30 seconds..."
+        time.sleep(30)
+        return nitrc_get(spec, fail=True)
+    return data
+
+
+def parse_nitrc(data):
+    if data is False:
+        return None
+    # simplify -- there is only one project in the data
+    project = data['projects'][0]
+    nitrc_filtered = {'downloads': 0,
+                      'id': project['id']}
+    for pkg in project['packages']:
+        for release in pkg['releases']:
+            for file in release['files']:
+                nitrc_filtered['downloads'] += file['download_count']
+    return nitrc_filtered
+
+
+def import_nitrc(cfg, db):
+    for p in db.keys():
+        if not cfg.has_option("nitrc ids", p):
+            continue
+        nitrc_spec = cfg.get("nitrc ids", p)
+        nitrc_data = nitrc_get(nitrc_spec)
+        nitrc_excerpt = parse_nitrc(nitrc_data)
+        if not nitrc_excerpt is None:
+            db[p]['nitrc'] = nitrc_excerpt
+    return db
+
+
 def import_dde(cfg, db):
     query_url = cfg.get('dde', 'pkgquery_url')
     for p in db.keys():
@@ -417,7 +510,7 @@ def import_dde(cfg, db):
                 if q.has_key('popcon'):
                     db[p]['main']['debian_popcon'] = q['popcon']
                 # if we have debian, need to get ubuntu
-                q = dde_get(query_url + "/packages/prio-ubuntu-karmic/%s" % p)
+                q = dde_get(query_url + "/packages/prio-ubuntu-natty/%s" % p)
                 if q and q.has_key('popcon'):
                     db[p]['main']['ubuntu_popcon'] = q['popcon']
             else:
@@ -459,6 +552,24 @@ def import_dde(cfg, db):
 
     return db
 
+def assure_unicode(s):
+    """Assure that argument is unicode
+
+    Necessary if strings are not carrying out Pythonish 'u' prefix to
+    signal UTF8 strings, but are in fact UTF8
+    """
+    if type(s) is unicode:
+        return s
+    elif type(s) is str:
+        # attempt regular unicode call and if fails -- just decode it
+        # into utf8
+        try:
+            return unicode(s)
+        except UnicodeDecodeError, e:
+            return s.decode('utf8')
+    else:
+        return assure_unicode(str(s))
+
 
 def convert_longdescr(ld):
     ld = ld.replace('% ', '%% ')
@@ -474,10 +585,13 @@ def convert_longdescr(ld):
     ld = ld.replace('#NEWLINEMARKER# ', '\n\n')
     # cleanup any leftover (e.g. trailing markers)
     ld = ld.replace('#NEWLINEMARKER#', '')
+    # safe-guard ReST active symbols
+    ld = re.sub(r'([\'`*])', r'\\\1', ld)
     return ld
 
 
-def generate_pkgpage(pkg, cfg, db, template, addenum_dir):
+def generate_pkgpage(pkg, cfg, db, template, addenum_dir, extracts_dir):
+    print pkg
     # local binding for ease of use
     pkgdb = db[pkg]
     # do nothing if there is not at least the very basic stuff
@@ -487,13 +601,21 @@ def generate_pkgpage(pkg, cfg, db, template, addenum_dir):
     underline = '*' * (len(title) + 2)
     title = '%s\n %s\n%s' % (underline, title, underline)
 
+    ex_dir = None
+    if 'sv' in pkgdb['main']:
+        ex_dir = os.path.join(extracts_dir, pkgdb['main']['sv'].split()[0])
+        if not os.path.exists(ex_dir):
+            ex_dir = None
     page = template.render(
             pkg=pkg,
             title=title,
-            long_description=convert_longdescr(pkgdb['main']['long_description']),
+            long_description=convert_longdescr(
+                assure_unicode(pkgdb['main']['long_description'])),
             cfg=cfg,
             db=pkgdb,
-            fulldb=db)
+            fulldb=db,
+            extracts_dir=ex_dir,
+            op=os.path)
     # the following can be replaced by something like
     # {% include "sidebar.html" ignore missing %}
     # in the template whenever jinja 2.2 becomes available
@@ -517,42 +639,69 @@ def read_db(filename):
 
 def write_sourceslist(jinja_env, cfg, outdir):
     create_dir(outdir)
-    create_dir(os.path.join(outdir, '_static'))
+    create_dir(os.path.join(outdir, 'lists'))
 
     repos = {}
     for release in cfg.options('release codenames'):
+        if release == 'data':
+            # no seperate list for the data archive
+            continue
         transrel = trans_codename(release, cfg)
         repos[transrel] = []
         for mirror in cfg.options('mirrors'):
-            listname = 'neurodebian.%s.%s.sources.list' % (release, mirror)
+            listname = '%s.%s' % (release, mirror)
             repos[transrel].append((mirror, listname))
-            lf = open(os.path.join(outdir, '_static', listname), 'w')
-            aptcfg = '%s %s main contrib non-free\n' % (cfg.get('mirrors', mirror),
-                                                      release)
-            lf.write('deb %s' % aptcfg)
-            lf.write('deb-src %s' % aptcfg)
+            lf = open(os.path.join(outdir, 'lists', listname), 'w')
+            for rel in ('data', release):
+                aptcfg = '%s %s main contrib non-free\n' % (cfg.get('mirrors', mirror),
+                                                          rel)
+                lf.write('deb %s' % aptcfg)
+                lf.write('#deb-src %s' % aptcfg)
             lf.close()
 
+    id2codename = dict([(cfg.get('release backport ids', r), r)
+                            for r in cfg.options('release codenames')])
+    id2relname = dict([(cfg.get('release backport ids', r), trans_codename(r, cfg))
+                            for r in cfg.options('release codenames')])
+    mirror2name = dict([(m, cfg.get('mirror names', m))
+                            for m in cfg.options('mirrors')])
+    mirror2url = dict([(m, cfg.get('mirrors', m))
+                            for m in cfg.options('mirrors')])
     srclist_template = jinja_env.get_template('sources_lists.rst')
     sl = open(os.path.join(outdir, 'sources_lists'), 'w')
-    sl.write(srclist_template.render(repos=repos))
+    sl.write(srclist_template.render(id2codename=id2codename,
+                                     id2relname=id2relname,
+                                     mirror2name=mirror2name,
+                                     mirror2url=mirror2url))
     sl.close()
 
 
-def write_pkgpages(jinja_env, cfg, db, outdir, addenum_dir):
+def write_pkgpages(jinja_env, cfg, db, outdir, addenum_dir, extracts_dir):
     create_dir(outdir)
     create_dir(os.path.join(outdir, 'pkgs'))
 
     # generate the TOC with all packages
     toc_template = jinja_env.get_template('pkgs_toc.rst')
     toc = codecs.open(os.path.join(outdir, 'pkgs.rst'), 'w', 'utf-8')
-    toc.write(toc_template.render(pkgs=db.keys()))
+    # this is a fragile test
+    toc.write(toc_template.render(
+        pkgs=[k for k in db.keys()
+                if not ('Datasets (data)', 'neurodebian-data') in db[k]]))
+    toc.close()
+    # and now only for dataset packages
+    toc_template = jinja_env.get_template('datasets_toc.rst')
+    toc = codecs.open(os.path.join(outdir, 'datasets.rst'), 'w', 'utf-8')
+    # this is a fragile test
+    toc.write(toc_template.render(
+        pkgs=[k for k in db.keys()
+                if ('Datasets (data)', 'neurodebian-data') in db[k]]))
     toc.close()
 
+
     # and now each individual package page
     pkg_template = jinja_env.get_template('pkg.rst')
     for p in db.keys():
-        page = generate_pkgpage(p, cfg, db, pkg_template, addenum_dir)
+        page = generate_pkgpage(p, cfg, db, pkg_template, addenum_dir, extracts_dir)
         # when no page is available skip this package
         if page is None:
             continue
@@ -587,6 +736,9 @@ def prepOptParser(op):
     op.add_option("--pkgaddenum", action="store", dest="addenum_dir",
                   type="string", default=None, help="None")
 
+    op.add_option("--extracts", action="store", dest="extracts_dir",
+                  type="string", default=None, help="None")
+
 
 def main():
     op = OptionParser(version="%prog 0.0.2")
@@ -627,7 +779,7 @@ def main():
         # get info from task files
         if cfg.has_option('packages', 'prospective'):
             for url in cfg.get('packages', 'prospective').split():
-                db = import_blendstask(db, url)
+                db = import_blendstask(cfg, db, url)
 
         # parse NeuroDebian repository
         if cfg.has_option('neurodebian', 'releases'):
@@ -636,6 +788,8 @@ def main():
 
         # collect package information from DDE
         db = import_dde(cfg, db)
+        # get info from NITRC
+        db = import_nitrc(cfg, db)
         # store the new DB
         store_db(db, opts.db)
         # and be done
@@ -648,7 +802,7 @@ def main():
     jinja_env = Environment(loader=PackageLoader('neurodebian', 'templates'))
 
     # generate package pages and TOC and write them to files
-    write_pkgpages(jinja_env, cfg, db, opts.outdir, opts.addenum_dir)
+    write_pkgpages(jinja_env, cfg, db, opts.outdir, opts.addenum_dir, opts.extracts_dir)
 
     write_sourceslist(jinja_env, cfg, opts.outdir)