Пример #1
0
    def _check_dsc(self, verify_signature=False):
        "Check that the dsc matches what we are expecting"
        assert self._dsc is not None
        self.source = self.dsc['Source']
        self.version = debian.debian_support.Version(self.dsc['Version'])

        valid = False
        message = None
        gpg_info = None
        try:
            gpg_info = self.dsc.get_gpg_info()
            valid = gpg_info.valid()
        except IOError:
            message = ('Signature on %s could not be verified, install '
                       'debian-keyring' % self.dsc_name)
        if message is None:
            if valid:
                message = 'Valid signature'
            else:
                message = ('Signature on %s could not be verified' %
                           self.dsc_name)
        if gpg_info is not None:
            if 'GOODSIG' in gpg_info:
                message = ('Good signature by %s (0x%s)' %
                           (gpg_info['GOODSIG'][1], gpg_info['GOODSIG'][0]))
            elif 'VALIDSIG' in gpg_info:
                message = 'Valid signature by 0x%s' % gpg_info['VALIDSIG'][0]
        if verify_signature:
            if valid:
                Logger.normal(message)
            else:
                Logger.error(message)
                raise DownloadError(message)
        else:
            Logger.info(message)
Пример #2
0
def ask_for_patch_or_branch(bug, attached_patches, linked_branches):
    patch = None
    branch = None
    if len(attached_patches) == 0:
        msg = "https://launchpad.net/bugs/%i has %i branches linked:" % \
              (bug.id, len(linked_branches))
    elif len(linked_branches) == 0:
        msg = "https://launchpad.net/bugs/%i has %i patches attached:" % \
              (bug.id, len(attached_patches))
    else:
        branches = "%i branch" % len(linked_branches)
        if len(linked_branches) > 1:
            branches += "es"
        patches = "%i patch" % len(attached_patches)
        if len(attached_patches) > 1:
            patches += "es"
        msg = "https://launchpad.net/bugs/%i has %s linked and %s attached:" % \
              (bug.id, branches, patches)
    Logger.normal(msg)
    i = 0
    for linked_branch in linked_branches:
        i += 1
        print("%i) %s" % (i, linked_branch.display_name))
    for attached_patch in attached_patches:
        i += 1
        print("%i) %s" % (i, attached_patch.title))
    selected = input_number("Which branch or patch do you want to download", 1,
                            i, i)
    if selected <= len(linked_branches):
        branch = linked_branches[selected - 1].bzr_identity
    else:
        patch = Patch(attached_patches[selected - len(linked_branches) - 1])
    return (patch, branch)
Пример #3
0
def get_open_ubuntu_bug_task(launchpad, bug, branch=None):
    """Returns an open Ubuntu bug task for a given Launchpad bug.

    The bug task needs to be open (not complete) and target Ubuntu. The user
    will be ask to select one if multiple open Ubuntu bug task exits for the
    bug.
    """
    bug_tasks = [BugTask(x, launchpad) for x in bug.bug_tasks]
    ubuntu_tasks = [x for x in bug_tasks if x.is_ubuntu_task()]
    bug_id = bug.id
    if branch:
        branch = branch.split('/')
        # Non-production LP?
        if len(branch) > 5:
            branch = branch[3:]

    if len(ubuntu_tasks) == 0:
        Logger.error("No Ubuntu bug task found on bug #%i." % (bug_id))
        sys.exit(1)
    elif len(ubuntu_tasks) == 1:
        task = ubuntu_tasks[0]
    if len(ubuntu_tasks) > 1 and branch and branch[1] == 'ubuntu':
        tasks = [
            t for t in ubuntu_tasks
            if t.get_series() == branch[2] and t.package == branch[3]
        ]
        if len(tasks) > 1:
            # A bug targeted to the development series?
            tasks = [t for t in tasks if t.series is not None]
        assert len(tasks) == 1
        task = tasks[0]
    elif len(ubuntu_tasks) > 1:
        task_list = [t.get_short_info() for t in ubuntu_tasks]
        Logger.info("%i Ubuntu tasks exist for bug #%i.\n%s",
                    len(ubuntu_tasks), bug_id, "\n".join(task_list))
        open_ubuntu_tasks = [x for x in ubuntu_tasks if not x.is_complete()]
        if len(open_ubuntu_tasks) == 1:
            task = open_ubuntu_tasks[0]
        else:
            Logger.normal(
                "https://launchpad.net/bugs/%i has %i Ubuntu tasks:" %
                (bug_id, len(ubuntu_tasks)))
            for i in range(len(ubuntu_tasks)):
                print("%i) %s" %
                      (i + 1, ubuntu_tasks[i].get_package_and_series()))
            selected = input_number(
                "To which Ubuntu task does the patch belong", 1,
                len(ubuntu_tasks))
            task = ubuntu_tasks[selected - 1]
    Logger.info("Selected Ubuntu task: %s" % (task.get_short_info()))
    return task
