上下文:我正在尝试追踪 Mercurial 扩展错误。
Mercurial 具有扩展功能,可扩展 Mercurial 的基本功能。您可以根据需要选择加载任意数量的这些扩展。有时它们会互相干扰。
Evolve 扩展中的命令hg fold
未按预期工作。问题似乎出在加载的其他扩展之一上,因为仅加载 Evolve 扩展,该命令就可以正常工作。在刚刚加载 Evolve 的情况下,它看起来如下。
HGRCPATH=/dev/null hg fold --config extensions.hgext3rd.evolve= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
我想对我加载的所有扩展进行二分搜索以隔离有问题的扩展。我似乎拥有的列表(来自hg debugconfig
)如下。
extensions.hgext.churn=
extensions.hgext.color=
extensions.hgext.convert=
extensions.hgext.extdiff=
extensions.hgext.graphlog=
extensions.hgext.hgk=
extensions.hgext.journal=
extensions.hgext.keyword=
extensions.hgext.mq=
extensions.hgext.pager=
extensions.hgext.patchbomb=
extensions.hgext.purge=
extensions.hgext.rebase=
extensions.hgext.record=
extensions.hgext.schemes=
extensions.hgext.progress=
extensions.hgext.histedit=
extensions.hgext.shelve=
extensions.hgext.narrow=
extensions.hgext.show=
extensions.hgext.share=
extensions.hgext3rd.evolve=
extensions.hgext3rd.topic=
我想要一个命令,让我指定要按行号包含的这些扩展的列表。所以像
HGRCPATH=/dev/null hg fold something(1, 3, 5) --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
其中将包括文件第 1、3 和 5 行的扩展名。这应该输出到
HGRCPATH=/dev/null hg fold --config extensions.hgext.churn= --config extensions.hgext.convert= --config extensions.hgext.graphlog= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
使用命令行检查错误需要我通过查看hg log
.我可以使用 Mercurial 的 Python API 进行自动检查,但这将是一项巨大的工作,除非我有人告诉我如何做到这一点,而且对于如此简单的问题来说不值得。鉴于此,尽可能少地进行测试是有意义的。因此,二分查找。
由于该--config
选项是全局的,因此可以将其放在命令的末尾,如果这样可以使事情变得更简单。
答案1
这个功能怎么样?
hg_fold() {
local -a config
mapfile -t config < <(hg debugconfig)
local -a opts
for i in "$@"; do
opts+=( --config "${config[i-1]}" )
done
opts+=(
--exact
-r 2024:8679fc70eae8
-r 2021:8b3257871eac
-m "Fold"
)
echo HGRCPATH=/dev/null hg fold "${opts[@]}"
}
hg_fold 1 3 5
echo
如果看起来不错,请将其删除。
如果你想要更具互动性的东西,也许
hg_fold() {
local -a opts
select_options opts
opts+=(
--exact
-r 2024:8679fc70eae8
-r 2021:8b3257871eac
-m "Fold"
)
echo HGRCPATH=/dev/null hg fold "${opts[@]}"
}
select_options() {
local -n options=$1
local -a config
mapfile -t config < <(hg debugconfig)
local selecting=true
PS3="Select a debugconfig item: "
while $selecting; do
select item in "${config[@]}" Done; do
if [[ $item == "Done" ]]; then
selecting=false
break
elif [[ -n $item ]]; then
options+=( --config "$item" )
config[REPLY-1]="*$item" # mark it as selected
break
fi
done
done
}
hg_fold
答案2
我想对我加载的所有扩展进行二分搜索以隔离有问题的扩展。
这是从分而治之的角度解决此问题的解决方案。基本思想是稍微准备一下输入文件,然后递归地将其分成两半;每半部分作为示例命令输出,然后在这些半部分上递归。您可以根据确定命令成功或失败所需的目视检查来选择要运行的示例命令。您只需执行其中四个命令即可找到罪魁祸首。
这是该过程的简单演示,以便更好地了解正在发生的事情。该脚本递归 23 行并按以下格式打印每行:
$key = sed -n $start, $end p 文件
输出是:
11 = sed -n 1,12p file
12 = sed -n 13,23p file
111 = sed -n 1,6p file
112 = sed -n 7,12p file
1111 = sed -n 1,3p file
1112 = sed -n 4,6p file
11111 = sed -n 1,2p file
11112 = sed -n 3,3p file
11121 = sed -n 4,5p file
11122 = sed -n 6,6p file
1121 = sed -n 7,9p file
1122 = sed -n 10,12p file
11211 = sed -n 7,8p file
11212 = sed -n 9,9p file
11221 = sed -n 10,11p file
11222 = sed -n 12,12p file
121 = sed -n 13,18p file
122 = sed -n 19,23p file
1211 = sed -n 13,15p file
1212 = sed -n 16,18p file
12111 = sed -n 13,14p file
12112 = sed -n 15,15p file
12121 = sed -n 16,17p file
12122 = sed -n 18,18p file
1221 = sed -n 19,21p file
1222 = sed -n 22,23p file
12211 = sed -n 19,20p file
12212 = sed -n 21,21p file
每个递归都以上一次运行的“1”或“2”为后缀。按照“11”作为 1..23 到第 1..12 行的第一次划分。从那里开始,它被分为“111”和“112”,分别是第1..6行和第7..12行。如果“11”命令成功了, 你跳过所有后续以“11..”为前缀的行。如果“11”命令失败的,你会专注于仅有的随后的“11..”前缀行。冲洗并在每个细分组的线路上重复。
下面的脚本使用相同的底层算法,但将输出处理为实际的命令和sed
输出。
#!/bin/sh
# prepare the file a bit
file=./extensions-file
sed 's/^/ --config /' "$file" > "$file".prepared
# specifically a () subshell instead of {} grouping, to insulate "N" variable changes
divide() (
# args = prefix, start, end, suffix
# output: recursive breakout of:
# $prefix $(sed start .. N) $suffix
# $prefix $(sed N+1 .. end) $suffix
# N = (end-start)/2
n=$(( $2 + ($3-$2)/2 ))
printf '%s %s %s\n' "${1}" "$(sed -n $2,${n}p "$file".prepared | tr -d '\n')" "$4"
printf '%s %s %s\n' "${1}" "$(sed -n $((n+1)),${3}p "$file".prepared | tr -d '\n')" "$4"
if [ $((n - $2)) -gt 1 ]
then
divide "${1}" "$2" "$n" "$4"
fi
if [ $(( $3 - (n+1) )) -gt 1 ]
then
divide "${1}" "$((n+1))" "$3" "$4"
fi
)
divide "HGRCPATH=/dev/null hg fold" \
1 \
"$(wc -l < "$file".prepared)" \
"--exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m \"Fold\""
rm "$file".prepared
该脚本通过在每行前面添加一个空格和“--config”文本来准备扩展输出文件,这样我们就不必每次打印它时都对其进行操作。最后删除临时文件。
定义并调用divide() 函数。 divide() 函数首先计算输入范围的中点(下限)。然后,它基于使用行 (start)..(n) 和 (n+1)..(end) 打印示例命令。的三个参数printf
是前缀、输出sed
和后缀。我们在对divide()的初始调用中定义了前缀和后缀——它们只是位于扩展位两侧的文本。该sed
命令从文件中打印请求的行,然后传递它们tr
以删除换行符,以使输出全部为一行。这就是准备工作有点帮助的地方——每行都有一个空格前缀意味着我们可以相当简单地连接行。
为了更轻松地跟踪事情,您可能需要过滤上述脚本的输出,nl
以便为每一行提供标识符。根据下面脚本的输出(也通过管道传输)跟踪这些标识符nl
。
以下脚本产生了上面的初始“准系统”输出。
#!/bin/sh
# specifically a () subshell instead of {} grouping, to insulate "N" variable changes
divide() (
# args = prefix, start, end
# output: recursive breakout of:
# "$prefix"1 = start .. N
# "$prefix"2 = N+1 .. end
# N = (end-start)/2
n=$(( $2 + ($3-$2)/2 ))
printf '%s = sed -n %d,%dp file\n' "${1}1" "$2" "$n"
printf '%s = sed -n %d,%dp file\n' "${1}2" "$((n+1))" "$3"
if [ $((n - $2)) -gt 1 ]
then
divide "${1}1" "$2" "$n"
fi
if [ $(( $3 - (n+1) )) -gt 1 ]
then
divide "${1}2" "$((n+1))" "$3"
fi
)
divide 1 1 23
为了完整起见,这是最终脚本的输出。注意——有些行很长!
HGRCPATH=/dev/null hg fold --config extensions.hgext.churn= --config extensions.hgext.color= --config extensions.hgext.convert= --config extensions.hgext.extdiff= --config extensions.hgext.graphlog= --config extensions.hgext.hgk= --config extensions.hgext.journal= --config extensions.hgext.keyword= --config extensions.hgext.mq= --config extensions.hgext.pager= --config extensions.hgext.patchbomb= --config extensions.hgext.purge= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.rebase= --config extensions.hgext.record= --config extensions.hgext.schemes= --config extensions.hgext.progress= --config extensions.hgext.histedit= --config extensions.hgext.shelve= --config extensions.hgext.narrow= --config extensions.hgext.show= --config extensions.hgext.share= --config extensions.hgext3rd.evolve= --config extensions.hgext3rd.topic= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.churn= --config extensions.hgext.color= --config extensions.hgext.convert= --config extensions.hgext.extdiff= --config extensions.hgext.graphlog= --config extensions.hgext.hgk= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.journal= --config extensions.hgext.keyword= --config extensions.hgext.mq= --config extensions.hgext.pager= --config extensions.hgext.patchbomb= --config extensions.hgext.purge= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.churn= --config extensions.hgext.color= --config extensions.hgext.convert= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.extdiff= --config extensions.hgext.graphlog= --config extensions.hgext.hgk= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.churn= --config extensions.hgext.color= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.convert= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.extdiff= --config extensions.hgext.graphlog= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.hgk= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.journal= --config extensions.hgext.keyword= --config extensions.hgext.mq= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.pager= --config extensions.hgext.patchbomb= --config extensions.hgext.purge= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.journal= --config extensions.hgext.keyword= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.mq= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.pager= --config extensions.hgext.patchbomb= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.purge= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.rebase= --config extensions.hgext.record= --config extensions.hgext.schemes= --config extensions.hgext.progress= --config extensions.hgext.histedit= --config extensions.hgext.shelve= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.narrow= --config extensions.hgext.show= --config extensions.hgext.share= --config extensions.hgext3rd.evolve= --config extensions.hgext3rd.topic= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.rebase= --config extensions.hgext.record= --config extensions.hgext.schemes= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.progress= --config extensions.hgext.histedit= --config extensions.hgext.shelve= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.rebase= --config extensions.hgext.record= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.schemes= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.progress= --config extensions.hgext.histedit= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.shelve= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.narrow= --config extensions.hgext.show= --config extensions.hgext.share= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext3rd.evolve= --config extensions.hgext3rd.topic= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.narrow= --config extensions.hgext.show= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
HGRCPATH=/dev/null hg fold --config extensions.hgext.share= --exact -r 2024:8679fc70eae8 -r 2021:8b3257871eac -m "Fold"
要使用输出来查找有问题的扩展,请对先前的输出进行编号(可能通过将其通过管道传输nl
)。我们现在有 28 个命令的列表。运行命令#1。根据以下说明进行下一步:
- 如果 #1 成功,则运行命令 #17。如果#1 失败,则运行命令#3。
- 如果 #3 成功,则运行命令 #11。如果 #3 失败,则运行命令 #5。
- 如果 #5 成功,则运行命令 #9。如果 #5 失败,则运行命令 #7。
- 如果 #7 成功,则问题出在扩展 3 上。如果 #7 失败,则问题出在扩展 1 或 2 上。
- 如果 #9 成功,则问题出在分机 6 上。如果 #9 失败,则问题出在分机 4 或 5 上。
- 如果 #11 成功,则运行命令 #15。如果 #11 失败,则运行命令 #13。
- 如果 #13 成功,则问题出在分机 9 上。如果 #13 失败,则问题出在分机 7 或 8 上。
- 如果 #15 成功,则问题出在扩展 12 上。如果 #15 失败,则问题出在扩展 10 或 11 上。
- 如果 #17 成功,则运行命令 #25。如果 #17 失败,则运行命令 #19。
- 如果 #19 成功,则运行命令 #21。如果 #19 失败,请运行命令 #23。
- 如果 #21 成功,则问题出在分机 15 上。如果 #21 失败,则问题出在分机 13 或 14 上。
- 如果 #23 成功,则问题出在分机 18 上。如果 #23 失败,则问题出在分机 16 或 17 上。
- 如果 #25 成功,则问题出在分机 22 或 23 上。如果 #25 失败,请运行命令 #27。
- 如果 #27 成功,则问题出在分机 21 上。如果 #27 失败,则问题出在分机 19 或 20 上。
有问题的扩展通过输出文件中的行号来识别hg debugconfig
。