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 #pylint: disable=import-error 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( 58 lib_path) or os.path.exists(lib64_path) or os.path.islink( 59 lib64_path) 60 61 installed_libraries = [lib for lib in libraries if IsInLibPath(lib)] 62 for item in installed_libraries: 63 if item not in getattr(pb, 'provideLibs'): 64 getattr(pb, 'provideLibs').append(item) 65 with open(args.output, 'wb') as f: 66 f.write(pb.SerializeToString()) 67 68 69def Append(args): 70 pb = linker_config_pb2.LinkerConfig() 71 with open(args.source, 'rb') as f: 72 pb.ParseFromString(f.read()) 73 74 if getattr(type(pb), 75 args.key).DESCRIPTOR.label == FieldDescriptor.LABEL_REPEATED: 76 for value in args.value.split(): 77 getattr(pb, args.key).append(value) 78 else: 79 setattr(pb, args.key, args.value) 80 81 with open(args.output, 'wb') as f: 82 f.write(pb.SerializeToString()) 83 84 85def Merge(args): 86 pb = linker_config_pb2.LinkerConfig() 87 for other in args.input: 88 with open(other, 'rb') as f: 89 pb.MergeFromString(f.read()) 90 91 with open(args.out, 'wb') as f: 92 f.write(pb.SerializeToString()) 93 94 95def GetArgParser(): 96 parser = argparse.ArgumentParser() 97 subparsers = parser.add_subparsers() 98 99 parser_proto = subparsers.add_parser( 100 'proto', 101 help='Convert the input JSON configuration file into protobuf.') 102 parser_proto.add_argument( 103 '-s', 104 '--source', 105 required=True, 106 type=str, 107 help='Source linker configuration file in JSON.') 108 parser_proto.add_argument( 109 '-o', 110 '--output', 111 required=True, 112 type=str, 113 help='Target path to create protobuf file.') 114 parser_proto.set_defaults(func=Proto) 115 116 print_proto = subparsers.add_parser( 117 'print', help='Print configuration in human-readable text format.') 118 print_proto.add_argument( 119 '-s', 120 '--source', 121 required=True, 122 type=str, 123 help='Source linker configuration file in protobuf.') 124 print_proto.set_defaults(func=Print) 125 126 system_provide_libs = subparsers.add_parser( 127 'systemprovide', 128 help='Append system provide libraries into the configuration.') 129 system_provide_libs.add_argument( 130 '-s', 131 '--source', 132 required=True, 133 type=str, 134 help='Source linker configuration file in protobuf.') 135 system_provide_libs.add_argument( 136 '-o', 137 '--output', 138 required=True, 139 type=str, 140 help='Target linker configuration file to write in protobuf.') 141 system_provide_libs.add_argument( 142 '--value', 143 required=True, 144 type=str, 145 help='Values of the libraries to append. If there are more than one ' 146 'it should be separated by empty space' 147 ) 148 system_provide_libs.add_argument( 149 '--system', required=True, type=str, help='Path of the system image.') 150 system_provide_libs.set_defaults(func=SystemProvide) 151 152 append = subparsers.add_parser( 153 'append', help='Append value(s) to given key.') 154 append.add_argument( 155 '-s', 156 '--source', 157 required=True, 158 type=str, 159 help='Source linker configuration file in protobuf.') 160 append.add_argument( 161 '-o', 162 '--output', 163 required=True, 164 type=str, 165 help='Target linker configuration file to write in protobuf.') 166 append.add_argument('--key', required=True, type=str, help='.') 167 append.add_argument( 168 '--value', 169 required=True, 170 type=str, 171 help='Values of the libraries to append. If there are more than one' 172 'it should be separated by empty space' 173 ) 174 append.set_defaults(func=Append) 175 176 append = subparsers.add_parser('merge', help='Merge configurations') 177 append.add_argument( 178 '-o', 179 '--out', 180 required=True, 181 type=str, 182 help='Output linker configuration file to write in protobuf.') 183 append.add_argument( 184 '-i', 185 '--input', 186 nargs='+', 187 type=str, 188 help='Linker configuration files to merge.') 189 append.set_defaults(func=Merge) 190 191 return parser 192 193 194def main(): 195 args = GetArgParser().parse_args() 196 args.func(args) 197 198 199if __name__ == '__main__': 200 main() 201