public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Girish Joshi <girish946@gmail.com>
To: Siddhesh Poyarekar <siddhesh@gotplt.org>,
	 Girish Joshi via Libc-alpha <libc-alpha@sourceware.org>
Cc: Andreas Schwab <schwab@linux-m68k.org>,
	Joseph Myers <joseph@codesourcery.com>
Subject: Re: [RFC] Updating patchwork patches on commit
Date: Thu, 4 Feb 2021 21:17:46 +0530	[thread overview]
Message-ID: <CALkY8p97h9XP7d4pWw3bd1Fa7PoGBccs1QCg7d9aPqB6SrBxGQ@mail.gmail.com> (raw)
In-Reply-To: <CALkY8p8S3CuF9HOQE3NeewYO4SP+0aWc_YiXPs1nGnUmbQYDDA@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 811 bytes --]

Hello Siddhesh,

On Thu, Jan 7, 2021 at 1:56 AM Girish Joshi <girish946@gmail.com> wrote:
>
> I've combined the two scripts to pull data from the patchwork instance
> instead of stdin or a csv file.
> Also to get the patch ids for the old patches that do not belong to any series.
> To get these individual patches
>     python scripts/apply-patches.py -u
>
> I'll try to fix a few small things like taking page numbers for
> pulling the data from the command line itself by this weekend.

I've done this change in the attached script.

> Once this is done, this script can be invoked after a regular interval
> of time to check if the new patches can be applied.
We can do this now.

There are a couple of functions that need refactoring.
But for now it does the job.
Could you please review it?

Girish Joshi

