Package: apt-file
Severity: wishlist

Hello,

Following our IRC conversation of a couple of months ago, I have created
a prototype "rapt-file" that works like apt-file, but queries a remote
index at dde.debian.net.  The prototype is attached to this mail.

rapt-file has the same command line interface of apt-file.

These options are ignored because they make no sense with rapt-file:
  -c / --cache
  -d / --cdrom-mount
  -y / --dummy
  -N / --non-interactive

These options cannot be made to work with the current index:
  -x / --regexp
  -i / --ignore-case

"--fixed-strings" is currently the default.  Partial patterns can be
implemented, but only partially: "bin/foo*" can be implemented, and so
can "*/bin/foo", but "*bin/foo" cannot.  The xapian index can already do
this, but I need to implement an interface to expose this in DDE.

The prototype is in python because I'm faster writing python these days;
however it can easily be ported to perl if needed.  The only
python-specific bit in the prototype is the serialisation via pickle,
but it can be simply be replaced with "csv".

What do you think we can do with this?


Ciao,

Enrico

-- System Information:
Debian Release: squeeze/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.26-1-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages apt-file depends on:
ii  curl                          7.18.2-8   Get a file from an HTTP, HTTPS or 
ii  libapt-pkg-perl               0.1.22+b1  Perl interface to libapt-pkg
pn  libconfig-file-perl           <none>     (no description available)
ii  liblist-moreutils-perl        0.22-1+b1  Addition list functions not found 
ii  perl                          5.10.0-19  Larry Wall's Practical Extraction 
ii  wget                          1.11.4-2   retrieves files from the web

Versions of packages apt-file recommends:
ii  menu                          2.1.41     generates programs menu for all me

Versions of packages apt-file suggests:
ii  openssh-client                1:5.1p1-5  secure shell client, an rlogin/rsh
ii  sudo                          1.6.9p17-2 Provide limited super user privile
#!/usr/bin/python

VERSION="0.1"

import sys, subprocess, os, os.path
import cPickle as pickle
from urllib2 import urlopen

def unpickle(inputfd):
    unp = pickle.Unpickler(inputfd)
    unp.find_global = None
    while True:
        try:
            yield unp.load()
        except EOFError:
            break

def get_architecture(opts):
    if opts.arch:
        return opts.arch
    else:
        return subprocess.Popen(["dpkg-architecture", "-qDEB_HOST_ARCH"], stdout=subprocess.PIPE).communicate()[0].strip()

DIST_WHITELIST = set(["sid", "squeeze", "lenny", "etch"])
DIST_ALIASES = {
        "unstable": "sid",
        "testing": "squeeze",
        "stable": "lenny",
        "oldstable": "etch",
}

def get_dists(opts):
    if opts.sources:
        infiles = [opts.sources]
    else:
        infiles = ["/etc/apt/sources.list"]
        sld = "/etc/apt/sources.list.d"
        if os.path.isdir(sld):
            for f in os.listdir(sld):
                infiles.append(os.path.join(sld, f))
    dists = set()
    for f in infiles:
        for line in open(f):
            line = line.strip()
            if not line or line[0] == "#": continue
            line = line.split()
            if len(line) < 4: continue
            dist = line[2].split("/")[0]
            dist = DIST_ALIASES.get(dist, dist)
            if dist in DIST_WHITELIST:
                dists.add(dist)
    return sorted(dists)




import optparse

class Parser(optparse.OptionParser):
    def __init__(self, *args, **kwargs):
        optparse.OptionParser.__init__(self, *args, **kwargs)

    def print_help(self, out=sys.stdout):
        optparse.OptionParser.print_help(self, out)
        print >>out
        print >>out, "Action:"
        print >>out, "  update                     Fetch Contents files from apt-sources (ignored)"
        print >>out, "  search|find  <pattern>     Search files in packages"
        print >>out, "  list|show    <pattern>     List files in packages"
        print >>out, "  purge                      Remove cache files (ignored)"

    def error(self, msg):
        sys.stderr.write("%s: error: %s\n\n" % (self.get_prog_name(), msg))
        self.print_help(sys.stderr)
        sys.exit(2)

parser = Parser(usage="usage: %prog [options] action [pattern]",
                version="%prog "+ VERSION,
                description="Search files in packages")

parser.add_option("-s", "--sources-list", metavar="FILE", dest="sources", help="sources.list location")
parser.add_option("-a", "--architecture", dest="arch", help="Use specific architecture")
parser.add_option("-l", "--package-only", dest="pkgonly", action="store_true", help="Only display package names")
parser.add_option("-v", "--verbose", action="store_true", help="run in verbose mode")

parser.add_option("-c", "--cache", dest="dir", help="Cache directory (ignored)")
parser.add_option("-d", "--cdrom-mount", dest="cdrom", help="Use specific cdrom mountpoint (ignored)")
parser.add_option("-N", "--non-interactive", action="store_true", help="Skip schemes requiring user input (useful in cron jobs) (ignored)")
parser.add_option("-x", "--regexp", action="store_true", help="pattern is a regular expression (ignored)")
parser.add_option("-y", "--dummy", action="store_true", help="run in dummy mode (no action) (ignored)");
parser.add_option("-i", "--ignore-case", action="store_true", help="Ignore case distinctions (ignored)")
parser.add_option("-F", "--fixed-string", action="store_true", help="Do not expand pattern (ignored)")

(options, args) = parser.parse_args()

action = args and args.pop(0) or None

# Skip ignored actions
if action in ("update", "purge"):
    sys.exit(0)
elif action in ("search", "find"):
    pattern = args.pop(0)
    arch = get_architecture(options)
    dists = get_dists(options)
    pkgs = set()
    for dist in dists:
        url = "http://dde.debian.net/dde/q/aptfile/byfile/%s-%s/%s?t=pickle"; % (dist, arch, pattern)
        if options.verbose: print >>sys.stderr, "Querying %s..." % url
        for res in unpickle(urlopen(url)):
            for pkg in res:
                pkgs.add(pkg)
    if options.pkgonly:
        for pkg in sorted(pkgs):
            print pkg
    else:
        import warnings
        # Yes, apt, thanks, I know, the api isn't stable, thank you so very much
        #warnings.simplefilter('ignore', FutureWarning)
        warnings.filterwarnings("ignore","apt API not stable yet")
        import apt
        warnings.resetwarnings()
        cache = apt.Cache()
        for pkg in sorted(pkgs):
            p = cache[pkg]
            print pkg, "-", p.summary
    sys.exit(0)
elif action in ("list", "show"):
    pattern = args.pop(0)
    arch = get_architecture(options)
    dists = get_dists(options)
    files = set()
    for dist in dists:
        url = "http://dde.debian.net/dde/q/aptfile/bypackage/%s-%s/%s?t=pickle"; % (dist, arch, pattern)
        if options.verbose: print >>sys.stderr, "Querying %s..." % url
        for res in unpickle(urlopen(url)):
            for f in res[0]:
                files.add(f)
    for f in sorted(files):
        print f
    sys.exit(0)
elif action is None:
    parser.print_help()
    sys.exit(0)
else:
    parser.error("Action '%s' is not valid" % action)


Reply via email to