tools: let `v gret` make an easily visible diff.png image after regressions, and upload it too, to make CI failures easier to diagnose

master
Delyan Angelov 2022-06-10 15:38:50 +03:00
parent fcaf529228
commit b27b6b2047
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
2 changed files with 54 additions and 82 deletions

View File

@ -21,10 +21,13 @@ jobs:
uses: actions/checkout@v2
- name: Build local v
run: make -j4
run: make
- uses: openrndr/setup-opengl@v1.1
- name: Setup dependencies
run: |
# imagemagick : convert, mogrify
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
# openimageio-tools : idiff
# libxcursor-dev libxi-dev : V gfx deps
@ -33,14 +36,9 @@ jobs:
sudo apt-get update
sudo apt-get install imagemagick openimageio-tools mesa-common-dev libxcursor-dev libxi-dev freeglut3-dev
wget https://raw.githubusercontent.com/tremby/imgur.sh/c98345d/imgur.sh
git clone https://github.com/Larpon/gg-regression-images gg-regression-images
chmod +x ./imgur.sh
- uses: openrndr/setup-opengl@v1.1
- uses: actions/checkout@v2
with:
repository: Larpon/gg-regression-images
path: gg-regression-images
- name: Sample and compare
id: compare
continue-on-error: true
@ -52,4 +50,5 @@ jobs:
if: steps.compare.outcome != 'success'
run: |
./imgur.sh /tmp/fail.png
./imgur.sh /tmp/diff.png
exit 1

View File

