Пример #1
0
def __send_message(msg_type, tmpl, options, *args):
    """Message sending dispatcher.
    """
    domain = options.domain or config.get('stgit.domain')

    if domain:
        if sys.version_info < (3, 2):
            raise CmdException("Setting domain requires Python version 3.2+")
        msg_id = email.utils.make_msgid('stgit', domain=domain)
    else:
        msg_id = email.utils.make_msgid('stgit')

    if msg_type == 'cover':
        assert len(args) == 1, 'too many args for msg_type == "cover"'
        patches = args[0]
        msg = __build_cover(tmpl, msg_id, options, patches)
        outstr = 'the cover message'
    elif msg_type == 'patch':
        patch, patch_nr, total_nr, ref_id = args
        msg = __build_message(tmpl, msg_id, options, patch, patch_nr, total_nr,
                              ref_id)
        outstr = 'patch "%s"' % patch
    else:
        raise AssertionError('invalid msg_type: %s' %
                             msg_type)  # pragma: no cover

    if hasattr(msg, 'as_bytes'):
        msg_bytes = msg.as_bytes(options.mbox)
    else:
        msg_bytes = msg.as_string(options.mbox)
        # Python 3.3 only has Message.as_string(). We encode it back to bytes
        # and hope for the best.
        if isinstance(msg_bytes, text):
            msg_bytes = msg_bytes.encode('utf-8')
    if options.mbox:
        out.stdout_bytes(msg_bytes + b'\n')
        return msg_id

    if not options.git:
        from_addr, to_addrs = __parse_addresses(msg)
        out.start('Sending ' + outstr)

    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
    if options.git:
        __send_message_git(msg_bytes, msg['From'], options)
    elif smtpserver.startswith('/'):
        # Use the sendmail tool
        __send_message_sendmail(smtpserver, msg_bytes)
    else:
        # Use the SMTP server (we have host and port information)
        __send_message_smtp(smtpserver, from_addr, to_addrs, msg_bytes,
                            options)

    # give recipients a chance of receiving related patches in correct order
    if msg_type == 'cover' or (msg_type == 'patch' and patch_nr < total_nr):
        sleep = options.sleep or config.getint('stgit.smtpdelay')
        time.sleep(sleep)
    if not options.git:
        out.done()
    return msg_id
Пример #2
0
def func(parser, options, args):
    """Create a new patch."""
    stack = directory.repository.current_stack
    if stack.repository.default_index.conflicts():
        raise CmdException(
            'Cannot create a new patch -- resolve conflicts first')

    # Choose a name for the new patch -- or None, which means make one
    # up later when we've gotten hold of the commit message.
    if len(args) == 0:
        name = None
    elif len(args) == 1:
        name = args[0]
        if not stack.patches.is_name_valid(name):
            raise CmdException('Invalid patch name: "%s"' % name)
        elif name in stack.patches:
            raise CmdException('%s: patch already exists' % name)
    else:
        parser.error('incorrect number of arguments')

    if options.verbose:
        verbose = options.verbose
    else:
        verbose_int = config.getint('commit.verbose')
        verbose = verbose_int > 0 if verbose_int else False

    cd = CommitData(
        tree=stack.head.data.tree,
        parents=[stack.head],
        message='',
        author=Person.author(),
        committer=Person.committer(),
    )
    cd = update_commit_data(
        cd,
        message=options.message,
        author=options.author(cd.author),
        sign_str=options.sign_str,
        edit=(not options.save_template and options.message is None),
        verbose=verbose,
    )

    if options.save_template:
        options.save_template(cd.message)
        return utils.STGIT_SUCCESS

    if not options.no_verify:
        cd = run_commit_msg_hook(stack.repository, cd)

    if name is None:
        name = stack.patches.make_name(cd.message_str)

    # Write the new patch.
    stack.repository.default_iw
    trans = StackTransaction(stack, 'new: %s' % name)
    trans.patches[name] = stack.repository.commit(cd)
    trans.applied.append(name)
    return trans.run()
