egencache: handle empty --portdir-overlay
[portage.git] / bin / glsa-check
old mode 100644 (file)
new mode 100755 (executable)
index 3cfe0ba..7fa3688
@@ -13,68 +13,67 @@ sys.path.insert(0, pym_path)
 import portage
 portage._internal_caller = True
 from portage import os
-from portage.output import *
-
-from optparse import OptionGroup, OptionParser
+from portage.output import green, red, nocolor, white
+from portage.util._argparse import ArgumentParser
 
 __program__ = "glsa-check"
 __author__ = "Marius Mauch <genone@gentoo.org>"
 __version__ = "1.0"
 
-def cb_version(*args, **kwargs):
-       """Callback for --version"""
-       sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
-       sys.stderr.write("Author: " + __author__ + "\n")
-       sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
-       sys.exit(0)
-
 # option parsing
-parser = OptionParser(usage="%prog <option> [glsa-list]",
-               version="%prog "+ __version__)
-parser.epilog = "glsa-list can contain an arbitrary number of GLSA ids," \
+epilog = "glsa-list can contain an arbitrary number of GLSA ids," \
                " filenames containing GLSAs or the special identifiers" \
                " 'all', 'new' and 'affected'"
+parser = ArgumentParser(usage=__program__ + " <option> [glsa-list]",
+       epilog=epilog)
 