@ -37,7 +37,7 @@ import flag
import toml
const (
tool_name = os.file_name(os.executable())
tool_name = 'vgret'
tool_version = '0.0.1'
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
@ -57,7 +57,7 @@ Examples:
const (
supported_hosts = ['linux']
// External tool executables
v_exe = vexe()
v_exe = os.getenv('VEXE')
idiff_exe = os.find_abs_path_of_executable('idiff') or { '' }
)
@ -105,11 +105,27 @@ mut:
config Config
}
fn (opt Options) verbose_execute(cmd string) os.Result {
opt.verbose_eprintln('Running `$cmd`')
return os.execute(cmd)
}
fn (opt Options) verbose_eprintln(msg string) {
if opt.verbose {
eprintln(msg)
}
}
fn main() {
if os.args.len == 1 {
println('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
if runtime_os !in supported_hosts {
eprintln('$tool_name is currently only supported on $supported_hosts hosts')
exit(1)
}
if os.args.len == 1 {
eprintln('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
exit(1)
}
mut fp := flag.new_flag_parser(os.args[1..])
fp.application(tool_name)
fp.version(tool_version)
@ -131,17 +147,17 @@ fn main() {
}
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
ensure_env(opt) or { panic(err) }
arg_paths := fp.finalize() or { panic(err) }
arg_paths := fp.finalize()?
if arg_paths.len == 0 {
println(fp.usage())
println('\nError missing arguments')
exit(1)
}
if !os.exists(tmp_dir) {
os.mkdir_all(tmp_dir)?
}
opt.config = new_config(opt.root_path, toml_conf)?
gen_in_path := arg_paths[0]
@ -154,13 +170,15 @@ fn main() {
all_paths_in_use := [path, gen_in_path, target_path]
for path_in_use in all_paths_in_use {
if !os.is_dir(path_in_use) {
panic('`$path_in_use` is not a directory')
eprintln('`$path_in_use` is not a directory')
exit(1)
}
}
if path == target_path || gen_in_path == target_path || gen_in_path == path {
panic('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
eprintln('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
exit(1)
}
compare_screenshots(opt, gen_in_path, target_path) or { panic(err) }
compare_screenshots(opt, gen_in_path, target_path)?
}
}
@ -184,21 +202,15 @@ fn generate_screenshots(mut opt Options, output_path string) ? {
rel_out_path = file
}
if opt.verbose {
eprintln('Compiling shaders (if needed) for `$file`')
}
sh_result := os.execute('${os.quoted_path(v_exe)} shader ${os.quoted_path(app_path)}')
opt.verbose_eprintln('Compiling shaders (if needed) for `$file`')
sh_result := opt.verbose_execute('${os.quoted_path(v_exe)} shader ${os.quoted_path(app_path)}')
if sh_result.exit_code != 0 {
if opt.verbose {
eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
}
opt.verbose_eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
continue
}
if !os.exists(dst_path) {
if opt.verbose {
eprintln('Creating output path `$dst_path`')
}
opt.verbose_eprintln('Creating output path `$dst_path`')
os.mkdir_all(dst_path)?
}
@ -221,18 +233,13 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
mut warns := map[string]string{}
for app_config in opt.config.apps {
screenshots := app_config.screenshots
if opt.verbose {
eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
}
opt.verbose_eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
for screenshot in screenshots {
relative_screenshot := screenshot.all_after(output_path + os.path_separator)
src := screenshot
target := os.join_path(target_path, relative_screenshot)
if opt.verbose {
eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
}
opt.verbose_eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
if app_config.compare.method == 'idiff' {
if idiff_exe == '' {
@ -242,14 +249,9 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
'.diff.tif')
flags := app_config.compare.flags.join(' ')
diff_cmd := '${os.quoted_path(idiff_exe)} $flags -abs -od -o ${os.quoted_path(diff_file)} -abs ${os.quoted_path(src)} ${os.quoted_path(target)}'
if opt.verbose {
eprintln('Running: $diff_cmd')
}
result := os.execute(diff_cmd)
if opt.verbose && result.exit_code == 0 {
eprintln('OUTPUT: \n$result.output')
result := opt.verbose_execute(diff_cmd)
if result.exit_code == 0 {
opt.verbose_eprintln('OUTPUT: \n$result.output')
}
if result.exit_code != 0 {
eprintln('OUTPUT: \n$result.output')
@ -278,15 +280,19 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
}
first := fails.keys()[0]
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
os.cp(first, fail_copy) or { panic(err) }
os.cp(first, fail_copy)?
eprintln('First failed file `$first` is copied to `$fail_copy`')
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
'.diff.tif')
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
if os.is_file(diff_file) {
os.cp(diff_file, diff_copy) or { panic(err) }
os.cp(diff_file, diff_copy)?
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
eprintln('Removing alpha channel from $diff_copy ...')
final_fail_result_file := os.join_path(os.temp_dir(), 'diff.png')
opt.verbose_execute('convert ${os.quoted_path(diff_copy)} -alpha off ${os.quoted_path(final_fail_result_file)}')
eprintln('Final diff file: `$final_fail_result_file`')
}
exit(1)
}
@ -295,25 +301,16 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
fn take_screenshots(opt Options, app AppConfig) ?[]string {
out_path := app.screenshots_path
if !opt.compare_only {
if opt.verbose {
eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
}
opt.verbose_eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
if app.capture.method == 'gg_record' {
for k, v in app.capture.env {
rv := v.replace('\$OUT_PATH', out_path)
if opt.verbose {
eprintln('Setting ENV `$k` = $rv ...')
}
opt.verbose_eprintln('Setting ENV `$k` = $rv ...')
os.setenv('$k', rv, true)
}
mut flags := app.capture.flags.join(' ')
v_cmd := '${os.quoted_path(v_exe)} $flags -d gg_record run ${os.quoted_path(app.abs_path)}'
if opt.verbose {
eprintln('Running `$v_cmd`')
}
result := os.execute('$v_cmd')
result := opt.verbose_execute('${os.quoted_path(v_exe)} $flags -d gg_record run ${os.quoted_path(app.abs_path)}')
if result.exit_code != 0 {
return error('Failed taking screenshot of `$app.abs_path`:\n$result.output')
}
@ -329,30 +326,6 @@ fn take_screenshots(opt Options, app AppConfig) ?[]string {
return screenshots
}
// ensure_env returns nothing if everything is okay.
fn ensure_env(opt Options) ? {
if !os.exists(tmp_dir) {
os.mkdir_all(tmp_dir)?
}
if runtime_os !in supported_hosts {
return error('$tool_name is currently only supported on $supported_hosts hosts')
}
}
// vexe returns the absolute path to the V compiler.
fn vexe() string {
mut exe := os.getenv('VEXE')
if os.is_executable(exe) {
return os.real_path(exe)
}
possible_symlink := os.find_abs_path_of_executable('v') or { '' }
if os.is_executable(possible_symlink) {
exe = os.real_path(possible_symlink)
}
return exe
}
fn new_config(root_path string, toml_config string) ?Config {
doc := if os.is_file(toml_config) {
toml.parse_file(toml_config)?