Пример #3
0
def patch_name_from_msg(msg):
    """Return a string to be used as a patch name. This is generated
    from the top line of the string passed as argument."""
    if not msg:
        return None

    name_len = config.getint("stgit.namelength")
    if not name_len:
        name_len = 30

    subject_line = msg.split("\n", 1)[0].lstrip().lower()
    return re.sub("[\W]+", "-", subject_line).strip("-")[:name_len]
Пример #4
0
def __send_message(msg_type, tmpl, options, *args):
    """Message sending dispatcher.
    """
    msg_id = email.utils.make_msgid('stgit',
                                    domain=options.domain
                                    or config.get('stgit.domain'))

    if msg_type == 'cover':
        assert len(args) == 1, 'too many args for msg_type == "cover"'
        patches = args[0]
        msg = __build_cover(tmpl, msg_id, options, patches)
        outstr = 'the cover message'
    elif msg_type == 'patch':
        patch, patch_nr, total_nr, ref_id = args
        msg = __build_message(tmpl, msg_id, options, patch, patch_nr, total_nr,
                              ref_id)
        outstr = 'patch "%s"' % patch
    else:
        raise AssertionError('invalid msg_type: %s' %
                             msg_type)  # pragma: no cover

    msg_bytes = msg.as_bytes(options.mbox)

    if options.mbox:
        out.stdout_bytes(msg_bytes + b'\n')
        return msg_id

    if not options.git:
        from_addr, to_addrs = __parse_addresses(msg)
        out.start('Sending ' + outstr)

    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
    if options.git:
        __send_message_git(msg_bytes, msg['From'], options)
    elif smtpserver.startswith('/'):
        # Use the sendmail tool
        __send_message_sendmail(smtpserver, msg_bytes)
    else:
        # Use the SMTP server (we have host and port information)
        __send_message_smtp(smtpserver, from_addr, to_addrs, msg_bytes,
                            options)

    # give recipients a chance of receiving related patches in correct order
    if msg_type == 'cover' or (msg_type == 'patch' and patch_nr < total_nr):
        sleep = options.sleep or config.getint('stgit.smtpdelay')
        time.sleep(sleep)
    if not options.git:
        out.done()
    return msg_id
Пример #5
0
def __send_message(type, tmpl, options, *args):
    """Message sending dispatcher.
    """
    (build, outstr) = {
        'cover': (__build_cover, 'the cover message'),
        'patch': (__build_message, 'patch "%s"' % args[0]),
    }[type]
    if type == 'patch':
        (patch_nr, total_nr) = (args[1], args[2])

    msg_id = email.utils.make_msgid('stgit')
    msg = build(tmpl, msg_id, options, *args)

    if hasattr(msg, 'as_bytes'):
        msg_bytes = msg.as_bytes(options.mbox)
    else:
        msg_bytes = msg.as_string(options.mbox)
        # Python 3.3 only has Message.as_string(). We encode it back to bytes
        # and hope for the best.
        if isinstance(msg_bytes, text):
            msg_bytes = msg_bytes.encode('utf-8')
    if options.mbox:
        out.stdout_bytes(msg_bytes + b'\n')
        return msg_id

    if not options.git:
        from_addr, to_addrs = __parse_addresses(msg)
        out.start('Sending ' + outstr)

    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
    if options.git:
        __send_message_git(msg_bytes, msg['From'], options)
    elif smtpserver.startswith('/'):
        # Use the sendmail tool
        __send_message_sendmail(smtpserver, msg_bytes)
    else:
        # Use the SMTP server (we have host and port information)
        __send_message_smtp(smtpserver, from_addr, to_addrs, msg_bytes,
                            options)

    # give recipients a chance of receiving related patches in correct order
    if type == 'cover' or (type == 'patch' and patch_nr < total_nr):
        sleep = options.sleep or config.getint('stgit.smtpdelay')
        time.sleep(sleep)
    if not options.git:
        out.done()
    return msg_id
Пример #6
0
def patch_name_from_msg(msg):
    """Return a string to be used as a patch name. This is generated
    from the top line of the string passed as argument."""
    if not msg:
        return None

    name_len = config.getint('stgit.namelength')
    if not name_len:
        name_len = 30

    subject_line = msg.split('\n', 1)[0].lstrip().lower()
    words = re.sub(r'[\W]+', ' ', subject_line).split()

    # use loop to avoid truncating the last name
    name = words and words[0] or 'unknown'
    for word in words[1:]:
        new = name + '-' + word
        if len(new) > name_len:
            break
        name = new

    return name
Пример #7
0
def patch_name_from_msg(msg):
    """Return a string to be used as a patch name. This is generated
    from the top line of the string passed as argument."""
    if not msg:
        return None

    name_len = config.getint('stgit.namelength')
    if not name_len:
        name_len = 30

    subject_line = msg.split('\n', 1)[0].lstrip().lower()
    words = re.sub(r'(?u)[\W]+', ' ', subject_line).split()

    # use loop to avoid truncating the last name
    name = words and words[0] or 'unknown'
    for word in words[1:]:
        new = name + '-' + word
        if len(new) > name_len:
            break
        name = new

    return name
Пример #8
0
def __send_message(type, tmpl, options, *args):
    """Message sending dispatcher.
    """
    (build, outstr) = {
        'cover': (__build_cover, 'the cover message'),
        'patch': (__build_message, 'patch "%s"' % args[0])
    }[type]
    if type == 'patch':
        (patch_nr, total_nr) = (args[1], args[2])

    msg_id = email.utils.make_msgid('stgit')
    msg = build(tmpl, msg_id, options, *args)

    msg_str = msg.as_string(options.mbox)
    if options.mbox:
        out.stdout_raw(msg_str + '\n')
        return msg_id

    if not options.git:
        from_addr, to_addrs = __parse_addresses(msg)
        out.start('Sending ' + outstr)

    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
    if options.git:
        __send_message_git(msg, options)
    elif smtpserver.startswith('/'):
        # Use the sendmail tool
        __send_message_sendmail(smtpserver, msg_str)
    else:
        # Use the SMTP server (we have host and port information)
        __send_message_smtp(smtpserver, from_addr, to_addrs, msg_str, options)

    # give recipients a chance of receiving related patches in correct order
    if type == 'cover' or (type == 'patch' and patch_nr < total_nr):
        sleep = options.sleep or config.getint('stgit.smtpdelay')
        time.sleep(sleep)
    if not options.git:
        out.done()
    return msg_id
Пример #9
0
Файл: mail.py Проект: samv/stgit
def __send_message(type, tmpl, options, *args):
    """Message sending dispatcher.
    """
    (build, outstr) = {'cover': (__build_cover, 'the cover message'),
                       'patch': (__build_message, 'patch "%s"' % args[0])}[type]
    if type == 'patch':
        (patch_nr, total_nr) = (args[1], args[2])

    msg_id = email.Utils.make_msgid('stgit')
    msg = build(tmpl, msg_id, options, *args)

    msg_str = msg.as_string(options.mbox)
    if options.mbox:
        out.stdout_raw(msg_str + '\n')
        return msg_id

    if not options.git:
        from_addr, to_addrs = __parse_addresses(msg)
        out.start('Sending ' + outstr)

    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
    if options.git:
        __send_message_git(msg, options)
    elif smtpserver.startswith('/'):
        # Use the sendmail tool
        __send_message_sendmail(smtpserver, msg_str)
    else:
        # Use the SMTP server (we have host and port information)
        __send_message_smtp(smtpserver, from_addr, to_addrs, msg_str, options)

    # give recipients a chance of receiving related patches in correct order
    if type == 'cover' or (type == 'patch' and patch_nr < total_nr):
        sleep = options.sleep or config.getint('stgit.smtpdelay')
        time.sleep(sleep)
    if not options.git:
        out.done()
    return msg_id
Пример #10
0
    def make_name(self, raw, unique=True, lower=True, allow=(), disallow=()):
        """Make a unique and valid patch name from provided raw name.

        The raw name may come from a filename, commit message, or email subject line.

        The generated patch name will meet the rules of `git check-ref-format` along
        with some additional StGit patch name rules.

        """
        default_name = 'patch'

        for line in raw.splitlines():
            trimmed = line.strip()
            if trimmed:
                candidate = trimmed
                break
        else:
            candidate = default_name

        if lower:
            candidate = candidate.lower()

        name = ""
        prev = ''

        # Git has a bunch of rules about which ascii symbols are valid
        # in ref names (see git-check-ref-format(1)), but to keep
        # generated patch names clean, most ascii symbols are mapped to
        # '-' in the generated patch name.
        #
        # Characters that are valid and _could_ be allowed in patchnames:
        #   ()<>!#$%'"`|;,]}+=
        #
        # Characters that are never valid:
        #   ~:^&*[  (along with control characters)
        #
        # Characters that are valid in some contexts:
        #   @{/.
        for c in candidate:
            if c.isspace() or not c.isprintable():
                # Replace all ascii and unicode whitespace and non-printables
                if prev != '-':
                    name += '-'
                    prev = '-'
            elif c.isalnum() or c == '_' or not ord(c) < 127:
                # Accept all ascii alphanumerics and '_' along with
                # remaining printable, non-whitespace unicode characters.
                name += c
                prev = c
            elif c in '-.':
                # '.' and '-' are okay, but not consecutively
                if prev not in '-.':
                    name += c
                    prev = c
            elif prev not in '-.':
                # Replace non-alphanumeric ascii chars with '-'
                name += '-'
                prev = '-'

        while True:
            prev_len = len(name)
            while name.endswith(".lock"):
                name = name.rsplit(".lock", 1)[0]
            name = name.strip('-.')
            if len(name) == prev_len:
                break

        # Might not be anything left after the above stripping
        if not name:
            name = default_name

        len_limit = config.getint('stgit.namelength')

        if len_limit is None or len_limit <= 0 or len(name) <= len_limit:
            short_name = name
        else:
            words = [w.strip('.') for w in name.split('-')]
            if words:
                short_name = words.pop(0)
            else:
                short_name = default_name

            for word in words:
                if len(short_name) + 1 + len(word) <= len_limit:
                    short_name += '-' + word
                else:
                    break

        assert self.is_name_valid(short_name), (candidate, short_name)

        if not unique:
            return short_name

        unique_name = short_name
        while unique_name not in allow and (unique_name in self
                                            or unique_name in disallow):
            m = re.match(r'(.*?)(-)?(\d+)$', unique_name)
            if m:
                base, sep, n_str = m.groups()
                n = int(n_str) + 1
                if sep:
                    unique_name = '%s%s%d' % (base, sep, n)
                else:
                    unique_name = '%s%d' % (base, n)
            else:
                unique_name = '%s-1' % unique_name

        assert self.is_name_valid(unique_name), (candidate, unique_name)
        return unique_name
Пример #11
0
    def make_name(self, raw, unique=True, lower=True, allow=(), disallow=()):
        """Make a unique and valid patch name from provided raw name.

        The raw name may come from a filename, commit message, or email subject line.

        The generated patch name will meet the rules of `git check-ref-format` along
        with some additional StGit patch name rules.

        """
        default_name = 'patch'

        for line in raw.split('\n'):
            if line:
                break

        if not line:
            line = default_name

        if lower:
            line = line.lower()

        parts = []
        for part in line.split('/'):
            # fmt: off
            part = re.sub(r'\.lock$', '', part)  # Disallowed in Git refs
            part = re.sub(r'^\.+|\.+$', '',
                          part)  # Cannot start or end with '.'
            part = re.sub(r'\.+', '.', part)  # No consecutive '.'
            part = re.sub(r'[^\w.]+', '-',
                          part)  # Non-word and whitespace to dashes
            part = re.sub(r'-+', '-', part)  # Squash consecutive dashes
            part = re.sub(r'^-+|-+$', '',
                          part)  # Remove leading and trailing dashes
            # fmt: on
            if part:
                parts.append(part)

        long_name = '/'.join(parts)

        # TODO: slashes could be allowed in the future.
        long_name = long_name.replace('/', '-')

        if not long_name:
            long_name = default_name

        assert self.is_name_valid(long_name)

        name_len = config.getint('stgit.namelength')

        words = long_name.split('-')
        short_name = words[0]
        for word in words[1:]:
            new_name = '%s-%s' % (short_name, word)
            if name_len <= 0 or len(new_name) <= name_len:
                short_name = new_name
            else:
                break
        assert self.is_name_valid(short_name)

        if not unique:
            return short_name

        unique_name = short_name
        while unique_name not in allow and (self.exists(unique_name)
                                            or unique_name in disallow):
            m = re.match(r'(.*?)(-)?(\d+)$', unique_name)
            if m:
                base, sep, n_str = m.groups()
                n = int(n_str) + 1
                if sep:
                    unique_name = '%s%s%d' % (base, sep, n)
                else:
                    unique_name = '%s%d' % (base, n)
            else:
                unique_name = '%s-1' % unique_name

        assert self.is_name_valid(unique_name)
        return unique_name
Пример #12
0
def func(parser, options, args):
    """Send the patches by e-mail using the patchmail.tmpl file as
    a template
    """
    smtpserver = config.get('stgit.smtpserver')

    applied = crt_series.get_applied()

    if options.all:
        patches = applied
    elif len(args) >= 1:
        unapplied = crt_series.get_unapplied()
        patches = parse_patches(args, applied + unapplied, len(applied))
    else:
        raise CmdException, 'Incorrect options. Unknown patches to send'

    smtppassword = options.smtp_password or config.get('stgit.smtppassword')
    smtpuser = options.smtp_user or config.get('stgit.smtpuser')

    if (smtppassword and not smtpuser):
        raise CmdException, 'SMTP password supplied, username needed'
    if (smtpuser and not smtppassword):
        raise CmdException, 'SMTP username supplied, password needed'

    total_nr = len(patches)
    if total_nr == 0:
        raise CmdException, 'No patches to send'

    if options.refid:
        if options.noreply or options.unrelated:
            raise CmdException, \
                  '--refid option not allowed with --noreply or --unrelated'
        ref_id = options.refid
    else:
        ref_id = None

    sleep = options.sleep or config.getint('stgit.smtpdelay')

    # send the cover message (if any)
    if options.cover or options.edit_cover:
        if options.unrelated:
            raise CmdException, 'cover sending not allowed with --unrelated'

        # find the template file
        if options.cover:
            tmpl = file(options.cover).read()
        else:
            tmpl = templates.get_template('covermail.tmpl')
            if not tmpl:
                raise CmdException, 'No cover message template file found'

        msg_id = email.Utils.make_msgid('stgit')
        msg = __build_cover(tmpl, total_nr, msg_id, options)
        from_addr, to_addr_list = __parse_addresses(msg)

        msg_string = msg.as_string(options.mbox)

        # subsequent e-mails are seen as replies to the first one
        if not options.noreply:
            ref_id = msg_id

        if options.mbox:
            out.stdout_raw(msg_string + '\n')
        else:
            out.start('Sending the cover message')
            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
                           sleep, smtpuser, smtppassword)
            out.done()

    # send the patches
    if options.template:
        tmpl = file(options.template).read()
    else:
        tmpl = templates.get_template('patchmail.tmpl')
        if not tmpl:
            raise CmdException, 'No e-mail template file found'

    for (p, patch_nr) in zip(patches, range(1, len(patches) + 1)):
        msg_id = email.Utils.make_msgid('stgit')
        msg = __build_message(tmpl, p, patch_nr, total_nr, msg_id, ref_id,
                              options)
        from_addr, to_addr_list = __parse_addresses(msg)

        msg_string = msg.as_string(options.mbox)

        # subsequent e-mails are seen as replies to the first one
        if not options.noreply and not options.unrelated and not ref_id:
            ref_id = msg_id

        if options.mbox:
            out.stdout_raw(msg_string + '\n')
        else:
            out.start('Sending patch "%s"' % p)
            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
                           sleep, smtpuser, smtppassword)
            out.done()
Пример #13
0
def func(parser, options, args):
    """Send the patches by e-mail using the patchmail.tmpl file as
    a template
    """
    smtpserver = config.get('stgit.smtpserver')

    applied = crt_series.get_applied()

    if options.all:
        patches = applied
    elif len(args) >= 1:
        unapplied = crt_series.get_unapplied()
        patches = parse_patches(args, applied + unapplied, len(applied))
    else:
        raise CmdException, 'Incorrect options. Unknown patches to send'

    smtppassword = options.smtp_password or config.get('stgit.smtppassword')
    smtpuser = options.smtp_user or config.get('stgit.smtpuser')

    if (smtppassword and not smtpuser):
        raise CmdException, 'SMTP password supplied, username needed'
    if (smtpuser and not smtppassword):
        raise CmdException, 'SMTP username supplied, password needed'

    total_nr = len(patches)
    if total_nr == 0:
        raise CmdException, 'No patches to send'

    if options.refid:
        if options.noreply or options.unrelated:
            raise CmdException, \
                  '--refid option not allowed with --noreply or --unrelated'
        ref_id = options.refid
    else:
        ref_id = None

    sleep = options.sleep or config.getint('stgit.smtpdelay')

    # send the cover message (if any)
    if options.cover or options.edit_cover:
        if options.unrelated:
            raise CmdException, 'cover sending not allowed with --unrelated'

        # find the template file
        if options.cover:
            tmpl = file(options.cover).read()
        else:
            tmpl = templates.get_template('covermail.tmpl')
            if not tmpl:
                raise CmdException, 'No cover message template file found'

        msg_id = email.Utils.make_msgid('stgit')
        msg = __build_cover(tmpl, total_nr, msg_id, options)
        from_addr, to_addr_list = __parse_addresses(msg)

        msg_string = msg.as_string(options.mbox)

        # subsequent e-mails are seen as replies to the first one
        if not options.noreply:
            ref_id = msg_id

        if options.mbox:
            out.stdout_raw(msg_string + '\n')
        else:
            out.start('Sending the cover message')
            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
                           sleep, smtpuser, smtppassword)
            out.done()

    # send the patches
    if options.template:
        tmpl = file(options.template).read()
    else:
        tmpl = templates.get_template('patchmail.tmpl')
        if not tmpl:
            raise CmdException, 'No e-mail template file found'

    for (p, patch_nr) in zip(patches, range(1, len(patches) + 1)):
        msg_id = email.Utils.make_msgid('stgit')
        msg = __build_message(tmpl, p, patch_nr, total_nr, msg_id, ref_id,
                              options)
        from_addr, to_addr_list = __parse_addresses(msg)

        msg_string = msg.as_string(options.mbox)

        # subsequent e-mails are seen as replies to the first one
        if not options.noreply and not options.unrelated and not ref_id:
            ref_id = msg_id

        if options.mbox:
            out.stdout_raw(msg_string + '\n')
        else:
            out.start('Sending patch "%s"' % p)
            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
                           sleep, smtpuser, smtppassword)
            out.done()
Пример #14
0
def func(parser, options, args):
    """Send the patches by e-mail using the patchmail.tmpl file as
    a template
    """
    smtpserver = options.smtp_server or config.get('stgit.smtpserver')

    applied = crt_series.get_applied()

    if options.all:
        patches = applied
    elif len(args) >= 1:
        unapplied = crt_series.get_unapplied()
        patches = parse_patches(args, applied + unapplied, len(applied))
    else:
        raise CmdException, 'Incorrect options. Unknown patches to send'

    # early test for sender identity
    __get_sender()

    out.start('Checking the validity of the patches')
    for p in patches:
        if crt_series.empty_patch(p):
            raise CmdException, 'Cannot send empty patch "%s"' % p
    out.done()

    smtppassword = options.smtp_password or config.get('stgit.smtppassword')
    smtpuser = options.smtp_user or config.get('stgit.smtpuser')
    smtpusetls = options.smtp_tls or config.get('stgit.smtptls') == 'yes'

    if (smtppassword and not smtpuser):
        raise CmdException, 'SMTP password supplied, username needed'
    if (smtpusetls and not smtpuser):
        raise CmdException, 'SMTP over TLS requested, username needed'
    if (smtpuser and not smtppassword):
        smtppassword = getpass.getpass("Please enter SMTP password: "******"%s"' % p)
            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
                           smtpuser, smtppassword, smtpusetls)
            # give recipients a chance of receiving related patches in the
            # correct order.
            if patch_nr < total_nr:
                time.sleep(sleep)
            out.done()