1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2023 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import optparse 17import os 18import sys 19import json 20import stat 21 22sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 23 os.pardir, os.pardir, os.pardir, "build")) 24from scripts.util import build_utils # noqa: E402 25 26#default json 27 28APP_SANDBOX_DEFAULT = ''' 29{ 30 "common" : [{ 31 "top-sandbox-switch": "ON", 32 "app-base" : [{ 33 "sandbox-root" : "/mnt/sandbox/<currentUserId>/<PackageName>", 34 "mount-paths" : [], 35 "symbol-links": [], 36 "flags-point" : [] 37 }], 38 "app-resources" : [{ 39 "sandbox-root" : "/mnt/sandbox/<currentUserId>/<PackageName>", 40 "mount-paths" : [], 41 "flags-point" : [], 42 "symbol-links" : [] 43 }] 44 }], 45 "individual" : [{}], 46 "permission" :[{}] 47} 48''' 49#only string in list 50 51def _merge_list(origin, new): 52 if origin is None or new is None: 53 return 54 for data1 in new: 55 if data1 not in origin: 56 origin.append(data1) 57 58def _is_same_data(data1, data2, keys): 59 for key in keys: 60 if data1.get(key) != data2.get(key): 61 return False 62 return True 63 64#for object in list 65 66def _handle_same_array(data1, data2): 67 for field in ["sandbox-root", "sandbox-path", "check-action-status", "fs-type", "link-name"]: 68 if data1.get(field) is not None: 69 data2[field] = data1[field] 70 71 for field in ["sandbox-flags"]: # by list merger 72 item = data1.get(field) 73 if item is not None and len(item) > 0: 74 _merge_list(data2[field], item) 75 76def _merge_scope_array(origin, new, keys): 77 for data1 in new: 78 found = False 79 for data2 in origin: 80 if _is_same_data(data1, data2, keys): 81 found = True 82 _handle_same_array(data1, data2) 83 break 84 if not found: 85 origin.append(data1) 86 87def _handle_same_data(data1, data2, field_infos): 88 for field in ["sandbox-root"]: 89 if data1.get(field) is not None: 90 data2[field] = data1[field] 91 92 # for array 93 for name, keys in field_infos.items(): 94 item = data1.get(name) 95 if item is not None and len(item) > 0: 96 _merge_scope_array(data2[field], item, keys) 97 98def _merge_scope_flags_point(origin, new): 99 field_infos = { 100 "mount-paths": ["src-path"] 101 } 102 for data1 in new: 103 found = False 104 for data2 in origin: 105 if _is_same_data(data1, data2, ["flags"]): 106 found = True 107 _handle_same_data(data1, data2, field_infos) 108 break 109 110 if not found: 111 origin.append(data1) 112 113def _merge_scope_app(origin, new): 114 field_infos = { 115 "mount-paths": ["src-path"], 116 "symbol-links": ["target-name"] 117 } 118 # normal filed 119 for k in ["sandbox-root", "sandbox-switch", "gids"]: 120 if new[0].get(k) is not None: 121 origin[0][k] = new[0].get(k) 122 123 # for flags-point 124 flags_points = new[0].get("flags-point") 125 if flags_points: 126 _merge_scope_flags_point(origin[0]["flags-point"], flags_points) 127 128 # for array 129 for name, keys in field_infos.items(): 130 item = new[0].get(name) 131 if item is not None and len(item) > 0: 132 _merge_scope_array(origin[0].get(name), item, keys) 133 134def _merge_scope_individual(origin, new): 135 for k, v in new.items(): 136 if k not in origin: 137 origin[k] = v 138 else: 139 _merge_scope_app(origin[k], v) 140 141 142def _merge_scope_permission(origin, new): 143 for k, v in new.items(): 144 if k not in origin: 145 origin[k] = v 146 else: 147 _merge_scope_app(origin[k], v) 148 149def _merge_scope_common(origin, new): 150 # 处理 top-sandbox-switch 151 for name in ["top-sandbox-switch"]: 152 if new.get(name) : 153 origin[name] = new.get(name) 154 155 #处理 app-base 156 app = new.get("app-base") 157 if app is not None and len(app) > 0: 158 _merge_scope_app(origin.get("app-base"), app) 159 pass 160 161 #处理 app-resources 162 app = new.get("app-resources") 163 if app is not None and len(app) > 0: 164 _merge_scope_app(origin.get("app-resources"), app) 165 pass 166 167def parse_args(args): 168 args = build_utils.expand_file_args(args) 169 parser = optparse.OptionParser() 170 build_utils.add_depfile_option(parser) 171 parser.add_option('--output', help='fixed sandbox configure file') 172 parser.add_option('--source-file', help='source para file') 173 parser.add_option('--patterns', action="append", 174 type="string", dest="patterns", help='replace string patterns like libpath:lib64') 175 parser.add_option('--extra_sandbox_cfg', action="append", 176 type="string", dest="extra_sandbox_cfgs", help='extra sandbox') 177 178 options, _ = parser.parse_args(args) 179 return options 180 181def __substitude_contents(options, source_file): 182 with open(source_file, "r") as f: 183 contents = f.read() 184 if not options.patterns: 185 return json.loads(contents) 186 for pattern in options.patterns: 187 parts = pattern.split(":") 188 contents = contents.replace("{%s}" % parts[0], parts[1]) 189 return json.loads(contents) 190 191def _get_json_list(options): 192 data_list = [] 193 #decode source file 194 contents = __substitude_contents(options, options.source_file) 195 if contents : 196 data_list.append(contents) 197 198 if options.extra_sandbox_cfgs is None: 199 return data_list 200 201 #decode extra file 202 for sandbox_cfg in options.extra_sandbox_cfgs: 203 contents = __substitude_contents(options, sandbox_cfg) 204 if contents : 205 data_list.append(contents) 206 return data_list 207 208def fix_sandbox_config_file(options): 209 data_list = _get_json_list(options) 210 #decode template 211 origin_json = json.loads(APP_SANDBOX_DEFAULT) 212 213 for data in data_list: 214 # 处理common 215 common = data.get("common") 216 if common is not None and len(common) > 0: 217 _merge_scope_common(origin_json.get("common")[0], common[0]) 218 219 #处理individual 220 individuals = data.get("individual") 221 if individuals is not None and len(individuals) > 0: 222 _merge_scope_individual(origin_json.get("individual")[0], individuals[0]) 223 pass 224 225 # 处理permission 226 permission = data.get("permission") 227 if permission is not None and len(permission) > 0: 228 _merge_scope_permission(origin_json.get("permission")[0], permission[0]) 229 230 # dump json to output 231 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC 232 modes = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP 233 with os.fdopen(os.open(options.output, flags, modes), 'w') as f: 234 f.write(json.dumps(origin_json, ensure_ascii=False, indent=2)) 235 236def main(args): 237 options = parse_args(args) 238 depfile_deps = ([options.source_file]) 239 fix_sandbox_config_file(options) 240 build_utils.write_depfile(options.depfile, options.output, depfile_deps, add_pydeps=False) 241 242if __name__ == '__main__': 243 sys.exit(main(sys.argv[1:])) 244