blob: 1ce8395165e64915481eaca2f81d98c4195e46f6 [file] [log] [blame]
Raphael48023782011-02-23 16:46:42 -08001#!/bin/bash
2#
3# Generates an SDK Repository XML based on the input files.
4
5set -e
6
7PROG_DIR=$(dirname $0)
8
Alan Viveretteaf9c8f22017-03-18 01:56:53 +00009TYPES="tool platform-tool build-tool platform sample doc add-on system-image source"
Raphael48023782011-02-23 16:46:42 -080010OSES="linux macosx windows any linux-x86 darwin"
11
12TMP_DIR=$(mktemp -d -t sdkrepo.tmp.XXXXXXXX)
13trap "rm -rf $TMP_DIR" EXIT
14
Jean-Baptiste Querue35ac782012-03-22 15:41:28 -070015function debug() {
16 echo "DEBUG: " $@ > /dev/stderr
17}
18
Raphael48023782011-02-23 16:46:42 -080019function error() {
20 echo "*** ERROR: " $@
21 usage
22}
23
24function usage() {
25 cat <<EOFU
26Usage: $0 output.xml xml-schema [type [os zip[:dest]]*...]*
27where:
Raphael Moll8f7e1f72012-02-27 15:18:29 -080028- schema is one of 'repository' or 'addon'
Raphael48023782011-02-23 16:46:42 -080029- type is one of ${TYPES// /, } (or their plural).
30- os is one of ${OSES// /, }.
31There can be more than one zip for the same type
32as long as they use different OSes.
33Zip can be in the form "source:dest" to be renamed on the fly.
34EOFU
35 exit 1
36}
37
38# Validate the tools we need
39if [[ ! -x $(which sha1sum) ]]; then
40 error "Missing tool: sha1sum (Linux: apt-get install coreutils; Mac: port install md5sha1sum)"
41fi
42
43# Parse input params
44OUT="$1"
45[[ -z "$OUT" ]] && error "Missing output.xml name."
46shift
47
Raphael Mollea40d2f2014-04-24 19:13:47 -070048# Get the schema filename. E.g. ".../.../sdk-repository-10.xsd". Can be relative or absolute.
Raphael48023782011-02-23 16:46:42 -080049SCHEMA="$1"
50[[ ! -f "$SCHEMA" ]] && error "Invalid XML schema name: $SCHEMA."
51shift
52
53# Get XML:NS for SDK from the schema
Raphael Moll8f7e1f72012-02-27 15:18:29 -080054# This will be something like "http://schemas.android.com/sdk/android/addon/3"
Raphael48023782011-02-23 16:46:42 -080055XMLNS=$(sed -n '/xmlns:sdk="/s/.*"\(.*\)".*/\1/p' "$SCHEMA")
56[[ -z "$XMLNS" ]] && error "Failed to find xmlns:sdk in $SCHEMA."
57echo "## Using xmlns:sdk=$XMLNS"
58
Raphael Moll8f7e1f72012-02-27 15:18:29 -080059# Extract the schema version number from the XMLNS, e.g. it would extract "3"
Raphael Mollb0650412012-05-10 23:20:56 -070060XSD_VERSION="${XMLNS##*/}"
Raphael Moll8f7e1f72012-02-27 15:18:29 -080061
Raphael48023782011-02-23 16:46:42 -080062# Get the root element from the schema. This is the first element
63# which name starts with "sdk-" (e.g. sdk-repository, sdk-addon)
64ROOT=$(sed -n -e '/xsd:element.*name="sdk-/s/.*name="\(sdk-[^"]*\)".*/\1/p' "$SCHEMA")
65[[ -z "$ROOT" ]] && error "Failed to find root element in $SCHEMA."
66echo "## Using root element $ROOT"
67
68# Generate XML header
69cat > "$OUT" <<EOFH
70<?xml version="1.0"?>
71<sdk:$ROOT
72 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
73 xmlns:sdk="$XMLNS">
74EOFH
75
76# check_enum value value1 value2 value3...
77# returns valueN if matched or nothing.
78function check_enum() {
79 local VALUE="$1"
80 local i
81 shift
82 for i in "$@"; do
83 if [[ "$i" == "$VALUE" ]]; then
84 echo "$VALUE"
85 break;
86 fi
87 done
88}
89
Raphael Mollb0650412012-05-10 23:20:56 -070090# Definition of the attributes we read from source.properties or manifest.ini
91# files and the equivalent XML element being generated.
Raphael48023782011-02-23 16:46:42 -080092
93ATTRS=(
Raphael Moll8f7e1f72012-02-27 15:18:29 -080094 # Columns:
95 # --------------------------+------------------------+----------------------
96 # Name read from | XML element written | Min-XSD version
97 # source.properties | to repository.xml | where XML can be used
98 # --------------------------+------------------------+----------------------
Jean-Baptiste Querue35ac782012-03-22 15:41:28 -070099 # from source.properties for repository.xml packages
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800100 Pkg.Revision revision 1
101 Pkg.Desc description 1
102 Platform.Version version 1
103 AndroidVersion.ApiLevel api-level 1
104 AndroidVersion.CodeName codename 1
105 Platform.IncludedAbi included-abi 5
106 Platform.MinToolsRev min-tools-rev 1
107 Platform.MinPlatformToolsRev min-platform-tools-rev 3
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800108 Sample.MinApiLevel min-api-level 2
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800109 Layoutlib.Api layoutlib/api 4
110 Layoutlib.Revision layoutlib/revision 4
Jean-Baptiste Querue35ac782012-03-22 15:41:28 -0700111 # from source.properties for addon.xml packages
112 # (note that vendor is mapped to different XML elements based on the XSD version)
113 Extra.VendorDisplay vendor-display 4
114 Extra.VendorId vendor-id 4
115 Extra.Vendor vendor-id 4
116 Extra.Vendor vendor 1
117 Extra.NameDisplay name-display 4
118 Extra.Path path 1
119 Extra.OldPaths old-paths 3
120 Extra.MinApiLevel min-api-level 2
Raphael Mollea40d2f2014-04-24 19:13:47 -0700121 # for system-image
122 SystemImage.Abi abi r:3,s:1
123 SystemImage.TagId tag-id r:9,s:2
124 SystemImage.TagDisplay tag-display r:9,s:2
Raphael Mollfa090e22014-08-21 15:15:02 -0700125 Addon.VendorId add-on/vendor-id s:3
126 Addon.VendorDisplay add-on/vendor-display s:3
Jean-Baptiste Querue35ac782012-03-22 15:41:28 -0700127 # from addon manifest.ini for addon.xml packages
128 # (note that vendor/name are mapped to different XML elements based on the XSD version)
129 vendor-id vendor-id 4
130 vendor-display vendor-display 4
131 vendor vendor-display 4
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800132 vendor vendor 1
Jean-Baptiste Querue35ac782012-03-22 15:41:28 -0700133 name-id name-id 4
134 name-display name-display 4
135 name name-display 4
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800136 name name 1
137 description description 1
138 api api-level 1
139 version revision 1
140 revision revision 1
Raphael48023782011-02-23 16:46:42 -0800141)
142
Raphael Mollea40d2f2014-04-24 19:13:47 -0700143# Start with repo-10, addon-7 and sys-img-3, we don't encode the os/arch
144# in the <archive> attributes anymore. Instead we have separate elements.
145
146function uses_new_host_os() {
147 if [[ "$ROOT" == "sdk-repository" && "$XSD_VERSION" -ge "10" ]]; then return 0; fi
148 if [[ "$ROOT" == "sdk-addon" && "$XSD_VERSION" -ge "7" ]]; then return 0; fi
149 if [[ "$ROOT" == "sdk-sys-img" && "$XSD_VERSION" -ge "3" ]]; then return 0; fi
150 return 1
151}
152
153ATTRS_ARCHIVE=(
154 Archive.HostOs host-os 1
155 Archive.HostBits host-bits 1
156 Archive.JvmBits jvm-bits 1
157 Archive.MinJvmVers min-jvm-version 1
158)
159
Raphael Mollb0650412012-05-10 23:20:56 -0700160
161# Starting with XSD repo-7 and addon-5, some revision elements are no longer just
162# integers. Instead they are in major.minor.micro.preview format. This defines
163# which elements. This depends on the XSD root element and the XSD version.
Raphael Moll7657a592013-09-30 11:57:17 -0700164#
165# Note: addon extra revision can't take a preview number. We don't enforce
166# this in this script. Instead schema validation will fail if the extra
167# source.property declares an RC and it gets inserted in the addon.xml here.
Raphael Mollb0650412012-05-10 23:20:56 -0700168
169if [[ "$ROOT" == "sdk-repository" && "$XSD_VERSION" -ge 7 ]] ||
170 [[ "$ROOT" == "sdk-addon" && "$XSD_VERSION" -ge 5 ]]; then
171FULL_REVISIONS=(
172 tool revision
Raphael Moll9ca69cf2013-02-12 13:48:39 -0800173 build-tool revision
Raphael Mollb0650412012-05-10 23:20:56 -0700174 platform-tool revision
Raphael Moll7657a592013-09-30 11:57:17 -0700175 extra revision
Raphael Mollb0650412012-05-10 23:20:56 -0700176 @ min-tools-rev
177 @ min-platform-tools-rev
178)
179else
180FULL_REVISIONS=()
181fi
182
183
184# Parse all archives.
185
186function needs_full_revision() {
187 local PARENT="$1"
188 local ELEMENT="$2"
189 shift
190 shift
191 local P E
192
193 while [[ "$1" ]]; do
194 P=$1
195 E=$2
196 if [[ "$E" == "$ELEMENT" ]] && [[ "$P" == "@" || "$P" == "$PARENT" ]]; then
197 return 0 # true
198 fi
199 shift
200 shift
201 done
202
203 return 1 # false
204}
205
206# Parses and print a full revision in the form "1.2.3 rc4".
Raphael Moll7657a592013-09-30 11:57:17 -0700207# Note that the format requires to have 1 space before the
Raphael Mollb0650412012-05-10 23:20:56 -0700208# optional "rc" (e.g. '1 rc4', not '1rc4') and no space after
209# the rc (so not '1 rc 4' either)
210function write_full_revision() {
211 local VALUE="$1"
212 local EXTRA_SPACE="$2"
213 local KEYS="major minor micro preview"
214 local V K
215
216 while [[ -n "$VALUE" && -n "$KEYS" ]]; do
217 # Take 1st segment delimited by . or space
218 V="${VALUE%%[. ]*}"
219
220 # Print it
221 if [[ "${V:0:2}" == "rc" ]]; then
222 V="${V:2}"
223 K="preview"
224 KEYS=""
225 else
226 K="${KEYS%% *}"
227 fi
228
229 if [[ -n "$V" && -n "$K" ]]; then
230 echo "$EXTRA_SPACE <sdk:$K>$V</sdk:$K>"
231 fi
232
233 # Take the rest.
234 K="${KEYS#* }"
235 if [[ "$K" == "$KEYS" ]]; then KEYS=""; else KEYS="$K"; fi
236 V="${VALUE#*[. ]}"
237 if [[ "$V" == "$VALUE" ]]; then VALUE=""; else VALUE="$V"; fi
238 done
239}
240
241
Raphael48023782011-02-23 16:46:42 -0800242function parse_attributes() {
243 local PROPS="$1"
244 shift
245 local RESULT=""
246 local VALUE
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800247 local REV
248 local USED
Raphael Mollea40d2f2014-04-24 19:13:47 -0700249 local S
250
251 # Get the first letter of the schema name (e.g. sdk-repo => 'r')
252 # This can be r, a or s and would match the min-XSD per-schema value
253 # in the ATTRS list.
254 S=$(basename "$SCHEMA")
255 S="${S:4:1}"
Raphael48023782011-02-23 16:46:42 -0800256
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800257 # $1 here is the ATTRS list above.
Raphael48023782011-02-23 16:46:42 -0800258 while [[ "$1" ]]; do
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800259 # Check the version in which the attribute was introduced and
260 # ignore things which are too *new* for this schema. This lets
261 # us generate old schemas for backward compatibility purposes.
262 SRC=$1
263 DST=$2
264 REV=$3
265
Raphael Mollea40d2f2014-04-24 19:13:47 -0700266 if [[ $REV =~ ([ras0-9:,]+,)?$S:([0-9])(,.*)? ]]; then
267 # Per-schema type min-XSD revision. Format is "[<type>:rev],*]
268 # where type is one of r, a or s matching $S above.
269 REV="${BASH_REMATCH[2]}"
270 fi
271
Raphael Moll4df9f462014-06-02 17:11:45 -0700272 if [[ ( $REV =~ ^[0-9]+ && $XSD_VERSION -ge $REV ) || $XSD_VERSION == $REV ]]; then
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800273 # Parse the property, if present. Any space is replaced by @
274 VALUE=$( grep "^$SRC=" "$PROPS" | cut -d = -f 2 | tr ' ' '@' | tr -d '\r' )
275 if [[ -n "$VALUE" ]]; then
276 # In case an XML element would be mapped multiple times,
277 # only use its first definition.
278 if [[ "${USED/$DST/}" == "$USED" ]]; then
279 USED="$USED $DST"
280 RESULT="$RESULT $DST $VALUE"
281 fi
282 fi
Raphael48023782011-02-23 16:46:42 -0800283 fi
284 shift
285 shift
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800286 shift
Raphael48023782011-02-23 16:46:42 -0800287 done
288
289 echo "$RESULT"
290}
291
292function output_attributes() {
Raphael Mollb0650412012-05-10 23:20:56 -0700293 local ELEMENT="$1"
294 local OUT="$2"
295 shift
Raphael48023782011-02-23 16:46:42 -0800296 shift
297 local KEY VALUE
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800298 local NODE LAST_NODE EXTRA_SPACE
Raphael48023782011-02-23 16:46:42 -0800299
300 while [[ "$1" ]]; do
301 KEY="$1"
302 VALUE="${2//@/ }"
Raphael Moll3acd4822011-09-17 22:50:43 -0700303 NODE="${KEY%%/*}"
304 KEY="${KEY##*/}"
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800305 if [[ "$NODE" == "$KEY" ]]; then
306 NODE=""
307 EXTRA_SPACE=""
Raphael Moll3acd4822011-09-17 22:50:43 -0700308 fi
Raphael Moll8f7e1f72012-02-27 15:18:29 -0800309 if [[ "$NODE" != "$LAST_NODE" ]]; then
310 EXTRA_SPACE=" "
311 [[ "$LAST_NODE" ]] && echo " </sdk:$LAST_NODE>" >> "$OUT"
312 LAST_NODE="$NODE"
313 [[ "$NODE" ]] && echo " <sdk:$NODE>" >> "$OUT"
314 fi
Raphael Mollb0650412012-05-10 23:20:56 -0700315 if needs_full_revision "$ELEMENT" "$KEY" ${FULL_REVISIONS[@]}; then
316 echo "$EXTRA_SPACE <sdk:$KEY>" >> "$OUT"
317 write_full_revision "$VALUE" "$EXTRA_SPACE" >> "$OUT"
318 echo "$EXTRA_SPACE </sdk:$KEY>" >> "$OUT"
319 else
320 echo "$EXTRA_SPACE <sdk:$KEY>$VALUE</sdk:$KEY>" >> "$OUT"
321 fi
Raphael48023782011-02-23 16:46:42 -0800322 shift
323 shift
324 done
Raphael Moll3acd4822011-09-17 22:50:43 -0700325 if [[ "$LAST_NODE" ]]; then echo " </sdk:$LAST_NODE>" >> "$OUT"; fi
Raphael48023782011-02-23 16:46:42 -0800326}
327
328while [[ -n "$1" ]]; do
329 # Process archives.
Raphael Moll4dedff62011-09-27 20:17:07 -0700330 # First we expect a type. For convenience the type can be plural.
Raphael48023782011-02-23 16:46:42 -0800331 TYPE=$(check_enum "${1%%s}" $TYPES)
332 [[ -z $TYPE ]] && error "Unknown archive type '$1'."
333 shift
334
Raphael Moll3d308aa2011-10-01 23:44:08 -0700335 ELEMENT="$TYPE"
Raphael Moll3d308aa2011-10-01 23:44:08 -0700336
Raphael48023782011-02-23 16:46:42 -0800337 MAP=""
338 FIRST="1"
339 LIBS_XML=""
340
341 OS=$(check_enum "$1" $OSES)
342 while [[ $OS ]]; do
343 shift
344 [[ $OS == "linux-x86" ]] && OS=linux
345 [[ $OS == "darwin" ]] && OS=macosx
346
347 SRC="$1"
348 DST="$1"
349 if [[ "${SRC/:/}" != "$SRC" ]]; then
350 DST="${SRC/*:/}"
351 SRC="${SRC/:*/}"
352 fi
353 [[ ! -f "$SRC" ]] && error "Missing file for archive $TYPE/$OS: $SRC"
354 shift
355
356 # Depending on the archive type, we need a number of attributes
357 # from the source.properties or the manifest.ini. We'll take
358 # these attributes from the first zip found.
359 #
360 # What we need vs. which package uses it:
361 # - description all
362 # - revision all
363 # - version platform
Raphael Moll3acd4822011-09-17 22:50:43 -0700364 # - included-abi platform
365 # - api-level platform sample doc add-on system-image
366 # - codename platform sample doc add-on system-image
Raphael48023782011-02-23 16:46:42 -0800367 # - min-tools-rev platform sample
368 # - min-platform-tools-rev tool
369 # - min-api-level extra
370 # - vendor extra add-on
371 # - path extra
Raphael Moll3acd4822011-09-17 22:50:43 -0700372 # - old-paths extra
373 # - abi system-image
Raphael48023782011-02-23 16:46:42 -0800374 #
375 # We don't actually validate here.
376 # Just take whatever is defined and put it in the XML.
377 # XML validation against the schema will be done at the end.
378
379 if [[ $FIRST ]]; then
380 FIRST=""
381
382 if unzip -t "$SRC" | grep -qs "source.properties" ; then
383 # Extract Source Properties
384 # unzip: -j=flat (no dirs), -q=quiet, -o=overwrite, -d=dest dir
385 unzip -j -q -o -d "$TMP_DIR" "$SRC" "*/source.properties"
386 PROPS="$TMP_DIR/source.properties"
387
388 elif unzip -t "$SRC" | grep -qs "manifest.ini" ; then
389 unzip -j -q -o -d "$TMP_DIR" "$SRC" "*/manifest.ini"
390 PROPS="$TMP_DIR/manifest.ini"
391
392 # Parse the libs for an addon and generate the <libs> node
393 # libraries is a semi-colon separated list
394 LIBS=$(parse_attributes "$PROPS" "libraries")
395 LIBS_XML=" <sdk:libs>"
396 for LIB in ${LIBS//;/ }; do
397 LIBS_XML="$LIBS_XML
398 <sdk:lib><sdk:name>$LIB</sdk:name></sdk:lib>"
399 done
400 LIBS_XML="$LIBS_XML
401 </sdk:libs>"
402
403 else
404 error "Failed to find source.properties or manifest.ini in $SRC"
405 fi
406
407 [[ ! -f $PROPS ]] && error "Failed to extract $PROPS from $SRC"
408 MAP=$(parse_attributes "$PROPS" ${ATTRS[@]})
409
410 # Time to generate the XML for the package
Raphael Moll3d308aa2011-10-01 23:44:08 -0700411 echo " <sdk:${ELEMENT}>" >> "$OUT"
Raphael Mollb0650412012-05-10 23:20:56 -0700412 output_attributes "$ELEMENT" "$OUT" $MAP
Raphael48023782011-02-23 16:46:42 -0800413 [[ -n "$LIBS_XML" ]] && echo "$LIBS_XML" >> "$OUT"
414 echo " <sdk:archives>" >> "$OUT"
415 fi
416
417 # Generate archive info
418 echo "## Add $TYPE/$OS archive $SRC"
419 if [[ $( uname ) == "Darwin" ]]; then
420 SIZE=$( stat -f %z "$SRC" )
421 else
422 SIZE=$( stat -c %s "$SRC" )
423 fi
424 SHA1=$( sha1sum "$SRC" | cut -d " " -f 1 )
425
Raphael Mollea40d2f2014-04-24 19:13:47 -0700426 if uses_new_host_os ; then
427 USE_HOST_OS=1
428 else
429 OLD_OS_ATTR=" os='$OS'"
430 fi
431
Raphael48023782011-02-23 16:46:42 -0800432 cat >> "$OUT" <<EOFA
Raphael Mollea40d2f2014-04-24 19:13:47 -0700433 <sdk:archive$OLD_OS_ATTR>
Raphael48023782011-02-23 16:46:42 -0800434 <sdk:size>$SIZE</sdk:size>
435 <sdk:checksum type='sha1'>$SHA1</sdk:checksum>
436 <sdk:url>$DST</sdk:url>
Raphael48023782011-02-23 16:46:42 -0800437EOFA
Raphael Mollea40d2f2014-04-24 19:13:47 -0700438 if [[ $USE_HOST_OS ]]; then
439 # parse the Archive.Host/Jvm info from the source.props if present
440 MAP=$(parse_attributes "$PROPS" ${ATTRS_ARCHIVE[@]})
441 # Always generate host-os if not present
442 if [[ "${MAP/ host-os /}" == "$MAP" ]]; then
443 MAP="$MAP host-os $OS"
444 fi
445 output_attributes "archive" "$OUT" $MAP
446 fi
447 echo " </sdk:archive>" >> "$OUT"
Raphael48023782011-02-23 16:46:42 -0800448
449 # Skip to next arch/zip entry.
450 # If not a valid OS, close the archives/package nodes.
451 OS=$(check_enum "$1" $OSES)
452
453 if [[ ! "$OS" ]]; then
454 echo " </sdk:archives>" >> "$OUT"
Raphael Moll3d308aa2011-10-01 23:44:08 -0700455 echo " </sdk:${ELEMENT}>" >> "$OUT"
Raphael48023782011-02-23 16:46:42 -0800456 fi
457 done
458
459done
460
461# Generate XML footer
462echo "</sdk:$ROOT>" >> "$OUT"
463
464echo "## Validate XML against schema"
465xmllint --schema $SCHEMA "$OUT"
Raphael Moll9ca69cf2013-02-12 13:48:39 -0800466