I want to do a binary search on all the extensions that I have loaded to isolate the problem one.
Here's a solution that approaches this problem from a divide and conquer perspective. The basic idea is to prepare the input file a tiny bit, then recursively divide it in halves; each half is output as a sample command and then recurses on those halves. You would choose which of the sample commands to run based on the visual inspection that's required to determine success or failure of the command. You should only need to execute four of the commands in order to find the culprit.
Here's a bare-bones demonstration of the process, to get a better feeling for what's happening. The script recurses against 23 lines and prints each line in this format:
$key = sed -n $start, $end p file
The output is:
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
Each recursion is suffixed by "1" or "2" from the previous run. Follow "11" as being the first division of 1..23 into lines 1..12. From there, it's divided into "111" and "112", which are the division into lines 1..6 and lines 7..12 respectively. If the "11" command succeeded, you'd skip all of the subsequent "11.."-prefixed lines. If the "11" command failed, you'd focus on only the subsequent "11.."-prefixed lines. Rinse and repeat on each subdivided group of lines.
The script below uses the same underlying algorithm, but massages the output into the actual commands and sed
output.
#!/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
The script prepares the extensions output file a bit by prefixing each line with a space and the "--config " text so that we don't have to manipulate it every time we print it out. The temporary file is removed at the end.
The divide() function is defined and then called. The divide() function first computes (the floor of) the midpoint of the incoming range. It then prints the sample commands, based on using lines (start)..(n) and (n+1)..(end). The three arguments to printf
are the prefix, the output from sed
, and the suffix. We defined the prefix and suffix in the initial call to divide() -- they're just the text that sits on either side of the extensions bits. The sed
command prints the requested lines from the file then passes them through tr
to remove the newlines in order to make the output all one line. This is where the preparations helped a bit -- having a space prefix each line means that we can join the lines fairly simply.
In order to keep track of things more easily, you may want to filter the above script's output through nl
in order to give an identifier to each line. Track those identifiers against the output from the script below, also piped through nl
.
The following script is the one that produced the initial "barebones" output above.
#!/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
For completeness, here's the output of the final script. Note -- some of the lines are very long!
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"
To use the output to find the problematic extension, number the previous output (perhaps by piping it through nl
). We now have a list of 28 commands. Run command #1. Base your next step on these instructions:
- If #1 succeeds, run command #17. If #1 fails, run command #3.
- If #3 succeeds, run command #11. If #3 fails, run command #5.
- If #5 succeeds, run command #9. If #5 fails, run command #7.
- If #7 succeeds, the problem is with extension 3. If #7 fails, the problem is with extension 1 or 2.
- If #9 succeeds, the problem is with extension 6. If #9 fails, the problem is with extension 4 or 5.
- If #11 succeeds, run command #15. If #11 fails, run command #13.
- If #13 succeeds, the problem is with extension 9. If #13 fails, the problem is with extension 7 or 8.
- If #15 succeeds, the problem is with extension 12. If #15 fails, the problem is with extension 10 or 11.
- If #17 succeeds, run command #25. If #17 fails, run command #19.
- If #19 succeeds, run command #21. If #19 fails, run command #23.
- If #21 succeeds, the problem is with extension 15. If #21 fails, the problem is with extension 13 or 14.
- If #23 succeeds, the problem is with extension 18. If #23 fails, the problem is with extension 16 or 17.
- If #25 succeeds, the problem is with extension 22 or 23. If #25 fails, run command #27.
- If #27 succeeds, the problem is with extension 21. If #27 fails, the problem is with extension 19 or 20.
The problematic extensions are identified by their line number in the hg debugconfig
output file.
something(1, 3, 5)
supposed to look like?extensions.hgext.churn=,extensions.hgext.convert=,extensions.hgext.graphlog=
? – Stephen Kitt Jan 8 at 16:14