-modes = OptionGroup(parser, "Modes")
-modes.add_option("-l", "--list", action="store_const",
+modes = parser.add_argument_group("Modes")
+modes.add_argument("-l", "--list", action="store_const",
                const="list", dest="mode",
                help="List all unapplied GLSA")
-modes.add_option("-d", "--dump", action="store_const",
+modes.add_argument("-d", "--dump", action="store_const",
                const="dump", dest="mode",
                help="Show all information about the given GLSA")
-modes.add_option("", "--print", action="store_const",
+modes.add_argument("--print", action="store_const",
                const="dump", dest="mode",
                help="Alias for --dump")
-modes.add_option("-t", "--test", action="store_const",
+modes.add_argument("-t", "--test", action="store_const",
                const="test", dest="mode",
                help="Test if this system is affected by the given GLSA")
-modes.add_option("-p", "--pretend", action="store_const",
+modes.add_argument("-p", "--pretend", action="store_const",
                const="pretend", dest="mode",
                help="Show the necessary commands to apply this GLSA")
-modes.add_option("-f", "--fix", action="store_const",
+modes.add_argument("-f", "--fix", action="store_const",
                const="fix", dest="mode",
                help="Try to auto-apply this GLSA (experimental)")
-modes.add_option("-i", "--inject", action="store_const", dest="mode",
-               help="Inject the given GLSA into the checkfile")
-modes.add_option("-m", "--mail", action="store_const",
+modes.add_argument("-i", "--inject", action="store_const",
+               const="inject", dest="mode",
+               help="inject the given GLSA into the glsa_injected file")
+modes.add_argument("-m", "--mail", action="store_const",
                const="mail", dest="mode",
                help="Send a mail with the given GLSAs to the administrator")
-parser.add_option_group(modes)
 
-parser.remove_option("--version")
-parser.add_option("-V", "--version", action="callback",
-               callback=cb_version, help="Some information about this tool")
-parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+parser.add_argument("-V", "--version", action="store_true",
+               help="Some information about this tool")
+parser.add_argument("-v", "--verbose", action="store_true", dest="verbose",
                help="Print more information")
-parser.add_option("-n", "--nocolor", action="callback",
-               callback=lambda *args, **kwargs: nocolor(),
+parser.add_argument("-n", "--nocolor", action="store_true",
                help="Disable colors")
-parser.add_option("-e", "--emergelike", action="store_false", dest="least_change",
+parser.add_argument("-e", "--emergelike", action="store_false", dest="least_change",
                help="Do not use a least-change algorithm")
-parser.add_option("-c", "--cve", action="store_true", dest="list_cve",
+parser.add_argument("-c", "--cve", action="store_true", dest="list_cve",
                help="Show CAN ids in listing mode")
 
-options, params = parser.parse_args()
+options, params = parser.parse_known_args()
+
+if options.nocolor:
+       nocolor()
+
+if options.version:
+       sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
+       sys.stderr.write("Author: " + __author__ + "\n")
+       sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
+       sys.exit(0)
 
 mode = options.mode
 least_change = options.least_change
@@ -100,7 +99,8 @@ elif mode == "list" and not params:
        params.append("new")
 
 # delay this for speed increase
-from portage.glsa import *
+from portage.glsa import (Glsa, GlsaTypeException, GlsaFormatException,
+       get_applied_glsas, get_glsa_list)
 
 eroot = portage.settings['EROOT']
 vardb = portage.db[eroot]["vartree"].dbapi
@@ -142,9 +142,16 @@ for p in params[:]:
 glsalist.extend([g for g in params if g not in glsalist])
 
 def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"):
+       # Get to the raw streams in py3k before wrapping them with an encoded writer
+       # to avoid writing bytes to a text stream (stdout/stderr are text streams
+       # by default in py3k)
+       if hasattr(fd1, "buffer"):
+               fd1 = fd1.buffer
+       if hasattr(fd2, "buffer"):
+               fd2 = fd2.buffer
        fd1 = codecs.getwriter(encoding)(fd1)
        fd2 = codecs.getwriter(encoding)(fd2)
-       fd2.write(white("[A]")+" means this GLSA was already applied,\n")
+       fd2.write(white("[A]")+" means this GLSA was marked as applied (injected),\n")
        fd2.write(green("[U]")+" means the system is not affected and\n")
        fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
 
@@ -156,7 +163,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"):
                        if verbose:
                                fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
                        continue
-               if myglsa.isApplied():
+               if myglsa.isInjected():
                        status = "[A]"
                        color = white
                elif myglsa.isVulnerable():
@@ -218,7 +225,7 @@ if mode in ["dump", "fix", "inject", "pretend"]:
                                        # using emerge for the actual merging as it contains the dependency
                                        # code and we want to be consistent in behaviour. Also this functionality
                                        # will be integrated in emerge later, so it shouldn't hurt much.
-                                       emergecmd = "emerge --oneshot " + glsaconfig["EMERGE_OPTS"] + " =" + pkg
+                                       emergecmd = "emerge --oneshot " + " =" + pkg
                                        if verbose:
                                                sys.stderr.write(emergecmd+"\n")
                                        exitcode = os.system(emergecmd)
@@ -229,7 +236,6 @@ if mode in ["dump", "fix", "inject", "pretend"]:
                                                sys.exit(exitcode)
                        if len(mergelist):
                                sys.stdout.write("\n")
-                       myglsa.inject()
                elif mode == "pretend":
                        sys.stdout.write("Checking GLSA "+myid+"\n")
                        if not myglsa.isVulnerable():
@@ -277,7 +283,7 @@ if mode == "test":
 # mail mode as requested by solar
 if mode == "mail":
        import portage.mail, socket
-       from io import StringIO
+       from io import BytesIO
        from email.mime.text import MIMEText
 
        # color doesn't make any sense for mail
@@ -296,11 +302,13 @@ if mode == "mail":
        mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
 
        # need a file object for summarylist()
-       myfd = StringIO()
-       myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn())
-       myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv))
+       myfd = BytesIO()
+       line = "GLSA Summary report for host %s\n" % socket.getfqdn()
+       myfd.write(line.encode("utf-8"))
+       line = "(Command was: %s)\n\n" % " ".join(sys.argv)
+       myfd.write(line.encode("utf-8"))
        summarylist(glsalist, fd1=myfd, fd2=myfd)
-       summary = str(myfd.getvalue())
+       summary = myfd.getvalue().decode("utf-8")
        myfd.close()
 
        myattachments = []
@@ -311,9 +319,10 @@ if mode == "mail":
                        if verbose:
                                sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
                        continue
-               myfd = StringIO()
+               myfd = BytesIO()
                myglsa.dump(outstream=myfd)
-               myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8"))
+               attachment = myfd.getvalue().decode("utf-8")
+               myattachments.append(MIMEText(attachment, _charset="utf8"))
                myfd.close()
 
        mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments)