Minor updates; should get a move on soon.
authorkarltk <karltk@gentoo.org>
Tue, 30 Dec 2003 23:15:24 +0000 (23:15 -0000)
committerkarltk <karltk@gentoo.org>
Tue, 30 Dec 2003 23:15:24 +0000 (23:15 -0000)
svn path=/; revision=46

trunk/TODO
trunk/src/gentool/ChangeLog
trunk/src/gentool/gentool
trunk/src/gentoolkit/gentoolkit.py
trunk/src/moo/moo

index 2adbf157b64e88c83ddd7956946a5845a4672e64..44714e17faf054e6fc7c5110e81843df35ae7817 100644 (file)
@@ -1,8 +1,10 @@
-- rename gentool to equery
+- add dist to Makefile
+- gentool:
+ - add --overlay, --portdir to uses
+ - add glsa pkgspec
+  - query for current GLSAs on installed package(s)
  - add changelog <from> <to> [--last] [--lastentry] [--current]
   - displays changelog entries
- - add installed [cat]
-  - displays installed packages (optionally only in a given cat)
  - add check <pkg-spec> [--full] [--display=pkgnames,full]
   - check md5 and timestamps (optionally also in CONFIG_PROTECT dirs)
  - add which
 - merge emerge-rsync and emerge-webrsync
 - drop pkg-size (callfwd to etcat size)
 - merge change and echangelog
-- merge useflag and euse
+- merge useflag and euse, have _one_ command line tool
+  - update ufed to rely on the CLI tool
+  - update ufed to rely on generate-use
+  - merge generate-use and ufed?
 - rewrite revdep-rebuild to use gentoolkit
 - rewrite distfiles-clean to use gentoolkit
 - rewrite etc-update to use gentoolkit, add UI
 - add genlop
 - look through forums.gentoo.org for additional scripts
 - write a Gentoolkit Guide
+- write efeatures for turning on/off FEATURES in make.conf
+- look at ekeys, ewatch
 
 + check esearch, eupdatedb: separate package for now
 + extract helper code from etcat
index 484afec1ba0404d876a10865a96b4e9bd2017438..94dfaafd5999c13e2b5289d04cf384e932e61112 100644 (file)
@@ -1,9 +1,14 @@
+2003-12-31 Karl Trygve Kalleberg <karltk@gentoo.org>
+       * Added which command
+       * Added check command (not finished)
+       
 2003-12-12 Karl Trygve Kalleberg <karltk@gentoo.org>
        * Added size command
        * Added depgraph command
        
 2003-12-11 Karl Trygve Kalleberg <karltk@gentoo.org>
        * Added list command
+       * Added uses command
        
 2003-10-05 Karl Trygve Kalleberg <karltk@gentoo.org>
        * Added files command
index 2481ed1942a6e516fa3feb54e76987ce70f77756..34128afe4288576d5653003cf1d9a29f46e1bc74 100755 (executable)
@@ -140,7 +140,7 @@ class CmdListFiles(Command):
                "  " + yellow("--md5sum") + "     - append md5sum\n" + \
                "  " + yellow("--type") + "       - prepend file type"               
     def shortHelp(self):
-        return yellow("<local-opts> ") + green("pkgspec") + " - list files owned by " + green("pkgspec")
+        return yellow("<local-opts> ") + teal("pkgspec") + " - list files owned by " + teal("pkgspec")
 
     
 class CmdListBelongs(Command):
@@ -209,7 +209,7 @@ class CmdListBelongs(Command):
                 break
                     
     def shortHelp(self):
-        return yellow("<local-opts> ") + green("query") + " - list all packages owning " + green("file")
+        return yellow("<local-opts> ") + teal("file") + " - list all packages owning " + teal("file")
     def longHelp(self):
         return "List all packages owning a particular file" + \
                "\n" + \
@@ -217,19 +217,158 @@ class CmdListBelongs(Command):
                turquoise("Note: ") + "Normally, only one package will own a file. If multiple packages own the same file, it usually consitutes a problem, and should be reported.\n" + \
                "\n" + \
                "Syntax:\n" + \
