tools: let `v gret` make an easily visible diff.png image after regressions, and upload it too, to make CI failures easier to diagnose
parent
fcaf529228
commit
b27b6b2047
|
@ -21,10 +21,13 @@ jobs:
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Build local v
|
- name: Build local v
|
||||||
run: make -j4
|
run: make
|
||||||
|
|
||||||
|
- uses: openrndr/setup-opengl@v1.1
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: Setup dependencies
|
||||||
run: |
|
run: |
|
||||||
|
# imagemagick : convert, mogrify
|
||||||
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
|
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
|
||||||
# openimageio-tools : idiff
|
# openimageio-tools : idiff
|
||||||
# libxcursor-dev libxi-dev : V gfx deps
|
# libxcursor-dev libxi-dev : V gfx deps
|
||||||
|
@ -33,14 +36,9 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install imagemagick openimageio-tools mesa-common-dev libxcursor-dev libxi-dev freeglut3-dev
|
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
|
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
|
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
|
- name: Sample and compare
|
||||||
id: compare
|
id: compare
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
@ -52,4 +50,5 @@ jobs:
|
||||||
if: steps.compare.outcome != 'success'
|
if: steps.compare.outcome != 'success'
|
||||||
run: |
|
run: |
|
||||||
./imgur.sh /tmp/fail.png
|
./imgur.sh /tmp/fail.png
|
||||||
|
./imgur.sh /tmp/diff.png
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -37,7 +37,7 @@ import flag
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tool_name = os.file_name(os.executable())
|
tool_name = 'vgret'
|
||||||
tool_version = '0.0.1'
|
tool_version = '0.0.1'
|
||||||
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
|
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ Examples:
|
||||||
const (
|
const (
|
||||||
supported_hosts = ['linux']
|
supported_hosts = ['linux']
|
||||||
// External tool executables
|
// External tool executables
|
||||||
v_exe = vexe()
|
v_exe = os.getenv('VEXE')
|
||||||
idiff_exe = os.find_abs_path_of_executable('idiff') or { '' }
|
idiff_exe = os.find_abs_path_of_executable('idiff') or { '' }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,11 +105,27 @@ mut:
|
||||||
config Config
|
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() {
|
fn main() {
|
||||||
if os.args.len == 1 {
|
if runtime_os !in supported_hosts {
|
||||||
println('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
|
eprintln('$tool_name is currently only supported on $supported_hosts hosts')
|
||||||
exit(1)
|
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..])
|
mut fp := flag.new_flag_parser(os.args[1..])
|
||||||
fp.application(tool_name)
|
fp.application(tool_name)
|
||||||
fp.version(tool_version)
|
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')
|
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
|
||||||
|
arg_paths := fp.finalize()?
|
||||||
ensure_env(opt) or { panic(err) }
|
|
||||||
|
|
||||||
arg_paths := fp.finalize() or { panic(err) }
|
|
||||||
|
|
||||||
if arg_paths.len == 0 {
|
if arg_paths.len == 0 {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
println('\nError missing arguments')
|
println('\nError missing arguments')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !os.exists(tmp_dir) {
|
||||||
|
os.mkdir_all(tmp_dir)?
|
||||||
|
}
|
||||||
|
|
||||||
opt.config = new_config(opt.root_path, toml_conf)?
|
opt.config = new_config(opt.root_path, toml_conf)?
|
||||||
|
|
||||||
gen_in_path := arg_paths[0]
|
gen_in_path := arg_paths[0]
|
||||||
|
@ -154,13 +170,15 @@ fn main() {
|
||||||
all_paths_in_use := [path, gen_in_path, target_path]
|
all_paths_in_use := [path, gen_in_path, target_path]
|
||||||
for path_in_use in all_paths_in_use {
|
for path_in_use in all_paths_in_use {
|
||||||
if !os.is_dir(path_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 {
|
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
|
rel_out_path = file
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Compiling shaders (if needed) for `$file`')
|
||||||
eprintln('Compiling shaders (if needed) for `$file`')
|
sh_result := opt.verbose_execute('${os.quoted_path(v_exe)} shader ${os.quoted_path(app_path)}')
|
||||||
}
|
|
||||||
sh_result := os.execute('${os.quoted_path(v_exe)} shader ${os.quoted_path(app_path)}')
|
|
||||||
if sh_result.exit_code != 0 {
|
if sh_result.exit_code != 0 {
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
|
||||||
eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !os.exists(dst_path) {
|
if !os.exists(dst_path) {
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Creating output path `$dst_path`')
|
||||||
eprintln('Creating output path `$dst_path`')
|
|
||||||
}
|
|
||||||
os.mkdir_all(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{}
|
mut warns := map[string]string{}
|
||||||
for app_config in opt.config.apps {
|
for app_config in opt.config.apps {
|
||||||
screenshots := app_config.screenshots
|
screenshots := app_config.screenshots
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
|
||||||
eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
|
|
||||||
}
|
|
||||||
for screenshot in screenshots {
|
for screenshot in screenshots {
|
||||||
relative_screenshot := screenshot.all_after(output_path + os.path_separator)
|
relative_screenshot := screenshot.all_after(output_path + os.path_separator)
|
||||||
|
|
||||||
src := screenshot
|
src := screenshot
|
||||||
target := os.join_path(target_path, relative_screenshot)
|
target := os.join_path(target_path, relative_screenshot)
|
||||||
|
opt.verbose_eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
|
||||||
if opt.verbose {
|
|
||||||
eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
|
|
||||||
}
|
|
||||||
|
|
||||||
if app_config.compare.method == 'idiff' {
|
if app_config.compare.method == 'idiff' {
|
||||||
if idiff_exe == '' {
|
if idiff_exe == '' {
|
||||||
|
@ -242,14 +249,9 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||||
'.diff.tif')
|
'.diff.tif')
|
||||||
flags := app_config.compare.flags.join(' ')
|
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)}'
|
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 {
|
result := opt.verbose_execute(diff_cmd)
|
||||||
eprintln('Running: $diff_cmd')
|
if result.exit_code == 0 {
|
||||||
}
|
opt.verbose_eprintln('OUTPUT: \n$result.output')
|
||||||
|
|
||||||
result := os.execute(diff_cmd)
|
|
||||||
|
|
||||||
if opt.verbose && result.exit_code == 0 {
|
|
||||||
eprintln('OUTPUT: \n$result.output')
|
|
||||||
}
|
}
|
||||||
if result.exit_code != 0 {
|
if result.exit_code != 0 {
|
||||||
eprintln('OUTPUT: \n$result.output')
|
eprintln('OUTPUT: \n$result.output')
|
||||||
|
@ -278,15 +280,19 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||||
}
|
}
|
||||||
first := fails.keys()[0]
|
first := fails.keys()[0]
|
||||||
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
|
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`')
|
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_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
|
||||||
'.diff.tif')
|
'.diff.tif')
|
||||||
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
||||||
if os.is_file(diff_file) {
|
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('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)
|
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 {
|
fn take_screenshots(opt Options, app AppConfig) ?[]string {
|
||||||
out_path := app.screenshots_path
|
out_path := app.screenshots_path
|
||||||
if !opt.compare_only {
|
if !opt.compare_only {
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
|
||||||
eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
|
|
||||||
}
|
|
||||||
|
|
||||||
if app.capture.method == 'gg_record' {
|
if app.capture.method == 'gg_record' {
|
||||||
for k, v in app.capture.env {
|
for k, v in app.capture.env {
|
||||||
rv := v.replace('\$OUT_PATH', out_path)
|
rv := v.replace('\$OUT_PATH', out_path)
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Setting ENV `$k` = $rv ...')
|
||||||
eprintln('Setting ENV `$k` = $rv ...')
|
|
||||||
}
|
|
||||||
os.setenv('$k', rv, true)
|
os.setenv('$k', rv, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut flags := app.capture.flags.join(' ')
|
mut flags := app.capture.flags.join(' ')
|
||||||
v_cmd := '${os.quoted_path(v_exe)} $flags -d gg_record run ${os.quoted_path(app.abs_path)}'
|
result := opt.verbose_execute('${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')
|
|
||||||
if result.exit_code != 0 {
|
if result.exit_code != 0 {
|
||||||
return error('Failed taking screenshot of `$app.abs_path`:\n$result.output')
|
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
|
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 {
|
fn new_config(root_path string, toml_config string) ?Config {
|
||||||
doc := if os.is_file(toml_config) {
|
doc := if os.is_file(toml_config) {
|
||||||
toml.parse_file(toml_config)?
|
toml.parse_file(toml_config)?
|
||||||
|
|
Loading…
Reference in New Issue