~khumba/public-inbox

16 2

[PATCH lazygl2shrt v2 01/15] Add .gitignore.

Details
Message ID
<20240602195752.28931-16-mcepl@cepl.eu>
DKIM signature
pass
Download raw message
Patch: +3 -0
---
 .gitignore | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 .gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1e51639
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
*.pyc
*.csv
*-log*.txt
-- 
2.45.1

[PATCH lazygl2shrt v2 02/15] Bit reformatting

Details
Message ID
<20240602195752.28931-17-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +4 -3
---
 import_issues.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index c1dbc21..550df54 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -500,7 +500,7 @@ def run(

        raise RuntimeError(
            f"Don't have all issues from 1 to {max_issue_id}{because_confidential_msg}, "
            f"please pass --create-missing-issues or --skip-missing-issues to proceed."
            "please pass --create-missing-issues or --skip-missing-issues to proceed."
        )

    issues_by_id = {}
@@ -516,7 +516,7 @@ def run(
    issue_id_map: Dict[int, int] = {}

    # While we're creating tickets, we can't just loop over the sorted
    # issue_jsons.  We have to loop over potential issue IDs and handle any that
    # issue_jsons. We have to loop over potential issue IDs and handle any that
    # are missing as well.
    for gitlab_issue_id in range(1, max_issue_id + 1):
        if gitlab_issue_id not in issues_by_id:
@@ -592,7 +592,8 @@ def run(

            body = note_json["note"]

            # The "Removed" part is a guess here, don't know if that actually shows up.
            # The "Removed" part is a guess here,
            # don't know if that actually shows up.
            if label_ids_to_names is not None and (
                system_action == "label"
                or re.search(r"^(Added|Removed) ~[0-9]+ label", body)
-- 
2.45.1

[PATCH lazygl2shrt v2 03/15] fix: better logging

Details
Message ID
<20240602195752.28931-18-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +2 -2
---
 import_issues.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index 550df54..c2ed789 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -191,7 +191,7 @@ def do_mail(
    else:
        raise ValueError(f"Unhandled mode {mode!r}.")

    log.info(f"{verb} email #{email_count}.")
    log.info("%s email #%d.", verb, email_count)

    date = format_datetime(datetime.now(timezone.utc))
    msg_id = make_msgid()
@@ -846,7 +846,7 @@ def main():
        assert smtp_user, f"No SMTP user given."
        assert smtp_password, f"No SMTP password given."

        log.info(f"Connecting to {smtp_host}:{smtp_port}, user {smtp_user!r}.")
        log.info("Connecting to %s:%d, user %r.", smtp_host, smtp_port, smtp_user)

        if smtp_ssl:
            smtp = smtplib.SMTP_SSL(host=smtp_host, port=smtp_port)
-- 
2.45.1

[PATCH lazygl2shrt v2 04/15] refactor: it is a general delay, not just the SMTP one.

Details
Message ID
<20240602195752.28931-19-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +20 -20
---
 import_issues.py | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index c2ed789..a3277cf 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -105,7 +105,7 @@
# specified either via parameters --smtp-{host,port,user,password} or the
# equivalent SMTP_{HOST,PORT,USER,PASSWORD} environment variables.  Pass
# --smtp-ssl to enable SSL.  Also by default there is a five-second delay
# between sending emails, that you may wish to change with --smtp-delay.
# between sending emails, that you may wish to change with --delay.
#
# ./import_issues.py \
#     --srht-owner=MY_SRHT_USER \
@@ -174,7 +174,7 @@ def read_id_map_file(file_path: Path) -> Dict[int, str]:
def do_mail(
    *,
    smtp,
    smtp_delay: float,
    delay: float,
    mode: str,
    frm: str,
    to: str,
@@ -226,7 +226,7 @@ def do_mail(

        smtp.send_message(msg)

        time.sleep(smtp_delay)
        time.sleep(delay)

    else:
        raise RuntimeError(f"Unknown mode: {mode!r}")
@@ -235,7 +235,7 @@ def do_mail(
def open_ticket(
    *,
    smtp,
    smtp_delay: float,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
@@ -282,7 +282,7 @@ def open_ticket(

    do_mail(
        smtp=smtp,
        smtp_delay=smtp_delay,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}@todo.sr.ht",
@@ -297,7 +297,7 @@ def open_ticket(
def file_missing_ticket(
    *,
    smtp,
    smtp_delay: float,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
@@ -308,7 +308,7 @@ def file_missing_ticket(

    do_mail(
        smtp=smtp,
        smtp_delay=smtp_delay,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}@todo.sr.ht",
@@ -322,7 +322,7 @@ def file_missing_ticket(
    # previous issue to be processed promptly.
    close_ticket(
        smtp=smtp,
        smtp_delay=smtp_delay,
        delay=delay,
        mode=mode,
        srht_owner=srht_owner,
        srht_tracker=srht_tracker,
@@ -336,7 +336,7 @@ def file_missing_ticket(
def send_comment(
    *,
    smtp,
    smtp_delay: float,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
@@ -375,7 +375,7 @@ def send_comment(

    do_mail(
        smtp=smtp,
        smtp_delay=smtp_delay,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}/{issue_id}@todo.sr.ht",
@@ -386,7 +386,7 @@ def send_comment(
def close_ticket(
    *,
    smtp,
    smtp_delay: float,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
@@ -408,7 +408,7 @@ def close_ticket(

    do_mail(
        smtp=smtp,
        smtp_delay=smtp_delay,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}/{issue_id}@todo.sr.ht",
@@ -419,7 +419,7 @@ def close_ticket(
def run(
    *,
    smtp,
    smtp_delay: float,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
@@ -523,7 +523,7 @@ def run(
            if create_missing_issues:
                file_missing_ticket(
                    smtp=smtp,
                    smtp_delay=smtp_delay,
                    delay=delay,
                    mode=mode,
                    srht_owner=srht_owner,
                    srht_tracker=srht_tracker,
@@ -555,7 +555,7 @@ def run(

        srht_issue_id = open_ticket(
            smtp=smtp,
            smtp_delay=smtp_delay,
            delay=delay,
            mode=mode,
            srht_owner=srht_owner,
            srht_tracker=srht_tracker,
@@ -625,7 +625,7 @@ def run(

            send_comment(
                smtp=smtp,
                smtp_delay=smtp_delay,
                delay=delay,
                mode=mode,
                srht_owner=srht_owner,
                srht_tracker=srht_tracker,
@@ -645,7 +645,7 @@ def run(
        if issue_json["state"] == "closed":
            close_ticket(
                smtp=smtp,
                smtp_delay=smtp_delay,
                delay=delay,
                mode=mode,
                srht_owner=srht_owner,
                srht_tracker=srht_tracker,
@@ -725,9 +725,9 @@ def main():
    )

    parser.add_argument(
        "--smtp-delay",
        "--delay",
        default=5,
        help="Decimal number of seconds to wait after sending each email.",
        help="Decimal number of seconds to wait between accessing the server.",
    )

    parser.add_argument(
@@ -864,7 +864,7 @@ def main():

    run(
        smtp=smtp,
        smtp_delay=float(args["smtp_delay"]),
        delay=float(args["delay"]),
        mode=mode,
        srht_owner=args["srht_owner"],
        srht_tracker=args["srht_tracker"],
-- 
2.45.1

[PATCH lazygl2shrt v2 05/15] refactor: simplify API signature

Details
Message ID
<20240602195752.28931-20-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +19 -26
We don't need to concatenate srht_owner and srht_tracker again
and again, when we really need only complete tracker name.
---
 import_issues.py | 45 +++++++++++++++++++--------------------------
 1 file changed, 19 insertions(+), 26 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index a3277cf..10ebd93 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -237,8 +237,7 @@ def open_ticket(
    smtp,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
    tracker: str,
    frm: str,
    title: str,
    body: str,
@@ -285,7 +284,7 @@ def open_ticket(
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}@todo.sr.ht",
        to=f"{tracker}@todo.sr.ht",
        subject=title,
        body="\n".join(lines),
    )
@@ -299,8 +298,7 @@ def file_missing_ticket(
    smtp,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
    tracker: str,
    frm: str,
    issue_id: int,
):
@@ -311,7 +309,7 @@ def file_missing_ticket(
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}@todo.sr.ht",
        to=f"{tracker}@todo.sr.ht",
        subject="Missing issue",
        body=f"Issue {issue_id} is not known.",
    )
@@ -324,8 +322,7 @@ def file_missing_ticket(
        smtp=smtp,
        delay=delay,
        mode=mode,
        srht_owner=srht_owner,
        srht_tracker=srht_tracker,
        tracker=tracker,
        frm=frm,
        issue_id=issue_count,
        closed_at=None,
@@ -338,8 +335,7 @@ def send_comment(
    smtp,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
    tracker: str,
    frm: str,
    issue_id: int,
    body: str,
@@ -378,7 +374,7 @@ def send_comment(
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}/{issue_id}@todo.sr.ht",
        to=f"{tracker}/{issue_id}@todo.sr.ht",
        body="\n".join(lines),
    )

@@ -388,8 +384,7 @@ def close_ticket(
    smtp,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
    tracker: str,
    frm: str,
    issue_id: int,
    closed_at: Optional[str],
@@ -411,7 +406,7 @@ def close_ticket(
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"~{srht_owner}/{srht_tracker}/{issue_id}@todo.sr.ht",
        to=f"{tracker}/{issue_id}@todo.sr.ht",
        body="\n".join(lines),
    )

@@ -421,8 +416,7 @@ def run(
    smtp,
    delay: float,
    mode: str,
    srht_owner: str,
    srht_tracker: str,
    tracker: str,
    frm: str,
    export_dir_path: Path,
    gitlab_project_url: str,
@@ -525,8 +519,7 @@ def run(
                    smtp=smtp,
                    delay=delay,
                    mode=mode,
                    srht_owner=srht_owner,
                    srht_tracker=srht_tracker,
                    tracker=tracker,
                    frm=frm,
                    issue_id=gitlab_issue_id,
                )
@@ -557,8 +550,7 @@ def run(
            smtp=smtp,
            delay=delay,
            mode=mode,
            srht_owner=srht_owner,
            srht_tracker=srht_tracker,
            tracker=tracker,
            frm=frm,
            title=issue_json["title"],
            body=issue_json["description"],
@@ -627,8 +619,7 @@ def run(
                smtp=smtp,
                delay=delay,
                mode=mode,
                srht_owner=srht_owner,
                srht_tracker=srht_tracker,
                tracker=tracker,
                frm=frm,
                issue_id=issue_id_map[issue_json["iid"]],
                body=body,
@@ -647,8 +638,7 @@ def run(
                smtp=smtp,
                delay=delay,
                mode=mode,
                srht_owner=srht_owner,
                srht_tracker=srht_tracker,
                tracker=tracker,
                frm=frm,
                issue_id=issue_id_map[issue_json["iid"]],
                closed_at=issue_json["closed_at"],
@@ -831,6 +821,10 @@ def main():
        include_confidential and skip_confidential
    ), f"Can accept at most one of --include-confidential and --skip-confidential."

    srht_owner = args["srht_owner"]
    srht_tracker = args["srht_tracker"]
    tracker = f"~{srht_owner}/{srht_tracker}"

    if mode == "print":
        smtp = None
    elif mode == "send":
@@ -866,8 +860,7 @@ def main():
        smtp=smtp,
        delay=float(args["delay"]),
        mode=mode,
        srht_owner=args["srht_owner"],
        srht_tracker=args["srht_tracker"],
        tracker=tracker,
        frm=frm,
        export_dir_path=export_dir_path,
        gitlab_project_url=args["gitlab_project_url"].rstrip("/"),
-- 
2.45.1

[PATCH lazygl2shrt v2 06/15] feat: add 'hut' option to the current 'print' and 'send' ones.

Details
Message ID
<20240602195752.28931-21-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +75 -37
All runs of the hut cmd are done by the special function run_hut().
---
 import_issues.py | 112 +++++++++++++++++++++++++++++++----------------
 1 file changed, 75 insertions(+), 37 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index 10ebd93..556e861 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -127,6 +127,7 @@ import logging
import json
import os
import re
import subprocess
import smtplib
import sys
import time
@@ -232,6 +233,19 @@ def do_mail(
        raise RuntimeError(f"Unknown mode: {mode!r}")


def run_hut(cmds, tracker, msg, args=None):
    if args is None:
        args = []
    res = subprocess.run(
        ["hut", "todo"] + cmds + ["-t", tracker] + args,
        encoding="utf-8",
        input=msg,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    return res


def open_ticket(
    *,
    smtp,
@@ -279,15 +293,21 @@ def open_ticket(
    lines.append("")
    lines.append(body)

    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}@todo.sr.ht",
        subject=title,
        body="\n".join(lines),
    )
    if mode in ["send", "print"]:
        do_mail(
            smtp=smtp,
            delay=delay,
            mode=mode,
            frm=frm,
            to=f"{tracker}@todo.sr.ht",
            subject=title,
            body="\n".join(lines),
        )
    elif mode == "hut":
        msg = title
        if len(lines):
            msg += "\n" + "\n".join(lines)
        run_hut(["ticket", "create", "--stdin"], tracker, msg)

    issue_count += 1
    return issue_count
@@ -304,15 +324,19 @@ def file_missing_ticket(
):
    global issue_count

    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}@todo.sr.ht",
        subject="Missing issue",
        body=f"Issue {issue_id} is not known.",
    )
    if mode in ["send", "print"]:
        do_mail(
            smtp=smtp,
            delay=delay,
            mode=mode,
            frm=frm,
            to=f"{tracker}@todo.sr.ht",
            subject="Missing issue",
            body=f"Issue {issue_id} is not known.",
        )
    elif mode == "hut":
        msg = f"Missing issue\n\nIssue {issue_id} is not known."
        run_hut(["ticket", "create"], tracker, msg, ["--stdin"])

    issue_count += 1

@@ -369,14 +393,18 @@ def send_comment(
        lines.append("")
        lines.append(f"(Last edited at {last_edited_at}.)")

    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}/{issue_id}@todo.sr.ht",
        body="\n".join(lines),
    )
    body = "\n".join(lines)

    if mode in ["send", "print"]:
        do_mail(
            smtp=smtp,
            delay=delay,
            mode=mode,
            frm=frm,
            to=f"{tracker}/{issue_id}@todo.sr.ht",
        )
    elif mode == "hut":
        run_hut(["ticket", "comment"], tracker, None, ["--stdin", issue_id])


def close_ticket(
@@ -398,17 +426,26 @@ def close_ticket(
    elif is_closed:
        lines.append("Ticket closed.")

    lines.append("")
    lines.append("!resolve fixed")
    if mode in ["send", "print"]:
        lines.append("")
        lines.append("!resolve fixed")

    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}/{issue_id}@todo.sr.ht",
        body="\n".join(lines),
    )
        do_mail(
            smtp=smtp,
            delay=delay,
            mode=mode,
            frm=frm,
            to=f"{tracker}/{issue_id}@todo.sr.ht",
            body="\n".join(lines),
        )

    elif mode == "hut":
        run_hut(
            ["ticket", "update-status"],
            tracker,
            None,
            ["--resolution", "fixed", "--status", "closed", issue_id],
        )


def run(
@@ -672,8 +709,9 @@ def main():

    parser.add_argument(
        "--mode",
        choices=["print", "send", "hut"],
        default="print",
        help="Action to take, 'print' or 'send'.",
        help="Action to take.",
    )

    parser.add_argument(
-- 
2.45.1

[PATCH lazygl2shrt v2 07/15] feat: check existence of labels

Details
Message ID
<20240602195752.28931-22-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +52 -11
use `hut graphql` instead
---
 import_issues.py | 63 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 52 insertions(+), 11 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index 556e861..c900ead 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -123,8 +123,8 @@

import argparse
import csv
import logging
import json
import logging
import os
import re
import subprocess
@@ -137,14 +137,44 @@ from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, List, Optional


ID_RE = re.compile(r"^[0-9]+$")

logging.basicConfig(
    format="%(levelname)s:%(funcName)s:%(message)s",
    level=logging.DEBUG,
    stream=sys.stdout,
)

ID_RE = re.compile(r"^[0-9]+$")


def get_labels(tracker: str) -> list[dict[str, str]]:
    """
    collects labels for your named tracker

    param: tracker: name of the tracker
    return: list of all labels in the tracker
    """
    query = (
        'query { me { tracker(name: "'
        + tracker
        + '") { labels { results { id, name, foregroundColor, backgroundColor, created } } } }}'
    )

    try:
        ret = subprocess.run(
            ["hut", "graphql", "todo", "--stdin"],
            input=query,
            text=True,
            check=True,
            capture_output=True,
        )
    except subprocess.CalledProcessError as ex:
        raise RuntimeError(
            f"hut failed with excitcode {ex.returncode} and stderr:\n{ex.stderr}"
        ) from ex
    data = json.loads(ret.stdout)
    return data["me"]["tracker"]["labels"]["results"]


log = logging.getLogger()

email_count = 0
@@ -448,6 +478,17 @@ def close_ticket(
        )


def ensure_label(tracker: str, name: str, bg_color: str, fg_color: str = "#FFFFFF"):
    labels = get_labels(tracker.split("/", 1)[1])
    if not ([x for x in labels if x["name"] == name]):
        run_hut(
            ["label", "create"],
            tracker,
            None,
            ["--background", bg_color, "--foreground", fg_color, name],
        )


def run(
    *,
    smtp,
@@ -824,7 +865,7 @@ def main():
    args = vars(parser.parse_args())

    export_dir = args["export_dir"]
    assert export_dir, f"Must have a exported project directory."
    assert export_dir, "Must have a exported project directory."
    export_dir_path = Path(export_dir)
    assert (
        export_dir_path.is_dir()
@@ -838,26 +879,26 @@ def main():
    skip_unknown_labels = args["skip_unknown_labels"]
    assert (
        labels_file or skip_labels
    ), f"One of --labels-file or --skip-labels must be provided."
    ), "One of --labels-file or --skip-labels must be provided."

    users_file = args["users_file"]
    skip_users = args["skip_users"]
    skip_unknown_users = args["skip_unknown_users"]
    assert (
        skip_users or users_file
    ), f"One of --users-file or --skip-users must be provided."
    ), "One of --users-file or --skip-users must be provided."

    skip_missing_issues = args["skip_missing_issues"]
    create_missing_issues = args["create_missing_issues"]
    assert not (
        skip_missing_issues and create_missing_issues
    ), f"Can accept at most one of --skip-missing-issues and --create-missing-issues."
    ), "Can accept at most one of --skip-missing-issues and --create-missing-issues."

    include_confidential = args["include_confidential"]
    skip_confidential = args["skip_confidential"]
    assert not (
        include_confidential and skip_confidential
    ), f"Can accept at most one of --include-confidential and --skip-confidential."
    ), "Can accept at most one of --include-confidential and --skip-confidential."

    srht_owner = args["srht_owner"]
    srht_tracker = args["srht_tracker"]
@@ -875,8 +916,8 @@ def main():
        smtp_user = args["smtp_user"] or os.environ.get("SMTP_USER", None)
        smtp_password = args["smtp_password"] or os.environ.get("SMTP_PASSWORD", None)

        assert smtp_user, f"No SMTP user given."
        assert smtp_password, f"No SMTP password given."
        assert smtp_user, "No SMTP user given."
        assert smtp_password, "No SMTP password given."

        log.info("Connecting to %s:%d, user %r.", smtp_host, smtp_port, smtp_user)

-- 
2.45.1

[PATCH lazygl2shrt v2 08/15] feat: have smaller delay between calls to hut than SMTP ones.

Details
Message ID
<20240602195752.28931-23-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +46 -17
---
 import_issues.py | 63 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 46 insertions(+), 17 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index c900ead..b4b4232 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -263,16 +263,32 @@ def do_mail(
        raise RuntimeError(f"Unknown mode: {mode!r}")


def run_hut(cmds, tracker, msg, args=None):
def run_hut(cmds, tracker, msg, args=None, delay=None):
    log.debug(
        f"run_hut: cmds = {cmds}, tracker = {tracker}, args = {args}\n\nmsg:\n{msg}"
    )
    if args is None:
        args = []
    res = subprocess.run(
        ["hut", "todo"] + cmds + ["-t", tracker] + args,
        encoding="utf-8",
        input=msg,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    if msg is None:
        res = subprocess.run(
            ["hut", "todo"] + cmds + ["-t", tracker] + args,
            check=True,
            encoding="utf-8",
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
    else:
        res = subprocess.run(
            ["hut", "todo"] + cmds + ["-t", tracker, "--stdin"] + args,
            check=True,
            encoding="utf-8",
            input=msg,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )

    time.sleep(delay)

    return res


@@ -337,7 +353,7 @@ def open_ticket(
        msg = title
        if len(lines):
            msg += "\n" + "\n".join(lines)
        run_hut(["ticket", "create", "--stdin"], tracker, msg)
        run_hut(["ticket", "create"], tracker, msg, delay=delay)

    issue_count += 1
    return issue_count
@@ -366,7 +382,7 @@ def file_missing_ticket(
        )
    elif mode == "hut":
        msg = f"Missing issue\n\nIssue {issue_id} is not known."
        run_hut(["ticket", "create"], tracker, msg, ["--stdin"])
        run_hut(["ticket", "create"], tracker, msg, delay=delay)

    issue_count += 1

@@ -434,7 +450,7 @@ def send_comment(
            to=f"{tracker}/{issue_id}@todo.sr.ht",
        )
    elif mode == "hut":
        run_hut(["ticket", "comment"], tracker, None, ["--stdin", issue_id])
        run_hut(["ticket", "comment"], tracker, body, [str(issue_id)], delay=delay)


def close_ticket(
@@ -474,11 +490,14 @@ def close_ticket(
            ["ticket", "update-status"],
            tracker,
            None,
            ["--resolution", "fixed", "--status", "closed", issue_id],
            [str(issue_id), "--resolution", "fixed", "--status", "resolved"],
            delay=delay,
        )


def ensure_label(tracker: str, name: str, bg_color: str, fg_color: str = "#FFFFFF"):
def ensure_label(
    tracker: str, name: str, bg_color: str, fg_color: str = "#FFFFFF", delay=None
):
    labels = get_labels(tracker.split("/", 1)[1])
    if not ([x for x in labels if x["name"] == name]):
        run_hut(
@@ -486,6 +505,7 @@ def ensure_label(tracker: str, name: str, bg_color: str, fg_color: str = "#FFFFF
            tracker,
            None,
            ["--background", bg_color, "--foreground", fg_color, name],
            delay=delay,
        )


@@ -795,7 +815,7 @@ def main():

    parser.add_argument(
        "--delay",
        default=5,
        default=None,
        help="Decimal number of seconds to wait between accessing the server.",
    )

@@ -904,9 +924,18 @@ def main():
    srht_tracker = args["srht_tracker"]
    tracker = f"~{srht_owner}/{srht_tracker}"

    if mode == "print":
    delay = args["delay"]
    if delay is None:
        if mode == "hut":
            delay = 0.5
        else:
            delay = 5
    else:
        delay = float(delay)

    if mode != "send":
        smtp = None
    elif mode == "send":
    else:
        smtp_ssl = args["smtp_ssl"]
        smtp_starttls = args["smtp_starttls"]
        smtp_host = args["smtp_host"] or os.environ.get("SMTP_HOST", "localhost")
@@ -937,7 +966,7 @@ def main():

    run(
        smtp=smtp,
        delay=float(args["delay"]),
        delay=delay,
        mode=mode,
        tracker=tracker,
        frm=frm,
-- 
2.45.1

[PATCH lazygl2shrt v2 09/15] feat: delayed closing of tickets.

Details
Message ID
<20240602195752.28931-24-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +24 -11
Delaying should hopefully help todo.sr.ht to process all previous
changes before the tickets are closed.
---
 import_issues.py | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index b4b4232..b919112 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -145,6 +145,8 @@ logging.basicConfig(

ID_RE = re.compile(r"^[0-9]+$")

tickets_to_be_closed = []


def get_labels(tracker: str) -> list[dict[str, str]]:
    """
@@ -386,17 +388,15 @@ def file_missing_ticket(

    issue_count += 1

    # TODO Send these emails at the end, so that there isn't such a need for the
    # previous issue to be processed promptly.
    close_ticket(
        smtp=smtp,
        delay=delay,
        mode=mode,
        tracker=tracker,
        frm=frm,
        issue_id=issue_count,
        closed_at=None,
        is_closed=False,  # Save one line of text.
    tickets_to_be_closed.append(
        (
            smtp,
            delay,
            mode,
            tracker,
            frm,
            issue_count,
        )
    )


@@ -743,6 +743,19 @@ def run(
                is_closed=(issue_json["state"] == "closed"),
            )

    log.info("Delayed closing issues.")
    for ticket in tickets_to_be_closed:
        close_ticket(
            smtp=ticket[0],
            delay=ticket[1],
            mode=ticket[2],
            tracker=ticket[3],
            frm=ticket[4],
            issue_id=ticket[5],
            closed_at=None,
            is_closed=False,
        )


def main():
    parser = argparse.ArgumentParser(
-- 
2.45.1

[PATCH lazygl2shrt v2 10/15] refactor: split open_ticket() into two subfunctions per modes.

Details
Message ID
<20240602195752.28931-25-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +117 -21
---
 import_issues.py | 138 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 117 insertions(+), 21 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index b919112..8f56e50 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -127,13 +127,13 @@ import json
import logging
import os
import re
import subprocess
import smtplib
import subprocess
import sys
import time
from datetime import datetime, timezone
from email.message import EmailMessage
from email.utils import format_datetime, make_msgid
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, List, Optional

@@ -267,7 +267,7 @@ def do_mail(

def run_hut(cmds, tracker, msg, args=None, delay=None):
    log.debug(
        f"run_hut: cmds = {cmds}, tracker = {tracker}, args = {args}\n\nmsg:\n{msg}"
        "cmds = %s, tracker = %s, args = %s\n\nmsg:\n%s", cmds, tracker, args, msg
    )
    if args is None:
        args = []
@@ -294,8 +294,55 @@ def run_hut(cmds, tracker, msg, args=None, delay=None):
    return res


def open_ticket(
    *,
def open_ticket_by_hut(
    delay: float,
    tracker: str,
    frm: str,
    title: str,
    body: str,
    created_by: Optional[str],
    created_at: str,
    closed_at: Optional[str],
    is_closed: bool,
    is_confidential: bool,
    labels: List[Dict[str, Any]],
    milestone_name: Optional[str],
    gitlab_ticket_url: str,
) -> str:

    lines = []
    pheaders = []

    pheaders.append(f"Migrated from: {gitlab_ticket_url}")

    if created_by:
        pheaders.append(f"Created by: {created_by}")
    pheaders.append(f"Created at: {created_at}")

    if closed_at is not None:
        pheaders.append(f"Closed at: {closed_at}")
    elif is_closed:
        pheaders.append("State: closed")

    if milestone_name:
        pheaders.append(f"Milestone: {milestone_name}")

    if is_confidential:
        pheaders.append("Confidential: true")

    lines.append(" \\\n".join(pheaders))
    lines.append("")
    lines.append(body)

    msg = title
    if len(lines):
        msg += "\n" + "\n".join(lines)
    out = run_hut(["ticket", "create"], tracker, msg, delay=delay)

    return out


def open_ticket_by_email(
    smtp,
    delay: float,
    mode: str,
@@ -311,9 +358,7 @@ def open_ticket(
    label_names: List[str],
    milestone_name: Optional[str],
    gitlab_ticket_url: str,
) -> int:
    global issue_count

):
    lines = []
    pheaders = []

@@ -341,21 +386,71 @@ def open_ticket(
    lines.append("")
    lines.append(body)

    if mode in ["send", "print"]:
        do_mail(
            smtp=smtp,
            delay=delay,
            mode=mode,
            frm=frm,
            to=f"{tracker}@todo.sr.ht",
            subject=title,
            body="\n".join(lines),
    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}@todo.sr.ht",
        subject=title,
        body="\n".join(lines),
    )


def open_ticket(
    *,
    smtp,
    delay: float,
    mode: str,
    tracker: str,
    frm: str,
    title: str,
    body: str,
    created_by: Optional[str],
    created_at: str,
    closed_at: Optional[str],
    is_closed: bool,
    is_confidential: bool,
    labels: List[Dict[str, Any]],
    milestone_name: Optional[str],
    gitlab_ticket_url: str,
) -> int:
    global issue_count

    if mode in ("send", "print"):
        open_ticket_by_email(
            smtp,
            delay,
            mode,
            tracker,
            frm,
            title,
            body,
            created_by,
            created_at,
            closed_at,
            is_closed,
            is_confidential,
            labels,
            milestone_name,
            gitlab_ticket_url,
        )
    elif mode == "hut":
        msg = title
        if len(lines):
            msg += "\n" + "\n".join(lines)
        run_hut(["ticket", "create"], tracker, msg, delay=delay)
        open_ticket_by_hut(
            delay,
            tracker,
            frm,
            title,
            body,
            created_by,
            created_at,
            closed_at,
            is_closed,
            is_confidential,
            labels,
            milestone_name,
            gitlab_ticket_url,
        )

    issue_count += 1
    return issue_count
@@ -448,6 +543,7 @@ def send_comment(
            mode=mode,
            frm=frm,
            to=f"{tracker}/{issue_id}@todo.sr.ht",
            body=body,
        )
    elif mode == "hut":
        run_hut(["ticket", "comment"], tracker, body, [str(issue_id)], delay=delay)
-- 
2.45.1

[PATCH lazygl2shrt v2 11/15] feat: add setting labels for individual tickets

Details
Message ID
<20240602195752.28931-26-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +96 -57
---
 import_issues.py | 153 +++++++++++++++++++++++++++++------------------
 1 file changed, 96 insertions(+), 57 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index 8f56e50..b6059ee 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -135,7 +135,7 @@ from datetime import datetime, timezone
from email.message import EmailMessage
from email.utils import format_datetime, make_msgid
from pathlib import Path
from typing import Dict, List, Optional
from typing import Any, Optional

logging.basicConfig(
    format="%(levelname)s:%(funcName)s:%(message)s",
@@ -183,9 +183,9 @@ email_count = 0
issue_count = 0


def read_id_map_file(file_path: Path) -> Dict[int, str]:
def read_id_map_file(file_path: Path) -> dict[int, str]:
    """Reads a CSV file with ID,NAME mappings and returns the resulting dict."""
    result: Dict[int, str] = {}
    result: dict[int, str] = {}

    with open(file_path, newline="") as fh:
        reader = csv.reader(fh)
@@ -294,8 +294,10 @@ def run_hut(cmds, tracker, msg, args=None, delay=None):
    return res


def open_ticket_by_hut(
def open_ticket_by_email(
    smtp,
    delay: float,
    mode: str,
    tracker: str,
    frm: str,
    title: str,
@@ -305,11 +307,10 @@ def open_ticket_by_hut(
    closed_at: Optional[str],
    is_closed: bool,
    is_confidential: bool,
    labels: List[Dict[str, Any]],
    labels: list[dict[str, Any]],
    milestone_name: Optional[str],
    gitlab_ticket_url: str,
) -> str:

):
    lines = []
    pheaders = []

@@ -327,6 +328,17 @@ def open_ticket_by_hut(
    if milestone_name:
        pheaders.append(f"Milestone: {milestone_name}")

    if labels:
        pheaders.append(
            "Labels: "
            + ", ".join(
                [
                    x["label"]["title"]
                    for x in sorted(labels, key=lambda x: x["label"]["title"])
                ]
            )
        )

    if is_confidential:
        pheaders.append("Confidential: true")

@@ -334,18 +346,19 @@ def open_ticket_by_hut(
    lines.append("")
    lines.append(body)

    msg = title
    if len(lines):
        msg += "\n" + "\n".join(lines)
    out = run_hut(["ticket", "create"], tracker, msg, delay=delay)

    return out
    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}@todo.sr.ht",
        subject=title,
        body="\n".join(lines),
    )


def open_ticket_by_email(
    smtp,
def open_ticket_by_hut(
    delay: float,
    mode: str,
    tracker: str,
    frm: str,
    title: str,
@@ -355,10 +368,11 @@ def open_ticket_by_email(
    closed_at: Optional[str],
    is_closed: bool,
    is_confidential: bool,
    label_names: List[str],
    labels: list[dict[str, Any]],
    milestone_name: Optional[str],
    gitlab_ticket_url: str,
):
) -> str:

    lines = []
    pheaders = []

@@ -376,9 +390,6 @@ def open_ticket_by_email(
    if milestone_name:
        pheaders.append(f"Milestone: {milestone_name}")

    if label_names:
        pheaders.append("Labels: " + ", ".join(sorted(label_names)))

    if is_confidential:
        pheaders.append("Confidential: true")

@@ -386,15 +397,38 @@ def open_ticket_by_email(
    lines.append("")
    lines.append(body)

    do_mail(
        smtp=smtp,
        delay=delay,
        mode=mode,
        frm=frm,
        to=f"{tracker}@todo.sr.ht",
        subject=title,
        body="\n".join(lines),
    )
    msg = title
    if len(lines):
        msg += "\n" + "\n".join(lines)
    out = run_hut(["ticket", "create"], tracker, msg, delay=delay)
    out.issue_id = int(out.stderr.strip()[len("Created new ticket #") :])

    for label in sorted(labels, key=lambda x: x["label"]["title"]):
        # {"target_type":"Issue",
        #  "created_at":"2023-11-03T22:10:29.419Z",
        #  "updated_at":"2023-11-03T22:10:29.419Z",
        #  "label":{"title":"smime",
        #           "color":"#00b140",
        #           "project_id":346279,
        #           "created_at":"2023-02-02T10:49:17.779Z",
        #           "updated_at":"2023-02-02T10:49:17.779Z",
        #           "template":false,
        #           "description":null,
        #           "group_id":null,
        #           "type":"ProjectLabel",
        #           "priorities":[]}}
        label_name = label["label"]["title"]
        label_color = label["label"]["color"]
        ensure_label(tracker, label_name, label_color, delay=delay)
        run_hut(
            ["ticket", "label"],
            tracker,
            None,
            args=[str(out.issue_id), "-l", label_name],
            delay=delay,
        )

    return out


def open_ticket(
@@ -411,7 +445,7 @@ def open_ticket(
    closed_at: Optional[str],
    is_closed: bool,
    is_confidential: bool,
    labels: List[Dict[str, Any]],
    labels: list[dict[str, Any]],
    milestone_name: Optional[str],
    gitlab_ticket_url: str,
) -> int:
@@ -623,10 +657,10 @@ def run(
    include_confidential: bool,
    skip_confidential: bool,
):
    label_ids_to_names: Optional[Dict[int, str]] = (
    label_ids_to_names: Optional[dict[int, str]] = (
        read_id_map_file(labels_file_path) if labels_file_path else None
    )
    user_ids_to_names: Optional[Dict[int, str]] = (
    user_ids_to_names: Optional[dict[int, str]] = (
        read_id_map_file(users_file_path) if users_file_path else None
    )
    # TODO Might be able to automatically map note.events.author_id to
@@ -701,7 +735,7 @@ def run(

    log.info("Creating tickets.")

    issue_id_map: Dict[int, int] = {}
    issue_id_map: dict[int, int] = {}

    # While we're creating tickets, we can't just loop over the sorted
    # issue_jsons. We have to loop over potential issue IDs and handle any that
@@ -753,7 +787,7 @@ def run(
            closed_at=issue_json["closed_at"],
            is_closed=(issue_json["state"] == "closed"),
            is_confidential=(issue_json.get("confidential") is True),
            label_names=[x["label"]["title"] for x in issue_json["label_links"]],
            labels=list(issue_json["label_links"]),
            milestone_name=issue_json.get("milestone", {}).get("title") or None,
            gitlab_ticket_url=f"{gitlab_project_url}/-/issues/{gitlab_issue_id}",
        )
@@ -853,7 +887,7 @@ def run(
        )


def main():
def parse_args(args_in: list[str]) -> dict[str, Any]:
    parser = argparse.ArgumentParser(
        prog="import_issues.py",
        description="Import Gitlab issues into Sourcehut via SMTP.",
@@ -991,7 +1025,11 @@ def main():
        help="Exported Gitlab tree/project/ directory containing ndjson files.",
    )

    args = vars(parser.parse_args())
    return vars(parser.parse_args(args_in))


def main():
    args = parse_args(sys.argv[1:])

    export_dir = args["export_dir"]
    assert export_dir, "Must have a exported project directory."
@@ -1073,26 +1111,27 @@ def main():
        if smtp_user:
            smtp.login(smtp_user, smtp_password)

    run(
        smtp=smtp,
        delay=delay,
        mode=mode,
        tracker=tracker,
        frm=frm,
        export_dir_path=export_dir_path,
        gitlab_project_url=args["gitlab_project_url"].rstrip("/"),
        labels_file_path=None if skip_labels else Path(labels_file),
        skip_unknown_labels=skip_unknown_labels,
        users_file_path=None if skip_users else Path(users_file),
        skip_unknown_users=skip_unknown_users,
        skip_missing_issues=skip_missing_issues,
        create_missing_issues=create_missing_issues,
        include_confidential=include_confidential,
        skip_confidential=skip_confidential,
    )

    if mode == "send":
        smtp.quit()
    try:
        run(
            smtp=smtp,
            delay=delay,
            mode=mode,
            tracker=tracker,
            frm=frm,
            export_dir_path=export_dir_path,
            gitlab_project_url=args["gitlab_project_url"].rstrip("/"),
            labels_file_path=None if skip_labels else Path(labels_file),
            skip_unknown_labels=skip_unknown_labels,
            users_file_path=None if skip_users else Path(users_file),
            skip_unknown_users=skip_unknown_users,
            skip_missing_issues=skip_missing_issues,
            create_missing_issues=create_missing_issues,
            include_confidential=include_confidential,
            skip_confidential=skip_confidential,
        )
    finally:
        if mode == "send":
            smtp.quit()


if __name__ == "__main__":
-- 
2.45.1

[PATCH lazygl2shrt v2 12/15] refactor: move processing of smtp args to special function

Details
Message ID
<20240602195752.28931-27-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +37 -30
---
 import_issues.py | 67 ++++++++++++++++++++++++++----------------------
 1 file changed, 37 insertions(+), 30 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index b6059ee..298fda7 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -931,6 +931,7 @@ def parse_args(args_in: list[str]) -> dict[str, Any]:
    parser.add_argument(
        "--smtp-port",
        default=None,
        type=int,
        help="SMTP port to use.",
    )

@@ -1028,6 +1029,41 @@ def parse_args(args_in: list[str]) -> dict[str, Any]:
    return vars(parser.parse_args(args_in))


def process_smtp(args: dict[str, Any]) -> Optional[smtplib.SMTP]:
    if args["mode"] != "send":
        return None
    else:
        smtp_ssl = args["smtp_ssl"]
        smtp_starttls = args["smtp_starttls"]
        smtp_host = args["smtp_host"] or os.environ.get("SMTP_HOST", "localhost")
        smtp_port = int(
            args["smtp_port"] or os.environ.get("SMTP_PORT", 465 if smtp_ssl else 25)
        )
        smtp_user = args["smtp_user"] or os.environ.get("SMTP_USER", None)
        smtp_password = args["smtp_password"] or os.environ.get("SMTP_PASSWORD", None)

        assert smtp_user, "No SMTP user given."
        assert smtp_password, "No SMTP password given."

        log.info("Connecting to %s:%d, user %r.", smtp_host, smtp_port, smtp_user)

        if smtp_ssl:
            smtp: smtplib.SMTP = smtplib.SMTP_SSL(host=smtp_host, port=smtp_port)
        else:
            smtp = smtplib.SMTP(host=smtp_host, port=smtp_port)

        # If SMTP isn't working:
        # smtp.set_debuglevel(2)

        if smtp_starttls:
            smtp.starttls()

        if smtp_user:
            smtp.login(smtp_user, smtp_password)

        return smtp


def main():
    args = parse_args(sys.argv[1:])

@@ -1080,36 +1116,7 @@ def main():
    else:
        delay = float(delay)

    if mode != "send":
        smtp = None
    else:
        smtp_ssl = args["smtp_ssl"]
        smtp_starttls = args["smtp_starttls"]
        smtp_host = args["smtp_host"] or os.environ.get("SMTP_HOST", "localhost")
        smtp_port = args["smtp_port"] or os.environ.get(
            "SMTP_PORT", 465 if smtp_ssl else 25
        )
        smtp_user = args["smtp_user"] or os.environ.get("SMTP_USER", None)
        smtp_password = args["smtp_password"] or os.environ.get("SMTP_PASSWORD", None)

        assert smtp_user, "No SMTP user given."
        assert smtp_password, "No SMTP password given."

        log.info("Connecting to %s:%d, user %r.", smtp_host, smtp_port, smtp_user)

        if smtp_ssl:
            smtp = smtplib.SMTP_SSL(host=smtp_host, port=smtp_port)
        else:
            smtp = smtplib.SMTP(host=smtp_host, port=smtp_port)

        # If SMTP isn't working:
        # smtp.set_debuglevel(2)

        if smtp_starttls:
            smtp.starttls()

        if smtp_user:
            smtp.login(smtp_user, smtp_password)
    smtp = process_smtp(args)

    try:
        run(
-- 
2.45.1

[PATCH lazygl2shrt v2 13/15] fix: handle a failure to run hut subprocess well

Details
Message ID
<20240602195752.28931-28-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +23 -18
Print the return and stderr of the failed subprocess.
---
 import_issues.py | 41 +++++++++++++++++++++++------------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index 298fda7..f524932 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -171,7 +171,7 @@ def get_labels(tracker: str) -> list[dict[str, str]]:
        )
    except subprocess.CalledProcessError as ex:
        raise RuntimeError(
            f"hut failed with excitcode {ex.returncode} and stderr:\n{ex.stderr}"
            f"hut failed with excitcode {ex.returncode}\n\nstdout:\n{ex.stdout}\n\nand stderr:\n{ex.stderr}"
        ) from ex
    data = json.loads(ret.stdout)
    return data["me"]["tracker"]["labels"]["results"]
@@ -271,23 +271,28 @@ def run_hut(cmds, tracker, msg, args=None, delay=None):
    )
    if args is None:
        args = []
    if msg is None:
        res = subprocess.run(
            ["hut", "todo"] + cmds + ["-t", tracker] + args,
            check=True,
            encoding="utf-8",
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
    else:
        res = subprocess.run(
            ["hut", "todo"] + cmds + ["-t", tracker, "--stdin"] + args,
            check=True,
            encoding="utf-8",
            input=msg,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
    try:
        if msg is None:
            res = subprocess.run(
                ["hut", "todo"] + cmds + ["-t", tracker] + args,
                check=True,
                encoding="utf-8",
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
        else:
            res = subprocess.run(
                ["hut", "todo"] + cmds + ["-t", tracker, "--stdin"] + args,
                check=True,
                encoding="utf-8",
                input=msg,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
    except subprocess.CalledProcessError as ex:
        raise RuntimeError(
            f"hut failed with excitcode {ex.returncode}\n\nstdout:\n{ex.stdout}\n\nand stderr:\n{ex.stderr}"
        ) from ex

    time.sleep(delay)

-- 
2.45.1

[PATCH lazygl2shrt v2 14/15] feat: add split_long_str() splitting strings keeping lines intact

Details
Message ID
<20240602195752.28931-29-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
todo.sr.ht has limited size of comments to 16k characters. When
splitting a string to multiple ones, we don't want to split lines
in the middle.

Also, start at least some unit tests.
---
 import_issues.py            |  18 +
 tests/209_description.txt   | 786 ++++++++++++++++++++++++++++++++++++
 tests/__init__.py           |   0
 tests/test_import_issues.py |  52 +++
 4 files changed, 856 insertions(+)
 create mode 100644 tests/209_description.txt
 create mode 100644 tests/__init__.py
 create mode 100644 tests/test_import_issues.py

diff --git a/import_issues.py b/import_issues.py
index f524932..5470f4e 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -145,9 +145,27 @@ logging.basicConfig(
 
 ID_RE = re.compile(r"^[0-9]+$")
 
+# todo.sr.ht seems to be limited to less than 16k comments
+# to be sure, we will do just 12k
+MAX_SIZE_COMMENT = 12 * 1024
+
 tickets_to_be_closed = []
 
 
+def split_long_str(in_str: str, max_len: int = MAX_SIZE_COMMENT) -> list[str]:
+    out = []
+    tmp_str = ""
+    for line in in_str.splitlines(keepends=True):
+        if len(tmp_str + line) < max_len:
+            tmp_str += line
+        else:
+            out.append(tmp_str)
+            tmp_str = line
+    if len(tmp_str) > 0:
+        out.append(tmp_str)
+    return out
+
+
 def get_labels(tracker: str) -> list[dict[str, str]]:
     """
     collects labels for your named tracker
diff --git a/tests/209_description.txt b/tests/209_description.txt
new file mode 100644
index 0000000..79de873
--- /dev/null
+++ b/tests/209_description.txt
@@ -0,0 +1,786 @@
+**https://pastebin.com/FDcfSU2z   More readable here** (doesn't have to be)
+
+```
+sudo pip install m2crypto==0.24.0
+Collecting m2crypto==0.24.0
+Downloading https://files.pythonhosted.org/packages/58/75/362faac80a1bc2742b4b696dc350518312043d568bfd2687a9270f18da88/M2Crypto-0.24.0.tar.gz (184kB)
+100% |████████████████████████████████| 194kB 234kB/s
+Building wheels for collected packages: m2crypto
+Running setup.py bdist_wheel for m2crypto ... error
+Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-cIFksT/m2crypto/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" bdist_wheel -d /tmp/tmpfQntJipip-wheel- --python-tag cp27:
+running bdist_wheel
+running build
+running build_py
+copying M2Crypto/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/threading.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/ftpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/EC.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/Rand.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2xmlrpclib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2urllib2.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/ASN1.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/SMIME.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/init.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/EVP.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/X509.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/util.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/BN.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/callback.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/BIO.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/Engine.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/DH.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/Err.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/httpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/RC4.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/DSA.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/AuthCookie.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2urllib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+creating build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Connection.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/TwistedProtocolWrapper.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Context.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Session.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Checker.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/init.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/SSLServer.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/cb.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Cipher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/ssl_dispatcher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/timeout.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+creating build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/PublicKeyRing.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/constants.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/PublicKey.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/init.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/packet.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+running build_ext
+building 'M2Crypto.__m2crypto' extension
+swigging SWIG/m2crypto.i to SWIG/m2crypto_wrap.c
+swig -python -D__x86_64 -I/usr/include/python2.7 -I/usr/include -I/usr/include/x86_64-linux-gnu -includeall -modern -builtin -outdir build/lib.linux-x86_64-2.7/M2Crypto -o SWIG/_m2crypto_wrap.c SWIG/_m2crypto.i
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:152: Warning 305: Bad constant value (ignored).
+/usr/include/x86_64-linux-gnu/bits/wchar.h:38: Warning 490: Fragment 'SWIG_From_wchar_t' not found.
+/usr/include/stdint.h:250: Warning 490: Fragment 'SWIG_From_wchar_t' not found.
+SWIG/_bio.i:64: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_rand.i:21: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_evp.i:169: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_dh.i:36: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_rsa.i:43: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_dsa.i:31: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_ssl.i:241: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_ssl.i:242: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_x509.i:323: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_pkcs7.i:44: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_pkcs7.i:44: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_util.i:11: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_ec.i:111: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_engine.i:168: Warning 454: Setting a pointer/reference variable may leak memory.
+creating build/temp.linux-x86_64-2.7
+creating build/temp.linux-x86_64-2.7/SWIG
+x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fdebug-prefix-map=/build/python2.7-DmWv1o/python2.7-2.7.14=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -I/usr/include -I/usr/include/x86_64-linux-gnu -I/tmp/pip-build-cIFksT/m2crypto/SWIG -c SWIG/_m2crypto_wrap.c -o build/temp.linux-x86_64-2.7/SWIG/_m2crypto_wrap.o -DTHREADING
+SWIG/_m2crypto_wrap.c:4186:35: error: ‘CRYPTO_NUM_LOCKS’ undeclared here (not in a function); did you mean ‘CRYPTO_UNLOCK’?
+static PyThread_type_lock lock_cs[CRYPTO_NUM_LOCKS];
+^~~~~~~~~~~~~~~~
+CRYPTO_UNLOCK
+SWIG/_m2crypto_wrap.c: In function ‘lib_init’:
+SWIG/_m2crypto_wrap.c:4567:5: warning: implicit declaration of function ‘SSLeay_add_all_algorithms’; did you mean ‘SSLeay_add_ssl_algorithms’? [-Wimplicit-function-declaration]
+SSLeay_add_all_algorithms();
+^~~~~~~~~~~~~~~~~~~~~~~~~
+SSLeay_add_ssl_algorithms
+SWIG/_m2crypto_wrap.c: In function ‘bn_rand’:
+SWIG/_m2crypto_wrap.c:4971:12: error: storage size of ‘rnd’ isn’t known
+BIGNUM rnd;
+^~~
+SWIG/_m2crypto_wrap.c:4975:5: warning: implicit declaration of function ‘BN_init’; did you mean ‘bio_init’? [-Wimplicit-function-declaration]
+BN_init(&rnd);
+^~~~~~~
+bio_init
+SWIG/_m2crypto_wrap.c:4971:12: warning: unused variable ‘rnd’ [-Wunused-variable]
+BIGNUM rnd;
+^~~
+SWIG/_m2crypto_wrap.c: In function ‘bn_rand_range’:
+SWIG/_m2crypto_wrap.c:5000:12: error: storage size of ‘rnd’ isn’t known
+BIGNUM rnd;
+^~~
+SWIG/_m2crypto_wrap.c:5000:12: warning: unused variable ‘rnd’ [-Wunused-variable]
+SWIG/_m2crypto_wrap.c: In function ‘rand_pseudo_bytes’:
+SWIG/_m2crypto_wrap.c:5131:5: warning: ‘RAND_pseudo_bytes’ is deprecated [-Wdeprecated-declarations]
+ret = RAND_pseudo_bytes(blob, n);
+^~~
+In file included from /usr/include/openssl/crypto.h:32:0,
+from /usr/include/openssl/bio.h:20,
+from /usr/include/openssl/err.h:21,
+from SWIG/_m2crypto_wrap.c:3829:
+/usr/include/openssl/rand.h:47:1: note: declared here
+DEPRECATEDIN_1_1_0(int RAND_pseudo_bytes(unsigned char *buf, int num))
+^
+SWIG/_m2crypto_wrap.c: In function ‘digest_final’:
+SWIG/_m2crypto_wrap.c:5249:34: error: dereferencing pointer to incomplete type ‘EVP_MD_CTX {aka struct evp_md_ctx_st}’
+if (!(blob = PyMem_Malloc(ctx->digest->md_size))) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘hmac_ctx_new’:
+SWIG/_m2crypto_wrap.c:5266:49: error: invalid application of ‘sizeof’ to incomplete type ‘HMAC_CTX {aka struct hmac_ctx_st}’
+if (!(ctx = (HMAC_CTX *)PyMem_Malloc(sizeof(HMAC_CTX)))) {
+^~~~~~~~
+SWIG/_m2crypto_wrap.c:5270:5: warning: implicit declaration of function ‘HMAC_CTX_init’; did you mean ‘HMAC_CTX_new’? [-Wimplicit-function-declaration]
+HMAC_CTX_init(ctx);
+^~~~~~~~~~~~~
+HMAC_CTX_new
+SWIG/_m2crypto_wrap.c: In function ‘hmac_ctx_free’:
+SWIG/_m2crypto_wrap.c:5275:5: warning: implicit declaration of function ‘HMAC_CTX_cleanup’; did you mean ‘HMAC_CTX_get_md’? [-Wimplicit-function-declaration]
+HMAC_CTX_cleanup(ctx);
+^~~~~~~~~~~~~~~~
+HMAC_CTX_get_md
+SWIG/_m2crypto_wrap.c: In function ‘hmac_init’:
+SWIG/_m2crypto_wrap.c:5286:5: warning: ‘HMAC_Init’ is deprecated [-Wdeprecated-declarations]
+if (!HMAC_Init(ctx, kbuf, klen, md)) {
+^~
+In file included from /usr/include/openssl/hmac.h:13:0,
+from /usr/include/openssl/ssl.h:56,
+from SWIG/_m2crypto_wrap.c:4247:
+/usr/include/openssl/hmac.h:28:1: note: declared here
+DEPRECATEDIN_1_1_0(__owur int HMAC_Init(HMAC_CTX *ctx, const void *key, int len,
+^
+SWIG/_m2crypto_wrap.c: In function ‘hmac_final’:
+SWIG/_m2crypto_wrap.c:5314:34: error: dereferencing pointer to incomplete type ‘HMAC_CTX {aka struct hmac_ctx_st}’
+if (!(blob = PyMem_Malloc(ctx->md->md_size))) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘cipher_ctx_new’:
+SWIG/_m2crypto_wrap.c:5353:55: error: invalid application of ‘sizeof’ to incomplete type ‘EVP_CIPHER_CTX {aka struct evp_cipher_ctx_st}’
+if (!(ctx = (EVP_CIPHER_CTX *)PyMem_Malloc(sizeof(EVP_CIPHER_CTX)))) {
+^~~~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘cipher_final’:
+SWIG/_m2crypto_wrap.c:5434:34: error: dereferencing pointer to incomplete type ‘EVP_CIPHER_CTX {aka struct evp_cipher_ctx_st}’
+if (!(obuf = PyMem_Malloc(ctx->cipher->block_size))) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘pkey_get_modulus’:
+SWIG/_m2crypto_wrap.c:5582:17: error: dereferencing pointer to incomplete type ‘EVP_PKEY {aka struct evp_pkey_st}’
+switch (pkey->type) {
+^~
+SWIG/_m2crypto_wrap.c:5593:35: error: dereferencing pointer to incomplete type ‘RSA {aka struct rsa_st}’
+if (!BN_print(bio, rsa->n)) {
+^~
+SWIG/_m2crypto_wrap.c:5618:35: error: dereferencing pointer to incomplete type ‘DSA {aka struct dsa_st}’
+if (!BN_print(bio, dsa->pub_key)) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘dh_generate_parameters’:
+SWIG/_m2crypto_wrap.c:5815:5: warning: ‘DH_generate_parameters’ is deprecated [-Wdeprecated-declarations]
+dh = DH_generate_parameters(plen, g, gendh_callback, (void *)pyfunc);
+^~
+In file included from /usr/include/openssl/bn.h:31:0,
+from /usr/include/openssl/asn1.h:24,
+from /usr/include/openssl/dh.h:18,
+from SWIG/_m2crypto_wrap.c:4243:
+/usr/include/openssl/dh.h:135:1: note: declared here
+DEPRECATEDIN_0_9_8(DH *DH_generate_parameters(int prime_len, int generator,
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_p’:
+SWIG/_m2crypto_wrap.c:5861:12: error: dereferencing pointer to incomplete type ‘DH {aka struct dh_st}’
+if (!dh->p) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘rsa_generate_key’:
+SWIG/_m2crypto_wrap.c:6319:5: warning: ‘RSA_generate_key’ is deprecated [-Wdeprecated-declarations]
+rsa = RSA_generate_key(bits, e, genrsa_callback, (void *)pyfunc);
+^~~
+In file included from /usr/include/openssl/rsa.h:13:0,
+from SWIG/_m2crypto_wrap.c:4246:
+/usr/include/openssl/rsa.h:193:1: note: declared here
+DEPRECATEDIN_0_9_8(RSA *RSA_generate_key(int bits, unsigned long e, void
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:6348:29: error: dereferencing pointer to incomplete type ‘DSA_SIG {aka struct DSA_SIG_st}’
+return bn_to_mpi(dsa_sig->r);
+^~
+SWIG/_m2crypto_wrap.c: In function ‘dsa_generate_parameters’:
+SWIG/_m2crypto_wrap.c:6378:5: warning: ‘DSA_generate_parameters’ is deprecated [-Wdeprecated-declarations]
+dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, genparam_callback, (void *)pyfunc);
+^~~
+In file included from /usr/include/openssl/dsa.h:28:0,
+from /usr/include/openssl/x509.h:32,
+from /usr/include/openssl/ssl.h:50,
+from SWIG/_m2crypto_wrap.c:4247:
+/usr/include/openssl/dsa.h:122:1: note: declared here
+DEPRECATEDIN_0_9_8(DSA *DSA_generate_parameters(int bits,
+^
+SWIG/_m2crypto_wrap.c: In function ‘sk_ssl_cipher_value’:
+SWIG/_m2crypto_wrap.c:7284:12: warning: return discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
+return sk_SSL_CIPHER_value(stack, idx);
+^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘x509_name_get_der’:
+SWIG/_m2crypto_wrap.c:7463:43: error: dereferencing pointer to incomplete type ‘X509_NAME {aka struct X509_name_st}’
+return PyString_FromStringAndSize(name->bytes->data, name->bytes->length);
+^~
+SWIG/_m2crypto_wrap.c: At top level:
+SWIG/_m2crypto_wrap.c:7523:2: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
+x509v3_lhash() {
+^~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘x509v3_lhash’:
+SWIG/_m2crypto_wrap.c:7524:12: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
+return lh_new(NULL, NULL); / Should probably be lh_CONF_VALUE_new but won't compile. */
+^~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘make_stack_from_der_sequence’:
+SWIG/_m2crypto_wrap.c:7640:13: warning: implicit declaration of function ‘ASN1_seq_unpack_X509’; did you mean ‘ASN1_item_unpack’? [-Wimplicit-function-declaration]
+certs = ASN1_seq_unpack_X509((unsigned char *)encoded_string, encoded_string_len, d2i_X509, X509_free );
+^~~~~~~~~~~~~~~~~~~~
+ASN1_item_unpack
+SWIG/_m2crypto_wrap.c:7640:11: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
+certs = ASN1_seq_unpack_X509((unsigned char *)encoded_string, encoded_string_len, d2i_X509, X509_free );
+^
+SWIG/_m2crypto_wrap.c: In function ‘get_der_encoding_stack’:
+SWIG/_m2crypto_wrap.c:7656:16: warning: implicit declaration of function ‘ASN1_seq_pack_X509’; did you mean ‘ASN1_item_pack’? [-Wimplicit-function-declaration]
+encoding = ASN1_seq_pack_X509(stack, i2d_X509, NULL, &len);
+^~~~~~~~~~~~~~~~~~
+ASN1_item_pack
+SWIG/_m2crypto_wrap.c:7656:14: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
+encoding = ASN1_seq_pack_X509(stack, i2d_X509, NULL, &len);
+^
+SWIG/_m2crypto_wrap.c: In function ‘ecdsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:8186:31: error: dereferencing pointer to incomplete type ‘ECDSA_SIG {aka struct ECDSA_SIG_st}’
+return bn_to_mpi(ecdsa_sig->r);
+^~
+SWIG/_m2crypto_wrap.c: In function ‘_wrap_sslv2_method’:
+SWIG/_m2crypto_wrap.c:18315:26: warning: implicit declaration of function ‘SSLv2_method’; did you mean ‘SSLv23_method’? [-Wimplicit-function-declaration]
+result = (SSL_METHOD *)SSLv2_method();
+^~~~~~~~~~~~
+SSLv23_method
+SWIG/_m2crypto_wrap.c:18315:12: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
+result = (SSL_METHOD *)SSLv2_method();
+^
+SWIG/_m2crypto_wrap.c: In function ‘_wrap_tlsv1_method’:
+SWIG/_m2crypto_wrap.c:18341:3: warning: ‘TLSv1_method’ is deprecated [-Wdeprecated-declarations]
+result = (SSL_METHOD *)TLSv1_method();
+^~~~~~
+In file included from /usr/include/openssl/ct.h:13:0,
+from /usr/include/openssl/ssl.h:61,
+from SWIG/_m2crypto_wrap.c:4247:
+/usr/include/openssl/ssl.h:1627:1: note: declared here
+DEPRECATEDIN_1_1_0(__owur const SSL_METHOD TLSv1_method(void)) / TLSv1.0 */
+^
+SWIG/_m2crypto_wrap.c: In function ‘_wrap_c2i_asn1_object’:
+SWIG/_m2crypto_wrap.c:25775:27: warning: implicit declaration of function ‘c2i_ASN1_OBJECT’; did you mean ‘d2i_ASN1_OBJECT’? [-Wimplicit-function-declaration]
+result = (ASN1_OBJECT *)c2i_ASN1_OBJECT(arg1,(unsigned char const **)arg2,arg3);
+^~~~~~~~~~~~~~~
+d2i_ASN1_OBJECT
+SWIG/_m2crypto_wrap.c:25775:12: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
+result = (ASN1_OBJECT *)c2i_ASN1_OBJECT(arg1,(unsigned char const **)arg2,arg3);
+^
+SWIG/_m2crypto_wrap.c: In function ‘init__m2crypto’:
+SWIG/_m2crypto_wrap.c:31639:79: warning: implicit declaration of function ‘SWIG_From_wchar_t’; did you mean ‘SWIG_FromCharPtr’? [-Wimplicit-function-declaration]
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^~~~~~~~~~~~~~~~~
+SWIG_FromCharPtr
+SWIG/_m2crypto_wrap.c:31639:120: error: stray ‘\’ in program
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31639:121: warning: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31639:121: error: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^~~~~~~~~~~
+SWIG/_m2crypto_wrap.c:31639:119: error: ‘L’ undeclared (first use in this function)
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31639:119: note: each undeclared identifier is reported only once for each function it appears in
+SWIG/_m2crypto_wrap.c:31640:3: error: expected ‘)’ before ‘SWIG_Python_SetConstant’
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MIN",SWIG_From_int((int)((-(0x7fffffff+L'\0') -1))));
+^~~~~~~~~~~~~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c:31691:118: error: stray ‘\’ in program
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31691:119: warning: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31691:119: error: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^~~~~~~~~~~
+SWIG/_m2crypto_wrap.c:31996:1: error: expected declaration or statement at end of input
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_p’:
+SWIG/_m2crypto_wrap.c:5866:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_g’:
+SWIG/_m2crypto_wrap.c:5874:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_pub’:
+SWIG/_m2crypto_wrap.c:5882:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_priv’:
+SWIG/_m2crypto_wrap.c:5890:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘rsa_get_e’:
+SWIG/_m2crypto_wrap.c:5999:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘rsa_get_n’:
+SWIG/_m2crypto_wrap.c:6007:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘rsa_check_pub_key’:
+SWIG/_m2crypto_wrap.c:6334:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:6349:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_sig_get_s’:
+SWIG/_m2crypto_wrap.c:6353:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_p’:
+SWIG/_m2crypto_wrap.c:6391:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_q’:
+SWIG/_m2crypto_wrap.c:6399:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_g’:
+SWIG/_m2crypto_wrap.c:6407:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_pub’:
+SWIG/_m2crypto_wrap.c:6415:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_priv’:
+SWIG/_m2crypto_wrap.c:6423:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_check_key’:
+SWIG/_m2crypto_wrap.c:6670:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_check_pub_key’:
+SWIG/_m2crypto_wrap.c:6674:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_keylen’:
+SWIG/_m2crypto_wrap.c:6678:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘x509_name_get_der’:
+SWIG/_m2crypto_wrap.c:7464:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘ecdsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:8187:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘ecdsa_sig_get_s’:
+SWIG/_m2crypto_wrap.c:8191:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+At top level:
+SWIG/_m2crypto_wrap.c:4187:13: warning: ‘lock_count’ defined but not used [-Wunused-variable]
+static long lock_count[CRYPTO_NUM_LOCKS];
+^~~~~~~~~~
+SWIG/_m2crypto_wrap.c:4186:27: warning: ‘lock_cs’ defined but not used [-Wunused-variable]
+static PyThread_type_lock lock_cs[CRYPTO_NUM_LOCKS];
+^~~~~~~
+error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
+ 
+Failed building wheel for m2crypto
+Running setup.py clean for m2crypto
+Failed to build m2crypto
+Installing collected packages: m2crypto
+Found existing installation: M2Crypto 0.26.2
+Uninstalling M2Crypto-0.26.2:
+Successfully uninstalled M2Crypto-0.26.2
+Running setup.py install for m2crypto ... error
+Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-cIFksT/m2crypto/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-cWZrMo-record/install-record.txt --single-version-externally-managed --compile:
+running install
+running build
+running build_py
+creating build
+creating build/lib.linux-x86_64-2.7
+creating build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/threading.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/ftpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/EC.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/Rand.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2xmlrpclib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2urllib2.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/ASN1.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/SMIME.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/init.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/EVP.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/X509.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/util.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/BN.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/callback.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/BIO.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/Engine.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/DH.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/Err.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/httpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/RC4.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/DSA.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/AuthCookie.py -> build/lib.linux-x86_64-2.7/M2Crypto
+copying M2Crypto/m2urllib.py -> build/lib.linux-x86_64-2.7/M2Crypto
+creating build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Connection.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/TwistedProtocolWrapper.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Context.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Session.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Checker.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/init.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/SSLServer.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/cb.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/Cipher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/ssl_dispatcher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+copying M2Crypto/SSL/timeout.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
+creating build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/PublicKeyRing.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/constants.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/PublicKey.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/init.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+copying M2Crypto/PGP/packet.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
+running build_ext
+building 'M2Crypto.__m2crypto' extension
+swigging SWIG/m2crypto.i to SWIG/m2crypto_wrap.c
+swig -python -D__x86_64 -I/usr/include/python2.7 -I/usr/include -I/usr/include/x86_64-linux-gnu -includeall -modern -builtin -outdir build/lib.linux-x86_64-2.7/M2Crypto -o SWIG/_m2crypto_wrap.c SWIG/_m2crypto.i
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:152: Warning 305: Bad constant value (ignored).
+/usr/include/x86_64-linux-gnu/bits/wchar.h:38: Warning 490: Fragment 'SWIG_From_wchar_t' not found.
+/usr/include/stdint.h:250: Warning 490: Fragment 'SWIG_From_wchar_t' not found.
+SWIG/_bio.i:64: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_rand.i:21: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_evp.i:169: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_dh.i:36: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_rsa.i:43: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_dsa.i:31: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_ssl.i:241: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_ssl.i:242: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_x509.i:323: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_pkcs7.i:44: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_pkcs7.i:44: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_util.i:11: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_ec.i:111: Warning 454: Setting a pointer/reference variable may leak memory.
+SWIG/_engine.i:168: Warning 454: Setting a pointer/reference variable may leak memory.
+creating build/temp.linux-x86_64-2.7
+creating build/temp.linux-x86_64-2.7/SWIG
+x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fdebug-prefix-map=/build/python2.7-DmWv1o/python2.7-2.7.14=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -I/usr/include -I/usr/include/x86_64-linux-gnu -I/tmp/pip-build-cIFksT/m2crypto/SWIG -c SWIG/_m2crypto_wrap.c -o build/temp.linux-x86_64-2.7/SWIG/_m2crypto_wrap.o -DTHREADING
+SWIG/_m2crypto_wrap.c:4186:35: error: ‘CRYPTO_NUM_LOCKS’ undeclared here (not in a function); did you mean ‘CRYPTO_UNLOCK’?
+static PyThread_type_lock lock_cs[CRYPTO_NUM_LOCKS];
+^~~~~~~~~~~~~~~~
+CRYPTO_UNLOCK
+SWIG/_m2crypto_wrap.c: In function ‘lib_init’:
+SWIG/_m2crypto_wrap.c:4567:5: warning: implicit declaration of function ‘SSLeay_add_all_algorithms’; did you mean ‘SSLeay_add_ssl_algorithms’? [-Wimplicit-function-declaration]
+SSLeay_add_all_algorithms();
+^~~~~~~~~~~~~~~~~~~~~~~~~
+SSLeay_add_ssl_algorithms
+SWIG/_m2crypto_wrap.c: In function ‘bn_rand’:
+SWIG/_m2crypto_wrap.c:4971:12: error: storage size of ‘rnd’ isn’t known
+BIGNUM rnd;
+^~~
+SWIG/_m2crypto_wrap.c:4975:5: warning: implicit declaration of function ‘BN_init’; did you mean ‘bio_init’? [-Wimplicit-function-declaration]
+BN_init(&rnd);
+^~~~~~~
+bio_init
+SWIG/_m2crypto_wrap.c:4971:12: warning: unused variable ‘rnd’ [-Wunused-variable]
+BIGNUM rnd;
+^~~
+SWIG/_m2crypto_wrap.c: In function ‘bn_rand_range’:
+SWIG/_m2crypto_wrap.c:5000:12: error: storage size of ‘rnd’ isn’t known
+BIGNUM rnd;
+^~~
+SWIG/_m2crypto_wrap.c:5000:12: warning: unused variable ‘rnd’ [-Wunused-variable]
+SWIG/_m2crypto_wrap.c: In function ‘rand_pseudo_bytes’:
+SWIG/_m2crypto_wrap.c:5131:5: warning: ‘RAND_pseudo_bytes’ is deprecated [-Wdeprecated-declarations]
+ret = RAND_pseudo_bytes(blob, n);
+^~~
+In file included from /usr/include/openssl/crypto.h:32:0,
+from /usr/include/openssl/bio.h:20,
+from /usr/include/openssl/err.h:21,
+from SWIG/_m2crypto_wrap.c:3829:
+/usr/include/openssl/rand.h:47:1: note: declared here
+DEPRECATEDIN_1_1_0(int RAND_pseudo_bytes(unsigned char *buf, int num))
+^
+SWIG/_m2crypto_wrap.c: In function ‘digest_final’:
+SWIG/_m2crypto_wrap.c:5249:34: error: dereferencing pointer to incomplete type ‘EVP_MD_CTX {aka struct evp_md_ctx_st}’
+if (!(blob = PyMem_Malloc(ctx->digest->md_size))) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘hmac_ctx_new’:
+SWIG/_m2crypto_wrap.c:5266:49: error: invalid application of ‘sizeof’ to incomplete type ‘HMAC_CTX {aka struct hmac_ctx_st}’
+if (!(ctx = (HMAC_CTX *)PyMem_Malloc(sizeof(HMAC_CTX)))) {
+^~~~~~~~
+SWIG/_m2crypto_wrap.c:5270:5: warning: implicit declaration of function ‘HMAC_CTX_init’; did you mean ‘HMAC_CTX_new’? [-Wimplicit-function-declaration]
+HMAC_CTX_init(ctx);
+^~~~~~~~~~~~~
+HMAC_CTX_new
+SWIG/_m2crypto_wrap.c: In function ‘hmac_ctx_free’:
+SWIG/_m2crypto_wrap.c:5275:5: warning: implicit declaration of function ‘HMAC_CTX_cleanup’; did you mean ‘HMAC_CTX_get_md’? [-Wimplicit-function-declaration]
+HMAC_CTX_cleanup(ctx);
+^~~~~~~~~~~~~~~~
+HMAC_CTX_get_md
+SWIG/_m2crypto_wrap.c: In function ‘hmac_init’:
+SWIG/_m2crypto_wrap.c:5286:5: warning: ‘HMAC_Init’ is deprecated [-Wdeprecated-declarations]
+if (!HMAC_Init(ctx, kbuf, klen, md)) {
+^~
+In file included from /usr/include/openssl/hmac.h:13:0,
+from /usr/include/openssl/ssl.h:56,
+from SWIG/_m2crypto_wrap.c:4247:
+/usr/include/openssl/hmac.h:28:1: note: declared here
+DEPRECATEDIN_1_1_0(__owur int HMAC_Init(HMAC_CTX *ctx, const void *key, int len,
+^
+SWIG/_m2crypto_wrap.c: In function ‘hmac_final’:
+SWIG/_m2crypto_wrap.c:5314:34: error: dereferencing pointer to incomplete type ‘HMAC_CTX {aka struct hmac_ctx_st}’
+if (!(blob = PyMem_Malloc(ctx->md->md_size))) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘cipher_ctx_new’:
+SWIG/_m2crypto_wrap.c:5353:55: error: invalid application of ‘sizeof’ to incomplete type ‘EVP_CIPHER_CTX {aka struct evp_cipher_ctx_st}’
+if (!(ctx = (EVP_CIPHER_CTX *)PyMem_Malloc(sizeof(EVP_CIPHER_CTX)))) {
+^~~~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘cipher_final’:
+SWIG/_m2crypto_wrap.c:5434:34: error: dereferencing pointer to incomplete type ‘EVP_CIPHER_CTX {aka struct evp_cipher_ctx_st}’
+if (!(obuf = PyMem_Malloc(ctx->cipher->block_size))) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘pkey_get_modulus’:
+SWIG/_m2crypto_wrap.c:5582:17: error: dereferencing pointer to incomplete type ‘EVP_PKEY {aka struct evp_pkey_st}’
+switch (pkey->type) {
+^~
+SWIG/_m2crypto_wrap.c:5593:35: error: dereferencing pointer to incomplete type ‘RSA {aka struct rsa_st}’
+if (!BN_print(bio, rsa->n)) {
+^~
+SWIG/_m2crypto_wrap.c:5618:35: error: dereferencing pointer to incomplete type ‘DSA {aka struct dsa_st}’
+if (!BN_print(bio, dsa->pub_key)) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘dh_generate_parameters’:
+SWIG/_m2crypto_wrap.c:5815:5: warning: ‘DH_generate_parameters’ is deprecated [-Wdeprecated-declarations]
+dh = DH_generate_parameters(plen, g, gendh_callback, (void *)pyfunc);
+^~
+In file included from /usr/include/openssl/bn.h:31:0,
+from /usr/include/openssl/asn1.h:24,
+from /usr/include/openssl/dh.h:18,
+from SWIG/_m2crypto_wrap.c:4243:
+/usr/include/openssl/dh.h:135:1: note: declared here
+DEPRECATEDIN_0_9_8(DH *DH_generate_parameters(int prime_len, int generator,
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_p’:
+SWIG/_m2crypto_wrap.c:5861:12: error: dereferencing pointer to incomplete type ‘DH {aka struct dh_st}’
+if (!dh->p) {
+^~
+SWIG/_m2crypto_wrap.c: In function ‘rsa_generate_key’:
+SWIG/_m2crypto_wrap.c:6319:5: warning: ‘RSA_generate_key’ is deprecated [-Wdeprecated-declarations]
+rsa = RSA_generate_key(bits, e, genrsa_callback, (void *)pyfunc);
+^~~
+In file included from /usr/include/openssl/rsa.h:13:0,
+from SWIG/_m2crypto_wrap.c:4246:
+/usr/include/openssl/rsa.h:193:1: note: declared here
+DEPRECATEDIN_0_9_8(RSA *RSA_generate_key(int bits, unsigned long e, void
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:6348:29: error: dereferencing pointer to incomplete type ‘DSA_SIG {aka struct DSA_SIG_st}’
+return bn_to_mpi(dsa_sig->r);
+^~
+SWIG/_m2crypto_wrap.c: In function ‘dsa_generate_parameters’:
+SWIG/_m2crypto_wrap.c:6378:5: warning: ‘DSA_generate_parameters’ is deprecated [-Wdeprecated-declarations]
+dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, genparam_callback, (void *)pyfunc);
+^~~
+In file included from /usr/include/openssl/dsa.h:28:0,
+from /usr/include/openssl/x509.h:32,
+from /usr/include/openssl/ssl.h:50,
+from SWIG/_m2crypto_wrap.c:4247:
+/usr/include/openssl/dsa.h:122:1: note: declared here
+DEPRECATEDIN_0_9_8(DSA *DSA_generate_parameters(int bits,
+^
+SWIG/_m2crypto_wrap.c: In function ‘sk_ssl_cipher_value’:
+SWIG/_m2crypto_wrap.c:7284:12: warning: return discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
+return sk_SSL_CIPHER_value(stack, idx);
+^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘x509_name_get_der’:
+SWIG/_m2crypto_wrap.c:7463:43: error: dereferencing pointer to incomplete type ‘X509_NAME {aka struct X509_name_st}’
+return PyString_FromStringAndSize(name->bytes->data, name->bytes->length);
+^~
+SWIG/_m2crypto_wrap.c: At top level:
+SWIG/_m2crypto_wrap.c:7523:2: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
+x509v3_lhash() {
+^~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘x509v3_lhash’:
+SWIG/_m2crypto_wrap.c:7524:12: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
+return lh_new(NULL, NULL); / Should probably be lh_CONF_VALUE_new but won't compile. */
+^~~~~~
+SWIG/_m2crypto_wrap.c: In function ‘make_stack_from_der_sequence’:
+SWIG/_m2crypto_wrap.c:7640:13: warning: implicit declaration of function ‘ASN1_seq_unpack_X509’; did you mean ‘ASN1_item_unpack’? [-Wimplicit-function-declaration]
+certs = ASN1_seq_unpack_X509((unsigned char *)encoded_string, encoded_string_len, d2i_X509, X509_free );
+^~~~~~~~~~~~~~~~~~~~
+ASN1_item_unpack
+SWIG/_m2crypto_wrap.c:7640:11: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
+certs = ASN1_seq_unpack_X509((unsigned char *)encoded_string, encoded_string_len, d2i_X509, X509_free );
+^
+SWIG/_m2crypto_wrap.c: In function ‘get_der_encoding_stack’:
+SWIG/_m2crypto_wrap.c:7656:16: warning: implicit declaration of function ‘ASN1_seq_pack_X509’; did you mean ‘ASN1_item_pack’? [-Wimplicit-function-declaration]
+encoding = ASN1_seq_pack_X509(stack, i2d_X509, NULL, &len);
+^~~~~~~~~~~~~~~~~~
+ASN1_item_pack
+SWIG/_m2crypto_wrap.c:7656:14: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
+encoding = ASN1_seq_pack_X509(stack, i2d_X509, NULL, &len);
+^
+SWIG/_m2crypto_wrap.c: In function ‘ecdsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:8186:31: error: dereferencing pointer to incomplete type ‘ECDSA_SIG {aka struct ECDSA_SIG_st}’
+return bn_to_mpi(ecdsa_sig->r);
+^~
+SWIG/_m2crypto_wrap.c: In function ‘_wrap_sslv2_method’:
+SWIG/_m2crypto_wrap.c:18315:26: warning: implicit declaration of function ‘SSLv2_method’; did you mean ‘SSLv23_method’? [-Wimplicit-function-declaration]
+result = (SSL_METHOD *)SSLv2_method();
+^~~~~~~~~~~~
+SSLv23_method
+SWIG/_m2crypto_wrap.c:18315:12: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
+result = (SSL_METHOD *)SSLv2_method();
+^
+SWIG/_m2crypto_wrap.c: In function ‘_wrap_tlsv1_method’:
+SWIG/_m2crypto_wrap.c:18341:3: warning: ‘TLSv1_method’ is deprecated [-Wdeprecated-declarations]
+result = (SSL_METHOD *)TLSv1_method();
+^~~~~~
+In file included from /usr/include/openssl/ct.h:13:0,
+from /usr/include/openssl/ssl.h:61,
+from SWIG/_m2crypto_wrap.c:4247:
+/usr/include/openssl/ssl.h:1627:1: note: declared here
+DEPRECATEDIN_1_1_0(__owur const SSL_METHOD TLSv1_method(void)) / TLSv1.0 */
+^
+SWIG/_m2crypto_wrap.c: In function ‘_wrap_c2i_asn1_object’:
+SWIG/_m2crypto_wrap.c:25775:27: warning: implicit declaration of function ‘c2i_ASN1_OBJECT’; did you mean ‘d2i_ASN1_OBJECT’? [-Wimplicit-function-declaration]
+result = (ASN1_OBJECT *)c2i_ASN1_OBJECT(arg1,(unsigned char const **)arg2,arg3);
+^~~~~~~~~~~~~~~
+d2i_ASN1_OBJECT
+SWIG/_m2crypto_wrap.c:25775:12: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
+result = (ASN1_OBJECT *)c2i_ASN1_OBJECT(arg1,(unsigned char const **)arg2,arg3);
+^
+SWIG/_m2crypto_wrap.c: In function ‘init__m2crypto’:
+SWIG/_m2crypto_wrap.c:31639:79: warning: implicit declaration of function ‘SWIG_From_wchar_t’; did you mean ‘SWIG_FromCharPtr’? [-Wimplicit-function-declaration]
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^~~~~~~~~~~~~~~~~
+SWIG_FromCharPtr
+SWIG/_m2crypto_wrap.c:31639:120: error: stray ‘\’ in program
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31639:121: warning: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31639:121: error: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^~~~~~~~~~~
+SWIG/_m2crypto_wrap.c:31639:119: error: ‘L’ undeclared (first use in this function)
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31639:119: note: each undeclared identifier is reported only once for each function it appears in
+SWIG/_m2crypto_wrap.c:31640:3: error: expected ‘)’ before ‘SWIG_Python_SetConstant’
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "__WCHAR_MIN",SWIG_From_int((int)((-(0x7fffffff+L'\0') -1))));
+^~~~~~~~~~~~~~~~~~~~~~~
+SWIG/_m2crypto_wrap.c:31691:118: error: stray ‘\’ in program
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31691:119: warning: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^
+SWIG/_m2crypto_wrap.c:31691:119: error: missing terminating ' character
+SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "WCHAR_MAX",SWIG_From_wchar_t((wchar_t)((0x7fffffff+L'\0'))));
+^~~~~~~~~~~
+SWIG/_m2crypto_wrap.c:31996:1: error: expected declaration or statement at end of input
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_p’:
+SWIG/_m2crypto_wrap.c:5866:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_g’:
+SWIG/_m2crypto_wrap.c:5874:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_pub’:
+SWIG/_m2crypto_wrap.c:5882:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dh_get_priv’:
+SWIG/_m2crypto_wrap.c:5890:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘rsa_get_e’:
+SWIG/_m2crypto_wrap.c:5999:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘rsa_get_n’:
+SWIG/_m2crypto_wrap.c:6007:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘rsa_check_pub_key’:
+SWIG/_m2crypto_wrap.c:6334:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:6349:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_sig_get_s’:
+SWIG/_m2crypto_wrap.c:6353:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_p’:
+SWIG/_m2crypto_wrap.c:6391:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_q’:
+SWIG/_m2crypto_wrap.c:6399:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_g’:
+SWIG/_m2crypto_wrap.c:6407:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_pub’:
+SWIG/_m2crypto_wrap.c:6415:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_get_priv’:
+SWIG/_m2crypto_wrap.c:6423:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_check_key’:
+SWIG/_m2crypto_wrap.c:6670:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_check_pub_key’:
+SWIG/_m2crypto_wrap.c:6674:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘dsa_keylen’:
+SWIG/_m2crypto_wrap.c:6678:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘x509_name_get_der’:
+SWIG/_m2crypto_wrap.c:7464:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘ecdsa_sig_get_r’:
+SWIG/_m2crypto_wrap.c:8187:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+SWIG/_m2crypto_wrap.c: In function ‘ecdsa_sig_get_s’:
+SWIG/_m2crypto_wrap.c:8191:1: warning: control reaches end of non-void function [-Wreturn-type]
+}
+^
+At top level:
+SWIG/_m2crypto_wrap.c:4187:13: warning: ‘lock_count’ defined but not used [-Wunused-variable]
+static long lock_count[CRYPTO_NUM_LOCKS];
+^~~~~~~~~~
+SWIG/_m2crypto_wrap.c:4186:27: warning: ‘lock_cs’ defined but not used [-Wunused-variable]
+static PyThread_type_lock lock_cs[CRYPTO_NUM_LOCKS];
+^~~~~~~
+error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
+ 
+----------------------------------------
+ 
+Rolling back uninstall of M2Crypto
+
+    Command "/usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-cIFksT/m2crypto/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-cWZrMo-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-cIFksT/m2crypto/
+```
\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_import_issues.py b/tests/test_import_issues.py
new file mode 100644
index 0000000..d6b2dbc
--- /dev/null
+++ b/tests/test_import_issues.py
@@ -0,0 +1,52 @@
+import os.path
+import textwrap
+import unittest
+
+from import_issues import MAX_SIZE_COMMENT, split_long_str
+
+
+class TestStringSplitting(unittest.TestCase):
+    maxDiff = None
+
+    def setUp(self):
+        __cur_dir = os.path.abspath(os.path.dirname(__file__))
+        with open(os.path.join(__cur_dir, "209_description.txt")) as inf:
+            self.long_str = inf.read()
+
+    def test_one_line(self):
+        in_str = "Testing string."
+        split_str = split_long_str(in_str, 100)
+        self.assertIsInstance(split_str, list)
+        self.assertEqual(len(split_str), 1)
+        self.assertEqual(in_str, "".join(split_str))
+
+    def test_short_str(self):
+        in_str = textwrap.dedent(
+            """\
+        Reader, I married him.
+        A quiet wedding we had: he and I, the parson and clerk, were alone present.
+        When we got back from church, I went into the kitchen of the manor-house, where Mary was cooking the dinner and John cleaning the knives, and I said—
+
+        “Mary, I have been married to Mr. Rochester this morning.”
+
+        The housekeeper and her husband were both of that decent phlegmatic order of people, to whom one may at any time safely communicate a remarkable piece of news without incurring the danger of having one’s ears pierced by some shrill ejaculation, and subsequently stunned by a torrent of wordy wonderment.
+        Mary did look up, and she did stare at me: the ladle with which she was basting a pair of chickens roasting at the fire, did for some three minutes hang suspended in air; and for the same space of time John’s knives also had rest from the polishing process: but Mary, bending again over the roast, said only—
+
+        “Have you, Miss? Well, for sure!”
+
+        """
+        )
+        split_str = split_long_str(in_str, 100)
+        self.assertIsInstance(split_str, list)
+        self.assertEqual(len(split_str), 6)
+        self.assertEqual(in_str, "".join(split_str))
+
+    def test_long_str(self):
+        split_str = split_long_str(self.long_str, MAX_SIZE_COMMENT)
+        self.assertIsInstance(split_str, list)
+        self.assertEqual(len(split_str), 4)
+        self.assertEqual(self.long_str, "".join(split_str))
+
+
+if __name__ == "__main__":
+    unittest.main()
-- 
2.45.1

[PATCH lazygl2shrt v2 15/15] fix: split too long descriptions or comments and send them separately

Details
Message ID
<20240602195752.28931-30-mcepl@cepl.eu>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +44 -13
---
 import_issues.py | 57 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 44 insertions(+), 13 deletions(-)

diff --git a/import_issues.py b/import_issues.py
index 5470f4e..a60354a 100755
--- a/import_issues.py
+++ b/import_issues.py
@@ -136,6 +136,7 @@ from email.message import EmailMessage
from email.utils import format_datetime, make_msgid
from pathlib import Path
from typing import Any, Optional
from urllib.parse import urlparse

logging.basicConfig(
    format="%(levelname)s:%(funcName)s:%(message)s",
@@ -369,6 +370,9 @@ def open_ticket_by_email(
    lines.append("")
    lines.append(body)

    body_split = split_long_str("\n".join(lines))

    # First create the ticket
    do_mail(
        smtp=smtp,
        delay=delay,
@@ -376,9 +380,24 @@ def open_ticket_by_email(
        frm=frm,
        to=f"{tracker}@todo.sr.ht",
        subject=title,
        body="\n".join(lines),
        body=body_split[0],
    )

    # then add remaining parts of the description as comments
    if len(body_split) > 1:
        url_split = urlparse(gitlab_ticket_url)
        issue_id = int(os.path.basename(url_split.path))

        for part in body_split[1:]:
            do_mail(
                smtp=smtp,
                delay=delay,
                mode=mode,
                frm=frm,
                to=f"{tracker}/{issue_id}@todo.sr.ht",
                body=part,
            )


def open_ticket_by_hut(
    delay: float,
@@ -423,7 +442,9 @@ def open_ticket_by_hut(
    msg = title
    if len(lines):
        msg += "\n" + "\n".join(lines)
    out = run_hut(["ticket", "create"], tracker, msg, delay=delay)
    msg_split = split_long_str(msg)

    out = run_hut(["ticket", "create"], tracker, msg_split[0], delay=delay)
    out.issue_id = int(out.stderr.strip()[len("Created new ticket #") :])

    for label in sorted(labels, key=lambda x: x["label"]["title"]):
@@ -451,6 +472,13 @@ def open_ticket_by_hut(
            delay=delay,
        )

    # then add remaining parts of the description as comments
    if len(msg_split) > 1:
        for part in msg_split[1:]:
            run_hut(
                ["ticket", "comment"], tracker, part, [str(out.issue_id)], delay=delay
            )

    return out


@@ -593,17 +621,20 @@ def send_comment(

    body = "\n".join(lines)

    if mode in ["send", "print"]:
        do_mail(
            smtp=smtp,
            delay=delay,
            mode=mode,
            frm=frm,
            to=f"{tracker}/{issue_id}@todo.sr.ht",
            body=body,
        )
    elif mode == "hut":
        run_hut(["ticket", "comment"], tracker, body, [str(issue_id)], delay=delay)
    body_split = split_long_str(body)

    for part in body_split:
        if mode in ["send", "print"]:
            do_mail(
                smtp=smtp,
                delay=delay,
                mode=mode,
                frm=frm,
                to=f"{tracker}/{issue_id}@todo.sr.ht",
                body=part,
            )
        elif mode == "hut":
            run_hut(["ticket", "comment"], tracker, part, [str(issue_id)], delay=delay)


def close_ticket(
-- 
2.45.1
Details
Message ID
<20240719210140.6a65b6db@kyouma>
In-Reply-To
<20240602195752.28931-16-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
Hi Matěj,

Very belatedly, thank you for this patchset!  It's great to have a
more reliable method than email, and to have labels applied and long
messages split automatically.  And to have tests.

I've applied this now.  I did some minor follow-up work, mostly to
make the code more strict, but also to restore label caching and fix a
corner case of using --mode=email with split messages together with
skipped confidential tickets.  (I skipped the "Bit reformatting"
commit, minor personal preference for the existing state of things
there.)

So, thanks again.  Can we add a copyright line for you?  You've done
plenty of work on this and you should get credit.

Cheers,
Bryan
Details
Message ID
<D2U9GL4FS84N.2DENWA5QZ40X4@cepl.eu>
In-Reply-To
<20240719210140.6a65b6db@kyouma> (view parent)
DKIM signature
pass
Download raw message
On Sat Jul 20, 2024 at 6:01 AM CEST, Bryan Gardiner wrote:
> So, thanks again.  Can we add a copyright line for you?  You've done
> plenty of work on this and you should get credit.

Sure, go ahead

Signed-off: Matěj Cepl <mcepl@cepl.eu>

Best,

Matěj

-- 
http://matej.ceplovi.cz/blog/, @mcepl@floss.social
GPG Finger: 3C76 A027 CA45 AD70 98B5  BC1D 7920 5802 880B C9D8
 
Afraid to die alone?
Become a bus driver.
  -- alleged easter egg in notepad++
Reply to thread Export thread (mbox)