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 "sandbox-ns-flags" : [], 35 "mount-paths" : [], 36 "symbol-links": [], 37 "flags-point" : [] 38 }], 39 "app-resources" : [{ 40 "sandbox-root" : "/mnt/sandbox/<currentUserId>/<PackageName>", 41 "mount-paths" : [], 42 "flags-point" : [], 43 "symbol-links" : [] 44 }] 45 }], 46 "individual" : [{}], 47 "permission" :[{}] 48} 49''' 50#only string in list 51 52def _merge_list(origin, new): 53 if origin is None or new is None: 54 return 55 for data1 in new: 56 if data1 not in origin: 57 origin.append(data1) 58 59def _is_same_data(data1, data2, keys): 60 for key in keys: 61 if data1.get(key) != data2.get(key): 62 return False 63 return True 64 65#for object in list 66 67def _handle_same_array(data1, data2): 68 for field in ["sandbox-root", "sandbox-path", "check-action-status", "fs-type", "link-name"]: 69 if data1.get(field) is not None: 70 data2[field] = data1[field] 71 72 for field in ["sandbox-flags"]: # by list merger 73 item = data1.get(field) 74 if item is not None and len(item) > 0: 75 _merge_list(data2[field], item) 76 77def _merge_scope_array(origin, new, keys): 78 for data1 in new: 79 found = False 80 for data2 in origin: 81 if _is_same_data(data1, data2, keys): 82 found = True 83 _handle_same_array(data1, data2) 84 break 85 if not found: 86 origin.append(data1) 87 88def _handle_same_data(data1, data2, field_infos): 89 for field in ["sandbox-root"]: 90 if data1.get(field) is not None: 91 data2[field] = data1[field] 92 93 # for array 94 for name, keys in field_infos.items(): 95 item = data1.get(name) 96 if item is not None and len(item) > 0: 97 _merge_scope_array(data2[field], item, keys) 98 99def _merge_scope_flags_point(origin, new): 100 field_infos = { 101 "mount-paths": ["src-path"] 102 } 103 for data1 in new: 104 found = False 105 for data2 in origin: 106 if _is_same_data(data1, data2, ["flags"]): 107 found = True 108 _handle_same_data(data1, data2, field_infos) 109 break 110 111 if not found: 112 origin.append(data1) 113 114def _merge_scope_app(origin, new): 115 field_infos = { 116 "mount-paths": ["src-path"], 117 "symbol-links": ["target-name"] 118 } 119 # normal filed 120 for k in ["sandbox-root", "sandbox-switch", "gids"]: 121 if new[0].get(k) is not None: 122 origin[0][k] = new[0].get(k) 123 124 # for flags-point 125 flags_points = new[0].get("flags-point") 126 if flags_points: 127 _merge_scope_flags_point(origin[0]["flags-point"], flags_points) 128 129 # for array 130 for name, keys in field_infos.items(): 131 item = new[0].get(name) 132 if item is not None and len(item) > 0: 133 _merge_scope_array(origin[0].get(name), item, keys) 134 135def _merge_scope_individual(origin, new): 136 for k, v in new.items(): 137 if k not in origin: 138 origin[k] = v 139 else: 140 _merge_scope_app(origin[k], v) 141 142 143def _merge_scope_permission(origin, new): 144 for k, v in new.items(): 145 if k not in origin: 146 origin[k] = v 147 else: 148 _merge_scope_app(origin[k], v) 149 150def _merge_scope_common(origin, new): 151 # 处理 top-sandbox-switch 152 for name in ["top-sandbox-switch"]: 153 if new.get(name) : 154 origin[name] = new.get(name) 155 156 #处理 app-base 157 app = new.get("app-base") 158 if app is not None and len(app) > 0: 159 _merge_scope_app(origin.get("app-base"), app) 160 pass 161 162 #处理 app-resources 163 app = new.get("app-resources") 164 if app is not None and len(app) > 0: 165 _merge_scope_app(origin.get("app-resources"), app) 166 pass 167 168def parse_args(args): 169 args = build_utils.expand_file_args(args) 170 parser = optparse.OptionParser() 171 build_utils.add_depfile_option(parser) 172 parser.add_option('--output', help='fixed sandbox configure file') 173 parser.add_option('--source-file', help='source para file') 174 parser.add_option('--patterns', action="append", 175 type="string", dest="patterns", help='replace string patterns like libpath:lib64') 176 parser.add_option('--extra_sandbox_cfg', action="append", 177 type="string", dest="extra_sandbox_cfgs", help='extra sandbox') 178 179 options, _ = parser.parse_args(args) 180 return options 181 182def __substitude_contents(options, source_file): 183 with open(source_file, "r") as f: 184 contents = f.read() 185 if not options.patterns: 186 return json.loads(contents) 187 for pattern in options.patterns: 188 parts = pattern.split(":") 189 contents = contents.replace("{%s}" % parts[0], parts[1]) 190 return json.loads(contents) 191 192def _get_json_list(options): 193 data_list = [] 194 #decode source file 195 contents = __substitude_contents(options, options.source_file) 196 if contents : 197 data_list.append(contents) 198 199 if options.extra_sandbox_cfgs is None: 200 return data_list 201 202 #decode extra file 203 for sandbox_cfg in options.extra_sandbox_cfgs: 204 contents = __substitude_contents(options, sandbox_cfg) 205 if contents : 206 data_list.append(contents) 207 return data_list 208 209def fix_sandbox_config_file(options): 210 data_list = _get_json_list(options) 211 #decode template 212 origin_json = json.loads(APP_SANDBOX_DEFAULT) 213 214 for data in data_list: 215 # 处理common 216 common = data.get("common") 217 if common is not None and len(common) > 0: 218 _merge_scope_common(origin_json.get("common")[0], common[0]) 219 220 #处理individual 221 individuals = data.get("individual") 222 if individuals is not None and len(individuals) > 0: 223 _merge_scope_individual(origin_json.get("individual")[0], individuals[0]) 224 pass 225 226 # 处理permission 227 permission = data.get("permission") 228 if permission is not None and len(permission) > 0: 229 _merge_scope_permission(origin_json.get("permission")[0], permission[0]) 230 231 # dump json to output 232 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC 233 modes = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP 234 with os.fdopen(os.open(options.output, flags, modes), 'w') as f: 235 f.write(json.dumps(origin_json, ensure_ascii=False, indent=2)) 236 237def main(args): 238 options = parse_args(args) 239 depfile_deps = ([options.source_file]) 240 fix_sandbox_config_file(options) 241 build_utils.write_depfile(options.depfile, options.output, depfile_deps, add_pydeps=False) 242 243if __name__ == '__main__': 244 sys.exit(main(sys.argv[1:])) 245