Esempio n. 1
0
 def test_get_bugs_list(self):
     """previous versions of python-debianbts accepted malformed key-value lists."""
     l = bts.get_bugs('submitter', '*****@*****.**', 'severity', 'normal')
     l2 = bts.get_bugs(['submitter', '*****@*****.**', 'severity', 'normal'])
     self.assertFalse(len(l) == 0)
     l.sort()
     l2.sort()
     self.assertEqual(l, l2)
def test_get_bugs_empty(caplog):
    """get_bugs should return empty list if no matching bugs where found."""
    bugs = bts.get_bugs(package="thisisatest")
    assert bugs == []

    bugs = bts.get_bugs("package", "thisisatest")
    assert bugs == []
    assert "deprecated" in caplog.text
Esempio n. 3
0
 def test_get_bugs_list(self):
     """previous versions of python-debianbts accepted malformed key-value lists."""
     l = bts.get_bugs('submitter', '*****@*****.**', 'severity',
                      'normal')
     l2 = bts.get_bugs(
         ['submitter', '*****@*****.**', 'severity', 'normal'])
     self.assertFalse(len(l) == 0)
     l.sort()
     l2.sort()
     self.assertEqual(l, l2)
Esempio n. 4
0
 def bugs_affecting(self, package):
     if not package in self._bugs_affecting_package:
         self._misses += 1
         signal(SIGALRM, alarm_handler)
         alarm(120)
         bugs = debianbts.get_bugs('affects', package, 'bugs', self.all_piuparts_bugs(), 'archive', 'both')
         bugs += debianbts.get_bugs('affects', 'src:' + package, 'bugs', self.all_piuparts_bugs(), 'archive', 'both')
         alarm(0)
         self._bugs_affecting_package[package] = sorted(set(bugs), reverse=True)
     self._queries += 1
     return self._bugs_affecting_package[package]
Esempio n. 5
0
def test_get_bugs_list():
    """older versions of python-debianbts accepted malformed key-val-lists."""
    bugs = bts.get_bugs(
            'submitter',
            '*****@*****.**',
            'severity',
            'normal')
    bugs2 = bts.get_bugs(
            ['submitter', '*****@*****.**', 'severity', 'normal'])
    assert len(bugs) != 0
    bugs.sort()
    bugs2.sort()
    assert bugs == bugs2
def test_get_bugs(caplog):
    """get_bugs should return list of bugnumbers."""
    bugs = bts.get_bugs(submitter="*****@*****.**")
    assert len(bugs) != 0
    assert isinstance(bugs, list)
    for i in bugs:
        assert isinstance(i, int)

    bugs = bts.get_bugs("submitter", "*****@*****.**")
    assert len(bugs) != 0
    assert isinstance(bugs, list)
    for i in bugs:
        assert isinstance(i, int)
    assert "deprecated" in caplog.text
Esempio n. 7
0
 def _get_bugs_thread(self, pkg):
     try:
         bugs = bts.get_bugs('package', pkg)
     except Exception as exc:
         self._thread_failed = True
         print('threaded get_bugs() call failed '
               'with exception {} {}'.format(type(exc), exc))
Esempio n. 8
0
 def test_get_bugs(self):
     """get_bugs should return list of bugnumbers."""
     l = bts.get_bugs("submitter", "*****@*****.**")
     self.assertFalse(len(l) == 0)
     self.assertEqual(type(l), type([]))
     for i in l:
         self.assertEqual(type(i), type(int()))
Esempio n. 9
0
def test_get_bugs():
    """get_bugs should return list of bugnumbers."""
    bugs = bts.get_bugs("submitter", "*****@*****.**")
    assert len(bugs) != 0
    assert isinstance(bugs, list)
    for i in bugs:
        assert isinstance(i, int)
Esempio n. 10
0
 def test_get_bugs(self):
     """get_bugs should return list of bugnumbers."""
     l = bts.get_bugs("submitter", "*****@*****.**")
     self.assertFalse(len(l) == 0)
     self.assertEqual(type(l), type([]))
     for i in l:
         self.assertEqual(type(i), type(int()))
Esempio n. 11
0
 def _get_bugs_thread(self, pkg):
     try:
         bugs = bts.get_bugs('package', pkg)
     except Exception as exc:
         self._thread_failed = True
         print('threaded get_bugs() call failed '
               'with exception {} {}'.format(type(exc), exc))
def test_get_bugs_list(caplog):
    """older versions of python-debianbts accepted malformed key-val-lists."""
    bugs = bts.get_bugs(submitter='*****@*****.**',
                        severity='normal')
    assert len(bugs) != 0

    bugs = bts.get_bugs(
            'submitter',
            '*****@*****.**',
            'severity',
            'normal')
    bugs2 = bts.get_bugs(
            ['submitter', '*****@*****.**', 'severity', 'normal'])
    assert len(bugs) != 0
    bugs.sort()
    bugs2.sort()
    assert bugs == bugs2
    assert "deprecated" in caplog.text
Esempio n. 13
0
    def unclassified_bugs(self):
        """
        Returns a list of open bugs which have not yet been classified
        by one of our usertags.
        """

        tagged_bugs = bts.get_usertag('*****@*****.**')
        tagged_bugs_ftp = []
        for tags in tagged_bugs.keys():
            tagged_bugs_ftp += tagged_bugs[tags]

        return [bug for bug in bts.get_status(bts.get_bugs("package", "ftp.debian.org"))
                     if bug.pending == 'pending' and bug.bug_num not in tagged_bugs_ftp]
Esempio n. 14
0
    def unclassified_bugs(self):
        """
        Returns a list of open bugs which have not yet been classified
        by one of our usertags.
        """

        tagged_bugs = bts.get_usertag('*****@*****.**')
        tagged_bugs_ftp = []
        for tags in tagged_bugs.keys():
            tagged_bugs_ftp += tagged_bugs[tags]

        return [bug for bug in bts.get_status(bts.get_bugs("package", "ftp.debian.org"))
                     if bug.pending == 'pending' and bug.bug_num not in tagged_bugs_ftp]
Esempio n. 15
0
File: bts.py Progetto: gcs-fga/pet
  def search(self, sources, bug_numbers=None):
    if bug_numbers is None:
      bug_numbers = set()
    else:
      bug_numbers = set(bug_numbers)
    bug_numbers.update(debianbts.get_bugs('src', sources))

    # process in batches. stolen from python-debianbts.
    BATCH_SIZE = 500
    result = []
    for i in range(0, len(bug_numbers), BATCH_SIZE):
        slice = list(bug_numbers)[i:i + BATCH_SIZE]
        result += debianbts.get_status(slice)

    return [ _DebianBugReport(b, self.binary_source_map, self.ignore_unknown_binaries) for b in result ]
Esempio n. 16
0
    def search(self, sources, bug_numbers=None):
        if bug_numbers is None:
            bug_numbers = set()
        else:
            bug_numbers = set(bug_numbers)
        bug_numbers.update(debianbts.get_bugs('src', sources))

        # process in batches. stolen from python-debianbts.
        BATCH_SIZE = 500
        result = []
        for i in range(0, len(bug_numbers), BATCH_SIZE):
            slice = list(bug_numbers)[i:i + BATCH_SIZE]
            result += debianbts.get_status(slice)

        return [
            _DebianBugReport(b, self.binary_source_map,
                             self.ignore_unknown_binaries) for b in result
        ]
Esempio n. 17
0
def piuparts_bugs_affecting(package):
    bugs = debianbts.get_bugs('affects', package, 'bugs', all_piuparts_bugs(),
                              'archive', 'both')
    bugs += debianbts.get_bugs('affects', 'src:' + package, 'bugs',
                               all_piuparts_bugs(), 'archive', 'both')
    return sorted(set(bugs), reverse=True)
