Skip to content

Commit

Permalink
Add a script to mass-update cluster revisions in our .zap files. (#26514
Browse files Browse the repository at this point in the history
)

We're going to need to do this for several clusters, and doing it by hand is
really painful.

Also fixes a bug in zap_convert_all.py when run in non-parallel mode.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Jul 24, 2023
1 parent a345e6e commit 1254136
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 1 deletion.
154 changes: 154 additions & 0 deletions scripts/tools/zap/update_cluster_revisions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import argparse
import json
import logging
import multiprocessing
import os
import subprocess
import sys
from pathlib import Path

CHIP_ROOT_DIR = os.path.realpath(
os.path.join(os.path.dirname(__file__), '../../..'))


def getTargets():
ROOTS_TO_SEARCH = [
'./examples',
'./src/controller/data_model',
'./scripts/tools/zap/tests/inputs',
]

targets = []
for root in ROOTS_TO_SEARCH:
for filepath in Path(root).rglob('*.zap'):
targets.append(filepath)

return targets


def checkPythonVersion():
if sys.version_info[0] < 3:
print('Must use Python 3. Current version is ' +
str(sys.version_info[0]))
exit(1)


def runArgumentsParser():
parser = argparse.ArgumentParser(
description='Update the ClusterRevision for a chosen cluster in all .zap files')
parser.add_argument('--cluster-id', default=None, action='store',
help='The id of the cluster, as hex, for which the cluster revision should be updated.')
parser.add_argument('--new-revision', default=None, action='store',
help='The new cluster revision as a decimal integer')
parser.add_argument('--old-revision', default=None, action='store',
help='If set, only clusters with this old revision will be updated. This is a decimal integer.')
parser.add_argument('--dry-run', default=False, action='store_true',
help="Don't do any generation, just log what .zap files would be updated (default: False)")
parser.add_argument('--parallel', action='store_true')
parser.add_argument('--no-parallel', action='store_false', dest='parallel')
parser.set_defaults(parallel=True)

args = parser.parse_args()

if args.cluster_id is None:
logging.error("Must have a cluster id")
sys.exit(1)

if args.new_revision is None:
logging.error("Must have a new cluster revision")
sys.exit(1)

args.cluster_id = int(args.cluster_id, 16)

return args


def isClusterRevisionAttribute(attribute):
if attribute['mfgCode'] is not None:
return False

if attribute['code'] != 0xFFFD:
return False

if attribute['name'] != "ClusterRevision":
logging.error("Attribute has ClusterRevision id but wrong name")
return False

return True


def updateOne(item):
"""
Helper method that may be run in parallel to update a single target.
"""
(args, target) = item

with open(target, "r") as file:
data = json.load(file)

for endpointType in data['endpointTypes']:
for cluster in endpointType['clusters']:
if cluster['mfgCode'] is None and cluster['code'] == args.cluster_id:
for attribute in cluster['attributes']:
if isClusterRevisionAttribute(attribute):
if args.old_revision is None or attribute['defaultValue'] == args.old_revision:
attribute['defaultValue'] = args.new_revision

with open(target, "w") as file:
json.dump(data, file)

# Now run convert.py on the file to have ZAP reformat it however it likes.
subprocess.check_call(['./scripts/tools/zap/convert.py', target])


def main():
checkPythonVersion()

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(name)s %(levelname)-7s %(message)s'
)

args = runArgumentsParser()

os.chdir(CHIP_ROOT_DIR)

targets = getTargets()

if args.dry_run:
for target in targets:
print(f"Will try to update: {target}")
sys.exit(0)

items = [(args, target) for target in targets]

if args.parallel:
# Ensure each zap run is independent
os.environ['ZAP_TEMPSTATE'] = '1'
with multiprocessing.Pool() as pool:
for _ in pool.imap_unordered(updateOne, items):
pass
else:
for item in items:
updateOne(item)


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion scripts/tools/zap_convert_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def main():
pass
else:
for target in targets:
generateOne(target)
convertOne(target)


if __name__ == '__main__':
Expand Down

0 comments on commit 1254136

Please sign in to comment.