Move gen-kotlin-build-file.sh to python

Kotlin common multiplatform sources support will require more
complexity in gen-kotlin-build-file.sh, move it to python instead.

Test: m checkbuild
Change-Id: I02312160ad781877f1fec971168331c0dcecf136
This commit is contained in:
Colin Cross
2020-06-25 17:12:28 -07:00
parent 8ba7d47bba
commit 9b1aa0cb86
7 changed files with 201 additions and 147 deletions

View File

@@ -152,5 +152,17 @@ python_test_host {
python_binary_host {
name: "lint-project-xml",
main: "lint-project-xml.py",
srcs: ["lint-project-xml.py"],
srcs: [
"lint-project-xml.py",
"ninja_rsp.py",
],
}
python_binary_host {
name: "gen-kotlin-build-file.py",
main: "gen-kotlin-build-file.py",
srcs: [
"gen-kotlin-build-file.py",
"ninja_rsp.py",
],
}

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
#
# Copyright 2018 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Generates kotlinc module xml file to drive kotlinc
import argparse
import os
from ninja_rsp import NinjaRspFileReader
def parse_args():
"""Parse commandline arguments."""
def convert_arg_line_to_args(arg_line):
for arg in arg_line.split():
if arg.startswith('#'):
return
if not arg.strip():
continue
yield arg
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.convert_arg_line_to_args = convert_arg_line_to_args
parser.add_argument('--out', dest='out',
help='file to which the module.xml contents will be written.')
parser.add_argument('--classpath', dest='classpath', action='append', default=[],
help='classpath to pass to kotlinc.')
parser.add_argument('--name', dest='name',
help='name of the module.')
parser.add_argument('--out_dir', dest='out_dir',
help='directory to which kotlinc will write output files.')
parser.add_argument('--srcs', dest='srcs', action='append', default=[],
help='file containing whitespace separated list of source files.')
parser.add_argument('--common_srcs', dest='common_srcs', action='append', default=[],
help='file containing whitespace separated list of common multiplatform source files.')
return parser.parse_args()
def main():
"""Program entry point."""
args = parse_args()
if not args.out:
raise RuntimeError('--out argument is required')
if not args.name:
raise RuntimeError('--name argument is required')
with open(args.out, 'w') as f:
# Print preamble
f.write('<modules>\n')
f.write(' <module name="%s" type="java-production" outputDir="%s">\n' % (args.name, args.out_dir or ''))
# Print classpath entries
for c in args.classpath:
for entry in c.split(':'):
path = os.path.abspath(entry)
f.write(' <classpath path="%s"/>\n' % path)
# For each rsp file, print source entries
for rsp_file in args.srcs:
for src in NinjaRspFileReader(rsp_file):
path = os.path.abspath(src)
if src.endswith('.java'):
f.write(' <javaSourceRoots path="%s"/>\n' % path)
elif src.endswith('.kt'):
f.write(' <sources path="%s"/>\n' % path)
else:
raise RuntimeError('unknown source file type %s' % file)
for rsp_file in args.common_srcs:
for src in NinjaRspFileReader(rsp_file):
path = os.path.abspath(src)
f.write(' <sources path="%s"/>\n' % path)
f.write(' <commonSources path="%s"/>\n' % path)
f.write(' </module>\n')
f.write('</modules>\n')
if __name__ == '__main__':
main()

View File

@@ -1,73 +0,0 @@
#!/bin/bash -e
# Copyright 2018 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Generates kotlinc module xml file to standard output based on rsp files
if [[ -z "$1" ]]; then
echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
exit 1
fi
# Classpath variable has a tendency to be prefixed by "-classpath", remove it.
if [[ $1 == "-classpath" ]]; then
shift
fi;
classpath=$1
name=$2
out_dir=$3
shift 3
# Path in the build file may be relative to the build file, we need to make them
# absolute
prefix="$(pwd)"
get_abs_path () {
local file="$1"
if [[ "${file:0:1}" == '/' ]] ; then
echo "${file}"
else
echo "${prefix}/${file}"
fi
}
# Print preamble
echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
# Print classpath entries
for file in $(echo "$classpath" | tr ":" "\n"); do
path="$(get_abs_path "$file")"
echo " <classpath path=\"${path}\"/>"
done
# For each rsp file, print source entries
while (( "$#" )); do
for file in $(cat "$1"); do
path="$(get_abs_path "$file")"
if [[ $file == *.java ]]; then
echo " <javaSourceRoots path=\"${path}\"/>"
elif [[ $file == *.kt ]]; then
echo " <sources path=\"${path}\"/>"
else
echo "Unknown source file type ${file}"
exit 1
fi
done
shift
done
echo "</module></modules>"

View File

@@ -19,6 +19,8 @@
import argparse
from ninja_rsp import NinjaRspFileReader
def check_action(check_type):
"""
@@ -91,74 +93,6 @@ def parse_args():
return parser.parse_args()
class NinjaRspFileReader:
"""
Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
non-standard character by surrounding the whole entry with single quotes, and then replacing
any single quotes in the entry with the escape sequence '\''.
"""
def __init__(self, filename):
self.f = open(filename, 'r')
self.r = self.character_reader(self.f)
def __iter__(self):
return self
def character_reader(self, f):
"""Turns a file into a generator that returns one character at a time."""
while True:
c = f.read(1)
if c:
yield c
else:
return
def __next__(self):
entry = self.read_entry()
if entry:
return entry
else:
raise StopIteration
def read_entry(self):
c = next(self.r, "")
if not c:
return ""
elif c == "'":
return self.read_quoted_entry()
else:
entry = c
for c in self.r:
if c == " " or c == "\n":
break
entry += c
return entry
def read_quoted_entry(self):
entry = ""
for c in self.r:
if c == "'":
# Either the end of the quoted entry, or the beginning of an escape sequence, read the next
# character to find out.
c = next(self.r)
if not c or c == " " or c == "\n":
# End of the item
return entry
elif c == "\\":
# Escape sequence, expect a '
c = next(self.r)
if c != "'":
# Malformed escape sequence
raise "malformed escape sequence %s'\\%s" % (entry, c)
entry += "'"
else:
raise "malformed escape sequence %s'%s" % (entry, c)
else:
entry += c
raise "unterminated quoted entry %s" % entry
def write_project_xml(f, args):
test_attr = "test='true' " if args.test else ""

83
scripts/ninja_rsp.py Normal file
View File

@@ -0,0 +1,83 @@
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""This file reads entries from a Ninja rsp file."""
class NinjaRspFileReader:
"""
Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
non-standard character by surrounding the whole entry with single quotes, and then replacing
any single quotes in the entry with the escape sequence '\''.
"""
def __init__(self, filename):
self.f = open(filename, 'r')
self.r = self.character_reader(self.f)
def __iter__(self):
return self
def character_reader(self, f):
"""Turns a file into a generator that returns one character at a time."""
while True:
c = f.read(1)
if c:
yield c
else:
return
def __next__(self):
entry = self.read_entry()
if entry:
return entry
else:
raise StopIteration
def read_entry(self):
c = next(self.r, "")
if not c:
return ""
elif c == "'":
return self.read_quoted_entry()
else:
entry = c
for c in self.r:
if c == " " or c == "\n":
break
entry += c
return entry
def read_quoted_entry(self):
entry = ""
for c in self.r:
if c == "'":
# Either the end of the quoted entry, or the beginning of an escape sequence, read the next
# character to find out.
c = next(self.r)
if not c or c == " " or c == "\n":
# End of the item
return entry
elif c == "\\":
# Escape sequence, expect a '
c = next(self.r)
if c != "'":
# Malformed escape sequence
raise "malformed escape sequence %s'\\%s" % (entry, c)
entry += "'"
else:
raise "malformed escape sequence %s'%s" % (entry, c)
else:
entry += c
raise "unterminated quoted entry %s" % entry