Пример #4
0
    def ack_sync(self, upload, task, launchpad):
        """Acknowledge a sync request and subscribe ubuntu-archive."""

        if upload == "ubuntu":
            self._print_logs()
            question = Question(["yes", "edit", "no"])
            answer = question.ask("Do you want to acknowledge the sync request",
                                  "no")
            if answer == "edit":
                return False
            elif answer == "no":
                user_abort()

            bug = task.bug
            task.status = "Confirmed"
            if task.importance == "Undecided":
                task.importance = "Wishlist"
            task.lp_save()
            Logger.info("Set bug #%i status to Confirmed.", bug.id)

            msg = "Sync request ACK'd."
            if self._build_log:
                msg = ("%s %s builds on %s. " + msg) % \
                      (self._package, self._version,
                       self._builder.get_architecture())
            bug.newMessage(content=msg, subject="sponsor-patch")
            Logger.info("Acknowledged sync request bug #%i.", bug.id)

            bug.subscribe(person=launchpad.people['ubuntu-archive'])
            Logger.info("Subscribed ubuntu-archive to bug #%i.", bug.id)

            bug.subscribe(person=launchpad.me)
            Logger.info("Subscribed me to bug #%i.", bug.id)

            sponsorsteam = launchpad.people['ubuntu-sponsors']
            for sub in bug.subscriptions:
                if sub.person == sponsorsteam and sub.canBeUnsubscribedByUser():
                    bug.unsubscribe(person=launchpad.people['ubuntu-sponsors'])
                    Logger.info("Unsubscribed ubuntu-sponsors from bug #%i.",
                                bug.id)
                elif sub.person == sponsorsteam:
                    Logger.info("Couldn't unsubscribe ubuntu-sponsors from "
                                "bug #%i.", bug.id)

            Logger.normal("Successfully acknowledged sync request bug #%i.",
                          bug.id)
        else:
            Logger.error("Sync requests can only be acknowledged when the "
                         "upload target is Ubuntu.")
            sys.exit(1)
        return True
Пример #5
0
    def _download_file(self, url, filename):
        "Download url to filename in workdir."
        pathname = os.path.join(self.workdir, filename)
        if self.dsc.verify_file(pathname):
            Logger.debug('Using existing %s', filename)
            return True
        size = [
            entry['size'] for entry in self.dsc['Files']
            if entry['name'] == filename
        ]
        assert len(size) == 1
        size = int(size[0])
        parsed = urlparse(url)
        if not self.quiet:
            Logger.normal('Downloading %s from %s (%0.3f MiB)', filename,
                          parsed.hostname, size / 1024.0 / 1024)

        if parsed.scheme == 'file':
            in_ = open(parsed.path, 'rb')
        else:
            try:
                in_ = self.url_opener.open(url)
            except URLError:
                return False

        downloaded = 0
        bar_width = 60
        try:
            with open(pathname, 'wb') as out:
                while True:
                    block = in_.read(10240)
                    if block == b'':
                        break
                    downloaded += len(block)
                    out.write(block)
                    if not self.quiet:
                        percent = downloaded * 100 // size
                        bar = '=' * int(round(downloaded * bar_width / size))
                        bar = (bar + '>' + ' ' * bar_width)[:bar_width]
                        Logger.stdout.write('[%s] %#3i%%\r' % (bar, percent))
                        Logger.stdout.flush()
            in_.close()
        finally:
            if not self.quiet:
                Logger.stdout.write(' ' * (bar_width + 7) + '\r')
                Logger.stdout.flush()
        if not self.dsc.verify_file(pathname):
            Logger.error('Checksum for %s does not match.', filename)
            return False
        return True
Пример #6
0
 def pull(self):
     "Pull into workdir"
     self._write_dsc()
     for entry in self.dsc['Files']:
         name = entry['name']
         for url in self._source_urls(name):
             try:
                 if self._download_file(url, name):
                     break
             except HTTPError as e:
                 Logger.normal('HTTP Error %i: %s', e.code, str(e))
             except URLError as e:
                 Logger.normal('URL Error: %s', e.reason)
         else:
             raise DownloadError('File %s could not be found' % name)
Пример #7
0
    def lp_spph(self):
        "Return the LP Source Package Publishing History entry"
        if not self._spph:
            try:
                return super(DebianSourcePackage, self).lp_spph
            except IndexError:
                pass

            Logger.normal('Using rmadison for component determination')
            comp = 'main'
            for record in rmadison(self.distribution, self.source):
                if record.get('source') != self.source:
                    continue
                comp = record['component']
                if record['version'] == self.version.full_version:
                    self._spph = FakeSPPH(record['source'], record['version'],
                                          comp, 'debian')
                    return self._spph

            Logger.normal('Guessing component from most recent upload')
            self._spph = FakeSPPH(self.source, self.version.full_version, comp,
                                  'debian')
        return self._spph