[-- Attachment #2: apply-patches.py --]
[-- Type: text/x-python, Size: 10264 bytes --]

#!python3

import subprocess as sp
import _thread as thread
import argparse
import csv
import os
import sys
import time

# if these strings are found in output of git/git-pw,
# we need to take some actions.
prune_warining = "warning: There are too many unreachable loose objects; run 'git prune' to remove them."
resource_not_found_warning = "Resource not found"
already_applied_warning = "No changes -- Patch already applied."

# These lists will contain merged and unmnerged series data.
merged = []
unmerged = []
unavailable = []
already_applied = []

# parse the csv entries
def read_rows(csvfile):

    # List for series entries
    series_data = []
    csvreader = csv.reader(csvfile, delimiter=",", quotechar='"')
    for row in csvreader:
        print(row)
        if not row:
            return
        if row and row[0] != "ID":
            series_data.append(row)
    return series_data


def run_cmd(cmd, debug=False):
    """
    Execute command and return the exit code and output.
    """
    exit_code = 0
    output = ""
    try:
        output = sp.check_output(
            cmd, stderr=sp.STDOUT, shell=True, universal_newlines=True
        )
    except sp.CalledProcessError as exc:
        if debug:
            print("Status : FAIL", exc.returncode, exc.output)
        exit_code, output = exc.returncode, exc.output
    else:
        if debug:
            print("{}\n".format(output))

    return exit_code, output


def write_file(filename, list_):
    """
    This function is used to write the IDs for patches/series that
    are merged/unmerged/unavailable after we have processed everything.
    """
    with open(filename, "w") as f:
        for i in list_:
            f.write(i[0] + "\n")


def write_json(file_name, data):
    import json

    with open(file_name, "w") as f:
        f.write(json.dumps(data))


def apply_(series):
    """if git throws a warning saying
    "warning: There are too many unreachable loose objects; run 'git prune' to remove them."
    `git prune` will be executed. otherwise output will be printed and exit code
    will be returned.
    """

    for i in series:
        try:
            print(
                f"{bcolors.OKGREEN}trying to apply:{type_}{bcolors.OKCYAN} {i[0]} {bcolors.ENDC}"
            )
            print(f"{bcolors.OKBLUE} {i[1]}, {bcolors.UNDERLINE}{i[2]}{bcolors.ENDC}")
            if i[0] == "ID":
                pass

            exit_code, output = run_cmd(f"git-pw {type_} apply {i[0]}")

            if prune_warining in output:
                print("running: git prune")
                run_cmd("git prune")

            if exit_code == 1 and resource_not_found_warning in output:
                print(f"{bcolors.WARNING}patch unavailable{bcolors.ENDC}")
                unavailable.append(i)

            if exit_code:
                # if `git-pw patch/series apply <id>` fails
                # resetting to HEAD

                print(
                    f"{bcolors.OKCYAN}git exit code: {bcolors.FAIL}{exit_code}{bcolors.ENDC}"
                )
                unmerged.append(i)

            else:
                if output.strip().endswith(already_applied_warning):
                    print(
                        f"{bcolors.WARNING}No changes -- already applied {bcolors.ENDC}\n"
                    )
                    already_applied.append(i)
                else:
                    print(f"{bcolors.OKCYAN}{type_} applied{bcolors.ENDC}\n")
                merged.append(i)

            print(f"{bcolors.FAIL}resetting to HEAD: {bcolors.ENDC}")

            if os.path.exists(".git/rebase-apply"):
                run_cmd("git am --abort")
            run_cmd("git reset --hard master", debug=True)

        except KeyboardInterrupt as ke:
            break
        except Exception as e:
            print(e)
            break


def get_patches(from_page=1, to_page=100):
    cmd = "git-pw patch list --page {0} -f csv --state 'new'"
    patches = []
    for i in range(from_page, to_page):
        exit_code, output = run_cmd(cmd.format(i), debug=True)

        if exit_code:
            print(f"git-pw exited with exit code {exit_code}")
            # patches.extend(output.strip().split("\n"))
            break

        patches.extend(output.strip().split("\n"))
        # print(patches)
    return patches


def get_series(from_page=1, to_page=100):
    cmd = "git-pw series list --page {0} -f csv"
    series = []
    for i in range(from_page, to_page):
        exit_code, output = run_cmd(cmd.format(i), debug=True)

        if exit_code:
            print(f"git-pw exited with exit code {exit_code}")
            # series.extend(output.strip().split("\n"))
            break

        series.extend(output.strip().split("\n"))
    return series


def get_patches_for_series(list_, index, series_dict, patch_ids):
    for i in list_:
        print(f"running: git-pw series show {i} -f csv")
        ret, op = run_cmd(f"git-pw series show {i} -f csv")
        print("****", index, "****")
        if ret:
            print(f"exitted with {ret}: {op}")
        series_data = read_rows(op.strip().split("\n"))
        print(series_data[1])
        for j in series_data[11:]:
            patch_data = j[1].split()
            print(patch_data[0], patch_data[1])
            series_dict[i].append(patch_data[0])
            if patch_data[0] in patch_ids:
                patch_ids.remove(patch_data[0])


def get_individual_patches():
    """This function iterates over all of the series and all of the patches.
    All of the patches that do not belong to any series are dumped into a file.
    """
    # TODO: This function needs a refactor.

    file_loc = "/tmp/pwanalysis"
    if not os.path.exists(file_loc):
        os.mkdir(file_loc)

    series = [i for i in read_rows(get_series())]
    # print(series)
    series_dict = {i[0]: [] for i in series}

    patches = read_rows(get_patches())
    patch_ids = [i[0] for i in patches]
    # print(patch_ids)
    series_ids = [i for i in series_dict.keys()]

    get_patches_for_series(series_ids, 0, series_dict, patch_ids)
    print("Individual patches", len(patch_ids))
    print("series_dict", series_dict)

    write_json(file_loc + "/dict", series_dict)
    write_json(file_loc + "/patch_ids", {"patches": patch_ids})


if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="Initial Ci script for patchwork")
    parser.add_argument(
        "-c", "--colors", default=False, action="store_true", help="Enable colors"
    )

    parser.add_argument(
        "-t",
        "--type",
        type=str,
        default="series",
        choices=["patch", "series"],
        help="type: patch/series",
    )
    parser.add_argument(
        "-a", "--action", type=str, default="apply", help="action: list/apply"
    )
    parser.add_argument(
        "-o",
        "--output-location",
        type=str,
        default="/tmp/pw-results",
        help="location for the output files containing merged, umerged and unavailable patches/series.",
    )
    parser.add_argument(
        "-i",
        "--input-file",
        type=str,
        default="",
        help="input file: csv file or '-' for the standard input. If no file is specified\
this data will be pulled from patchwork instance.",
    )
    parser.add_argument(
        "-p",
        "--page-range",
        default="1-100",
        help="page range for patchwork in the format 'from_pageNo'-'to_pageNo' for example '1-100'",
    )

    parser.add_argument(
        "-u",
        "--get-individual-patches",
        default=False,
        action="store_true",
        help="""Get individual patches.
In this case the series data and the patches data is pulled and compared to
find out the individual patches that do not belong to any series.""",
    )
    args = parser.parse_args()
    print(args)

    csv_data = []
    if args.input_file == "-":

        # Get the csv data from stdin
        for line in sys.stdin:
            if not '"ID"' in line:
                print(line)
                csv_data.append(line.strip())

    elif os.path.exists(args.input_file):
        data = open(args.input_file).read().strip().split("\n")
        for line in data:
            if not '"ID"' in line:
                # print(line)
                csv_data.append(line.strip())

    # option that we will be operating upon, series or the patch
    # this is the command line argument to git-pw
    # for example "git-pw patch apply 12345" or "git-pw series apply "12356"
    type_ = args.type

    series_data = read_rows(csv_data)
    output_files_loc = args.output_location
    if not os.path.exists(output_files_loc):
        os.mkdir(output_files_loc)

    if args.get_individual_patches:
        print("getting individual patches")
        get_individual_patches()
        sys.exit(0)

    colors = args.colors

    class bcolors:
        if colors:
            HEADER = "\033[95m"
            OKBLUE = "\033[94m"
            OKCYAN = "\033[96m"
            OKGREEN = "\033[92m"
            WARNING = "\033[93m"
            FAIL = "\033[91m"
            ENDC = "\033[0m"
            BOLD = "\033[1m"
            UNDERLINE = "\033[4m"
        else:
            HEADER = ""
            OKBLUE = ""
            OKCYAN = ""
            OKGREEN = ""
            WARNING = ""
            FAIL = ""
            ENDC = ""
            BOLD = ""
            UNDERLINE = ""

    print(len(series_data))
    if args.action == "apply":
        if args.input_file == "":
            try:
                from_range, to_range = [int(i) for i in args.page_range.split("-")]
            except ValueError as ve:
                print("invalid page range")
                sys.exit(1)
            series_data = [i for i in read_rows(get_series(from_range, to_range + 1))]
        apply_(series_data)

    print(
        "total merged: {0}, total unmerged {1}, total unavailable{2}".format(
            len(merged), len(unmerged), len(unavailable)
        )
    )
    write_file(f"{output_files_loc}/merged.txt", merged)
    write_file(f"{output_files_loc}/unmerged.txt", unmerged)
    write_file(f"{output_files_loc}/unavailable.txt", unavailable)
    write_file(f"{output_files_loc}/already_applied.txt", already_applied)

  reply	other threads:[~2021-02-04 15:47 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-07  5:48 Siddhesh Poyarekar
2020-12-07  8:45 ` Florian Weimer
2020-12-07  9:30   ` Siddhesh Poyarekar
2020-12-07 16:15 ` DJ Delorie
2020-12-07 16:39   ` Siddhesh Poyarekar
2020-12-07 17:02     ` DJ Delorie
2020-12-07 18:11       ` Joseph Myers
2020-12-08  2:57         ` Siddhesh Poyarekar
2020-12-08  9:08           ` Andreas Schwab
2020-12-08 10:10             ` Siddhesh Poyarekar
2020-12-16 18:35               ` Girish Joshi
2020-12-16 18:49                 ` Siddhesh Poyarekar
2020-12-17 17:49                   ` Girish Joshi
2020-12-18  4:04                     ` Siddhesh Poyarekar
2020-12-19 13:25                       ` Girish Joshi
2020-12-22 15:13                         ` Girish Joshi
2021-01-06 20:26                           ` Girish Joshi
2021-02-04 15:47                             ` Girish Joshi [this message]
2021-02-12  5:25                               ` Siddhesh Poyarekar
2021-02-12  9:02                               ` Siddhesh Poyarekar
2021-02-12 13:04                                 ` Carlos O'Donell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CALkY8p97h9XP7d4pWw3bd1Fa7PoGBccs1QCg7d9aPqB6SrBxGQ@mail.gmail.com \
    --to=girish946@gmail.com \
    --cc=joseph@codesourcery.com \
    --cc=libc-alpha@sourceware.org \
    --cc=schwab@linux-m68k.org \
    --cc=siddhesh@gotplt.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).