-               "  " + green("belongs") + yellow(" <local-opts> ") + green("filename") + \
+               "  " + green("belongs") + yellow(" <local-opts> ") + teal("filename") + \
                "\n" + \
                yellow("<local-opts>") + " is either of: \n" + \
                "  " + yellow("-c, --category cat") + " - only search in category " + yellow("cat") + "\n" + \
                "  " + yellow("-e, --earlyout") + "     - stop when first match found\n"
-    
-class CmdListDepends(Command):
-    """List all packages directly or indirectly depending on pkgQuery"""
-    pass
 
 class CmdDisplayUSEs(Command):
     """Advanced report of a package's USE flags"""
-    pass
+    def __init__(self):
+        self.default_opts = {
+            }
+    def parseArgs(self, args):
+
+        query = ""
+        need_help = 0
+        opts = self.default_opts
+        skip = 0
+        
+        for i in xrange(len(args)):
+
+            if skip:
+                skip -= 1
+                continue
+            x = args[i]
+            
+            if x in ["-h","--help"]:
+                need_help = 1
+                break
+            else:
+                query = x
+
+        if need_help or query == "":
+            print self.longHelp()
+            sys.exit(-1)
+            
+        return (query, opts)
+
+    def perform(self, args):
+
+        (query, opts) = self.parseArgs(args)
+        
+        matches = gentoolkit.find_packages(query)
+
+        useflags = gentoolkit.settings["USE"].split()    
+        usedesc = {}
+        uselocaldesc = {}
+
+        # Load global USE flag descriptions
+        try:
+            fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.desc")
+            usedesc = {}
+            for line in fd.readlines():
+                if line[0] == "#":
+                    continue
+                fields = line.split(" - ")
+                if len(fields) == 2:
+                    usedesc[fields[0].strip()] = fields[1].strip()
+        except IOError:
+            if Config["verbosityLevel"] >= 5:
+                print "Warning: Could not load USE flag descriptions from " + gentoolkit.settings["PORTDIR"] + "/profiles/use.desc"
+
+        # Load local USE flag descriptions
+        try:
+            fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.local.desc")
+            for line in fd.readlines():
+                if line[0] == "#":
+                    continue
+                fields = line.split(" - ")
+                if len(fields) == 2:
+                    catpkguse = re.search("([a-z]+-[a-z]+/.*):(.*)", fields[0])
+                    if catpkguse:
+                        if not uselocaldesc.has_key(catpkguse.group(1).strip()):
+                            uselocaldesc[catpkguse.group(1).strip()] = {catpkguse.group(2).strip() : fields[1].strip()}
+                        else:
+                            uselocaldesc[catpkguse.group(1).strip()][catpkguse.group(2).strip()] = fields[1].strip()
+        except IOError:
+            if Config["verbosityLevel"] >= 5:
+                print "Warning: Could not load USE flag descriptions from " + gentoolkit.settings["PORTDIR"] + "/profiles/use.desc"
+       
+        print "[ Colour Code : " + green("set") + " " + red("unset") + " ]"
+        print "[ Legend      : (U) Col 1 - Current USE flags        ]"
+        print "[             : (I) Col 2 - Installed With USE flags ]"
+
+        # Iterate through matches, printing a report for each package
+        for p in matches:
+            if not p.is_installed():
+                continue
+    
+            bestver = p.get_cpv()
+            iuse = p.get_env_var("IUSE")
+       
+            if iuse: usevar = iuse.split()
+            else: usevar = []
+       
+            inuse = []
+            used = p.get_use_vars().split()
+
+            # store (inuse, inused, flag, desc)
+            output = []
+
+            for u in usevar:
+                inuse = 0
+                inused = 0
+                try:
+                    desc = usedesc[u]
+                except KeyError:
+                    try:
+                        desc = uselocaldesc[p][u]
+                    except KeyError:
+                        desc = ""
+
+                if u in useflags: inuse = 1
+                if u in used: inused = 1
+               
+                output.append((inuse, inused, u, desc))
+
+            # pretty print
+            if output:
+                print
+                print white(" U I ") + "[ Found these USE variables in : " + white(bestver) + " ]"
+                maxflag_len = 0
+                for inuse, inused, u, desc in output:
+                    if len(u) > maxflag_len:
+                        maxflag_len = len(u)
+       
+                for inuse, inused, u, desc in output:
+                    flag = ["-","+"]
+                    colour = [red, green]
+                    if inuse != inused:
+                        print yellow(" %s %s" % (flag[inuse], flag[inused])),
+                    else:
+                        print " %s %s" % (flag[inuse], flag[inused]),
+
+                        print colour[inuse](u.ljust(maxflag_len)),
+           
+                    # print description
+                    if desc:
+                        print ":", desc
+                    else:
+                        print ": unknown"
+            else:
+                print "[ No USE flags found for :", white(p.get_cpv()), "]"
+    def shortHelp(self):
+        return yellow("<local-opts> ") + teal("pkgspec") + " - display USE flags for " + teal("pkgspec")
+    def longHelp(self):
+        return "Display USE flags for a given package\n" + \
+               "\n" + \
+               "Syntax:\n" + \
+               "  " + green("uses") + yellow(" <local-opts> ") + teal("pkgspec") + \
+               "\n" + \
+               yellow("<local-opts>") + " is either of: \n"
+
 
 class CmdDisplayDepGraph(Command):
     """Display tree graph of deps for pkgQuery"""
@@ -311,21 +450,17 @@ class CmdDisplayDepGraph(Command):
         return pkgtbl
 
     def shortHelp(self):
-        return yellow("<local-opts> ") + green("pkgspec") + " - display a dependency tree for " + green("pkgspec")
+        return yellow("<local-opts> ") + teal("pkgspec") + " - display a dependency tree for " + teal("pkgspec")
     def longHelp(self):
         return "Display a dependency tree for a given package\n" + \
                "\n" + \
                "Syntax:\n" + \
-               "  " + green("depgraph") + yellow(" <local-opts> ") + green("pkgspec") + \
+               "  " + green("depgraph") + yellow(" <local-opts> ") + teal("pkgspec") + \
                "\n" + \
                yellow("<local-opts>") + " is either of: \n" + \
                "  " + yellow("-U, --no-useflags") + " - do not show USE flags\n" + \
                "  " + yellow("-l, --linear") + "      - do not use fancy formatting"
 
-class CmdDisplayChanges(Command):
-    """Display changes for pkgQuery"""
-    pass
-
 class CmdDisplaySize(Command):
     """Display disk size consumed by a package"""
     def __init__(self):
@@ -386,24 +521,170 @@ class CmdDisplaySize(Command):
 
                     
     def shortHelp(self):
-        return yellow("<local-opts> ") + green("pkgspec") + " - print size of files contained in packages " + green("pkgspec")
+        return yellow("<local-opts> ") + teal("pkgspec") + " - print size of files contained in package " + teal("pkgspec")
     def longHelp(self):
         return "Print size total size of files contained in a given package" + \
                "\n" + \
                "Syntax:\n" + \
-               "  " + green("size") + yellow(" <local-opts> ") + green("pkgspec") + \
+               "  " + green("size") + yellow(" <local-opts> ") + teal("pkgspec") + \
                "\n" + \
                yellow("<local-opts>") + " is either of: \n" + \
                "  " + yellow("-b, --bytes") + " - report size in bytes\n"
 
-class CmdCheckIntegrity(Command):
-    """Check timestamps and md5sums for files owned by pkgQuery"""
+class CmdDisplayChanges(Command):
+    """Display changes for pkgQuery"""
     pass
 
