blob: a1563327250731f3703c5aa50829c989751adf83 [file] [log] [blame]
Patrick Williams847a0c32020-06-24 15:18:10 -05001#!/usr/bin/env bash
2
3set -e
4
5function show_usage {
6 cat \
7<<EOF
8Usage: $(basename "$0") [options] <command-args>*
9
10Generate meson.build files from a directory tree containing YAML files and
11facilitate building the sdbus++ sources.
12
13Options:
14 --help - Display this message
15 --command <cmd> - Command mode to execute (default 'meson').
16 --directory <path> - Root directory of the YAML source (default '.').
17 --output <path> - Root directory of the output (default '.').
18 --tool <path> - Path to the processing tool (default 'sdbus++').
19 --version - Display this tool's version string.
20
21Commands:
22 meson - Generate a tree of meson.build files corresponding
23 to the source YAML files.
24 cpp <intf> - Generate the source files from a YAML interface.
25 markdown <intf> - Generate the markdown files from a YAML interface.
26 version - Display this tool's version string.
27
28EOF
29}
30
31## The version is somewhat arbitrary but is used to create a warning message
32## if a repository contains old copies of the generated meson.build files and
33## needs an update. We should increment the version number whenever the
34## resulting meson.build would change.
35tool_version="sdbus++-gen-meson version 1"
36function show_version {
37 echo "$tool_version"
38}
39
40# Set up defaults.
41sdbuspp="sdbus++"
42outputdir="."
43cmd="meson"
44rootdir="."
45
46# Parse options.
47options="$(getopt -o hc:d:o:t:v --long help,command:,directory:,output:,tool:,version -- "$@")"
48eval set -- "$options"
49
50while true;
51do
52 case "$1" in
53 -h | --help)
54 show_usage
55 exit
56 ;;
57
58 -c | --command)
59 shift
60 cmd="$1"
61 shift
62 ;;
63
64 -d | --directory)
65 shift
66 rootdir="$1"
67 shift
68 ;;
69
70 -o | --output)
71 shift
72 outputdir="$1"
73 shift
74 ;;
75
76 -t | --tool)
77 shift
78 sdbuspp="$1"
79 shift
80 ;;
81
82 -v | --version)
83 show_version
84 exit
85 ;;
86
87 --)
88 shift
89 break
90 ;;
91 esac
92done
93
94## Create an initially empty meson.build file.
95## $1 - path to create meson.build at.
96function meson_empty_file {
97 mkdir -p "$1"
98 echo "# Generated file; do not modify." > "$1/meson.build"
99}
100
101## Create the root-level meson.build
102##
103## Inserts rules to run the available version of this tool to ensure the
104## version has not changed.
105function meson_create_root {
106 meson_empty_file "$outputdir"
107
108 cat >> "$outputdir/meson.build" \
109<<EOF
110sdbuspp_gen_meson_ver = run_command(
111 sdbuspp_gen_meson_prog,
112 '--version',
113).stdout().strip().split('\n')[0]
114
115if sdbuspp_gen_meson_ver != '$tool_version'
116 warning('Generated meson files from wrong version of sdbus++-gen-meson.')
117 warning(
118 'Expected "$tool_version", got:',
119 sdbuspp_gen_meson_ver
120 )
121endif
122
123EOF
124}
125
126## hash-tables to store:
127## meson_paths - list of subdirectory paths for which an empty meson.build
128## has already been created.
129## interfaces - list of interface paths which a YAML has been found and
130## which YAML types (interface, errors, etc.).
131declare -A meson_paths
132declare -A interfaces
133
134## Ensure the meson.build files to a path have been created.
135## $1 - The path requiring to be created.
136function meson_create_path {
137
138 meson_path="$outputdir"
139 prev_meson_path=""
140
141 # Split the path into segments.
142 for part in $(echo "$1" | tr '/' '\n');
143 do
144 prev_meson_path="$meson_path"
145 meson_path="$meson_path/$part"
146
147 # Create the meson.build for this segment if it doesn't already exist.
148 if [ "x" == "x${meson_paths[$meson_path]}" ];
149 then
150 meson_paths["$meson_path"]="1"
151 meson_empty_file "$meson_path"
152
153 # Add the 'subdir' link into the parent's meson.build.
154 # We need to skip adding the links into the 'root' meson.build
155 # because most repositories want to selectively add TLDs based
156 # on config flags. Let them figure out their own logic for that.
157 if [ "x$outputdir" != "x$prev_meson_path" ];
158 then
159 echo "subdir('$part')" >> "$prev_meson_path/meson.build"
160 fi
161 fi
162 done
163}
164
165## Generate the meson target for the source files (.cpp/.hpp) from a YAML
166## interface.
167##
168## $1 - The interface to generate a target for.
169function meson_cpp_target {
170
171 # Determine the source and output files based on the YAMLs present.
172 sources=""
173 outputs=""
174 for s in ${interfaces[$1]};
175 do
176 sources="${sources}meson.source_root() / '$1.$s', "
177
178 case "$s" in
179 errors.yaml)
180 outputs="${outputs}'error.cpp', 'error.hpp', "
181 ;;
182
183 interface.yaml)
184 outputs="${outputs}'server.cpp', 'server.hpp', "
185 outputs="${outputs}'client.hpp', "
186 ;;
187 esac
188 done
189
190 # Create the target to generate the 'outputs'.
191 cat >> "$outputdir/$1/meson.build" \
192<<EOF
193generated_sources += custom_target(
194 '$1__cpp'.underscorify(),
195 input: [ $sources ],
196 output: [ $outputs ],
197 command: [
198 sdbuspp_gen_meson_prog, '--command', 'cpp',
199 '--output', meson.current_build_dir(),
200 '--tool', sdbusplusplus_prog,
201 '--directory', meson.source_root(),
202 '$1',
203 ],
204)
205
206EOF
207}
208
209## Generate the meson target for the markdown files from a YAML interface.
210## $1 - The interface to generate a target for.
211function meson_md_target {
212
213 # Determine the source files based on the YAMLs present.
214 sources=""
215 for s in ${interfaces[$1]};
216 do
217 sources="${sources}meson.source_root() / '$1.$s', "
218 done
219
220 # Create the target to generate the interface.md file.
221 cat >> "$outputdir/$(dirname "$1")/meson.build" \
222<<EOF
223generated_others += custom_target(
224 '$1__markdown'.underscorify(),
225 input: [ $sources ],
226 output: [ '$(basename "$1").md' ],
227 command: [
228 sdbuspp_gen_meson_prog, '--command', 'markdown',
229 '--output', meson.current_build_dir(),
230 '--tool', sdbusplusplus_prog,
231 '--directory', meson.source_root(),
232 '$1',
233 ],
234 build_by_default: true,
235)
236
237EOF
238}
239
240## Handle command=meson by generating the tree of meson.build files.
241function cmd_meson {
242 TLDs="com net org xyz"
243 yamls=""
244
245 # Find all the YAML files in the TLD subdirectories.
246 for d in $TLDs;
247 do
248 dir="$rootdir/$d"
249 if [ ! -d "$dir" ];
250 then
251 continue
252 fi
253
254 yamls="\
255 $yamls \
256 $(find "$dir" -name '*.interface.yaml' -o -name '*.errors.yaml') \
257 "
258 done
259
260 # Sort YAMLs
261 yamls="$(echo "$yamls" | tr " " "\n" | sort)"
262
263 # Assign the YAML files into the hash-table by interface name.
264 for y in $yamls;
265 do
266 rel="$(realpath "--relative-to=$rootdir" "$y")"
267 dir="$(dirname "$rel")"
268 ext="${rel#*.}"
269 base="$(basename "$rel" ".$ext")"
270
271 interfaces["$dir/$base"]="${interfaces[$dir/$base]} $ext"
272 done
273
274 # Create the meson.build files.
275 meson_create_root
276 sorted_ifaces="$(echo "${!interfaces[@]}" | tr " " "\n" | sort)"
277 for i in ${sorted_ifaces};
278 do
279 meson_create_path "$i"
280 meson_cpp_target "$i"
281 meson_md_target "$i"
282 done
283}
284
285## Handle command=cpp by calling sdbus++ as appropriate.
286## $1 - interface to generate.
287##
288## For an interface foo/bar, the outputdir is expected to be foo/bar.
289function cmd_cpp {
290
291 if [ "x" == "x$1" ];
292 then
293 show_usage
294 exit 1
295 fi
296
297 if [ ! -e "$rootdir/$1.interface.yaml" ] && \
298 [ ! -e "$rootdir/$1.errors.yaml" ];
299 then
300 echo "Missing YAML for $1."
301 exit 1
302 fi
303
304 mkdir -p "$outputdir"
305
306 sdbusppcmd="$sdbuspp -r $rootdir"
307 intf="${1//\//.}"
308
309 if [ -e "$rootdir/$1.interface.yaml" ];
310 then
311 $sdbusppcmd interface server-header "$intf" > "$outputdir/server.hpp"
312 $sdbusppcmd interface server-cpp "$intf" > "$outputdir/server.cpp"
313 $sdbusppcmd interface client-header "$intf" > "$outputdir/client.hpp"
314 fi
315
316 if [ -e "$rootdir/$1.errors.yaml" ];
317 then
318 $sdbusppcmd error exception-header "$intf" > "$outputdir/error.hpp"
319 $sdbusppcmd error exception-cpp "$intf" > "$outputdir/error.cpp"
320 fi
321}
322
323## Handle command=markdown by calling sdbus++ as appropriate.
324## $1 - interface to generate.
325##
326## For an interface foo/bar, the outputdir is expected to be foo.
327function cmd_markdown {
328
329 if [ "x" == "x$1" ];
330 then
331 show_usage
332 exit 1
333 fi
334
335 if [ ! -e "$rootdir/$1.interface.yaml" ] && \
336 [ ! -e "$rootdir/$1.errors.yaml" ];
337 then
338 echo "Missing YAML for $1."
339 exit 1
340 fi
341
342 mkdir -p "$outputdir"
343
344 sdbusppcmd="$sdbuspp -r $rootdir"
345 intf="${1//\//.}"
346 base="$(basename "$1")"
347
348 echo -n > "$outputdir/$base.md"
349 if [ -e "$rootdir/$1.interface.yaml" ];
350 then
351 $sdbusppcmd interface markdown "$intf" >> "$outputdir/$base.md"
352 fi
353
354 if [ -e "$rootdir/$1.errors.yaml" ];
355 then
356 $sdbusppcmd error markdown "$intf" >> "$outputdir/$base.md"
357 fi
358}
359
360## Handle command=version.
361function cmd_version {
362 show_version
363}
364
365"cmd_$cmd" "$*"