Пример #1
0
def main():
    import argparse

    parser = argparse.ArgumentParser(
        description=wraptext(DESCRIPTION),
        epilog=wraptext(EPILOG),
        formatter_class=argparse.RawDescriptionHelpFormatter
    )

    parser.add_argument(
        "-c", "--config",
        metavar="FILE",
        type=argparse.FileType("r"),
        help="Configuration file",
    )
    parser.add_argument(
        "-y",
        dest="ask_confirmation",
        default=True,
        action="store_false",
        help="'I trust this script to do the right thing and send emails"
        "without asking for confirmation.'"
    )
    parser.add_argument(
        "--no-proto",
        dest="include_protoxep",
        default=True,
        action="store_false",
        help="Do not announce ProtoXEPs",
    )
    parser.add_argument(
        "-n", "--dry-run",
        dest="dry_run",
        action="store_true",
        default=False,
        help="Instead of sending emails, print them to stdout (implies -y)",
    )
    parser.add_argument(
        "--no-editorial",
        action="store_false",
        default=True,
        dest="include_editorial",
        help="Do not announce editorial changes."
    )
    parser.add_argument(
        "--no-non-editorial",
        action="store_false",
        default=True,
        dest="include_non_editorial",
        help="Do not announce non-editorial changes."
    )

    parser.add_argument(
        "old",
        type=argparse.FileType("rb"),
        help="Old xep-infos XML file",
    )
    parser.add_argument(
        "new",
        type=argparse.FileType("rb"),
        help="New xep-infos XML file",
    )

    parser.add_argument(
        "to",
        nargs="+",
        help="The mail addresses to send the update mails to."
    )

    args = parser.parse_args()

    can_be_interactive = (
        os.isatty(sys.stdin.fileno()) and
        os.isatty(sys.stdout.fileno())
    )

    if args.dry_run:
        args.ask_confirmation = False

    if args.ask_confirmation and not can_be_interactive:
        print("Cannot ask for confirmation (stdio is not a TTY), but -y is",
              "not given either. Aborting.", sep="\n", file=sys.stderr)
        sys.exit(2)

    config = configparser.ConfigParser()
    if args.config is not None:
        config.read_file(args.config)

    with args.old as f:
        tree = etree.parse(f)
    old_accepted, old_proto = load_xepinfos(tree)

    with args.new as f:
        tree = etree.parse(f)
    new_accepted, new_proto = load_xepinfos(tree)

    old_xeps = set(old_accepted.keys())
    new_xeps = set(new_accepted.keys())

    common_xeps = old_xeps & new_xeps
    added_xeps = new_xeps - old_xeps

    added_protos = set(new_proto.keys()) - set(old_proto.keys())

    updates = []

    for common_xep in common_xeps:
        old_info = old_accepted[common_xep]
        new_info = new_accepted[common_xep]

        action = diff_infos(old_info, new_info)
        if action == Action.UPDATE and not filter_bump_level(
                extract_version(old_info),
                extract_version(new_info),
                args.include_editorial,
                args.include_non_editorial):
            continue

        if action is not None:
            updates.append((common_xep, action, new_info))

    for added_xep in added_xeps:
        old_info = dummy_info(added_xep)
        new_info = new_accepted[added_xep]

        action = diff_infos(old_info, new_info)
        if action is not None:
            updates.append((added_xep, action, new_info))

    if args.include_protoxep:
        for added_proto in added_protos:
            old_info = dummy_info('xxxx')
            new_info = new_proto[added_proto]

            action = diff_infos(old_info, new_info)
            if action is not None:
                updates.append((added_proto, action, new_info))

    if args.dry_run:
        smtpconn = make_fake_smtpconn()
    else:
        if can_be_interactive:
            interactively_extend_smtp_config(config)

        try:
            smtpconn = make_smtpconn(config)
        except (configparser.NoSectionError,
                configparser.NoOptionError) as exc:
            print("Missing configuration: {}".format(exc),
                  file=sys.stderr)
            print("(cannot ask for configuration on stdio because it is "
                  "not a TTY)", file=sys.stderr)
            sys.exit(3)

    try:
        for id_, action, info in updates:
            if action == Action.PROTO:
                mail = make_proto_mail(info)
            else:
                mail = make_nonproto_mail(action, info)
            mail["Date"] = datetime.utcnow()
            mail["From"] = config.get("smtp", "from")
            mail["To"] = args.to

            if args.ask_confirmation:
                print()
                print("---8<---")
                print(mail.as_string())
                print("--->8---")
                print()
                choice = choose(
                    "Send this email? [y]es, [n]o, [a]bort: ",
                    "yna",
                    eof="a",
                )

                if choice == "n":
                    continue
                elif choice == "a":
                    print("Exiting on user request.", file=sys.stderr)
                    sys.exit(4)

            smtpconn.send_message(mail)
    finally:
        smtpconn.close()
