mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vgret: add region support (#15651)
This commit is contained in:
parent
45e21bc311
commit
0d0c2b278d
@ -39,8 +39,9 @@ import toml
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
tool_name = 'vgret'
|
tool_name = 'vgret'
|
||||||
tool_version = '0.0.1'
|
tool_version = '0.0.2'
|
||||||
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
|
tool_description = '\n Dump and/or compare rendered frames of graphical apps
|
||||||
|
both external and `gg` based apps is supported.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Generate screenshots to `/tmp/test`
|
Generate screenshots to `/tmp/test`
|
||||||
@ -82,11 +83,24 @@ mut:
|
|||||||
flags []string
|
flags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CaptureRegion {
|
||||||
|
mut:
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
width int
|
||||||
|
height int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (cr CaptureRegion) is_empty() bool {
|
||||||
|
return cr.width == 0 && cr.height == 0
|
||||||
|
}
|
||||||
|
|
||||||
struct CaptureOptions {
|
struct CaptureOptions {
|
||||||
mut:
|
mut:
|
||||||
method string = 'gg_record'
|
method string = 'gg_record'
|
||||||
wait_ms int // used by "generic_screenshot" to wait X milliseconds *after* execution of the app
|
wait_ms int // used by "generic_screenshot" to wait X milliseconds *after* execution of the app
|
||||||
flags []string
|
flags []string
|
||||||
|
regions []CaptureRegion
|
||||||
env map[string]string
|
env map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,10 +157,6 @@ fn main() {
|
|||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
|
|
||||||
show_help := fp.bool('help', `h`, false, 'Show this help text.')
|
show_help := fp.bool('help', `h`, false, 'Show this help text.')
|
||||||
if show_help {
|
|
||||||
println(fp.usage())
|
|
||||||
exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect tool options
|
// Collect tool options
|
||||||
mut opt := Options{
|
mut opt := Options{
|
||||||
@ -157,6 +167,11 @@ 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()?
|
arg_paths := fp.finalize()?
|
||||||
|
if show_help {
|
||||||
|
println(fp.usage())
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
if arg_paths.len == 0 {
|
if arg_paths.len == 0 {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
println('\nError missing arguments')
|
println('\nError missing arguments')
|
||||||
@ -338,6 +353,10 @@ fn take_screenshots(opt Options, app AppConfig) ![]string {
|
|||||||
|
|
||||||
flags := app.capture.flags
|
flags := app.capture.flags
|
||||||
|
|
||||||
|
if !os.exists(app.abs_path) {
|
||||||
|
return error('Failed starting app `$app.abs_path`, the path does not exist')
|
||||||
|
}
|
||||||
|
opt.verbose_eprintln('Running $app.abs_path $flags')
|
||||||
mut p_app := os.new_process(app.abs_path)
|
mut p_app := os.new_process(app.abs_path)
|
||||||
p_app.set_args(flags)
|
p_app.set_args(flags)
|
||||||
p_app.run()
|
p_app.run()
|
||||||
@ -347,8 +366,13 @@ fn take_screenshots(opt Options, app AppConfig) ![]string {
|
|||||||
return error('Failed starting app `$app.abs_path` (before screenshot):\n$output')
|
return error('Failed starting app `$app.abs_path` (before screenshot):\n$output')
|
||||||
}
|
}
|
||||||
if app.capture.wait_ms > 0 {
|
if app.capture.wait_ms > 0 {
|
||||||
|
opt.verbose_eprintln('Waiting $app.capture.wait_ms before capturing')
|
||||||
time.sleep(app.capture.wait_ms * time.millisecond)
|
time.sleep(app.capture.wait_ms * time.millisecond)
|
||||||
}
|
}
|
||||||
|
if !p_app.is_alive() {
|
||||||
|
output := p_app.stdout_slurp() + '\n' + p_app.stderr_slurp()
|
||||||
|
return error('App `$app.abs_path` exited ($p_app.code) before a screenshot could be captured:\n$output')
|
||||||
|
}
|
||||||
// Use ImageMagick's `import` tool to take the screenshot
|
// Use ImageMagick's `import` tool to take the screenshot
|
||||||
out_file := os.join_path(out_path, os.file_name(app.path) +
|
out_file := os.join_path(out_path, os.file_name(app.path) +
|
||||||
'_screenshot_${existing_screenshots.len:02}.png')
|
'_screenshot_${existing_screenshots.len:02}.png')
|
||||||
@ -357,6 +381,34 @@ fn take_screenshots(opt Options, app AppConfig) ![]string {
|
|||||||
p_app.signal_kill()
|
p_app.signal_kill()
|
||||||
return error('Failed taking screenshot of `$app.abs_path` to "$out_file":\n$result.output')
|
return error('Failed taking screenshot of `$app.abs_path` to "$out_file":\n$result.output')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When using regions the capture is split up into regions.len
|
||||||
|
// And name the output based on each region's properties
|
||||||
|
if app.capture.regions.len > 0 {
|
||||||
|
for region in app.capture.regions {
|
||||||
|
region_id := 'x${region.x}y${region.y}w${region.width}h$region.height'
|
||||||
|
region_out_file := os.join_path(out_path, os.file_name(app.path) +
|
||||||
|
'_screenshot_${existing_screenshots.len:02}_region_${region_id}.png')
|
||||||
|
// If the region is empty (w, h == 0, 0) infer a full screenshot,
|
||||||
|
// This allows for capturing both regions *and* the complete screen
|
||||||
|
if region.is_empty() {
|
||||||
|
os.cp(out_file, region_out_file) or {
|
||||||
|
return error('Failed copying original screenshot "$out_file" to region file "$region_out_file"')
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
extract_result := opt.verbose_execute('convert -extract ${region.width}x$region.height+$region.x+$region.y "$out_file" "$region_out_file"')
|
||||||
|
if extract_result.exit_code != 0 {
|
||||||
|
p_app.signal_kill()
|
||||||
|
return error('Failed extracting region $region_id from screenshot of `$app.abs_path` to "$region_out_file":\n$result.output')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// When done, remove the original file that was split into regions.
|
||||||
|
opt.verbose_eprintln('Removing "$out_file" (region mode)')
|
||||||
|
os.rm(out_file) or {
|
||||||
|
return error('Failed removing original screenshot "$out_file"')
|
||||||
|
}
|
||||||
|
}
|
||||||
p_app.signal_kill()
|
p_app.signal_kill()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -395,6 +447,17 @@ fn new_config(root_path string, toml_config string) !Config {
|
|||||||
}
|
}
|
||||||
capture_method := doc.value('capture.method').default_to('gg_record').string()
|
capture_method := doc.value('capture.method').default_to('gg_record').string()
|
||||||
capture_flags := doc.value('capture.flags').default_to(empty_toml_array).array().as_strings()
|
capture_flags := doc.value('capture.flags').default_to(empty_toml_array).array().as_strings()
|
||||||
|
capture_regions_any := doc.value('capture.regions').default_to(empty_toml_array).array()
|
||||||
|
mut capture_regions := []CaptureRegion{}
|
||||||
|
for capture_region_any in capture_regions_any {
|
||||||
|
region := CaptureRegion{
|
||||||
|
x: capture_region_any.value('x').default_to(0).int()
|
||||||
|
y: capture_region_any.value('y').default_to(0).int()
|
||||||
|
width: capture_region_any.value('width').default_to(0).int()
|
||||||
|
height: capture_region_any.value('height').default_to(0).int()
|
||||||
|
}
|
||||||
|
capture_regions << region
|
||||||
|
}
|
||||||
capture_wait_ms := doc.value('capture.wait_ms').default_to(0).int()
|
capture_wait_ms := doc.value('capture.wait_ms').default_to(0).int()
|
||||||
capture_env := doc.value('capture.env').default_to(empty_toml_map).as_map()
|
capture_env := doc.value('capture.env').default_to(empty_toml_map).as_map()
|
||||||
mut env_map := map[string]string{}
|
mut env_map := map[string]string{}
|
||||||
@ -405,6 +468,7 @@ fn new_config(root_path string, toml_config string) !Config {
|
|||||||
method: capture_method
|
method: capture_method
|
||||||
wait_ms: capture_wait_ms
|
wait_ms: capture_wait_ms
|
||||||
flags: capture_flags
|
flags: capture_flags
|
||||||
|
regions: capture_regions
|
||||||
env: env_map
|
env: env_map
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +489,6 @@ fn new_config(root_path string, toml_config string) !Config {
|
|||||||
|
|
||||||
mut merged_capture := CaptureOptions{}
|
mut merged_capture := CaptureOptions{}
|
||||||
merged_capture.method = app_any.value('capture.method').default_to(default_capture.method).string()
|
merged_capture.method = app_any.value('capture.method').default_to(default_capture.method).string()
|
||||||
merged_capture.wait_ms = app_any.value('capture.wait_ms').default_to(default_capture.wait_ms).int()
|
|
||||||
merged_capture_flags := app_any.value('capture.flags').default_to(empty_toml_array).array().as_strings()
|
merged_capture_flags := app_any.value('capture.flags').default_to(empty_toml_array).array().as_strings()
|
||||||
if merged_capture_flags.len > 0 {
|
if merged_capture_flags.len > 0 {
|
||||||
merged_capture.flags = merged_capture_flags
|
merged_capture.flags = merged_capture_flags
|
||||||
@ -433,6 +496,31 @@ fn new_config(root_path string, toml_config string) !Config {
|
|||||||
merged_capture.flags = default_capture.flags
|
merged_capture.flags = default_capture.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app_capture_regions_any := app_any.value('capture.regions').default_to(empty_toml_array).array()
|
||||||
|
mut app_capture_regions := []CaptureRegion{}
|
||||||
|
for capture_region_any in app_capture_regions_any {
|
||||||
|
region := CaptureRegion{
|
||||||
|
x: capture_region_any.value('x').default_to(0).int()
|
||||||
|
y: capture_region_any.value('y').default_to(0).int()
|
||||||
|
width: capture_region_any.value('width').default_to(0).int()
|
||||||
|
height: capture_region_any.value('height').default_to(0).int()
|
||||||
|
}
|
||||||
|
app_capture_regions << region
|
||||||
|
}
|
||||||
|
mut merged_capture_regions := []CaptureRegion{}
|
||||||
|
for default_capture_region in default_capture.regions {
|
||||||
|
if default_capture_region !in app_capture_regions {
|
||||||
|
merged_capture_regions << default_capture_region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for app_capture_region in app_capture_regions {
|
||||||
|
if app_capture_region !in default_capture.regions {
|
||||||
|
merged_capture_regions << app_capture_region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
merged_capture.regions = merged_capture_regions
|
||||||
|
|
||||||
|
merged_capture.wait_ms = app_any.value('capture.wait_ms').default_to(default_capture.wait_ms).int()
|
||||||
merge_capture_env := app_any.value('capture.env').default_to(empty_toml_map).as_map()
|
merge_capture_env := app_any.value('capture.env').default_to(empty_toml_map).as_map()
|
||||||
mut merge_env_map := default_capture.env.clone()
|
mut merge_env_map := default_capture.env.clone()
|
||||||
for k, v in merge_capture_env {
|
for k, v in merge_capture_env {
|
||||||
|
@ -2,7 +2,8 @@ Usage:
|
|||||||
v gret [options] PATH [PATH]
|
v gret [options] PATH [PATH]
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
Dump and/or compare rendered frames of `gg` based apps
|
Dump and/or compare rendered frames of graphical apps
|
||||||
|
both external and `gg` based apps is supported.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Generate screenshots to `/tmp/test`
|
Generate screenshots to `/tmp/test`
|
||||||
@ -12,8 +13,11 @@ Examples:
|
|||||||
Compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
|
Compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
|
||||||
v gret --compare-only /tmp/src /tmp/dst
|
v gret --compare-only /tmp/src /tmp/dst
|
||||||
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help Show this help text.
|
-h, --help Show this help text.
|
||||||
-v, --verbose Be verbose about the tool's progress.
|
-v, --verbose Be verbose about the tool's progress.
|
||||||
-c, --compare-only Don't generate screenshots - only compare input directories
|
-c, --compare-only Don't generate screenshots - only compare input directories
|
||||||
|
-r, --root-path Root path of the comparison
|
||||||
|
-t, --toml-config Path or string with TOML configuration
|
||||||
|
|
||||||
|
--version output version information and exit
|
||||||
|
Loading…
Reference in New Issue
Block a user