Esempio n. 18
0
def remove(session,
           reason,
           suites,
           removals,
           whoami=None,
           partial=False,
           components=None,
           done_bugs=None,
           date=None,
           carbon_copy=None,
           close_related_bugs=False):
    """Batch remove a number of packages
    Verify that the files listed in the Files field of the .dsc are
    those expected given the announced Format.

    @type session: SQLA Session
    @param session: The database session in use

    @type reason: string
    @param reason: The reason for the removal (e.g. "[auto-cruft] NBS (no longer built by <source>)")

    @type suites: list
    @param suites: A list of the suite names in which the removal should occur

    @type removals: list
    @param removals: A list of the removals.  Each element should be a tuple (or list) of at least the following
        for 4 items from the database (in order): package, version, architecture, (database) id.
        For source packages, the "architecture" should be set to "source".

    @type partial: bool
    @param partial: Whether the removal is "partial" (e.g. architecture specific).

    @type components: list
    @param components: List of components involved in a partial removal.  Can be an empty list to not restrict the
        removal to any components.

    @type whoami: string
    @param whoami: The person (or entity) doing the removal.  Defaults to utils.whoami()

    @type date: string
    @param date: The date of the removal. Defaults to commands.getoutput("date -R")

    @type done_bugs: list
    @param done_bugs: A list of bugs to be closed when doing this removal.

    @type close_related_bugs: bool
    @param done_bugs: Whether bugs related to the package being removed should be closed as well.  NB: Not implemented
      for more than one suite.

    @type carbon_copy: list
    @param carbon_copy: A list of mail addresses to CC when doing removals.  NB: all items are taken "as-is" unlike
        "dak rm".

    @rtype: None
    @return: Nothing
    """
    # Generate the summary of what's to be removed
    d = {}
    summary = ""
    sources = []
    binaries = []
    whitelists = []
    versions = []
    suite_ids_list = []
    suites_list = utils.join_with_commas_and(suites)
    cnf = utils.get_conf()
    con_components = ''

    #######################################################################################################

    if not reason:
        raise ValueError("Empty removal reason not permitted")

    if not removals:
        raise ValueError("Nothing to remove!?")

    if not suites:
        raise ValueError("Removals without a suite!?")

    if whoami is None:
        whoami = utils.whoami()

    if date is None:
        date = commands.getoutput("date -R")

    if partial and components:

        component_ids_list = []
        for componentname in components:
            component = get_component(componentname, session=session)
            if component is None:
                raise ValueError("component '%s' not recognised." %
                                 componentname)
            else:
                component_ids_list.append(component.component_id)
        if component_ids_list:
            con_components = "AND component IN (%s)" % ", ".join(
                [str(i) for i in component_ids_list])

    for i in removals:
        package = i[0]
        version = i[1]
        architecture = i[2]
        if package not in d:
            d[package] = {}
        if version not in d[package]:
            d[package][version] = []
        if architecture not in d[package][version]:
            d[package][version].append(architecture)

    for package in sorted(d):
        versions = sorted(d[package], cmp=apt_pkg.version_compare)
        for version in versions:
            d[package][version].sort(utils.arch_compare_sw)
            summary += "%10s | %10s | %s\n" % (package, version, ", ".join(
                d[package][version]))

    for package in summary.split("\n"):
        for row in package.split("\n"):
            element = row.split("|")
            if len(element) == 3:
                if element[2].find("source") > 0:
                    sources.append(
                        "%s_%s" %
                        tuple(elem.strip(" ") for elem in element[:2]))
                    element[2] = sub("source\s?,?", "", element[2]).strip(" ")
                if element[2]:
                    binaries.append("%s_%s [%s]" %
                                    tuple(elem.strip(" ") for elem in element))

    dsc_type_id = get_override_type('dsc', session).overridetype_id
    deb_type_id = get_override_type('deb', session).overridetype_id

    for suite in suites:
        s = get_suite(suite, session=session)
        if s is not None:
            suite_ids_list.append(s.suite_id)
            whitelists.append(s.mail_whitelist)

    #######################################################################################################
    log_filename = cnf["Rm::LogFile"]
    log822_filename = cnf["Rm::LogFile822"]
    with utils.open_file(log_filename, "a") as logfile, utils.open_file(
            log822_filename, "a") as logfile822:
        fcntl.lockf(logfile, fcntl.LOCK_EX)
        fcntl.lockf(logfile822, fcntl.LOCK_EX)

        logfile.write(
            "=========================================================================\n"
        )
        logfile.write("[Date: %s] [ftpmaster: %s]\n" % (date, whoami))
        logfile.write("Removed the following packages from %s:\n\n%s" %
                      (suites_list, summary))
        if done_bugs:
            logfile.write("Closed bugs: %s\n" % (", ".join(done_bugs)))
        logfile.write(
            "\n------------------- Reason -------------------\n%s\n" % reason)
        logfile.write("----------------------------------------------\n")

        logfile822.write("Date: %s\n" % date)
        logfile822.write("Ftpmaster: %s\n" % whoami)
        logfile822.write("Suite: %s\n" % suites_list)

        if sources:
            logfile822.write("Sources:\n")
            for source in sources:
                logfile822.write(" %s\n" % source)

        if binaries:
            logfile822.write("Binaries:\n")
            for binary in binaries:
                logfile822.write(" %s\n" % binary)

        logfile822.write("Reason: %s\n" % reason.replace('\n', '\n '))
        if done_bugs:
            logfile822.write("Bug: %s\n" % (", ".join(done_bugs)))

        for i in removals:
            package = i[0]
            architecture = i[2]
            package_id = i[3]
            for suite_id in suite_ids_list:
                if architecture == "source":
                    session.execute(
                        "DELETE FROM src_associations WHERE source = :packageid AND suite = :suiteid",
                        {
                            'packageid': package_id,
                            'suiteid': suite_id
                        })
                else:
                    session.execute(
                        "DELETE FROM bin_associations WHERE bin = :packageid AND suite = :suiteid",
                        {
                            'packageid': package_id,
                            'suiteid': suite_id
                        })
                # Delete from the override file
                if not partial:
                    if architecture == "source":
                        type_id = dsc_type_id
                    else:
                        type_id = deb_type_id
                    # TODO: Fix this properly to remove the remaining non-bind argument
                    session.execute(
                        "DELETE FROM override WHERE package = :package AND type = :typeid AND suite = :suiteid %s"
                        % (con_components), {
                            'package': package,
                            'typeid': type_id,
                            'suiteid': suite_id
                        })

        session.commit()
        # ### REMOVAL COMPLETE - send mail time ### #

        # If we don't have a Bug server configured, we're done
        if "Dinstall::BugServer" not in cnf:
            if done_bugs or close_related_bugs:
                utils.warn(
                    "Cannot send mail to BugServer as Dinstall::BugServer is not configured"
                )

            logfile.write(
                "=========================================================================\n"
            )
            logfile822.write("\n")
            return

        # read common subst variables for all bug closure mails
        Subst_common = {}
        Subst_common["__RM_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
        Subst_common["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
        Subst_common["__CC__"] = "X-DAK: dak rm"
        if carbon_copy:
            Subst_common["__CC__"] += "\nCc: " + ", ".join(carbon_copy)
        Subst_common["__SUITE_LIST__"] = suites_list
        Subst_common["__SUBJECT__"] = "Removed package(s) from %s" % (
            suites_list)
        Subst_common["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
        Subst_common["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
        Subst_common["__WHOAMI__"] = whoami

        # Send the bug closing messages
        if done_bugs:
            Subst_close_rm = Subst_common
            bcc = []
            if cnf.find("Dinstall::Bcc") != "":
                bcc.append(cnf["Dinstall::Bcc"])
            if cnf.find("Rm::Bcc") != "":
                bcc.append(cnf["Rm::Bcc"])
            if bcc:
                Subst_close_rm["__BCC__"] = "Bcc: " + ", ".join(bcc)
            else:
                Subst_close_rm["__BCC__"] = "X-Filler: 42"
            summarymail = "%s\n------------------- Reason -------------------\n%s\n" % (
                summary, reason)
            summarymail += "----------------------------------------------\n"
            Subst_close_rm["__SUMMARY__"] = summarymail

            for bug in done_bugs:
                Subst_close_rm["__BUG_NUMBER__"] = bug
                if close_related_bugs:
                    mail_message = utils.TemplateSubst(
                        Subst_close_rm,
                        cnf["Dir::Templates"] + "/rm.bug-close-with-related")
                else:
                    mail_message = utils.TemplateSubst(
                        Subst_close_rm,
                        cnf["Dir::Templates"] + "/rm.bug-close")
                utils.send_mail(mail_message, whitelists=whitelists)

        # close associated bug reports
        if close_related_bugs:
            Subst_close_other = Subst_common
            bcc = []
            wnpp = utils.parse_wnpp_bug_file()
            versions = list(set([re_bin_only_nmu.sub('', v)
                                 for v in versions]))
            if len(versions) == 1:
                Subst_close_other["__VERSION__"] = versions[0]
            else:
                logfile.write(
                    "=========================================================================\n"
                )
                logfile822.write("\n")
                raise ValueError(
                    "Closing bugs with multiple package versions is not supported.  Do it yourself."
                )
            if bcc:
                Subst_close_other["__BCC__"] = "Bcc: " + ", ".join(bcc)
            else:
                Subst_close_other["__BCC__"] = "X-Filler: 42"
            # at this point, I just assume, that the first closed bug gives
            # some useful information on why the package got removed
            Subst_close_other["__BUG_NUMBER__"] = done_bugs[0]
            if len(sources) == 1:
                source_pkg = source.split("_", 1)[0]
            else:
                logfile.write(
                    "=========================================================================\n"
                )
                logfile822.write("\n")
                raise ValueError(
                    "Closing bugs for multiple source packages is not supported.  Please do it yourself."
                )
            Subst_close_other["__BUG_NUMBER_ALSO__"] = ""
            Subst_close_other["__SOURCE__"] = source_pkg
            merged_bugs = set()
            other_bugs = bts.get_bugs('src', source_pkg, 'status', 'open',
                                      'status', 'forwarded')
            if other_bugs:
                for bugno in other_bugs:
                    if bugno not in merged_bugs:
                        for bug in bts.get_status(bugno):
                            for merged in bug.mergedwith:
                                other_bugs.remove(merged)
                                merged_bugs.add(merged)
                logfile.write("Also closing bug(s):")
                logfile822.write("Also-Bugs:")
                for bug in other_bugs:
                    Subst_close_other["__BUG_NUMBER_ALSO__"] += str(
                        bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
                    logfile.write(" " + str(bug))
                    logfile822.write(" " + str(bug))
                logfile.write("\n")
                logfile822.write("\n")
            if source_pkg in wnpp:
                logfile.write("Also closing WNPP bug(s):")
                logfile822.write("Also-WNPP:")
                for bug in wnpp[source_pkg]:
                    # the wnpp-rm file we parse also contains our removal
                    # bugs, filtering that out
                    if bug != Subst_close_other["__BUG_NUMBER__"]:
                        Subst_close_other["__BUG_NUMBER_ALSO__"] += str(
                            bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
                        logfile.write(" " + str(bug))
                        logfile822.write(" " + str(bug))
                logfile.write("\n")
                logfile822.write("\n")

            mail_message = utils.TemplateSubst(
                Subst_close_other,
                cnf["Dir::Templates"] + "/rm.bug-close-related")
            if Subst_close_other["__BUG_NUMBER_ALSO__"]:
                utils.send_mail(mail_message)

        logfile.write(
            "=========================================================================\n"
        )
        logfile822.write("\n")
Esempio n. 19
0
def piuparts_bugs_affecting(package):
    bugs = debianbts.get_bugs('affects', package, 'bugs', all_piuparts_bugs(), 'archive', 'both')
    bugs += debianbts.get_bugs('affects', 'src:' + package, 'bugs', all_piuparts_bugs(), 'archive', 'both')
    return sorted(set(bugs), reverse=True)
Esempio n. 20
0
def piuparts_bugs_affecting(package):
    bugs = debianbts.get_bugs('affects', package, 'bugs', all_piuparts_bugs(),
                              'archive', 'both')
    bugs.sort(reverse=True)
    return bugs
Esempio n. 21
0
def piuparts_bugs_in(package):
    return debianbts.get_bugs("package", package, "bugs", all_piuparts_bugs()) + debianbts.get_bugs(
        "affects", package, "bugs", all_piuparts_bugs()
    )
Esempio n. 22
0
def get_reports(package, timeout, system='debian', mirrors=None, version=None,
                http_proxy='', archived=False, source=False):

    if system == 'debian':
        if isinstance(package, basestring):
            if source:
                pkg_filter = 'src'
            else:
                pkg_filter = 'package'
            bugs = debianbts.get_bugs(pkg_filter, package)
        else:
            bugs = map(int, package)

        # retrieve bugs and generate the hierarchy
        stats = debianbts.get_status(bugs)

        d = defaultdict(list)
        for s in stats:
            # We now return debianbts.Bugreport objects, containing all the info
            # for a bug, so UIs can extract them as needed
            d[s.severity].append(s)

        # keep the bugs ordered per severity
        # XXX: shouldn't it be something UI-related?
        #
        # The hierarchy is a list of tuples:
        #     (description of the severity, list of bugs for that severity)
        hier = []
        for sev in SEVLIST:
            if sev in d:
                hier.append(('Bugs with severity %s' % sev, d[sev]))

        return (len(bugs), 'Bug reports for %s' % package, hier)

    # XXX: is the code below used at all now? can we remove it?
    if isinstance(package, basestring):
        if SYSTEMS[system].get('cgiroot'):
            try:
                result = get_cgi_reports(package, timeout, system, http_proxy, archived,
                                     source, version=version)
            except:
                raise NoNetwork
            if result: return result

        url = package_url(system, package, mirrors, source)
        try:
            page = open_url(url, http_proxy, timeout)
        except:
            raise NoNetwork
        if not page:
            return (0, None, None)

        #content = page.read()
        #if 'Maintainer' not in content:
        #    return (0, None, None)

        parser = BTSParser()
        for line in page:
            parser.feed(line)
        parser.close()
        try:
            page.fp._sock.recv = None
        except:
            pass
        page.close()

        return parser.bugcount, parser.title, parser.hierarchy

    # A list of bug numbers
    this_hierarchy = []
    package = [int(x) for x in package]
    package.sort()
    for bug in package:
        result = get_report(bug, timeout, system, mirrors, http_proxy, archived)
        if result:
            title, body = result
            this_hierarchy.append(title)
            #print title

    title = "Multiple bug reports"
    bugcount = len(this_hierarchy)
    hierarchy = [('Reports', this_hierarchy)]

    return bugcount, title, hierarchy
Esempio n. 23
0
def test_get_bugs_single_int_bug():
    """bugs parameter in get_bugs can be a list of int or a int"""
    bugs1 = bts.get_bugs('bugs', 400040, 'archive', True)
    bugs2 = bts.get_bugs('bugs', [400040], 'archive', True)
    assert bugs1 == bugs2
Esempio n. 24
0
 def testGetBugsEmpty(self):
     """get_bugs should return empty list if no matching bugs where found."""
     l = bts.get_bugs("package", "thisisatest")
     self.assertEqual(l, [])
Esempio n. 25
0
 def test_get_bugs_empty(self):
     """get_bugs should return empty list if no matching bugs where found."""
     l = bts.get_bugs("package", "thisisatest")
     self.assertEqual(l, [])
Esempio n. 26
0
 def testGetBugs(self):
     """get_bugs should return list of bugnumbers."""
     l = bts.get_bugs("owner", "*****@*****.**")
     self.assertEqual(type(l), type([]))
     for i in l:
         self.assertEqual(type(i), type(int()))
Esempio n. 27
0
 def test_get_bugs_single_int_bug(self):
     """bugs parameter in get_bugs can be a list of int or a int"""
     bugs1 = bts.get_bugs('bugs', 400040, 'archive', True)
     bugs2 = bts.get_bugs('bugs', [400040], 'archive', True)
     self.assertEquals(bugs1, bugs2)
Esempio n. 28
0
 def test_get_bugs_int_bugs(self):
     """It is possible to pass a list of bug number to get_bugs"""
     bugs = bts.get_bugs('bugs', [400010, 400012], 'archive', True)
     self.assertEquals(set(bugs), set((400010, 400012)))
Esempio n. 29
0
def remove(session, reason, suites, removals,
           whoami=None, partial=False, components=None, done_bugs=None, date=None,
           carbon_copy=None, close_related_bugs=False):
    """Batch remove a number of packages
    Verify that the files listed in the Files field of the .dsc are
    those expected given the announced Format.

    @type session: SQLA Session
    @param session: The database session in use

    @type reason: string
    @param reason: The reason for the removal (e.g. "[auto-cruft] NBS (no longer built by <source>)")

    @type suites: list
    @param suites: A list of the suite names in which the removal should occur

    @type removals: list
    @param removals: A list of the removals.  Each element should be a tuple (or list) of at least the following
        for 4 items from the database (in order): package, version, architecture, (database) id.
        For source packages, the "architecture" should be set to "source".

    @type partial: bool
    @param partial: Whether the removal is "partial" (e.g. architecture specific).

    @type components: list
    @param components: List of components involved in a partial removal.  Can be an empty list to not restrict the
        removal to any components.

    @type whoami: string
    @param whoami: The person (or entity) doing the removal.  Defaults to utils.whoami()

    @type date: string
    @param date: The date of the removal. Defaults to commands.getoutput("date -R")

    @type done_bugs: list
    @param done_bugs: A list of bugs to be closed when doing this removal.

    @type close_related_bugs: bool
    @param done_bugs: Whether bugs related to the package being removed should be closed as well.  NB: Not implemented
      for more than one suite.

    @type carbon_copy: list
    @param carbon_copy: A list of mail addresses to CC when doing removals.  NB: all items are taken "as-is" unlike
        "dak rm".

    @rtype: None
    @return: Nothing
    """
    # Generate the summary of what's to be removed
    d = {}
    summary = ""
    sources = []
    binaries = []
    whitelists = []
    versions = []
    suite_ids_list = []
    suites_list = utils.join_with_commas_and(suites)
    cnf = utils.get_conf()
    con_components = ''

    #######################################################################################################

    if not reason:
        raise ValueError("Empty removal reason not permitted")

    if not removals:
        raise ValueError("Nothing to remove!?")

    if not suites:
        raise ValueError("Removals without a suite!?")

    if whoami is None:
        whoami = utils.whoami()

    if date is None:
        date = commands.getoutput("date -R")

    if partial and components:

        component_ids_list = []
        for componentname in components:
            component = get_component(componentname, session=session)
            if component is None:
                raise ValueError("component '%s' not recognised." % componentname)
            else:
                component_ids_list.append(component.component_id)
        if component_ids_list:
            con_components = "AND component IN (%s)" % ", ".join([str(i) for i in component_ids_list])

    for i in removals:
        package = i[0]
        version = i[1]
        architecture = i[2]
        if package not in d:
            d[package] = {}
        if version not in d[package]:
            d[package][version] = []
        if architecture not in d[package][version]:
            d[package][version].append(architecture)

    for package in sorted(d):
        versions = sorted(d[package], cmp=apt_pkg.version_compare)
        for version in versions:
            d[package][version].sort(utils.arch_compare_sw)
            summary += "%10s | %10s | %s\n" % (package, version, ", ".join(d[package][version]))

    for package in summary.split("\n"):
        for row in package.split("\n"):
            element = row.split("|")
            if len(element) == 3:
                if element[2].find("source") > 0:
                    sources.append("%s_%s" % tuple(elem.strip(" ") for elem in element[:2]))
                    element[2] = sub("source\s?,?", "", element[2]).strip(" ")
                if element[2]:
                    binaries.append("%s_%s [%s]" % tuple(elem.strip(" ") for elem in element))

    dsc_type_id = get_override_type('dsc', session).overridetype_id
    deb_type_id = get_override_type('deb', session).overridetype_id

    for suite in suites:
        s = get_suite(suite, session=session)
        if s is not None:
            suite_ids_list.append(s.suite_id)
            whitelists.append(s.mail_whitelist)

    #######################################################################################################
    log_filename = cnf["Rm::LogFile"]
    log822_filename = cnf["Rm::LogFile822"]
    with utils.open_file(log_filename, "a") as logfile, utils.open_file(log822_filename, "a") as logfile822:
        fcntl.lockf(logfile, fcntl.LOCK_EX)
        fcntl.lockf(logfile822, fcntl.LOCK_EX)

        logfile.write("=========================================================================\n")
        logfile.write("[Date: %s] [ftpmaster: %s]\n" % (date, whoami))
        logfile.write("Removed the following packages from %s:\n\n%s" % (suites_list, summary))
        if done_bugs:
            logfile.write("Closed bugs: %s\n" % (", ".join(done_bugs)))
        logfile.write("\n------------------- Reason -------------------\n%s\n" % reason)
        logfile.write("----------------------------------------------\n")

        logfile822.write("Date: %s\n" % date)
        logfile822.write("Ftpmaster: %s\n" % whoami)
        logfile822.write("Suite: %s\n" % suites_list)

        if sources:
            logfile822.write("Sources:\n")
            for source in sources:
                logfile822.write(" %s\n" % source)

        if binaries:
            logfile822.write("Binaries:\n")
            for binary in binaries:
                logfile822.write(" %s\n" % binary)

        logfile822.write("Reason: %s\n" % reason.replace('\n', '\n '))
        if done_bugs:
            logfile822.write("Bug: %s\n" % (", ".join(done_bugs)))

        for i in removals:
            package = i[0]
            architecture = i[2]
            package_id = i[3]
            for suite_id in suite_ids_list:
                if architecture == "source":
                    session.execute("DELETE FROM src_associations WHERE source = :packageid AND suite = :suiteid",
                                    {'packageid': package_id, 'suiteid': suite_id})
                else:
                    session.execute("DELETE FROM bin_associations WHERE bin = :packageid AND suite = :suiteid",
                                    {'packageid': package_id, 'suiteid': suite_id})
                # Delete from the override file
                if not partial:
                    if architecture == "source":
                        type_id = dsc_type_id
                    else:
                        type_id = deb_type_id
                    # TODO: Fix this properly to remove the remaining non-bind argument
                    session.execute("DELETE FROM override WHERE package = :package AND type = :typeid AND suite = :suiteid %s" % (con_components), {'package': package, 'typeid': type_id, 'suiteid': suite_id})

        session.commit()
        # ### REMOVAL COMPLETE - send mail time ### #

        # If we don't have a Bug server configured, we're done
        if "Dinstall::BugServer" not in cnf:
            if done_bugs or close_related_bugs:
                utils.warn("Cannot send mail to BugServer as Dinstall::BugServer is not configured")

            logfile.write("=========================================================================\n")
            logfile822.write("\n")
            return

        # read common subst variables for all bug closure mails
        Subst_common = {}
        Subst_common["__RM_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
        Subst_common["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
        Subst_common["__CC__"] = "X-DAK: dak rm"
        if carbon_copy:
            Subst_common["__CC__"] += "\nCc: " + ", ".join(carbon_copy)
        Subst_common["__SUITE_LIST__"] = suites_list
        Subst_common["__SUBJECT__"] = "Removed package(s) from %s" % (suites_list)
        Subst_common["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
        Subst_common["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
        Subst_common["__WHOAMI__"] = whoami

        # Send the bug closing messages
        if done_bugs:
            Subst_close_rm = Subst_common
            bcc = []
            if cnf.find("Dinstall::Bcc") != "":
                bcc.append(cnf["Dinstall::Bcc"])
            if cnf.find("Rm::Bcc") != "":
                bcc.append(cnf["Rm::Bcc"])
            if bcc:
                Subst_close_rm["__BCC__"] = "Bcc: " + ", ".join(bcc)
            else:
                Subst_close_rm["__BCC__"] = "X-Filler: 42"
            summarymail = "%s\n------------------- Reason -------------------\n%s\n" % (summary, reason)
            summarymail += "----------------------------------------------\n"
            Subst_close_rm["__SUMMARY__"] = summarymail

            for bug in done_bugs:
                Subst_close_rm["__BUG_NUMBER__"] = bug
                if close_related_bugs:
                    mail_message = utils.TemplateSubst(Subst_close_rm,cnf["Dir::Templates"]+"/rm.bug-close-with-related")
                else:
                    mail_message = utils.TemplateSubst(Subst_close_rm,cnf["Dir::Templates"]+"/rm.bug-close")
                utils.send_mail(mail_message, whitelists=whitelists)

        # close associated bug reports
        if close_related_bugs:
            Subst_close_other = Subst_common
            bcc = []
            wnpp = utils.parse_wnpp_bug_file()
            versions = list(set([re_bin_only_nmu.sub('', v) for v in versions]))
            if len(versions) == 1:
                Subst_close_other["__VERSION__"] = versions[0]
            else:
                logfile.write("=========================================================================\n")
                logfile822.write("\n")
                raise ValueError("Closing bugs with multiple package versions is not supported.  Do it yourself.")
            if bcc:
                Subst_close_other["__BCC__"] = "Bcc: " + ", ".join(bcc)
            else:
                Subst_close_other["__BCC__"] = "X-Filler: 42"
            # at this point, I just assume, that the first closed bug gives
            # some useful information on why the package got removed
            Subst_close_other["__BUG_NUMBER__"] = done_bugs[0]
            if len(sources) == 1:
                source_pkg = source.split("_", 1)[0]
            else:
                logfile.write("=========================================================================\n")
                logfile822.write("\n")
                raise ValueError("Closing bugs for multiple source packages is not supported.  Please do it yourself.")
            Subst_close_other["__BUG_NUMBER_ALSO__"] = ""
            Subst_close_other["__SOURCE__"] = source_pkg
            merged_bugs = set()
            other_bugs = bts.get_bugs('src', source_pkg, 'status', 'open', 'status', 'forwarded')
            if other_bugs:
                for bugno in other_bugs:
                    if bugno not in merged_bugs:
                        for bug in bts.get_status(bugno):
                            for merged in bug.mergedwith:
                                other_bugs.remove(merged)
                                merged_bugs.add(merged)
                logfile.write("Also closing bug(s):")
                logfile822.write("Also-Bugs:")
                for bug in other_bugs:
                    Subst_close_other["__BUG_NUMBER_ALSO__"] += str(bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
                    logfile.write(" " + str(bug))
                    logfile822.write(" " + str(bug))
                logfile.write("\n")
                logfile822.write("\n")
            if source_pkg in wnpp:
                logfile.write("Also closing WNPP bug(s):")
                logfile822.write("Also-WNPP:")
                for bug in wnpp[source_pkg]:
                    # the wnpp-rm file we parse also contains our removal
                    # bugs, filtering that out
                    if bug != Subst_close_other["__BUG_NUMBER__"]:
                        Subst_close_other["__BUG_NUMBER_ALSO__"] += str(bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
                        logfile.write(" " + str(bug))
                        logfile822.write(" " + str(bug))
                logfile.write("\n")
                logfile822.write("\n")

            mail_message = utils.TemplateSubst(Subst_close_other, cnf["Dir::Templates"]+"/rm.bug-close-related")
            if Subst_close_other["__BUG_NUMBER_ALSO__"]:
                utils.send_mail(mail_message)

        logfile.write("=========================================================================\n")
        logfile822.write("\n")
def test_get_bugs_int_bugs():
    """It is possible to pass a list of bug number to get_bugs"""
    bugs = bts.get_bugs('bugs', [400010, 400012], 'archive', True)
    assert set(bugs) == set((400010, 400012))
Esempio n. 31
0
def piuparts_bugs_affecting(package):
    bugs = debianbts.get_bugs('affects', package, 'bugs', all_piuparts_bugs(), 'archive', 'both')
    bugs.sort(reverse=True)
    return bugs
Esempio n. 32
0
def test_get_bugs_int_bugs():
    """It is possible to pass a list of bug number to get_bugs"""
    bugs = bts.get_bugs('bugs', [400010, 400012], 'archive', True)
    assert set(bugs) == set((400010, 400012))
Esempio n. 33
0
 def _get_bugs_thread(self, pkg):
     try:
         bts.get_bugs('package', pkg)
     except Exception:
         self._thread_failed = True
         logger.exception('Threaded get_bugs() call failed.')
Esempio n. 34
0
def test_get_bugs_empty():
    """get_bugs should return empty list if no matching bugs where found."""
    bugs = bts.get_bugs("package", "thisisatest")
    assert bugs == []
Esempio n. 35
0
 def test_get_bugs_single_int_bug(self):
     """bugs parameter in get_bugs can be a list of int or a int"""
     bugs1 = bts.get_bugs('bugs', 400040, 'archive', True)
     bugs2 = bts.get_bugs('bugs', [400040], 'archive', True)
     self.assertEquals(bugs1, bugs2)
Esempio n. 36
0
    def issues(self):
        # Initialise empty list of bug numbers
        collected_bugs = []

        # Search BTS for bugs owned by email address
        if self.email:
            owned_bugs = debianbts.get_bugs("owner", self.email, "status",
                                            "open")
            collected_bugs.extend(owned_bugs)

        # Search BTS for bugs related to specified packages
        if self.packages:
            packages = self.packages.split(",")
            for pkg in packages:
                pkg_bugs = debianbts.get_bugs("package", pkg, "status", "open")
                for bug in pkg_bugs:
                    if bug not in collected_bugs:
                        collected_bugs.append(bug)

        # Search UDD bugs search for bugs belonging to packages that
        # are maintained by the email address
        if self.udd:
            udd_bugs = self._get_udd_bugs()
            for bug in udd_bugs:
                if bug not in collected_bugs:
                    collected_bugs.append(bug['id'])

        issues = [
            self._record_for_bug(bug)
            for bug in debianbts.get_status(collected_bugs)
        ]

        log.debug(" Found %i total.", len(issues))

        if self.ignore_pkg:
            ignore_pkg = self.ignore_pkg.split(",")
            for pkg in ignore_pkg:
                issues = [
                    issue for issue in issues if not issue['package'] == pkg
                ]

        if self.ignore_src:
            ignore_src = self.ignore_src.split(",")
            for src in ignore_src:
                issues = [
                    issue for issue in issues if not issue['source'] == src
                ]

        if self.ignore_pending:
            issues = [
                issue for issue in issues
                if not issue['status'] == 'pending-fixed'
            ]

        issues = [
            issue for issue in issues
            if not (issue['status'] == 'done' or issue['status'] == 'fixed')
        ]

        log.debug(" Pruned down to %i.", len(issues))

        for issue in issues:
            issue_obj = self.get_issue_for_record(issue)
            extra = {'annotations': self.annotations(issue, issue_obj)}
            issue_obj.update_extra(extra)
            yield issue_obj
Esempio n. 37
0
    def lineedit_return_pressed(self):
        #
        # just in case ;)
        #
        text = unicode(self.lineEdit.text())
        if text.startswith("http://"):
            self._show_url(text)
            return
        if len(text) == 0:
            return

        self.logger.info("Return pressed.")
        self.lineEdit.clear()
        # TODO: self.lineEdit.clear() does not always work, why?
        #QtCore.QTimer.singleShot(0,self.lineEdit,QtCore.SLOT("clear()"))
        query = rng.translate_query(text)
        self.logger.debug("Query: %s" % str(query))

        # test if there is a submit-as field available and rename the packages
        # if nececesairy
        for i in range(0, len(query), 2):
            if query[i] == 'package':
                realname = bug.submit_as(query[i+1])
                if query[i+1] != realname:
                    self.logger.debug("Using %s as package name as requested by developer." % str(realname))
                    query[i+1] = realname
        # Single bug or list of bugs?
        if query[0]:
            buglist = bts.get_bugs(query)
        else:
            buglist = [query[1]]
        # ok, we know the package, so enable some buttons which don't depend
        # on the existence of the acutal packe (wnpp) or bugreports for that
        # package.
        if query[0] in ("src", "package"):
            self._stateChanged(query[1], None)
        # if we got a bugnumber we'd like to select it and enable some more
        # buttons. unfortunately we don't know if the bugnumber actually exists
        # for now, so we have to wait a bit until the bug is fetched.
        else:
            self._stateChanged(None, None)
        self.logger.debug("Buglist matching the query: %s" % str(buglist))
        chunksize = 50
        if len(buglist) > chunksize:
            self.load_started()
            self.logger.debug("Buglist longer than %i, splitting in chunks." % chunksize)
            self.bugs = []
            i = 0
            for chunk in chunks(buglist, chunksize):
                i += 1
                progress = int(100. * i * chunksize / len(buglist))
                if progress > 100:
                    progress = 100
                self.load_progress(progress)
                bl = bts.get_status(chunk)
                if len(bl) == 0:
                    self.logger.error("One of the following bugs caused the BTS to hickup: %s" % str(bl))
                self.bugs.extend(bl)
            self.load_finished(True)
        else:
            self.bugs = bts.get_status(buglist)
        # ok, we fetched the bugs. see if the list isn't empty
        if query[0] in (None,) and len(self.bugs) > 0:
            self.currentBug = self.bugs[0]
            self.currentPackage = self.currentBug.package
            self._stateChanged(self.currentPackage, self.currentBug)
        self.model.set_elements(self.bugs)
        self.tableView.resizeRowsToContents()
Esempio n. 38
0
def get_reports(package,
                timeout,
                system='debian',
                mirrors=None,
                version=None,
                http_proxy='',
                archived=False,
                source=False):
    if system == 'debian':
        if isinstance(package, str):
            if source:
                pkg_filter = 'src'
            else:
                pkg_filter = 'package'
            bugs = debianbts.get_bugs(pkg_filter, package)
        else:
            bugs = list(map(int, package))

        try:
            # retrieve bugs and generate the hierarchy
            stats = debianbts.get_status(bugs)
        except:
            raise QuertBTSError

        d = defaultdict(list)
        for s in stats:
            # We now return debianbts.Bugreport objects, containing all the info
            # for a bug, so UIs can extract them as needed
            d[s.severity].append(s)

        # keep the bugs ordered per severity
        # XXX: shouldn't it be something UI-related?
        #
        # The hierarchy is a list of tuples:
        #     (description of the severity, list of bugs for that severity)
        hier = []
        for sev in SEVLIST:
            if sev in d:
                hier.append(('Bugs with severity %s' % sev, d[sev]))

        return (len(bugs), 'Bug reports for %s' % package, hier)

    # XXX: is the code below used at all now? can we remove it?
    if isinstance(package, str):
        if SYSTEMS[system].get('cgiroot'):
            try:
                result = get_cgi_reports(package,
                                         timeout,
                                         system,
                                         http_proxy,
                                         archived,
                                         source,
                                         version=version)
            except:
                raise NoNetwork
            if result:
                return result

        url = package_url(system, package, mirrors, source)
        try:
            page = open_url(url, http_proxy, timeout)
        except:
            raise NoNetwork
        if not page:
            return (0, None, None)

        # content = page.read()
        # if 'Maintainer' not in content:
        #    return (0, None, None)

        parser = BTSParser()
        for line in page.splitlines():
            parser.feed(line)
        parser.close()

        return parser.bugcount, parser.title, parser.hierarchy

    # A list of bug numbers
    this_hierarchy = []
    package = [int(x) for x in package]
    package.sort()
    for bug in package:
        result = get_report(bug, timeout, system, mirrors, http_proxy,
                            archived)
        if result:
            title, body = result
            this_hierarchy.append(title)
            # print title

    title = "Multiple bug reports"
    bugcount = len(this_hierarchy)
    hierarchy = [('Reports', this_hierarchy)]

    return bugcount, title, hierarchy
Esempio n. 39
0
def fetch_bug_numbers_by_package(pkg_name):
    """Fetch non-archived bugs"""
    return debianbts.get_bugs('package', pkg_name, 'archive', 'false')
 def _get_bugs_thread(self, pkg):
     try:
         bts.get_bugs('package', pkg)
     except Exception:
         self._thread_failed = True
         logger.exception('Threaded get_bugs() call failed.')
Esempio n. 41
0
File: rm.py Progetto: abhi11/dak
def main ():
    global Options

    cnf = Config()

    Arguments = [('h',"help","Rm::Options::Help"),
                 ('a',"architecture","Rm::Options::Architecture", "HasArg"),
                 ('b',"binary", "Rm::Options::Binary"),
                 ('B',"binary-only", "Rm::Options::Binary-Only"),
                 ('c',"component", "Rm::Options::Component", "HasArg"),
                 ('C',"carbon-copy", "Rm::Options::Carbon-Copy", "HasArg"), # Bugs to Cc
                 ('d',"done","Rm::Options::Done", "HasArg"), # Bugs fixed
                 ('D',"do-close","Rm::Options::Do-Close"),
                 ('R',"rdep-check", "Rm::Options::Rdep-Check"),
                 ('m',"reason", "Rm::Options::Reason", "HasArg"), # Hysterical raisins; -m is old-dinstall option for rejection reason
                 ('n',"no-action","Rm::Options::No-Action"),
                 ('p',"partial", "Rm::Options::Partial"),
                 ('s',"suite","Rm::Options::Suite", "HasArg"),
                 ('S',"source-only", "Rm::Options::Source-Only"),
                 ]

    for i in [ "architecture", "binary", "binary-only", "carbon-copy", "component",
               "done", "help", "no-action", "partial", "rdep-check", "reason",
               "source-only", "Do-Close" ]:
        if not cnf.has_key("Rm::Options::%s" % (i)):
            cnf["Rm::Options::%s" % (i)] = ""
    if not cnf.has_key("Rm::Options::Suite"):
        cnf["Rm::Options::Suite"] = "unstable"

    arguments = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
    Options = cnf.subtree("Rm::Options")

    if Options["Help"]:
        usage()

    session = DBConn().session()

    # Sanity check options
    if not arguments:
        utils.fubar("need at least one package name as an argument.")
    if Options["Architecture"] and Options["Source-Only"]:
        utils.fubar("can't use -a/--architecture and -S/--source-only options simultaneously.")
    if ((Options["Binary"] and Options["Source-Only"])
            or (Options["Binary"] and Options["Binary-Only"])
            or (Options["Binary-Only"] and Options["Source-Only"])):
        utils.fubar("Only one of -b/--binary, -B/--binary-only and -S/--source-only can be used.")
    if Options.has_key("Carbon-Copy") and not Options.has_key("Done"):
        utils.fubar("can't use -C/--carbon-copy without also using -d/--done option.")
    if Options["Architecture"] and not Options["Partial"]:
        utils.warn("-a/--architecture implies -p/--partial.")
        Options["Partial"] = "true"
    if Options["Do-Close"] and not Options["Done"]:
        utils.fubar("No.")
    if (Options["Do-Close"]
           and (Options["Binary"] or Options["Binary-Only"] or Options["Source-Only"])):
        utils.fubar("No.")

    # Force the admin to tell someone if we're not doing a 'dak
    # cruft-report' inspired removal (or closing a bug, which counts
    # as telling someone).
    if not Options["No-Action"] and not Options["Carbon-Copy"] \
           and not Options["Done"] and Options["Reason"].find("[auto-cruft]") == -1:
        utils.fubar("Need a -C/--carbon-copy if not closing a bug and not doing a cruft removal.")

    # Process -C/--carbon-copy
    #
    # Accept 3 types of arguments (space separated):
    #  1) a number - assumed to be a bug number, i.e. [email protected]
    #  2) the keyword 'package' - cc's [email protected] for every argument
    #  3) contains a '@' - assumed to be an email address, used unmofidied
    #
    carbon_copy = []
    for copy_to in utils.split_args(Options.get("Carbon-Copy")):
        if copy_to.isdigit():
            if cnf.has_key("Dinstall::BugServer"):
                carbon_copy.append(copy_to + "@" + cnf["Dinstall::BugServer"])
            else:
                utils.fubar("Asked to send mail to #%s in BTS but Dinstall::BugServer is not configured" % copy_to)
        elif copy_to == 'package':
            for package in arguments:
                if cnf.has_key("Dinstall::PackagesServer"):
                    carbon_copy.append(package + "@" + cnf["Dinstall::PackagesServer"])
                if cnf.has_key("Dinstall::TrackingServer"):
                    carbon_copy.append(package + "@" + cnf["Dinstall::TrackingServer"])
        elif '@' in copy_to:
            carbon_copy.append(copy_to)
        else:
            utils.fubar("Invalid -C/--carbon-copy argument '%s'; not a bug number, 'package' or email address." % (copy_to))

    if Options["Binary"]:
        field = "b.package"
    else:
        field = "s.source"
    con_packages = "AND %s IN (%s)" % (field, ", ".join([ repr(i) for i in arguments ]))

    (con_suites, con_architectures, con_components, check_source) = \
                 utils.parse_args(Options)

    # Additional suite checks
    suite_ids_list = []
    whitelists = []
    suites = utils.split_args(Options["Suite"])
    suites_list = utils.join_with_commas_and(suites)
    if not Options["No-Action"]:
        for suite in suites:
            s = get_suite(suite, session=session)
            if s is not None:
                suite_ids_list.append(s.suite_id)
                whitelists.append(s.mail_whitelist)
            if suite in ("oldstable", "stable"):
                print "**WARNING** About to remove from the (old)stable suite!"
                print "This should only be done just prior to a (point) release and not at"
                print "any other time."
                game_over()
            elif suite == "testing":
                print "**WARNING About to remove from the testing suite!"
                print "There's no need to do this normally as removals from unstable will"
                print "propogate to testing automagically."
                game_over()

    # Additional architecture checks
    if Options["Architecture"] and check_source:
        utils.warn("'source' in -a/--argument makes no sense and is ignored.")

    # Additional component processing
    over_con_components = con_components.replace("c.id", "component")

    # Don't do dependency checks on multiple suites
    if Options["Rdep-Check"] and len(suites) > 1:
        utils.fubar("Reverse dependency check on multiple suites is not implemented.")

    to_remove = []
    maintainers = {}

    # We have 3 modes of package selection: binary, source-only, binary-only
    # and source+binary.

    # XXX: TODO: This all needs converting to use placeholders or the object
    #            API. It's an SQL injection dream at the moment

    if Options["Binary"]:
        # Removal by binary package name
        q = session.execute("SELECT b.package, b.version, a.arch_string, b.id, b.maintainer FROM binaries b, bin_associations ba, architecture a, suite su, files f, files_archive_map af, component c WHERE ba.bin = b.id AND ba.suite = su.id AND b.architecture = a.id AND b.file = f.id AND af.file_id = f.id AND af.archive_id = su.archive_id AND af.component_id = c.id %s %s %s %s" % (con_packages, con_suites, con_components, con_architectures))
        to_remove.extend(q)
    else:
        # Source-only
        if not Options["Binary-Only"]:
            q = session.execute("SELECT s.source, s.version, 'source', s.id, s.maintainer FROM source s, src_associations sa, suite su, archive, files f, files_archive_map af, component c WHERE sa.source = s.id AND sa.suite = su.id AND archive.id = su.archive_id AND s.file = f.id AND af.file_id = f.id AND af.archive_id = su.archive_id AND af.component_id = c.id %s %s %s" % (con_packages, con_suites, con_components))
            to_remove.extend(q)
        if not Options["Source-Only"]:
            # Source + Binary
            q = session.execute("""
                    SELECT b.package, b.version, a.arch_string, b.id, b.maintainer
                    FROM binaries b
                         JOIN bin_associations ba ON b.id = ba.bin
                         JOIN architecture a ON b.architecture = a.id
                         JOIN suite su ON ba.suite = su.id
                         JOIN archive ON archive.id = su.archive_id
                         JOIN files_archive_map af ON b.file = af.file_id AND af.archive_id = archive.id
                         JOIN component c ON af.component_id = c.id
                         JOIN source s ON b.source = s.id
                         JOIN src_associations sa ON s.id = sa.source AND sa.suite = su.id
                    WHERE TRUE %s %s %s %s""" % (con_packages, con_suites, con_components, con_architectures))
            to_remove.extend(q)

    if not to_remove:
        print "Nothing to do."
        sys.exit(0)

    # If we don't have a reason; spawn an editor so the user can add one
    # Write the rejection email out as the <foo>.reason file
    if not Options["Reason"] and not Options["No-Action"]:
        (fd, temp_filename) = utils.temp_filename()
        editor = os.environ.get("EDITOR","vi")
        result = os.system("%s %s" % (editor, temp_filename))
        if result != 0:
            utils.fubar ("vi invocation failed for `%s'!" % (temp_filename), result)
        temp_file = utils.open_file(temp_filename)
        for line in temp_file.readlines():
            Options["Reason"] += line
        temp_file.close()
        os.unlink(temp_filename)

    # Generate the summary of what's to be removed
    d = {}
    for i in to_remove:
        package = i[0]
        version = i[1]
        architecture = i[2]
        maintainer = i[4]
        maintainers[maintainer] = ""
        if not d.has_key(package):
            d[package] = {}
        if not d[package].has_key(version):
            d[package][version] = []
        if architecture not in d[package][version]:
            d[package][version].append(architecture)

    maintainer_list = []
    for maintainer_id in maintainers.keys():
        maintainer_list.append(get_maintainer(maintainer_id).name)
    summary = ""
    removals = d.keys()
    removals.sort()
    versions = []
    for package in removals:
        versions = d[package].keys()
        versions.sort(apt_pkg.version_compare)
        for version in versions:
            d[package][version].sort(utils.arch_compare_sw)
            summary += "%10s | %10s | %s\n" % (package, version, ", ".join(d[package][version]))
    print "Will remove the following packages from %s:" % (suites_list)
    print
    print summary
    print "Maintainer: %s" % ", ".join(maintainer_list)
    if Options["Done"]:
        print "Will also close bugs: "+Options["Done"]
    if carbon_copy:
        print "Will also send CCs to: " + ", ".join(carbon_copy)
    if Options["Do-Close"]:
        print "Will also close associated bug reports."
    print
    print "------------------- Reason -------------------"
    print Options["Reason"]
    print "----------------------------------------------"
    print

    if Options["Rdep-Check"]:
        arches = utils.split_args(Options["Architecture"])
        reverse_depends_check(removals, suites[0], arches, session)

    # If -n/--no-action, drop out here
    if Options["No-Action"]:
        sys.exit(0)

    print "Going to remove the packages now."
    game_over()

    whoami = utils.whoami()
    date = commands.getoutput('date -R')

    # Log first; if it all falls apart I want a record that we at least tried.
    logfile = utils.open_file(cnf["Rm::LogFile"], 'a')
    logfile.write("=========================================================================\n")
    logfile.write("[Date: %s] [ftpmaster: %s]\n" % (date, whoami))
    logfile.write("Removed the following packages from %s:\n\n%s" % (suites_list, summary))
    if Options["Done"]:
        logfile.write("Closed bugs: %s\n" % (Options["Done"]))
    logfile.write("\n------------------- Reason -------------------\n%s\n" % (Options["Reason"]))
    logfile.write("----------------------------------------------\n")

    # Do the same in rfc822 format
    logfile822 = utils.open_file(cnf["Rm::LogFile822"], 'a')
    logfile822.write("Date: %s\n" % date)
    logfile822.write("Ftpmaster: %s\n" % whoami)
    logfile822.write("Suite: %s\n" % suites_list)
    sources = []
    binaries = []
    for package in summary.split("\n"):
        for row in package.split("\n"):
            element = row.split("|")
            if len(element) == 3:
                if element[2].find("source") > 0:
                    sources.append("%s_%s" % tuple(elem.strip(" ") for elem in element[:2]))
                    element[2] = sub("source\s?,?", "", element[2]).strip(" ")
                if element[2]:
                    binaries.append("%s_%s [%s]" % tuple(elem.strip(" ") for elem in element))
    if sources:
        logfile822.write("Sources:\n")
        for source in sources:
            logfile822.write(" %s\n" % source)
    if binaries:
        logfile822.write("Binaries:\n")
        for binary in binaries:
            logfile822.write(" %s\n" % binary)
    logfile822.write("Reason: %s\n" % Options["Reason"].replace('\n', '\n '))
    if Options["Done"]:
        logfile822.write("Bug: %s\n" % Options["Done"])

    dsc_type_id = get_override_type('dsc', session).overridetype_id
    deb_type_id = get_override_type('deb', session).overridetype_id

    # Do the actual deletion
    print "Deleting...",
    sys.stdout.flush()

    for i in to_remove:
        package = i[0]
        architecture = i[2]
        package_id = i[3]
        for suite_id in suite_ids_list:
            if architecture == "source":
                session.execute("DELETE FROM src_associations WHERE source = :packageid AND suite = :suiteid",
                                {'packageid': package_id, 'suiteid': suite_id})
                #print "DELETE FROM src_associations WHERE source = %s AND suite = %s" % (package_id, suite_id)
            else:
                session.execute("DELETE FROM bin_associations WHERE bin = :packageid AND suite = :suiteid",
                                {'packageid': package_id, 'suiteid': suite_id})
                #print "DELETE FROM bin_associations WHERE bin = %s AND suite = %s" % (package_id, suite_id)
            # Delete from the override file
            if not Options["Partial"]:
                if architecture == "source":
                    type_id = dsc_type_id
                else:
                    type_id = deb_type_id
                # TODO: Again, fix this properly to remove the remaining non-bind argument
                session.execute("DELETE FROM override WHERE package = :package AND type = :typeid AND suite = :suiteid %s" % (over_con_components), {'package': package, 'typeid': type_id, 'suiteid': suite_id})
    session.commit()
    print "done."

    # If we don't have a Bug server configured, we're done
    if not cnf.has_key("Dinstall::BugServer"):
        if Options["Done"] or Options["Do-Close"]:
            print "Cannot send mail to BugServer as Dinstall::BugServer is not configured"

        logfile.write("=========================================================================\n")
        logfile.close()

        logfile822.write("\n")
        logfile822.close()

        return

    # read common subst variables for all bug closure mails
    Subst_common = {}
    Subst_common["__RM_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
    Subst_common["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
    Subst_common["__CC__"] = "X-DAK: dak rm"
    if carbon_copy:
        Subst_common["__CC__"] += "\nCc: " + ", ".join(carbon_copy)
    Subst_common["__SUITE_LIST__"] = suites_list
    Subst_common["__SUBJECT__"] = "Removed package(s) from %s" % (suites_list)
    Subst_common["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
    Subst_common["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
    Subst_common["__WHOAMI__"] = whoami

    # Send the bug closing messages
    if Options["Done"]:
        Subst_close_rm = Subst_common
        bcc = []
        if cnf.find("Dinstall::Bcc") != "":
            bcc.append(cnf["Dinstall::Bcc"])
        if cnf.find("Rm::Bcc") != "":
            bcc.append(cnf["Rm::Bcc"])
        if bcc:
            Subst_close_rm["__BCC__"] = "Bcc: " + ", ".join(bcc)
        else:
            Subst_close_rm["__BCC__"] = "X-Filler: 42"
        summarymail = "%s\n------------------- Reason -------------------\n%s\n" % (summary, Options["Reason"])
        summarymail += "----------------------------------------------\n"
        Subst_close_rm["__SUMMARY__"] = summarymail

        for bug in utils.split_args(Options["Done"]):
            Subst_close_rm["__BUG_NUMBER__"] = bug
            if Options["Do-Close"]:
                mail_message = utils.TemplateSubst(Subst_close_rm,cnf["Dir::Templates"]+"/rm.bug-close-with-related")
            else:
                mail_message = utils.TemplateSubst(Subst_close_rm,cnf["Dir::Templates"]+"/rm.bug-close")
            utils.send_mail(mail_message, whitelists=whitelists)

    # close associated bug reports
    if Options["Do-Close"]:
        Subst_close_other = Subst_common
        bcc = []
        wnpp = utils.parse_wnpp_bug_file()
        versions = list(set([re_bin_only_nmu.sub('', v) for v in versions]))
        if len(versions) == 1:
            Subst_close_other["__VERSION__"] = versions[0]
        else:
            utils.fubar("Closing bugs with multiple package versions is not supported.  Do it yourself.")
        if bcc:
            Subst_close_other["__BCC__"] = "Bcc: " + ", ".join(bcc)
        else:
            Subst_close_other["__BCC__"] = "X-Filler: 42"
        # at this point, I just assume, that the first closed bug gives
        # some useful information on why the package got removed
        Subst_close_other["__BUG_NUMBER__"] = utils.split_args(Options["Done"])[0]
        if len(sources) == 1:
            source_pkg = source.split("_", 1)[0]
        else:
            utils.fubar("Closing bugs for multiple source packages is not supported.  Do it yourself.")
        Subst_close_other["__BUG_NUMBER_ALSO__"] = ""
        Subst_close_other["__SOURCE__"] = source_pkg
        merged_bugs = set()
        other_bugs = bts.get_bugs('src', source_pkg, 'status', 'open', 'status', 'forwarded')
        if other_bugs:
            for bugno in other_bugs:
                if bugno not in merged_bugs:
                    for bug in bts.get_status(bugno):
                        for merged in bug.mergedwith:
                            other_bugs.remove(merged)
                            merged_bugs.add(merged)
            logfile.write("Also closing bug(s):")
            logfile822.write("Also-Bugs:")
            for bug in other_bugs:
                Subst_close_other["__BUG_NUMBER_ALSO__"] += str(bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
                logfile.write(" " + str(bug))
                logfile822.write(" " + str(bug))
            logfile.write("\n")
            logfile822.write("\n")
        if source_pkg in wnpp.keys():
            logfile.write("Also closing WNPP bug(s):")
            logfile822.write("Also-WNPP:")
            for bug in wnpp[source_pkg]:
                # the wnpp-rm file we parse also contains our removal
                # bugs, filtering that out
                if bug != Subst_close_other["__BUG_NUMBER__"]:
                    Subst_close_other["__BUG_NUMBER_ALSO__"] += str(bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
                    logfile.write(" " + str(bug))
                    logfile822.write(" " + str(bug))
            logfile.write("\n")
            logfile822.write("\n")

        mail_message = utils.TemplateSubst(Subst_close_other,cnf["Dir::Templates"]+"/rm.bug-close-related")
        if Subst_close_other["__BUG_NUMBER_ALSO__"]:
            utils.send_mail(mail_message)


    logfile.write("=========================================================================\n")
    logfile.close()

    logfile822.write("\n")
    logfile822.close()
Esempio n. 42
0
    def issues(self):
        # Initialise empty list of bug numbers
        collected_bugs = []

        # Search BTS for bugs owned by email address
        if self.email:
            owned_bugs = debianbts.get_bugs("owner", self.email,
                                            "status", "open")
            collected_bugs.extend(owned_bugs)

        # Search BTS for bugs related to specified packages
        if self.packages:
            packages = self.packages.split(",")
            for pkg in packages:
                pkg_bugs = debianbts.get_bugs("package", pkg,
                                              "status", "open")
                for bug in pkg_bugs:
                    if bug not in collected_bugs:
                        collected_bugs.append(bug)

        # Search UDD bugs search for bugs belonging to packages that
        # are maintained by the email address
        if self.udd:
            udd_bugs = self._get_udd_bugs()
            for bug in udd_bugs:
                if bug not in collected_bugs:
                    collected_bugs.append(bug['id'])

        issues = [self._record_for_bug(bug)
                  for bug in debianbts.get_status(collected_bugs)]

        log.debug(" Found %i total.", len(issues))

        if self.ignore_pkg:
            ignore_pkg = self.ignore_pkg.split(",")
            for pkg in ignore_pkg:
                issues = [issue
                          for issue in issues if not issue['package'] == pkg]

        if self.ignore_src:
            ignore_src = self.ignore_src.split(",")
            for src in ignore_src:
                issues = [issue
                          for issue in issues if not issue['source'] == src]

        if self.ignore_pending:
            issues = [issue
                      for issue in issues
                      if not issue['status'] == 'pending-fixed']

        issues = [issue
                  for issue in issues
                  if not (issue['status'] == 'done' or
                          issue['status'] == 'fixed')]

        log.debug(" Pruned down to %i.", len(issues))

        for issue in issues:
            issue_obj = self.get_issue_for_record(issue)
            extra = {
                'annotations': self.annotations(issue, issue_obj)
            }
            issue_obj.update_extra(extra)
            yield issue_obj
Esempio n. 43
0
    import_cmd += ' --upstream-tag=' + pkg_name + '/' + upstream_tag
    import_cmd += '/' + pkg_ver + ' --upstream-version=' + pkg_ver
    import_cmd += ' ' + import_tarball
    if verbose: print "Importing with this command:\n%s" % import_cmd
    if dry_run:
        print "DRY RUN: command not executed"
    else:
        if os.system(import_cmd) == 0:
            if verbose: print "Command executed successfully!"
        else:
            print "Command execution failed! Bailing out ..."
            sys.exit(1)

    # Pull bug reports, and remind user to check for closures
    try:
        bugs_fixed_upstream = debianbts.get_bugs('package', pkg_name, 'tag',
                                                 'fixed-upstream')
        bugs_upstream = debianbts.get_bugs('package', pkg_name, 'tag',
                                           'upstream')
        bugs_all = debianbts.get_bugs('package', pkg_name)
        print "\n" + "**********" * 8
        if len(bugs_fixed_upstream) > 0:
            print "\nBugs tagged 'fixed-upstream':"
        for b in bugs_fixed_upstream:
            if b in bugs_all: bugs_all.remove(b)  # avoid repeats below
            s = debianbts.get_status(b)
            if not s[0].done:
                print "\tBug %s: %s" % (s[0].bug_num, s[0].subject)
        if len(bugs_upstream) > 0: print "\nBugs tagged 'upstream':"
        for b in bugs_upstream:
            if b in bugs_all: bugs_all.remove(b)  # avoid repeats below
            s = debianbts.get_status(b)
Esempio n. 44
0
def fetch_bug_numbers_by_package(pkg_name):
    """Fetch non-archived bugs"""
    return debianbts.get_bugs('package', pkg_name, 'archive', 'false')
def test_get_bugs_single_int_bug():
    """bugs parameter in get_bugs can be a list of int or a int"""
    bugs1 = bts.get_bugs('bugs', 400040, 'archive', True)
    bugs2 = bts.get_bugs('bugs', [400040], 'archive', True)
    assert bugs1 == bugs2
Esempio n. 46
0
                        action="store_true",
                        help='dont generate images (for DEBUG)')
    parser.add_argument('--no-pypi',
                        default=False,
                        action="store_true",
                        help='dont look for modules on PyPI (for DEBUG)')
    args = parser.parse_args()

    if not os.path.isdir(args.destdir):
        os.makedirs(args.destdir)

    log('Retrieving WNPP bugs information...')
    if args.bugs:
        wnpp_bugs_ids = args.bugs
    else:
        wnpp_bugs_ids = debianbts.get_bugs('package', 'wnpp')
    if args.limit:
        wnpp_bugs_ids = wnpp_bugs_ids[:args.limit]
    log(f"Found {len(wnpp_bugs_ids)} WNPP bugs, getting status...")
    wnpp_bugs = debianbts.get_status(wnpp_bugs_ids)
    wnpp = {}
    for wnpp_bug in wnpp_bugs:
        if wnpp_bug.done:
            continue
        m = WNPPRE.match(wnpp_bug.subject)
        if m:
            tag, src = m.groups()
            wnpp[src] = (tag, wnpp_bug.bug_num)
        else:
            log(f"Badly formatted WNPP bug: retitle {wnpp_bug.bug_num} \"{wnpp_bug.subject}\""
                )
Esempio n. 47
0
    def lineedit_return_pressed(self):
        #
        # just in case ;)
        #
        text = unicode(self.lineEdit.text())
        if text.startswith("http://"):
            self._show_url(text)
            return
        if len(text) == 0:
            return

        self.logger.info("Return pressed.")
        self.lineEdit.clear()
        # TODO: self.lineEdit.clear() does not always work, why?
        #QtCore.QTimer.singleShot(0,self.lineEdit,QtCore.SLOT("clear()"))
        query = rng.translate_query(text)
        self.logger.debug("Query: %s" % str(query))

        # test if there is a submit-as field available and rename the packages
        # if nececesairy
        for i in range(0, len(query), 2):
            if query[i] == 'package':
                realname = bug.submit_as(query[i + 1])
                if query[i + 1] != realname:
                    self.logger.debug(
                        "Using %s as package name as requested by developer." %
                        str(realname))
                    query[i + 1] = realname
        # Single bug or list of bugs?
        if query[0]:
            buglist = bts.get_bugs(query)
        else:
            buglist = [query[1]]
        # ok, we know the package, so enable some buttons which don't depend
        # on the existence of the acutal packe (wnpp) or bugreports for that
        # package.
        if query[0] in ("src", "package"):
            self._stateChanged(query[1], None)
        # if we got a bugnumber we'd like to select it and enable some more
        # buttons. unfortunately we don't know if the bugnumber actually exists
        # for now, so we have to wait a bit until the bug is fetched.
        else:
            self._stateChanged(None, None)
        self.logger.debug("Buglist matching the query: %s" % str(buglist))
        chunksize = 50
        if len(buglist) > chunksize:
            self.load_started()
            self.logger.debug("Buglist longer than %i, splitting in chunks." %
                              chunksize)
            self.bugs = []
            i = 0
            for chunk in chunks(buglist, chunksize):
                i += 1
                progress = int(100. * i * chunksize / len(buglist))
                if progress > 100:
                    progress = 100
                self.load_progress(progress)
                bl = bts.get_status(chunk)
                if len(bl) == 0:
                    self.logger.error(
                        "One of the following bugs caused the BTS to hickup: %s"
                        % str(bl))
                self.bugs.extend(bl)
            self.load_finished(True)
        else:
            self.bugs = bts.get_status(buglist)
        # ok, we fetched the bugs. see if the list isn't empty
        if query[0] in (None, ) and len(self.bugs) > 0:
            self.currentBug = self.bugs[0]
            self.currentPackage = self.currentBug.package
            self._stateChanged(self.currentPackage, self.currentBug)
        self.model.set_elements(self.bugs)
        self.tableView.resizeRowsToContents()
Esempio n. 48
0
def get_package_bugs(source):
    import debianbts

    return set(debianbts.get_bugs(src=source, status="open"))
Esempio n. 49
0
 def test_get_bugs_int_bugs(self):
     """It is possible to pass a list of bug number to get_bugs"""
     bugs = bts.get_bugs('bugs', [400010, 400012], 'archive', True)
     self.assertEquals(set(bugs), set((400010, 400012)))