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