+class CheckException:
+    def __init__(self, s):
+        self.s = s
+    
+class CmdCheckIntegrity(Command):
+    """Check timestamps and md5sums for files owned by pkgspec"""
+    def __init__(self):
+        self.default_opts = {
+            "showSummary" : 1,
+            "showGoodFiles" : 0,
+            "showBadFiles" : 1,
+            "checkTimestamp" : 1,
+            "checkMD5sum": 1
+            }
+
+    def parseArgs(self, args):
+
+        query = ""
+        need_help = 0
+        opts = self.default_opts
+        skip = 0
+        
+        for i in xrange(len(args)):
+            if skip:
+                skip -= 1
+                continue
+            x = args[i]
+            
+            if x in ["-h","--help"]:
+                need_help = 1
+                break
+            else:
+                query = x
+
+        if need_help or query == "":
+            print self.longHelp()
+            sys.exit(-1)
+            
+        return (query, opts)
+
+    def checkMD5sum(self, file):
+        return 1
+    
+    def perform(self, args):
+        (query, opts) = self.parseArgs(args)
+
+        matches = gentoolkit.find_packages(query)
+
+        for pkg in matches:
+            if not pkg.is_installed():
+                continue
+            files = pkg.get_contents()
+            for file in files.keys():
+                type = files[file][0]
+                try:
+                    st = os.lstat(file)
+                    if type == "dir":
+                        if not os.path.isdir(file):
+                            raise CheckException(file + " exists, but is not a directory")
+                    elif type == "obj":
+                        mtime = files[file][1]
+                        if opts["checkTimestamp"]:
+                            if st.st_mtime != int(mtime):
+                                raise CheckException(file + (" has wrong mtime (is %d, should be %s)" % (st.st_mtime, mtime)))
+                        if opts["checkMD5sum"]:
+                            if not self.checkMD5sum(file):
+                                raise CheckException(file + " has incorrect md5sum")
+                    elif type == "sym":
+                        # FIXME: nastry strippery; portage should have this fixed!
+                        t = files[file][2]
+                        i = t.find("(")
+                        target = t[0:i].strip()
+                        if not os.path.islink(file):
+                            raise CheckException(file + " exists, but is not a symlink")
+                        tgt = os.readlink(file)
+                        if tgt != target:
+                            raise CheckException(file + " does not point to " + target)
+                            
+                    else:
+                        print file
+                        print files[file]
+                        print type
+                        raise "Unknown type"
+                except CheckException, (e):
+                    print e.s
+                except OSError:
+                    print file + " does not exist"
+                    
+    def shortHelp(self):
+        return teal("pkgspec") + " - check package's files against recorded MD5 sums and timestamps"
+    def longHelp(self):
+        return "Check package's files against recorded MD5 sums and timestamps"
+
 class CmdDisplayStatistics(Command):
     """Display statistics about installed and uninstalled packages"""
     pass
 
+class CmdWhich(Command):
+    """Display the filename of the ebuild for a given package
+       that would be used by Portage with the current configuration."""
+    def __init__(self):
+        self.default_opts = {}
+
+    def parseArgs(self, args):
+
+        query = ""
+        need_help = 0
+        opts = self.default_opts
+        skip = 0
+        
+        for i in xrange(len(args)):
+
+            if skip:
+                skip -= 1
+                continue
+            x = args[i]
+            
+            if x in ["-h","--help"]:
+                need_help = 1
+                break
+            else:
+                query = x
+
+        if need_help or query == "":
+            print self.longHelp()
+            sys.exit(-1)
+            
+        return (query, opts)
+                
+    def perform(self, args):
+        (query, opts) = self.parseArgs(args)
+
+        matches = gentoolkit.find_packages(query)
+
+        for pkg in matches:
+            print os.path.normpath(pkg.get_ebuild_path())
+                    
+    def shortHelp(self):
+        return teal("pkgspec") + " - print full path to ebuild for package " + teal("pkgspec")
+    def longHelp(self):
+        return "Print full path to ebuild for a given package"
+
+class CmdListGLSAs(Command):
+    """List outstanding GLSAs."""
+    pass
+
+class CmdListDepends(Command):
+    """List all packages directly or indirectly depending on pkgQuery"""
+    pass
+
 class CmdListPackages(Command):
     """List packages satisfying pkgQuery"""
     def __init__(self):
@@ -510,12 +791,12 @@ class CmdListPackages(Command):
                     print pfxmodes[status] + " " + pkg.get_cpv()
                     
     def shortHelp(self):
-        return yellow("<local-opts> ") + green("pkgspec") + " - list all packages matching " + green("pkgspec")
+        return yellow("<local-opts> ") + teal("pkgspec") + " - list all packages matching " + teal("pkgspec")
     def longHelp(self):
         return "List all packages matching a query pattern" + \
                "\n" + \
                "Syntax:\n" + \
