Skip to content

Commit

Permalink
src: build: Add --from-sha <SHA> option
Browse files Browse the repository at this point in the history
Add --from-sha <SHA> option that builds every commit from <SHA> to actual commit
Closes kworkflow#666

Signed-off-by: Marcelo Mendes Spessoto Junior <[email protected]>
  • Loading branch information
MarceloSpessoto committed May 31, 2024
1 parent 5c24d6b commit bf6d40b
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 19 deletions.
13 changes: 13 additions & 0 deletions documentation/man/features/kw-build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ SYNOPSIS
| *kw* (*b* | *build*) [(-c | \--clean)] [\--alert=(s | v | (sv | vs) | n)]
| *kw* (*b* | *build*) [(-f | \--full-cleanup)] [\--alert=(s | v | (sv | vs) | n)]
| *kw* (*b* | *build*) [\--cflags]
| *kw* (*b* | *build*) [\--from-sha <SHA>]
| *kw* (*b* | *build*) [\--verbose]
DESCRIPTION
Expand Down Expand Up @@ -102,6 +103,10 @@ OPTIONS
| **sv** or **vs** enables both.
| **n** (or any other option) disables notifications (this is the default).
\--from-sha:
Build every commit after <SHA> to branch head. Useful for testing if all patches in
patchset compile.