Пример #2
0
def main():
    import argparse

    parser = argparse.ArgumentParser()

    parser.add_argument(
        "-c", "--config",
        metavar="FILE",
        type=argparse.FileType("r"),
        help="Configuration file",
    )
    parser.add_argument(
        "-y",
        dest="ask_confirmation",
        default=True,
        action="store_false",
        help="'I trust this script to do the right thing and send emails"
        "without asking for confirmation.'"
    )
    parser.add_argument(
        "-n", "--dry-run",
        dest="dry_run",
        action="store_true",
        default=False,
        help="Instead of sending emails, print them to stdout (implies -y)",
    )

    parser.add_argument(
        "--duration", "-d",
        metavar="DAYS",
        default=14,
        help="Duration of the CFE in days (default and at least: 14)",
        type=int,
    )

    parser.add_argument(
        "--xeplist",
        default=None,
        type=argparse.FileType("r")
    )

    parser.add_argument(
        "-x", "--xep",
        type=int,
        dest="xeps",
        action="append",
        default=[],
        help="XEP(s) to issue a CFE for"
    )

    parser.add_argument(
        "to",
        nargs="+",
        help="The mail addresses to send the update mails to."
    )

    args = parser.parse_args()

    can_be_interactive = (
        os.isatty(sys.stdin.fileno()) and
        os.isatty(sys.stdout.fileno())
    )

    if not args.xeps:
        print("nothing to do (use -x/--xep)", file=sys.stderr)
        sys.exit(1)

    if args.duration < 14:
        print("duration must be at least 14", file=sys.stderr)
        sys.exit(1)

    enddate = (datetime.utcnow() + timedelta(days=args.duration)).date()

    if args.dry_run:
        args.ask_confirmation = False

    if args.ask_confirmation and not can_be_interactive:
        print("Cannot ask for confirmation (stdio is not a TTY), but -y is",
              "not given either. Aborting.", sep="\n", file=sys.stderr)
        sys.exit(2)

    config = configparser.ConfigParser()
    if args.config is not None:
        config.read_file(args.config)

    if args.xeplist is None:
        args.xeplist = open("build/xeplist.xml", "rb")

    with args.xeplist as f:
        tree = etree.parse(f)
    accepted, _ = load_xepinfos(tree)

    matched_xeps = []
    has_error = False
    for num in args.xeps:
        try:
            info = accepted[num]
        except KeyError:
            print("no such xep: {}".format(num), file=sys.stderr)
            has_error = True
            continue

        if info["status"] != Status.DRAFT:
            print("XEP-{:04d} is in {}, but must be Draft".format(
                num,
                info["status"].value,
            ))
            has_error = True
            continue

        matched_xeps.append(info)

    if has_error:
        sys.exit(1)

    if args.dry_run:
        smtpconn = make_fake_smtpconn()
    else:
        if can_be_interactive:
            interactively_extend_smtp_config(config)

        try:
            smtpconn = make_smtpconn(config)
        except (configparser.NoSectionError,
                configparser.NoOptionError) as exc:
            print("Missing configuration: {}".format(exc),
                  file=sys.stderr)
            print("(cannot ask for configuration on stdio because it is "
                  "not a TTY)", file=sys.stderr)
            sys.exit(3)

    try:
        for info in matched_xeps:
            mail = make_mail(info, enddate)
            mail["Date"] = datetime.utcnow()
            mail["From"] = config.get("smtp", "from")
            mail["To"] = args.to

            if args.ask_confirmation:
                print()
                print("---8<---")
                print(mail.as_string())
                print("--->8---")
                print()
                choice = choose(
                    "Send this email? [y]es, [n]o, [a]bort: ",
                    "yna",
                    eof="a",
                )

                if choice == "n":
                    continue
                elif choice == "a":
                    print("Exiting on user request.", file=sys.stderr)
                    sys.exit(4)

            smtpconn.send_message(mail)
    finally:
        smtpconn.close()
Пример #3
0
def main():
    import argparse

    parser = argparse.ArgumentParser(
        description="Accept an inbox XEP."
    )

    parser.add_argument(
        "-l", "--xeplist",
        type=argparse.FileType("rb"),
        default=None,
        help="XEP list to use (defaults to {})".format(DEFAULT_XEPLIST_PATH)
    )

    parser.add_argument(
        "-y", "--yes",
        dest="ask",
        action="store_false",
        help="Assume default answer to all questions.",
        default=True,
    )

    parser.add_argument(
        "-f", "--force",
        dest="force",
        action="store_true",
        default=False,
        help="Force acceptance even if suspicious.",
    )

    parser.add_argument(
        "-c", "--commit",
        default=False,
        action="store_true",
        help="Make a git commit",
    )

    parser.add_argument(
        "item",
        help="Inbox name"
    )

    parser.add_argument(
        "votedate",
        type=isodate,
        help="The date of the vote, in ISO format (%%Y-%%m-%%d)."
    )

    parser.add_argument(
        "initials",
        help="Your editor initials"
    )

    args = parser.parse_args()

    if args.item.endswith(".xml"):
        # strip the path
        p = pathlib.Path(args.item)
        args.item = p.parts[-1].rsplit(".")[0]

    if args.xeplist is None:
        args.xeplist = open(DEFAULT_XEPLIST_PATH, "rb")

    if args.xeplist is not None:
        with args.xeplist as f:
            tree = etree.parse(f)
        accepted, inbox = load_xepinfos(tree)

    try:
        xepinfo = inbox[args.item]
    except KeyError:
        print("no such inbox xep: {!r}".format(args.item), file=sys.stderr)
        print("maybe run make build/xeplist.xml first?", file=sys.stderr)
        sys.exit(1)

    new_number = get_next_xep_number(accepted)

    new_filename = pathlib.Path(".") / "xep-{:04d}.xml".format(new_number)
    inbox_path = pathlib.Path("inbox") / "{}.xml".format(args.item)
    if new_filename.exists():
        raise FileExistsError(
            "Internal error: XEP file does already exist! ({})".format(
                new_filename
            )
        )
    if not inbox_path.exists():
        print("inbox file does not exist or is not readable: {}".format(
            inbox_path
        ))

    if args.ask:
        print("I am going to accept:")
        print()
        print("  Title: {!r}".format(xepinfo["title"]))
        print("  Abstract: {!r}".format(xepinfo["abstract"]))
        print("  Last Revision: {} ({})".format(
            xepinfo["last_revision"]["date"].date(),
            xepinfo["last_revision"]["version"],
        ))
        print()
        print("as new XEP-{:04d}.".format(new_number))
        print()
        choice = choose("Is this correct? [y]es, [n]o: ", "yn", eof="n")
        if choice != "y":
            print("aborted at user request")
            sys.exit(2)

    shutil.copy(str(inbox_path), str(new_filename))

    accept_xep(new_number,
               xepinfo["last_revision"]["version"],
               args.initials,
               xepinfo["approver"],
               args.votedate.date())

    if args.commit:
        subprocess.check_call([
            "git", "reset", "HEAD", ".",
        ])
        subprocess.check_call([
            "git", "add", new_filename.parts[-1],
        ])
        if args.ask:
            flags = ["-ve"]
        else:
            flags = []
        subprocess.check_call(
            [
                "git", "commit", "-m", "Accept {} as XEP-{:04}".format(
                    inbox_path,
                    new_number,
                )
            ] + flags
        )
Пример #4
0
def main():
    import argparse

    parser = argparse.ArgumentParser()

    parser.add_argument(
        "-c",
        "--config",
        metavar="FILE",
        type=argparse.FileType("r"),
        help="Configuration file",
    )
    parser.add_argument(
        "-y",
        dest="ask_confirmation",
        default=True,
        action="store_false",
        help="'I trust this script to do the right thing and send emails"
        "without asking for confirmation.'")
    parser.add_argument(
        "-n",
        "--dry-run",
        dest="dry_run",
        action="store_true",
        default=False,
        help="Instead of sending emails, print them to stdout (implies -y)",
    )

    parser.add_argument(
        "--duration",
        "-d",
        metavar="DAYS",
        default=14,
        help="Duration of the CFE in days (default and at least: 14)",
        type=int,
    )

    parser.add_argument("--xeplist", default=None, type=argparse.FileType("r"))

    parser.add_argument("-x",
                        "--xep",
                        type=int,
                        dest="xeps",
                        action="append",
                        default=[],
                        help="XEP(s) to issue a CFE for")

    parser.add_argument("to",
                        nargs="+",
                        help="The mail addresses to send the update mails to.")

    args = parser.parse_args()

    can_be_interactive = (os.isatty(sys.stdin.fileno())
                          and os.isatty(sys.stdout.fileno()))

    if not args.xeps:
        print("nothing to do (use -x/--xep)", file=sys.stderr)
        sys.exit(1)

    if args.duration < 14:
        print("duration must be at least 14", file=sys.stderr)
        sys.exit(1)

    enddate = (datetime.utcnow() + timedelta(days=args.duration)).date()

    if args.dry_run:
        args.ask_confirmation = False

    if args.ask_confirmation and not can_be_interactive:
        print("Cannot ask for confirmation (stdio is not a TTY), but -y is",
              "not given either. Aborting.",
              sep="\n",
              file=sys.stderr)
        sys.exit(2)

    config = configparser.ConfigParser()
    if args.config is not None:
        config.read_file(args.config)

    if args.xeplist is None:
        args.xeplist = open("build/xeplist.xml", "rb")

    with args.xeplist as f:
        tree = etree.parse(f)
    accepted, _ = load_xepinfos(tree)

    matched_xeps = []
    has_error = False
    for num in args.xeps:
        try:
            info = accepted[num]
        except KeyError:
            print("no such xep: {}".format(num), file=sys.stderr)
            has_error = True
            continue

        if info["status"] != Status.DRAFT:
            print("XEP-{:04d} is in {}, but must be Draft".format(
                num,
                info["status"].value,
            ))
            has_error = True
            continue

        matched_xeps.append(info)

    if has_error:
        sys.exit(1)

    if args.dry_run:
        smtpconn = make_fake_smtpconn()
    else:
        if can_be_interactive:
            interactively_extend_smtp_config(config)

        try:
            smtpconn = make_smtpconn(config)
        except (configparser.NoSectionError,
                configparser.NoOptionError) as exc:
            print("Missing configuration: {}".format(exc), file=sys.stderr)
            print(
                "(cannot ask for configuration on stdio because it is "
                "not a TTY)",
                file=sys.stderr)
            sys.exit(3)

    try:
        for info in matched_xeps:
            mail = make_mail(info, enddate)
            mail["Date"] = datetime.utcnow()
            mail["From"] = config.get("smtp", "from")
            mail["To"] = args.to

            if args.ask_confirmation:
                print()
                print("---8<---")
                print(mail.as_string())
                print("--->8---")
                print()
                choice = choose(
                    "Send this email? [y]es, [n]o, [a]bort: ",
                    "yna",
                    eof="a",
                )

                if choice == "n":
                    continue
                elif choice == "a":
                    print("Exiting on user request.", file=sys.stderr)
                    sys.exit(4)

            smtpconn.send_message(mail)
    finally:
        smtpconn.close()
Пример #5
0
def main():
    import argparse

    parser = argparse.ArgumentParser(description="Accept an inbox XEP.")

    parser.add_argument(
        "-l",
        "--xeplist",
        type=argparse.FileType("rb"),
        default=None,
        help="XEP list to use (defaults to {})".format(DEFAULT_XEPLIST_PATH))

    parser.add_argument(
        "-y",
        "--yes",
        dest="ask",
        action="store_false",
        help="Assume default answer to all questions.",
        default=True,
    )

    parser.add_argument(
        "-f",
        "--force",
        dest="force",
        action="store_true",
        default=False,
        help="Force acceptance even if suspicious.",
    )

    parser.add_argument(
        "-c",
        "--commit",
        default=False,
        action="store_true",
        help="Make a git commit",
    )

    parser.add_argument("item", help="Inbox name")

    parser.add_argument("votedate",
                        type=isodate,
                        help="The date of the vote, in ISO format (%Y-%m-%d).")

    parser.add_argument("initials", help="Your editor initials")

    args = parser.parse_args()

    if args.item.endswith(".xml"):
        # strip the path
        p = pathlib.Path(args.item)
        args.item = p.parts[-1].rsplit(".")[0]

    if args.xeplist is None:
        args.xeplist = open(DEFAULT_XEPLIST_PATH, "rb")

    if args.xeplist is not None:
        with args.xeplist as f:
            tree = etree.parse(f)
        accepted, inbox = load_xepinfos(tree)

    try:
        xepinfo = inbox[args.item]
    except KeyError:
        print("no such inbox xep: {!r}".format(args.item), file=sys.stderr)
        print("maybe run make build/xeplist.xml first?", file=sys.stderr)
        sys.exit(1)

    new_number = get_next_xep_number(accepted)

    new_filename = pathlib.Path(".") / "xep-{:04d}.xml".format(new_number)
    inbox_path = pathlib.Path("inbox") / "{}.xml".format(args.item)
    if new_filename.exists():
        raise FileExistsError(
            "Internal error: XEP file does already exist! ({})".format(
                new_filename))
    if not inbox_path.exists():
        print("inbox file does not exist or is not readable: {}".format(
            inbox_path))

    if args.ask:
        print("I am going to accept:")
        print()
        print("  Title: {!r}".format(xepinfo["title"]))
        print("  Abstract: {!r}".format(xepinfo["abstract"]))
        print("  Last Revision: {} ({})".format(
            xepinfo["last_revision"]["date"].date(),
            xepinfo["last_revision"]["version"],
        ))
        print()
        print("as new XEP-{:04d}.".format(new_number))
        print()
        choice = choose("Is this correct? [y]es, [n]o: ", "yn", eof="n")
        if choice != "y":
            print("aborted at user request")
            sys.exit(2)

    shutil.copy(str(inbox_path), str(new_filename))

    accept_xep(new_number, xepinfo["last_revision"]["version"], args.initials,
               xepinfo["approver"], args.votedate.date())

    if args.commit:
        subprocess.check_call([
            "git",
            "reset",
            "HEAD",
            ".",
        ])
        subprocess.check_call([
            "git",
            "add",
            new_filename.parts[-1],
        ])
        if args.ask:
            flags = ["-ve"]
        else:
            flags = []
        subprocess.check_call([
            "git", "commit", "-m", "Accept {} as XEP-{:04}".format(
                inbox_path,
                new_number,
            )
        ] + flags)