-               "  " + green("list") + yellow(" <local-opts> ") + green("pkgspec") + \
+               "  " + green("list") + yellow(" <local-opts> ") + teal("pkgspec") + \
                "\n" + \
                yellow("<local-opts>") + " is either of: \n" + \
                "  " + yellow("-i, --installed") + "         - search installed packages (default)\n" + \
@@ -534,7 +815,9 @@ Known_commands = {
     "changes": CmdDisplayChanges(),
     "size": CmdDisplaySize(),
     "check": CmdCheckIntegrity(),
-    "stats": CmdDisplayStatistics()
+    "stats": CmdDisplayStatistics(),
+    "glsa": CmdListGLSAs(),
+    "which": CmdWhich()
     }
 
 Config = {
@@ -611,3 +894,4 @@ if __name__ == "__main__":
     (cmd, local_opts) = parseArgs(sys.argv[1:])
     if cmd:
         cmd.perform(local_opts)
+
index db0d001abf8dac61ad2995bb2d729f0604b06b54..ffab7306824b2b1be4fa981a0aefccfa78f60637 100644 (file)
@@ -22,7 +22,7 @@ import portage
 import re
 import string
 
-settings = portage.settings
+settings = portage.config(clone=portage.settings)
 porttree = portage.db[portage.root]["porttree"]
 vartree  = portage.db[portage.root]["vartree"]
 virtuals = portage.db[portage.root]["virtuals"]
@@ -36,9 +36,10 @@ class Package:
     state of a package, its contents, name manipulation, ebuild info and
     similar."""
     def __init__(self,cpv):
-        self._cpv=cpv
-        self._scpv=portage.catpkgsplit(self._cpv)
-        self._db=None
+        self._cpv = cpv
+        self._scpv = portage.catpkgsplit(self._cpv)
+        self._db = None
+        self._settings = None
     def get_name(self):
         """Returns base name of package, no category nor version"""
         return self._scpv[1]
@@ -170,7 +171,7 @@ class Package:
         if not self._db:
             cat=self.get_category()
             pnv=self.get_name()+"-"+self.get_version()
-            self._db=portage.dblink(cat,pnv,"")
+            self._db=portage.dblink(cat,pnv,"",settings)
 
 #
 # Global helper functions
@@ -240,13 +241,10 @@ def find_all_installed_packages(prefilter=None):
 def find_all_uninstalled_packages(prefilter=None):
     """Returns a list of all uninstalled packages, after applying the prefilter
     function"""
-    t=porttree.getallnodes()
+    t=porttree.getallcpv()
     if prefilter:
         t=filter(prefilter,t)
-    t2 = []
-    for x in t:
-        t2 += porttree.dep_match(x)
-    return map(lambda x: Package(x), t2)
+    return map(lambda x: Package(x), t)
 
 def find_all_packages(prefilter=None):
     """Returns a list of all known packages, installed or not, after applying
@@ -277,6 +275,4 @@ def split_package_name(name):
 if __name__ == "__main__":
     print "This module is for import only"
 
-# - get dependencies
-# - walk dependency tree
 
index 5c925c5fb6b5aaaa2909366061dbca99f3921221..5013c771782b35b88ebc7fe812939f88322f7d9e 100755 (executable)
@@ -7,7 +7,13 @@ import signal
 
 CONFDIR="/tmp/moo"
 
+class Config:
+    pass
 
+def die(code, msg):
+    sys.stdout.write(msg + "\n")
+    sys.edit(code)
+    
 def printUsage():
     print "Usage: moo <options> [command] <command-options>\n" + \
               "Where [command] is one of:\n" + \
@@ -19,9 +25,12 @@ def scanNetworks():
     pass
 
 def runCmd(cmd):
-    print "Executing \"" + cmd + "\""
+    if Config.verbosity > 5:
+        print "Executing \"" + cmd + "\""
     v = os.system(cmd)
-    print "Result: " + str(v)
+    if Config.verbosity > 5:
+        print "Result: " + str(v)
+    return v
 
 class ProfileHandler:
     def __init__(self):
@@ -54,11 +63,13 @@ class Profile:
         self.broadcast = ""
         self.gateway = ""
         self.exclusive = "no"
+        self.netmask = ""
+        self.nameserver = ""
 
         ins = open(filename)
         for s in ins.readlines():
             for x in ["description","ifaceName","ip","broadcast",
-                      "gateway","exclusive"]:
+                      "gateway","exclusive","nameserver","wepkey"]:
                 if s.find(x+"=") == 0:
                     val=s.replace(x+"=","").strip()
                     self.__dict__[x] = val
