0 issues 1 contributor 4 branches 0 releases
Additions: 101 Deletions: 9 View patch
1
2 const (
3 tool_name = 'vgret'
4- tool_version = '0.0.1'
5- tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
6+ tool_version = '0.0.2'
7+ tool_description = '\n Dump and/or compare rendered frames of graphical apps
8+ both external and `gg` based apps is supported.
9
10 Examples:
11 Generate screenshots to `/tmp/test`
12 flags []string
13 }
14
15+struct CaptureRegion {
16+mut:
17+ x int
18+ y int
19+ width int
20+ height int
21+}
22+
23+fn (cr CaptureRegion) is_empty() bool {
24+ return cr.width == 0 && cr.height == 0
25+}
26+
27 struct CaptureOptions {
28 mut:
29 method string = 'gg_record'
30 wait_ms int // used by "generic_screenshot" to wait X milliseconds *after* execution of the app
31 flags []string
32+ regions []CaptureRegion
33 env map[string]string
34 }
35
36 fp.skip_executable()
37
38 show_help := fp.bool('help', `h`, false, 'Show this help text.')
39- if show_help {
40- println(fp.usage())
41- exit(0)
42- }
43
44 // Collect tool options
45 mut opt := Options{
46
47 toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
48 arg_paths := fp.finalize()?
49+ if show_help {
50+ println(fp.usage())
51+ exit(0)
52+ }
53+
54 if arg_paths.len == 0 {
55 println(fp.usage())
56 println('\nError missing arguments')
57
58 flags := app.capture.flags
59
60+ if !os.exists(app.abs_path) {
61+ return error('Failed starting app `$app.abs_path`, the path does not exist')
62+ }
63+ opt.verbose_eprintln('Running $app.abs_path $flags')
64 mut p_app := os.new_process(app.abs_path)
65 p_app.set_args(flags)
66 p_app.run()
67 return error('Failed starting app `$app.abs_path` (before screenshot):\n$output')
68 }
69 if app.capture.wait_ms > 0 {
70+ opt.verbose_eprintln('Waiting $app.capture.wait_ms before capturing')
71 time.sleep(app.capture.wait_ms * time.millisecond)
72 }
73+ if !p_app.is_alive() {
74+ output := p_app.stdout_slurp() + '\n' + p_app.stderr_slurp()
75+ return error('App `$app.abs_path` exited ($p_app.code) before a screenshot could be captured:\n$output')
76+ }
77 // Use ImageMagick's `import` tool to take the screenshot
78 out_file := os.join_path(out_path, os.file_name(app.path) +
79 '_screenshot_${existing_screenshots.len:02}.png')
80 p_app.signal_kill()
81 return error('Failed taking screenshot of `$app.abs_path` to "$out_file":\n$result.output')
82 }
83+
84+ // When using regions the capture is split up into regions.len
85+ // And name the output based on each region's properties
86+ if app.capture.regions.len > 0 {
87+ for region in app.capture.regions {
88+ region_id := 'x${region.x}y${region.y}w${region.width}h$region.height'
89+ region_out_file := os.join_path(out_path, os.file_name(app.path) +
90+ '_screenshot_${existing_screenshots.len:02}_region_${region_id}.png')
91+ // If the region is empty (w, h == 0, 0) infer a full screenshot,
92+ // This allows for capturing both regions *and* the complete screen
93+ if region.is_empty() {
94+ os.cp(out_file, region_out_file) or {
95+ return error('Failed copying original screenshot "$out_file" to region file "$region_out_file"')
96+ }
97+ continue
98+ }
99+ extract_result := opt.verbose_execute('convert -extract ${region.width}x$region.height+$region.x+$region.y "$out_file" "$region_out_file"')
100+ if extract_result.exit_code != 0 {
101+ p_app.signal_kill()
102+ return error('Failed extracting region $region_id from screenshot of `$app.abs_path` to "$region_out_file":\n$result.output')
103+ }
104+ }
105+ // When done, remove the original file that was split into regions.
106+ opt.verbose_eprintln('Removing "$out_file" (region mode)')
107+ os.rm(out_file) or {
108+ return error('Failed removing original screenshot "$out_file"')
109+ }
110+ }
111 p_app.signal_kill()
112 }
113 else {
114 }
115 capture_method := doc.value('capture.method').default_to('gg_record').string()
116 capture_flags := doc.value('capture.flags').default_to(empty_toml_array).array().as_strings()
117+ capture_regions_any := doc.value('capture.regions').default_to(empty_toml_array).array()
118+ mut capture_regions := []CaptureRegion{}
119+ for capture_region_any in capture_regions_any {
120+ region := CaptureRegion{
121+ x: capture_region_any.value('x').default_to(0).int()
122+ y: capture_region_any.value('y').default_to(0).int()
123+ width: capture_region_any.value('width').default_to(0).int()
124+ height: capture_region_any.value('height').default_to(0).int()
125+ }
126+ capture_regions << region
127+ }
128 capture_wait_ms := doc.value('capture.wait_ms').default_to(0).int()
129 capture_env := doc.value('capture.env').default_to(empty_toml_map).as_map()
130 mut env_map := map[string]string{}
131 method: capture_method
132 wait_ms: capture_wait_ms
133 flags: capture_flags
134+ regions: capture_regions
135 env: env_map
136 }
137
138
139 mut merged_capture := CaptureOptions{}
140 merged_capture.method = app_any.value('capture.method').default_to(default_capture.method).string()
141- merged_capture.wait_ms = app_any.value('capture.wait_ms').default_to(default_capture.wait_ms).int()
142 merged_capture_flags := app_any.value('capture.flags').default_to(empty_toml_array).array().as_strings()
143 if merged_capture_flags.len > 0 {
144 merged_capture.flags = merged_capture_flags
145 merged_capture.flags = default_capture.flags
146 }
147
148+ app_capture_regions_any := app_any.value('capture.regions').default_to(empty_toml_array).array()
149+ mut app_capture_regions := []CaptureRegion{}
150+ for capture_region_any in app_capture_regions_any {
151+ region := CaptureRegion{
152+ x: capture_region_any.value('x').default_to(0).int()
153+ y: capture_region_any.value('y').default_to(0).int()
154+ width: capture_region_any.value('width').default_to(0).int()
155+ height: capture_region_any.value('height').default_to(0).int()
156+ }
157+ app_capture_regions << region
158+ }
159+ mut merged_capture_regions := []CaptureRegion{}
160+ for default_capture_region in default_capture.regions {
161+ if default_capture_region !in app_capture_regions {
162+ merged_capture_regions << default_capture_region
163+ }
164+ }
165+ for app_capture_region in app_capture_regions {
166+ if app_capture_region !in default_capture.regions {
167+ merged_capture_regions << app_capture_region
168+ }
169+ }
170+ merged_capture.regions = merged_capture_regions
171+
172+ merged_capture.wait_ms = app_any.value('capture.wait_ms').default_to(default_capture.wait_ms).int()
173 merge_capture_env := app_any.value('capture.env').default_to(empty_toml_map).as_map()
174 mut merge_env_map := default_capture.env.clone()
175 for k, v in merge_capture_env {
176
1 v gret [options] PATH [PATH]
2
3 Description:
4- Dump and/or compare rendered frames of `gg` based apps
5+ Dump and/or compare rendered frames of graphical apps
6+ both external and `gg` based apps is supported.
7
8 Examples:
9 Generate screenshots to `/tmp/test`
10 Compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
11 v gret --compare-only /tmp/src /tmp/dst
12
13-
14 Options:
15 -h, --help Show this help text.
16 -v, --verbose Be verbose about the tool's progress.
17 -c, --compare-only Don't generate screenshots - only compare input directories
18+ -r, --root-path Root path of the comparison
19+ -t, --toml-config Path or string with TOML configuration
20+
21+ --version output version information and exit
22