• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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