1#!/usr/bin/env python 2# 3# Copyright (C) 2020 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16""" A tool to convert json file into pb with linker config format.""" 17 18import argparse 19import collections 20import json 21import os 22 23import linker_config_pb2 24from google.protobuf.descriptor import FieldDescriptor 25from google.protobuf.json_format import ParseDict 26from google.protobuf.text_format import MessageToString 27 28 29def Proto(args): 30 json_content = '' 31 with open(args.source) as f: 32 for line in f: 33 if not line.lstrip().startswith('//'): 34 json_content += line 35 obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict) 36 pb = ParseDict(obj, linker_config_pb2.LinkerConfig()) 37 with open(args.output, 'wb') as f: 38 f.write(pb.SerializeToString()) 39 40 41def Print(args): 42 with open(args.source, 'rb') as f: 43 pb = linker_config_pb2.LinkerConfig() 44 pb.ParseFromString(f.read()) 45 print(MessageToString(pb)) 46 47 48def SystemProvide(args): 49 pb = linker_config_pb2.LinkerConfig() 50 with open(args.source, 'rb') as f: 51 pb.ParseFromString(f.read()) 52 libraries = args.value.split() 53 54 def IsInLibPath(lib_name): 55 lib_path = os.path.join(args.system, 'lib', lib_name) 56 lib64_path = os.path.join(args.system, 'lib64', lib_name) 57 return os.path.exists(lib_path) or os.path.islink(lib_path) or os.path.exists(lib64_path) or os.path.islink(lib64_path) 58 59 installed_libraries = list(filter(IsInLibPath, libraries)) 60 for item in installed_libraries: 61 if item not in getattr(pb, 'provideLibs'): 62 getattr(pb, 'provideLibs').append(item) 63 with open(args.output, 'wb') as f: 64 f.write(pb.SerializeToString()) 65 66 67def Append(args): 68 pb = linker_config_pb2.LinkerConfig() 69 with open(args.source, 'rb') as f: 70 pb.ParseFromString(f.read()) 71 72 if getattr(type(pb), args.key).DESCRIPTOR.label == FieldDescriptor.LABEL_REPEATED: 73 for value in args.value.split(): 74 getattr(pb, args.key).append(value) 75 else: 76 setattr(pb, args.key, args.value) 77 78 with open(args.output, 'wb') as f: 79 f.write(pb.SerializeToString()) 80 81def Merge(args): 82 pb = linker_config_pb2.LinkerConfig() 83 for other in args.input: 84 with open(other, 'rb') as f: 85 pb.MergeFromString(f.read()) 86 87 with open(args.out, 'wb') as f: 88 f.write(pb.SerializeToString()) 89 90def GetArgParser(): 91 parser = argparse.ArgumentParser() 92 subparsers = parser.add_subparsers() 93 94 parser_proto = subparsers.add_parser( 95 'proto', help='Convert the input JSON configuration file into protobuf.') 96 parser_proto.add_argument( 97 '-s', 98 '--source', 99 required=True, 100 type=str, 101 help='Source linker configuration file in JSON.') 102 parser_proto.add_argument( 103 '-o', 104 '--output', 105 required=True, 106 type=str, 107 help='Target path to create protobuf file.') 108 parser_proto.set_defaults(func=Proto) 109 110 print_proto = subparsers.add_parser( 111 'print', help='Print configuration in human-readable text format.') 112 print_proto.add_argument( 113 '-s', 114 '--source', 115 required=True, 116 type=str, 117 help='Source linker configuration file in protobuf.') 118 print_proto.set_defaults(func=Print) 119 120 system_provide_libs = subparsers.add_parser( 121 'systemprovide', help='Append system provide libraries into the configuration.') 122 system_provide_libs.add_argument( 123 '-s', 124 '--source', 125 required=True, 126 type=str, 127 help='Source linker configuration file in protobuf.') 128 system_provide_libs.add_argument( 129 '-o', 130 '--output', 131 required=True, 132 type=str, 133 help='Target linker configuration file to write in protobuf.') 134 system_provide_libs.add_argument( 135 '--value', 136 required=True, 137 type=str, 138 help='Values of the libraries to append. If there are more than one it should be separated by empty space') 139 system_provide_libs.add_argument( 140 '--system', 141 required=True, 142 type=str, 143 help='Path of the system image.') 144 system_provide_libs.set_defaults(func=SystemProvide) 145 146 append = subparsers.add_parser( 147 'append', help='Append value(s) to given key.') 148 append.add_argument( 149 '-s', 150 '--source', 151 required=True, 152 type=str, 153 help='Source linker configuration file in protobuf.') 154 append.add_argument( 155 '-o', 156 '--output', 157 required=True, 158 type=str, 159 help='Target linker configuration file to write in protobuf.') 160 append.add_argument( 161 '--key', 162 required=True, 163 type=str, 164 help='.') 165 append.add_argument( 166 '--value', 167 required=True, 168 type=str, 169 help='Values of the libraries to append. If there are more than one it should be separated by empty space') 170 append.set_defaults(func=Append) 171 172 append = subparsers.add_parser( 173 'merge', help='Merge configurations') 174 append.add_argument( 175 '-o', 176 '--out', 177 required=True, 178 type=str, 179 help='Ouptut linker configuration file to write in protobuf.') 180 append.add_argument( 181 '-i', 182 '--input', 183 nargs='+', 184 type=str, 185 help='Linker configuration files to merge.') 186 append.set_defaults(func=Merge) 187 188 return parser 189 190 191def main(): 192 args = GetArgParser().parse_args() 193 args.func(args) 194 195 196if __name__ == '__main__': 197 main() 198