Пример #6
0
def main():
    import argparse

    parser = argparse.ArgumentParser(
        description=wraptext(DESCRIPTION),
        epilog=wraptext(EPILOG),
        formatter_class=argparse.RawDescriptionHelpFormatter
    )

    parser.add_argument(
        "-c", "--config",
        metavar="FILE",
        type=argparse.FileType("r"),
        help="Configuration file",
    )
    parser.add_argument(
        "-y",
        dest="ask_confirmation",
        default=True,
        action="store_false",
        help="'I trust this script to do the right thing and send emails"
        "without asking for confirmation.'"
    )
    parser.add_argument(
        "--no-proto",
        dest="process_proto",
        default=True,
        action="store_false",
        help="Disable processing of ProtoXEPs.",
    )
    parser.add_argument(
        "-n", "--dry-run",
        dest="dry_run",
        action="store_true",
        default=False,
        help="Instead of sending emails, print them to stdout (implies -y)",
    )

    parser.add_argument(
        "old",
        type=argparse.FileType("rb"),
        help="Old xep-infos XML file",
    )
    parser.add_argument(
        "new",
        type=argparse.FileType("rb"),
        help="New xep-infos XML file",
    )

    parser.add_argument(
        "to",
        nargs="+",
        help="The mail addresses to send the update mails to."
    )

    args = parser.parse_args()

    can_be_interactive = (
        os.isatty(sys.stdin.fileno()) and
        os.isatty(sys.stdout.fileno())
    )

    if args.dry_run:
        args.ask_confirmation = False

    if args.ask_confirmation and not can_be_interactive:
        print("Cannot ask for confirmation (stdio is not a TTY), but -y is",
              "not given either. Aborting.", sep="\n", file=sys.stderr)
        sys.exit(2)

    config = configparser.ConfigParser()
    if args.config is not None:
        config.read_file(args.config)

    with args.old as f:
        tree = etree.parse(f)
    old_accepted, old_proto = load_xepinfos(tree)

    with args.new as f:
        tree = etree.parse(f)
    new_accepted, new_proto = load_xepinfos(tree)

    old_xeps = set(old_accepted.keys())
    new_xeps = set(new_accepted.keys())

    common_xeps = old_xeps & new_xeps
    added_xeps = new_xeps - old_xeps

    added_protos = set(new_proto.keys()) - set(old_proto.keys())

    updates = []

    for common_xep in common_xeps:
        old_info = old_accepted[common_xep]
        new_info = new_accepted[common_xep]

        action = diff_infos(old_info, new_info)
        if action is not None:
            updates.append((common_xep, action, new_info))

    for added_xep in added_xeps:
        old_info = dummy_info(added_xep)
        new_info = new_accepted[added_xep]

        action = diff_infos(old_info, new_info)
        if action is not None:
            updates.append((added_xep, action, new_info))

    if args.process_proto:
        for added_proto in added_protos:
            old_info = dummy_info('xxxx')
            new_info = new_proto[added_proto]

            action = diff_infos(old_info, new_info)
            if action is not None:
                updates.append((added_proto, action, new_info))

    if args.dry_run:
        smtpconn = make_fake_smtpconn()
    else:
        if can_be_interactive:
            interactively_extend_smtp_config(config)

        try:
            smtpconn = make_smtpconn(config)
        except (configparser.NoSectionError,
                configparser.NoOptionError) as exc:
            print("Missing configuration: {}".format(exc),
                  file=sys.stderr)
            print("(cannot ask for configuration on stdio because it is "
                  "not a TTY)", file=sys.stderr)
            sys.exit(3)

    try:
        for id_, action, info in updates:
            if action == Action.PROTO:
                mail = make_proto_mail(info)
            else:
                mail = make_nonproto_mail(action, info)
            mail["Date"] = datetime.utcnow()
            mail["From"] = config.get("smtp", "from")
            mail["To"] = args.to

            if args.ask_confirmation:
                print()
                print("---8<---")
                print(mail.as_string())
                print("--->8---")
                print()
                choice = choose(
                    "Send this email? [y]es, [n]o, [a]bort: ",
                    "yna",
                    eof="a",
                )

                if choice == "n":
                    continue
                elif choice == "a":
                    print("Exiting on user request.", file=sys.stderr)
                    sys.exit(4)

            smtpconn.send_message(mail)
    finally:
        smtpconn.close()