@@ -68,7 +79,8 @@ class Profile:
               "ip          = " + self.ip + "\n" + \
               "broadcast   = " + self.broadcast + "\n" + \
               "gateway     = " + self.gateway + "\n" + \
-              "exclusive   = " + self.exclusive + "\n"
+              "gateway     = " + self.nameserver + "\n" + \
+              "exclusive   = " + self.exclusive + "\n" 
 
 class Interface:
     def __init__(self, name):
@@ -77,17 +89,29 @@ class Interface:
         self.broadcast = ""
         self.ip = ""
         self.gateway = ""
+        self.nameserver = ""
+        self.wepkey = ""
         self._loadIPV4Info()
     def _loadIPV4Info(self):
         pass
+    def getNameserver(self):
+        return self.nameserver
     def getNetmask(self):
         return self.netmask
     def getName(self):
         return self.name
     def getBroadcast(self):
         return self.broadcast
+    def getWEPKey(self):
+        return self.wepkey
     def getGateway(self):
         return self.gateway
+    def setNameserver(self,nameserver):
+        self.nameserver = nameserver
+    def setIP(self, ip):
+        self.ip = ip
+    def setWEPKey(self,key):
+        self.wepkey = key
     def setGateway(self,gw):
         self.gateway = gw
     def setBroadcast(self,broadcast):
@@ -105,15 +129,37 @@ class Interface:
             os.kill(pid,signal.SIGTERM)
             time.sleep(1)
     def up(self):
+        options = ""
+
+        if self.wepkey:
+            if runCmd("iwconfig eth1 key " + self.wepkey):
+              die(4, "Failed to set WEP key for " + self.name)
+              
         if self.ip:
             options += self.ip + " "
         if self.broadcast:
             options += "broadcast " + self.broadcast + " "
         if self.netmask:
             options += "netmask " + self.netmask + " "
-        runCmd("ifconfig " + self.name + " " + options + " up")
+
+        if runCmd("ifconfig " + self.name + " " + options + " up"):
+            die(2, "Failed to bring up " + self.name)
+            
         if self.gateway:
-            runCmd("route add default gw " + self.gateway + " " + self.name)
+            if runCmd("route add default gw " + self.gateway + " " + self.name):
+                die(3, "Failed to set default gateway for " + self.name)
+            
+        if self.nameserver:
+            if Config.verbosity > 5:
+                print("Using nameserver " + self.nameserver)
+            try: 
+                ous = open("/etc/resolv.conf","w")
+                ous.write("nameserver " + self.nameserver)
+                ous.close()
+            except OSError:
+                die("Failed to set nameserver")
+        if Config.verbosity > 3:
+            print "Brough interface " + self.name + " up"
             
 class InterfaceHandler:
     def __init__(self):
@@ -151,16 +197,23 @@ class Moo:
         if prof.ip == "dhcp":
             iface.runDHCP()
         else:
-            iface.setIPAddr(prof.ip)
+            iface.setIP(prof.ip)
             iface.setBroadcast(prof.broadcast)
             iface.setNetmask(prof.netmask)
             iface.setGateway(prof.gateway)
+            iface.setNameserver(prof.nameserver)
             iface.up()
             
     def listProfiles(self,detailed=0):
         self.profileHandler.listProfiles(detailed)
-        
+
+def initConfig():
+    Config.verbosity = 3
+    
 def main():
+
+    initConfig()
+    
     if len(sys.argv) < 2:
         printUsage()
         sys.exit(1)