EXAMPLES
========
For these examples, we assume that the relevant fields in your configuration
Expand Down Expand Up @@ -159,3 +164,11 @@ If you want to reset the kernel tree to its default, `all config and script outp
If you want to use cflags::

kw b --cflags "-O3 -pipe -march=native"

If you want to build every commit after HEAD~2 to HEAD::

kw b --from-sha HEAD~2

If you want to build every commit after ee3b5 to HEAD::

kw b --from-sha ee3b5
9 changes: 9 additions & 0 deletions documentation/tutorials/buildlinux.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,12 @@ Well, that's it. kw will automatically infer the number of job slots for
compiling based on the number of cores of your machine (i.e. when running make
``-j<number>``, *<number>* is an integer that specifies the number of processes
that will run at the same time), and compilation will begin!

Compiling patchsets
-------------------
You may want to try compiling every patch in your patchset to test if everything is alright.
You can do this by using the "from-sha" flag::

kw build --from-sha SHA

This will compile every patch after the commit with given SHA to the branch HEAD.
24 changes: 12 additions & 12 deletions src/_kw
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,18 @@ _kw_build()
{
_arguments : \
'(--verbose)--verbose[enable verbose mode]' \
'(-i --info -c --clean -f --full-cleanup -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags)'{-i,--info}'[display kernel release name, version and number of modules to compile]' \
'(-c --clean -f --full-cleanup -i --info -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags)'{-c,--clean}'[remove files generated by the kernel build system]' \
'(-f --full-cleanup -c --clean -i --info -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags)'{-f,--full-cleanup}'[reset the kernel tree to its default option integrated into env]' \
'(-n --menu -i --info -c --clean -f --full-cleanup -d --doc --cflags)'{-n,--menu}'[invoke kernel menuconfig]' \
'(-d --doc -i --info -c --clean -f --full-cleanup -n --menu --cflags)'{-d,--doc}'[build the kernel-doc]' \
'(-i --info -c --clean -f --full-cleanup --cflags)--ccache[enable ccache during compilation tasks]' \
'(-w --warnings -i --info -c --clean -f --full-cleanup --cflags)'{-w,--warnings}'[enable compilation warnings]:log level:(1 2 3 12 13 23 123)' \
'(-S --cpu-scaling -i --info -c --clean -f --full-cleanup --cflags)'{-S,--cpu-scaling}'[set CPU usage]:scaling percentage: ' \
'(-s --save-log-to -i --info -c --clean -f --full-cleanup --cflags)'{-s,--save-log-to}'[save full compilation log with the enabled warnings to the specified path]:log path:_files' \
'(-i --info -c --clean -f --full-cleanup --cflags)--llvm[enable the usage of the LLVM toolchain]' \
'(-i --info -c --clean -f --full-cleanup -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags)--cflags[customize kernel compilation with specific flags]'

'(-i --info -c --clean -f --full-cleanup -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags --from-sha)'{-i,--info}'[display kernel release name, version and number of modules to compile]' \
'(-c --clean -f --full-cleanup -i --info -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags --from-sha)'{-c,--clean}'[remove files generated by the kernel build system]' \
'(-f --full-cleanup -c --clean -i --info -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags --from-sha)'{-f,--full-cleanup}'[reset the kernel tree to its default option integrated into env]' \
'(-n --menu -i --info -c --clean -f --full-cleanup -d --doc --cflags --from-sha)'{-n,--menu}'[invoke kernel menuconfig]' \
'(-d --doc -i --info -c --clean -f --full-cleanup -n --menu --cflags --from-sha)'{-d,--doc}'[build the kernel-doc]' \
'(-i --info -c --clean -f --full-cleanup --cflags --from-sha)--ccache[enable ccache during compilation tasks]' \
'(-w --warnings -i --info -c --clean -f --full-cleanup --cflags --from-sha)'{-w,--warnings}'[enable compilation warnings]:log level:(1 2 3 12 13 23 123)' \
'(-S --cpu-scaling -i --info -c --clean -f --full-cleanup --cflags --from-sha)'{-S,--cpu-scaling}'[set CPU usage]:scaling percentage: ' \
'(-s --save-log-to -i --info -c --clean -f --full-cleanup --cflags --from-sha)'{-s,--save-log-to}'[save full compilation log with the enabled warnings to the specified path]:log path:_files' \
'(-i --info -c --clean -f --full-cleanup --cflags --from-sha)--llvm[enable the usage of the LLVM toolchain]' \
'(-i --info -c --clean -f --full-cleanup -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags --from-sha)--cflags[customize kernel compilation with specific flags]' \
'(-i --info -c --clean -f --full-cleanup -n --menu -d --doc --ccache -w --warnings -S --cpu-scaling -s --save-log-to --llvm --cflags --from-sha)--from-sha[Compile all commits from given sha value to branch head]: :'
}

_kw_clear-cache()
Expand Down
2 changes: 1 addition & 1 deletion src/bash_autocomplete.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function _kw_autocomplete()
kw_options['init']='--arch --remote --target --force --template --verbose'

kw_options['build']='--help --info --menu --cpu-scaling --ccache --llvm --clean
--full-cleanup --verbose --doc --warnings --save-log-to --cflags'
--full-cleanup --verbose --doc --warnings --save-log-to --cflags --from-sha'

kw_options['b']="${kw_options['build']}"

Expand Down
73 changes: 71 additions & 2 deletions src/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ function build_kernel_main()
local clean
local output_kbuild_flag=''
local cflags
local from_sha_arg
local sha_base
local merge_base

parse_build_options "$@"

Expand All @@ -59,6 +62,7 @@ function build_kernel_main()
clean=${options_values['CLEAN']}
full_cleanup=${options_values['FULL_CLEANUP']}
cflags=${options_values['CFLAGS']}
from_sha_arg=${options_values['FROM_SHA_ARG']}

[[ -n "${options_values['VERBOSE']}" ]] && flag='VERBOSE'
flag=${flag:-'SILENT'}
Expand Down Expand Up @@ -124,6 +128,41 @@ function build_kernel_main()
return "$?"
fi

if [[ -n "$from_sha_arg" ]]; then
# Check if there is a rebase in process.
if [[ -d .git/rebase-merge ]]; then
warning 'ERROR: Abort the repository rebase before continuing with build from sha (use "git rebase --abort")!'
return 125 # ECANCELED
elif [[ -f .git/MERGE_HEAD ]]; then
warning 'ERROR: Abort the repository merge before continuing with build from sha (use "git rebase --abort")!'
return 125 # ECANCELED
elif [[ -f .git/BISECT_LOG ]]; then
warning 'ERROR: Stop the repository bisect before continuing with build from sha (use "git bisect reset")!'
return 125 # ECANCELED
elif [[ -d .git/rebase-apply ]]; then
printf 'ERROR: Abort the repository patch apply before continuing with build from sha (use "git am --abort")!'
return 125 # ECANCELED
fi

# Check if given SHA represents real commit
cmd_manager 'SILENT' "git cat-file -e ${from_sha_arg}^{commit} 2> /dev/null"
if [[ "$?" != 0 ]]; then
complain "ERROR: The given SHA (${from_sha_arg}) does not represent a valid commit sha."
return 22 # EINVAL
fi

# Check if given SHA is in working tree.
sha_base=$(git rev-parse --verify "$from_sha_arg")
merge_base=$(git merge-base "$from_sha_arg" HEAD)
if [[ "$sha_base" != "$merge_base" ]]; then
complain "ERROR: Given SHA (${from_sha_arg}) is invalid. Check if it is an ancestor of the branch head."
return 22 # EINVAL
fi

build_from_sha "$flag" "$from_sha_arg"
return "$?"
fi

command="make ${optimizations} ${llvm}ARCH=${platform_ops}${warnings}"

if [[ -n "$cflags" ]]; then
Expand Down Expand Up @@ -247,9 +286,33 @@ function full_cleanup()
cmd_manager "$flag" "$cmd"
}

# This functions uses iteractive 'git rebase' with '--exec' flag under the hood
# to apply a 'kw build' over each commit from SHA to branch head.
#
# @flag How to display a command, see `src/lib/kwlib.sh` function `cmd_manager`.
# @sha The SHA from the first commit to be compiled until the branch head.
#
# Return:
# 0 if successfully compiled patchset, 125 (ECANCELED) otherwise.
function build_from_sha()
{
local flag="$1"
local sha="$2"
local cmd

flag=${flag:-'SILENT'}
cmd="git rebase ${sha} --exec 'kw build'"
cmd_manager "$flag" "$cmd"

if [[ "$?" != 0 ]]; then
complain "kw build failed during the compilation of a patch! Check the rebase in progress for more information."
return 125 #ECANCELED
fi
}

function parse_build_options()
{
local long_options='help,info,menu,doc,ccache,cpu-scaling:,warnings::,save-log-to:,llvm,clean,full-cleanup,verbose,cflags:'
local long_options='help,info,menu,doc,ccache,cpu-scaling:,warnings::,save-log-to:,llvm,clean,full-cleanup,verbose,cflags:,from-sha:'
local short_options='h,i,n,d,S:,w::,s:,c,f'
local doc_type
local file_name_size
Expand Down Expand Up @@ -279,6 +342,7 @@ function parse_build_options()
options_values['FULL_CLEANUP']=''
options_values['VERBOSE']=''
options_values['CFLAGS']="${build_config[cflags]}"
options_values['FROM_SHA_ARG']=''

# Check llvm option
if [[ ${options_values['USE_LLVM_TOOLCHAIN']} =~ 'yes' ]]; then
Expand Down Expand Up @@ -362,6 +426,10 @@ function parse_build_options()
options_values['LOG_PATH']="$2"
shift 2
;;
--from-sha)
options_values['FROM_SHA_ARG']="$2"
shift 2
;;
--)
shift
;;
Expand Down Expand Up @@ -394,7 +462,8 @@ function build_help()
' build (-c | --clean) - Clean option integrated into env' \
' build (-f | --full-cleanup) - Reset the kernel tree to its default option integrated into env' \
' build (--cflags) - Customize kernel compilation with specific flags' \
' build (--verbose) - Show a detailed output'
' build (--verbose) - Show a detailed output' \
' build (--from-sha <SHA>) - Build all commits from <SHA> to actual commit'
}

# Every time build.sh is loaded its proper configuration has to be loaded as well
Expand Down
116 changes: 116 additions & 0 deletions tests/unit/build_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,122 @@ function test_kernel_build_cpu_scaling_llvm_warning_sava_log_to()
compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha()
{
local expected_result
local output
local sha='HEAD^'

mk_fake_git

output=$(build_kernel_main 'TEST_MODE' --from-sha ${sha})
declare -a expected_result=(
"git rebase HEAD^ --exec 'kw build'"
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha_nonexisting_sha()
{
local expected_result
local output
local sha='fakesha'

mk_fake_git

output=$(build_kernel_main 'TEST_MODE' --from-sha ${sha})
declare -a expected_result=(
"ERROR: The given SHA (${sha}) does not represent a valid commit sha."
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha_sha_not_ancestor()
{
local expected_result
local output

mk_fake_git
mk_git_branch 'branch'

output=$(build_kernel_main 'TEST_MODE' --from-sha branch)
declare -a expected_result=(
'ERROR: Given SHA (branch) is invalid. Check if it is an ancestor of the branch head.'
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha_pending_rebase()
{
local expected_result
local output
local sha='HEAD^'

mk_fake_git
mkdir '.git/rebase-merge'

output=$(build_kernel_main 'TEST_MODE' --from-sha ${sha})
declare -a expected_result=(
'ERROR: Abort the repository rebase before continuing with build from sha (use "git rebase --abort")!'
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha_pending_merge()
{
local expected_result
local output
local sha='HEAD^'

mk_fake_git
touch '.git/MERGE_HEAD'

output=$(build_kernel_main 'TEST_MODE' --from-sha ${sha})
declare -a expected_result=(
'ERROR: Abort the repository merge before continuing with build from sha (use "git rebase --abort")!'
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha_pending_bisect()
{
local expected_result
local output
local sha='HEAD^'

mk_fake_git
touch '.git/BISECT_LOG'

output=$(build_kernel_main 'TEST_MODE' --from-sha ${sha})
declare -a expected_result=(
'ERROR: Stop the repository bisect before continuing with build from sha (use "git bisect reset")!'
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_from_sha_pending_apply()
{
local expected_result
local output
local sha='HEAD^'

mk_fake_git
mkdir '.git/rebase-apply'

output=$(build_kernel_main 'TEST_MODE' --from-sha ${sha})
declare -a expected_result=(
'ERROR: Abort the repository patch apply before continuing with build from sha (use "git am --abort")!'
)

compare_command_sequence '' "($LINENO)" 'expected_result' "$output"
}

function test_kernel_build_inside_an_env()
{
local output
Expand Down
8 changes: 4 additions & 4 deletions tests/unit/lib/kw_include_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ function oneTimeSetUp()
touch "${test_files[@]}"

# the next files will be checked for name collisions
printf "%s\n" "function test1(){ printf '%s\n' 'output of test1';}" > \
"$SHUNIT_TMPDIR/include_test_similar_path.sh"
printf "%s\n" "function test1(){ printf '%s\n' 'output of test1';}" > "\
$SHUNIT_TMPDIR/include_test_similar_path.sh"

mkdir "$SHUNIT_TMPDIR/include_test"

printf "%s\n" "function test2(){ printf '%s\n' 'output of test2';}" > \
"$SHUNIT_TMPDIR/include_test/similar_path.sh"
printf "%s\n" "function test2(){ printf '%s\n' 'output of test2';}" > "\
$SHUNIT_TMPDIR/include_test/similar_path.sh"
}

function oneTimeTearDown()
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,21 @@ function mk_fake_git()
git commit --allow-empty -q -m 'Third commit'
}

# Create a new git branch for current local repository and return to master branch afterwards.
#
# @branch_name The name of the new branch to be created.
function mk_git_branch()
{
local branch_name="$1"

git checkout --quiet HEAD^
git checkout --quiet -b "$branch_name"
touch branch_file
git add branch_file
git commit --message "create_branch" --quiet
git checkout --quiet master
}

function mk_fake_kw_folder()
{
local target_folder="$1"
Expand Down

0 comments on commit bf6d40b

Please sign in to comment.