Пример #8
0
def mail_bug(srcpkg, subscribe, status, bugtitle, bugtext, bug_mail_domain,
             keyid, myemailaddr, mailserver_host, mailserver_port,
             mailserver_user, mailserver_pass):
    '''
    Submit the sync request per email.
    '''

    to = 'new@' + bug_mail_domain

    # generate mailbody
    if srcpkg:
        mailbody = ' affects ubuntu/%s\n' % srcpkg
    else:
        mailbody = ' affects ubuntu\n'
    mailbody += '''\
 status %s
 importance wishlist
 subscribe %s
 done

%s''' % (status, subscribe, bugtext)

    # prepare sign command
    gpg_command = None
    for cmd in ('gnome-gpg', 'gpg2', 'gpg'):
        if os.access('/usr/bin/%s' % cmd, os.X_OK):
            gpg_command = [cmd]
            break

    if not gpg_command:
        Logger.error("Cannot locate gpg, please install the 'gnupg' package!")
        sys.exit(1)

    gpg_command.append('--clearsign')
    if keyid:
        gpg_command.extend(('-u', keyid))

    # sign the mail body
    gpg = subprocess.Popen(gpg_command,
                           stdin=subprocess.PIPE,
                           stdout=subprocess.PIPE)
    signed_report = gpg.communicate(
        mailbody.encode('utf-8'))[0].decode('utf-8')
    if gpg.returncode != 0:
        Logger.error("%s failed.", gpg_command[0])
        sys.exit(1)

    # generate email
    mail = u'''\
From: %s
To: %s
Subject: %s
Content-Type: text/plain; charset=UTF-8

%s''' % (myemailaddr, to, bugtitle, signed_report)

    print('The final report is:\n%s' % mail)
    confirmation_prompt()

    # save mail in temporary file
    backup = tempfile.NamedTemporaryFile(
        mode='w',
        delete=False,
        prefix='requestsync-' +
        re.sub(r'[^a-zA-Z0-9_-]', '', bugtitle.replace(' ', '_')))
    with backup:
        backup.write(mail)

    Logger.normal(
        'The e-mail has been saved in %s and will be deleted '
        'after succesful transmission', backup.name)

    # connect to the server
    while True:
        try:
            Logger.normal('Connecting to %s:%s ...', mailserver_host,
                          mailserver_port)
            s = smtplib.SMTP(mailserver_host, mailserver_port)
            break
        except smtplib.SMTPConnectError as s:
            try:
                # py2 path
                # pylint: disable=unsubscriptable-object
                Logger.error('Could not connect to %s:%s: %s (%i)',
                             mailserver_host, mailserver_port, s[1], s[0])
            except TypeError:
                # pylint: disable=no-member
                Logger.error('Could not connect to %s:%s: %s (%i)',
                             mailserver_host, mailserver_port, s.strerror,
                             s.errno)
            if s.smtp_code == 421:
                confirmation_prompt(
                    message='This is a temporary error, press [Enter] '
                    'to retry. Press [Ctrl-C] to abort now.')
        except socket.error as s:
            try:
                # py2 path
                # pylint: disable=unsubscriptable-object
                Logger.error('Could not connect to %s:%s: %s (%i)',
                             mailserver_host, mailserver_port, s[1], s[0])
            except TypeError:
                # pylint: disable=no-member
                Logger.error('Could not connect to %s:%s: %s (%i)',
                             mailserver_host, mailserver_port, s.strerror,
                             s.errno)
            return

    if mailserver_user and mailserver_pass:
        try:
            s.login(mailserver_user, mailserver_pass)
        except smtplib.SMTPAuthenticationError:
            Logger.error('Error authenticating to the server: '
                         'invalid username and password.')
            s.quit()
            return
        except smtplib.SMTPException:
            Logger.error('Unknown SMTP error.')
            s.quit()
            return

    while True:
        try:
            s.sendmail(myemailaddr, to, mail.encode('utf-8'))
            s.quit()
            os.remove(backup.name)
            Logger.normal('Sync request mailed.')
            break
        except smtplib.SMTPRecipientsRefused as smtperror:
            smtp_code, smtp_message = smtperror.recipients[to]
            Logger.error('Error while sending: %i, %s', smtp_code,
                         smtp_message)
            if smtp_code == 450:
                confirmation_prompt(
                    message='This is a temporary error, press [Enter] '
                    'to retry. Press [Ctrl-C] to abort now.')
            else:
                return
        except smtplib.SMTPResponseException as e:
            Logger.error('Error while sending: %i, %s', e.smtp_code,
                         e.smtp_error)
            return
        except smtplib.SMTPServerDisconnected:
            Logger.error('Server disconnected while sending the mail.')
            return