• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #!/bin/bash
2 #
3 # Generates an SDK Repository XML based on the input files.
4 
5 set -e
6 
7 PROG_DIR=$(dirname $0)
8 
9 TYPES="tool platform-tool platform sample doc add-on"
10 OSES="linux macosx windows any linux-x86 darwin"
11 
12 TMP_DIR=$(mktemp -d -t sdkrepo.tmp.XXXXXXXX)
13 trap "rm -rf $TMP_DIR" EXIT
14 
15 function error() {
16   echo "*** ERROR: " $@
17   usage
18 }
19 
20 function usage() {
21   cat <<EOFU
22 Usage: $0 output.xml xml-schema [type [os zip[:dest]]*...]*
23 where:
24 - type is one of ${TYPES// /, } (or their plural).
25 - os   is one of  ${OSES// /, }.
26 There can be more than one zip for the same type
27 as long as they use different OSes.
28 Zip can be in the form "source:dest" to be renamed on the fly.
29 EOFU
30   exit 1
31 }
32 
33 # Validate the tools we need
34 if [[ ! -x $(which sha1sum) ]]; then
35   error "Missing tool: sha1sum (Linux: apt-get install coreutils; Mac: port install md5sha1sum)"
36 fi
37 
38 # Parse input params
39 OUT="$1"
40 [[ -z "$OUT" ]] && error "Missing output.xml name."
41 shift
42 
43 SCHEMA="$1"
44 [[ ! -f "$SCHEMA" ]] && error "Invalid XML schema name: $SCHEMA."
45 shift
46 
47 # Get XML:NS for SDK from the schema
48 XMLNS=$(sed -n '/xmlns:.*schemas.android.com\/sdk\/android\//s/.*"\(.*\)".*/\1/p' "$SCHEMA")
49 [[ -z "$XMLNS" ]] && error "Failed to find xmlns:sdk in $SCHEMA."
50 echo "## Using xmlns:sdk=$XMLNS"
51 
52 # Get the root element from the schema. This is the first element
53 # which name starts with "sdk-" (e.g. sdk-repository, sdk-addon)
54 ROOT=$(sed -n -e '/xsd:element.*name="sdk-/s/.*name="\(sdk-[^"]*\)".*/\1/p' "$SCHEMA")
55 [[ -z "$ROOT" ]] && error "Failed to find root element in $SCHEMA."
56 echo "## Using root element $ROOT"
57 
58 # Generate XML header
59 cat > "$OUT" <<EOFH
60 <?xml version="1.0"?>
61 <sdk:$ROOT
62     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
63     xmlns:sdk="$XMLNS">
64 EOFH
65 
66 # check_enum value value1 value2 value3...
67 # returns valueN if matched or nothing.
68 function check_enum() {
69   local VALUE="$1"
70   local i
71   shift
72   for i in "$@"; do
73     if [[ "$i" == "$VALUE" ]]; then
74       echo "$VALUE"
75       break;
76     fi
77   done
78 }
79 
80 # Parse all archives.
81 
82 ATTRS=(
83   # for repository packages
84   Pkg.Revision                  revision
85   Pkg.Desc                      description
86   Platform.Version              version
87   AndroidVersion.ApiLevel       api-level
88   AndroidVersion.CodeName       codename
89   Platform.MinToolsRev          min-tools-rev
90   Platform.MinPlatformToolsRev  min-platform-tools-rev
91   Extra.Path                    path
92   Extra.Vendor                  vendor
93   Extra.MinApiLevel             min-api-level
94   Sample.MinApiLevel            min-api-level
95   # for addon packages
96   vendor                        vendor
97   name                          name
98   description                   description
99   api                           api-level
100   version                       revision
101   revision                      revision
102 )
103 
104 function parse_attributes() {
105   local PROPS="$1"
106   shift
107   local RESULT=""
108   local VALUE
109 
110   while [[ "$1" ]]; do
111     # Parse the property, if present. Any space is replaced by @
112     VALUE=$( grep "^$1=" "$PROPS" | cut -d = -f 2 | tr ' ' '@' | tr -d '\r' )
113     if [[ -n "$VALUE" ]]; then
114       RESULT="$RESULT $2 $VALUE"
115     fi
116     shift
117     shift
118   done
119 
120   echo "$RESULT"
121 }
122 
123 function output_attributes() {
124   local OUT="$1"
125   shift
126   local KEY VALUE
127 
128   while [[ "$1" ]]; do
129     KEY="$1"
130     VALUE="${2//@/ }"
131     echo "        <sdk:$KEY>$VALUE</sdk:$KEY>" >> "$OUT"
132     shift
133     shift
134   done
135 }
136 
137 while [[ -n "$1" ]]; do
138   # Process archives.
139   # First we expect a type. For conveniency the type can be plural.
140   TYPE=$(check_enum "${1%%s}" $TYPES)
141   [[ -z $TYPE ]] && error "Unknown archive type '$1'."
142   shift
143 
144   MAP=""
145   FIRST="1"
146   LIBS_XML=""
147 
148   OS=$(check_enum "$1" $OSES)
149   while [[ $OS ]]; do
150     shift
151     [[ $OS == "linux-x86" ]] && OS=linux
152     [[ $OS == "darwin" ]] && OS=macosx
153 
154     SRC="$1"
155     DST="$1"
156     if [[ "${SRC/:/}" != "$SRC" ]]; then
157       DST="${SRC/*:/}"
158       SRC="${SRC/:*/}"
159     fi
160     [[ ! -f "$SRC" ]] && error "Missing file for archive $TYPE/$OS: $SRC"
161     shift
162 
163     # Depending on the archive type, we need a number of attributes
164     # from the source.properties or the manifest.ini. We'll take
165     # these attributes from the first zip found.
166     #
167     # What we need vs. which package uses it:
168     # - description             all
169     # - revision                all
170     # - version                 platform
171     # - api-level               platform sample doc add-on
172     # - codename                platform sample doc add-on
173     # - min-tools-rev           platform sample
174     # - min-platform-tools-rev  tool
175     # - min-api-level           extra
176     # - vendor                  extra               add-on
177     # - path                    extra
178     #
179     # We don't actually validate here.
180     # Just take whatever is defined and put it in the XML.
181     # XML validation against the schema will be done at the end.
182 
183     if [[ $FIRST ]]; then
184       FIRST=""
185 
186       if unzip -t "$SRC" | grep -qs "source.properties" ; then
187         # Extract Source Properties
188         # unzip: -j=flat (no dirs), -q=quiet, -o=overwrite, -d=dest dir
189         unzip -j -q -o -d "$TMP_DIR" "$SRC" "*/source.properties"
190         PROPS="$TMP_DIR/source.properties"
191 
192       elif unzip -t "$SRC" | grep -qs "manifest.ini" ; then
193         unzip -j -q -o -d "$TMP_DIR" "$SRC" "*/manifest.ini"
194         PROPS="$TMP_DIR/manifest.ini"
195 
196         # Parse the libs for an addon and generate the <libs> node
197         # libraries is a semi-colon separated list
198         LIBS=$(parse_attributes "$PROPS" "libraries")
199         LIBS_XML="        <sdk:libs>"
200         for LIB in ${LIBS//;/ }; do
201           LIBS_XML="$LIBS_XML
202            <sdk:lib><sdk:name>$LIB</sdk:name></sdk:lib>"
203         done
204         LIBS_XML="$LIBS_XML
205         </sdk:libs>"
206 
207       else
208         error "Failed to find source.properties or manifest.ini in $SRC"
209       fi
210 
211       [[ ! -f $PROPS ]] && error "Failed to extract $PROPS from $SRC"
212       MAP=$(parse_attributes "$PROPS" ${ATTRS[@]})
213 
214       # Time to generate the XML for the package
215       echo "    <sdk:${TYPE}>" >> "$OUT"
216       output_attributes "$OUT" $MAP
217       [[ -n "$LIBS_XML" ]] && echo "$LIBS_XML" >> "$OUT"
218       echo "        <sdk:archives>" >> "$OUT"
219     fi
220 
221     # Generate archive info
222     echo "## Add $TYPE/$OS archive $SRC"
223     if [[ $( uname ) == "Darwin" ]]; then
224       SIZE=$( stat -f %z "$SRC" )
225     else
226       SIZE=$( stat -c %s "$SRC" )
227     fi
228     SHA1=$( sha1sum "$SRC" | cut -d " "  -f 1 )
229 
230     cat >> "$OUT" <<EOFA
231             <sdk:archive os='$OS' arch='any'>
232                 <sdk:size>$SIZE</sdk:size>
233                 <sdk:checksum type='sha1'>$SHA1</sdk:checksum>
234                 <sdk:url>$DST</sdk:url>
235             </sdk:archive>
236 EOFA
237 
238     # Skip to next arch/zip entry.
239     # If not a valid OS, close the archives/package nodes.
240     OS=$(check_enum "$1" $OSES)
241 
242     if [[ ! "$OS" ]]; then
243       echo "        </sdk:archives>" >> "$OUT"
244       echo "    </sdk:${TYPE}>" >> "$OUT"
245     fi
246   done
247 
248 done
249 
250 # Generate XML footer
251 echo "</sdk:$ROOT>" >> "$OUT"
252 
253 echo "## Validate XML against schema"
254 xmllint --schema $SCHEMA "$OUT"
255