The branch main has been updated by emaste:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=48f3fcabea807b243aa73cacbd0cb1d32793b003

commit 48f3fcabea807b243aa73cacbd0cb1d32793b003
Author:     Ed Maste <ema...@freebsd.org>
AuthorDate: 2024-04-16 17:41:27 +0000
Commit:     Ed Maste <ema...@freebsd.org>
CommitDate: 2024-11-15 20:09:53 +0000

    mfc-candidates: Convert to Lua
    
    d51c59002367 added a Lua script to process the lists of candidate and
    completed MFC commits to address sorting issues in the original shell
    implementation.
    
    Instead of having a mix of shell and Lua, just implement the entire
    tool in Lua.  This is more maintainable and gives a reasonable
    improvement in performace.
    
    Reviewed by:    imp
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D47416
---
 tools/tools/git/candidatematch.lua |  74 -------------
 tools/tools/git/mfc-candidates.lua | 218 +++++++++++++++++++++++++++++++++++++
 tools/tools/git/mfc-candidates.sh  | 138 +----------------------
 3 files changed, 220 insertions(+), 210 deletions(-)

diff --git a/tools/tools/git/candidatematch.lua 
b/tools/tools/git/candidatematch.lua
deleted file mode 100755
index 481c1f38fea1..000000000000
--- a/tools/tools/git/candidatematch.lua
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/libexec/flua
-
--- MFC candidate script utility - $0 from-file to-file
---
--- from-file specifies hashes that exist only in the "MFC from" branch and
--- to-file specifies the original hashes of commits already merged to the
--- "MFC to" branch.
-
--- SPDX-License-Identifier: BSD-2-Clause
--- Copyright 2024 The FreeBSD Foundation
-
--- Read a file and return its content as a table
-local function read_file(filename)
-       local file = assert(io.open(filename, "r"))
-       local content = {}
-       for line in file:lines() do
-               table.insert(content, line)
-       end
-       file:close()
-       return content
-end
-
--- Remove hashes from 'set1' list that are present in 'set2' list
-local function set_difference(set1, set2)
-       local set2_values = {}
-       for _, value in ipairs(set2) do
-               set2_values[value] = true
-       end
-
-       local result = {}
-       for _, value in ipairs(set1) do
-               if not set2_values[value] then
-                       table.insert(result, value)
-               end
-       end
-       return result
-end
-
--- Execute a command and print to stdout
-local function exec_command(command)
-       local handle = io.popen(command)
-       local output = handle:read("a")
-       handle:close()
-       io.write(output)
-end
-
--- Main function
-local function main()
-       local from_file = arg[1]
-       local to_file = arg[2]
-       local exclude_file = arg[3]
-
-       if not from_file or not to_file then
-               print("Usage: flua $0 from-file to-file")
-               return
-       end
-
-       local from_hashes = read_file(from_file)
-       local to_hashes = read_file(to_file)
-
-       local result_hashes = set_difference(from_hashes, to_hashes)
-
-       if exclude_file then
-               exclude_hashes = read_file(exclude_file)
-               result_hashes = set_difference(result_hashes, exclude_hashes)
-       end
-
-       -- Print the result
-       for _, hash in ipairs(result_hashes) do
-               exec_command("git show --pretty='%h %s' --no-patch " .. hash)
-       end
-end
-
-main()
diff --git a/tools/tools/git/mfc-candidates.lua 
b/tools/tools/git/mfc-candidates.lua
new file mode 100755
index 000000000000..a8ac89bde327
--- /dev/null
+++ b/tools/tools/git/mfc-candidates.lua
@@ -0,0 +1,218 @@
+#!/usr/libexec/flua
+
+-- SPDX-License-Identifier: BSD-2-Clause
+-- Copyright 2024 The FreeBSD Foundation
+
+-- MFC candidate search utility.  Identify hashes that exist only in the
+-- "MFC from" branch and do not have a corresponding "cherry picked from"
+-- commit in the "MFC to" branch.
+
+-- Execute a command and return its output.  A final newline is stripped,
+-- similar to sh.
+local function exec_command(command)
+       local handle = assert(io.popen(command))
+       local output = handle:read("a")
+       handle:close()
+       if output:sub(-1) == "\n" then
+               return output:sub(1, -2)
+       end
+       return output
+end
+
+-- Return a table of cherry-pick (MFC) candidates.
+local function read_from(from_branch, to_branch, author, dirspec)
+       local command = "git rev-list --first-parent --reverse "
+       command = command .. to_branch .. ".." .. from_branch
+       if #author > 0 then
+               command = command .. " --committer \\<" .. author .. "@"
+       end
+       if dirspec then
+               command = command .. " " .. dirspec
+       end
+       if verbose > 1 then
+               print("Obtaining MFC-from commits using command:")
+               print(command)
+       end
+       local handle = assert(io.popen(command))
+       local content = {}
+       for line in handle:lines() do
+               table.insert(content, line)
+       end
+       handle:close()
+       return content
+end
+
+-- Return a table of original hashes of changes that have already been
+-- cherry-picked (MFC'd).
+local function read_to(from_branch, to_branch, dirspec)
+       local command = "git log " .. from_branch .. ".." .. to_branch
+       command = command .. " --grep 'cherry picked from'"
+       if dirspec then
+               command = command .. " " .. dirspec
+       end
+       if verbose > 1 then
+               print("Obtaining MFC-to commits using command:")
+               print(command)
+       end
+       local handle = assert(io.popen(command))
+       local content = {}
+       for line in handle:lines() do
+               local hash = line:match("%(cherry picked from commit 
([0-9a-f]+)%)")
+               if hash then
+                       table.insert(content, hash)
+               end
+       end
+       handle:close()
+       return content
+end
+
+-- Read a commit exclude file and return its content as a table.  Comments
+-- starting with # and text after a hash is ignored.
+local function read_exclude(filename)
+       local file = assert(io.open(filename, "r"))
+       local content = {}
+       for line in file:lines() do
+               local hash = line:match("^%x+")
+               if hash then
+                       -- Hashes are 40 chars; if less, expand short hash.
+                       if #hash < 40 then
+                               hash = exec_command(
+                                   "git show --pretty=%H --no-patch " .. hash)
+                       end
+                       table.insert(content, hash)
+               end
+       end
+       file:close()
+       return content
+end
+
+--- Remove hashes from 'set1' list that are present in 'set2' list
+local function set_difference(set1, set2)
+       local set2_values = {}
+       for _, value in ipairs(set2) do
+               set2_values[value] = true
+       end
+
+       local result = {}
+       for _, value in ipairs(set1) do
+               if not set2_values[value] then
+                       table.insert(result, value)
+               end
+       end
+       return result
+end
+
+-- Global state
+verbose = 0
+
+local function params(from_branch, to_branch, author)
+       print("from:             " .. from_branch)
+       print("to:               " .. to_branch)
+       if #author > 0 then
+               print("author/committer: " .. author)
+       else
+               print("author/committer: <all>")
+       end
+end
+
+local function usage(from_branch, to_branch, author)
+       local script_name = arg[0]:match("([^/]+)$")
+       print(script_name .. " [-ah] [-f from_branch] [-t to_branch] [-u user] 
[-X exclude_file] [path ...]")
+       print()
+       params(from_branch, to_branch, author)
+end
+
+-- Main function
+local function main()
+       local from_branch = "freebsd/main"
+       local to_branch = ""
+       local author = os.getenv("USER") or ""
+       local dirspec = nil
+
+       local url = exec_command("git remote get-url freebsd")
+       local freebsd_repo = string.match(url, "[^/]+$")
+       freebsd_repo = string.gsub(freebsd_repo, ".git$", "")
+       if freebsd_repo == "ports" or freebsd_repo == "freebsd-ports" then
+               local year = os.date("%Y")
+               local month = os.date("%m")
+               local qtr = math.ceil(month / 3)
+               to_branch = "freebsd/" .. year .. "Q" .. qtr
+       elseif freebsd_repo == "src" or freebsd_repo == "freebsd-src" then
+               to_branch = "freebsd/stable/14"
+               -- If pwd is a stable or release branch tree, default to it.
+               local cur_branch = exec_command("git symbolic-ref --short HEAD")
+               if string.match(cur_branch, "^stable/") then
+                       to_branch = cur_branch
+               elseif string.match(cur_branch, "^releng/") then
+                       to_branch = cur_branch
+                       local major = string.match(cur_branch, "%d+")
+                       from_branch = "freebsd/stable/" .. major
+               end
+       else
+               print("pwd is not under a ports or src repository.")
+               return
+       end
+
+       local do_help = false
+       local exclude_file = nil
+       local i = 1
+       while i <= #arg and arg[i] do
+               local opt = arg[i]
+               if opt == "-a" then
+                       author = ""
+               elseif opt == "-f" then
+                       from_branch = arg[i + 1]
+                       i = i + 1
+               elseif opt == "-h" then
+                       do_help = true
+                       i = i + 1
+               elseif opt == "-t" then
+                       to_branch = arg[i + 1]
+                       i = i + 1
+               elseif opt == "-u" then
+                       author = arg[i + 1]
+                       i = i + 1
+               elseif opt == "-v" then
+                       verbose = verbose + 1
+               elseif opt == "-X" then
+                       exclude_file = arg[i + 1]
+                       print ("-X not working")
+                       i = i + 1
+               else
+                       break
+               end
+               i = i + 1
+       end
+
+       if do_help then
+               usage(from_branch, to_branch, author)
+               return
+       end
+
+       if arg[i] then
+               dirspec = arg[i]
+               --print("dirspec = " .. dirspec)
+               -- XXX handle multiple dirspecs?
+       end
+
+       if verbose > 0 then
+               params(from_branch, to_branch, author)
+       end
+
+       local from_hashes = read_from(from_branch, to_branch, author, dirspec)
+       local to_hashes = read_to(from_branch, to_branch, dirspec)
+
+       local result_hashes = set_difference(from_hashes, to_hashes)
+
+       if exclude_file then
+               exclude_hashes = read_exclude(exclude_file)
+               result_hashes = set_difference(result_hashes, exclude_hashes)
+       end
+
+       -- Print the result
+       for _, hash in ipairs(result_hashes) do
+               print(exec_command("git show --pretty='%h %s' --no-patch " .. 
hash))
+       end
+end
+
+main()
diff --git a/tools/tools/git/mfc-candidates.sh 
b/tools/tools/git/mfc-candidates.sh
index 7af4d29df67e..53fad909c91f 100644
--- a/tools/tools/git/mfc-candidates.sh
+++ b/tools/tools/git/mfc-candidates.sh
@@ -29,139 +29,5 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 
-from_branch=freebsd/main
-author="${USER}"
-
-# Get the FreeBSD repository
-repo=$(basename "$(git remote get-url freebsd 2>/dev/null)" .git 2>/dev/null)
-
-if [ "${repo}" = "ports" -o "${repo}" = "freebsd-ports" ]; then
-       year=$(date '+%Y')
-       month=$(date '+%m')
-       qtr=$(((month-1) / 3 + 1))
-       to_branch="freebsd/${year}Q${qtr}"
-elif [ "${repo}" = "src" -o "${repo}" = "freebsd-src" ]; then
-       to_branch=freebsd/stable/14
-       # If pwd is a stable or release branch tree, default to it.
-       cur_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
-       case $cur_branch in
-       stable/*)
-               to_branch=$cur_branch
-               ;;
-       releng/*)
-               to_branch=$cur_branch
-               major=${cur_branch#releng/}
-               major=${major%.*}
-               from_branch=freebsd/stable/$major
-       esac
-else
-       echo "pwd is not under a ports or src repository."
-       exit 0
-fi
-
-params()
-{
-       echo "from:             $from_branch"
-       echo "to:               $to_branch"
-       if [ -n "$author" ]; then
-               echo "author/committer: $author"
-       else
-               echo "author/committer: <all>"
-       fi
-}
-
-usage()
-{
-       echo "usage: $(basename $0) [-ah] [-f from_branch] [-t to_branch] [-u 
user] [-X exclude_file] [path ...]"
-       echo
-       params
-       exit 0
-}
-
-while getopts "af:ht:u:vX:" opt; do
-       case $opt in
-       a)
-               # All authors/committers
-               author=
-               ;;
-       f)
-               from_branch=$OPTARG
-               ;;
-       h)
-               usage
-               ;;
-       t)
-               to_branch=$OPTARG
-               ;;
-       u)
-               author=$OPTARG
-               ;;
-       v)
-               verbose=1
-               ;;
-       X)
-               if [ ! -r "$OPTARG" ]; then
-                       echo "Exclude file $OPTARG not readable" >&2
-                       exit 1
-               fi
-               exclude_file=$OPTARG
-               ;;
-       esac
-done
-shift $(($OPTIND - 1))
-
-if [ $verbose ]; then
-       params
-       echo
-fi
-
-authorarg=
-if [ -n "$author" ]; then
-       # Match user ID in the email portion of author or committer
-       authorarg="--committer <${author}@"
-fi
-
-# Commits in from_branch after branch point
-commits_from()
-{
-       git rev-list --first-parent --reverse $authorarg 
$to_branch..$from_branch "$@"
-}
-
-# "cherry picked from" hashes from commits in to_branch after branch point
-commits_to()
-{
-       git log $from_branch..$to_branch --grep 'cherry picked from' "$@" |\
-           sed -E -n 's/^[[:space:]]*\(cherry picked from commit 
([0-9a-f]+)\)[[:space:]]*$/\1/p'
-}
-
-# Turn a list of short hashes (and optional descriptions) into a list of full
-# hashes.
-canonicalize_hashes()
-{
-       while read hash rest; do
-               case "${hash}" in
-               "#"*)   continue ;;
-               esac
-               if ! git show --pretty=%H --no-patch $hash; then
-                       echo "error parsing hash list" >&2
-                       exit 1
-               fi
-       done | sort
-}
-
-workdir=$(mktemp -d /tmp/find-mfc.XXXXXXXXXX)
-from_list=$workdir/commits-from
-to_list=$workdir/commits-to
-
-if [ -n "$exclude_file" ]; then
-       exclude_list=$workdir/commits-exclude
-       canonicalize_hashes < $exclude_file > $exclude_list
-fi
-
-commits_from "$@" > $from_list
-commits_to "$@" > $to_list
-
-/usr/libexec/flua $(dirname $0)/candidatematch.lua \
-    $from_list $to_list $exclude_list
-
-rm -rf "$workdir"
+# Backwards compatibility wrapper
+/usr/libexec/flua $(dirname $0)/mfc-candidates.lua "$@"

Reply via email to