| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- #!/usr/bin/env python3
- # Copyright (c) 2023 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.
- # This automates ZAP version changes as the zap version is repeated
- # in many places
- import logging
- import os
- import re
- import sys
- from enum import Flag, auto
- import click
- import coloredlogs
- # Supported log levels, mapping string values required for argument
- # parsing into logging constants
- __LOG_LEVELS__ = {
- 'debug': logging.DEBUG,
- 'info': logging.INFO,
- 'warn': logging.WARN,
- 'fatal': logging.FATAL,
- }
- # A version is of the form: v2023.01.09-nightly
- #
- # At this time we hard-code nightly however we may need to figure out a more
- # generic version string once we stop using nightly builds
- ZAP_VERSION_RE = re.compile(r'v(\d\d\d\d)\.(\d\d)\.(\d\d)-nightly')
- # A list of files where ZAP is maintained. You can get a similar list using:
- #
- # rg v2023.01.09-nightly --hidden --no-ignore --files-with-matches
- #
- # Excluding THIS file and excluding anything in .environment (logs)
- #
- # Set as a separate list to not pay the price of a full grep as the list of
- # files is not likely to change often
- USAGE_FILES_DEPENDING_ON_ZAP_VERSION = [
- 'integrations/docker/images/chip-cert-bins/Dockerfile',
- 'scripts/setup/zap.json',
- 'scripts/setup/zap.version',
- ]
- class UpdateChoice(Flag):
- # Usage updates the CI, chip-cert and execution logic. Generally everything
- # that would make use of the updated zap version
- USAGE = auto()
- __UPDATE_CHOICES__ = {
- 'usage': UpdateChoice.USAGE,
- }
- # Apart from the above files which contain an exact ZAP version, the zap
- # execution script contains the mimimal zap execution version, which generally
- # we also enforce to be the current version.
- #
- # That line is of the form "MIN_ZAP_VERSION = '2021.1.9'"
- ZAP_EXECUTION_SCRIPT = 'scripts/tools/zap/zap_execution.py'
- ZAP_EXECUTION_MIN_RE = re.compile(
- r'(MIN_ZAP_VERSION = .)(\d\d\d\d\.\d\d?\.\d\d?)(.)')
- CHIP_ROOT_DIR = os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..', '..'))
- @click.command()
- @click.option(
- '--log-level',
- default='INFO',
- type=click.Choice(__LOG_LEVELS__.keys(), case_sensitive=False),
- help='Determines the verbosity of script output.')
- @click.option(
- '--update',
- default='usage',
- type=click.Choice(__UPDATE_CHOICES__.keys(), case_sensitive=False),
- help='What to update: usage (only choice currently).')
- @click.option(
- '--new-version',
- default=None,
- help='What version of ZAP to update to (like "v2023.01.09-nightly". If not set, versions will just be printed.')
- def version_update(log_level, update, new_version):
- coloredlogs.install(level=__LOG_LEVELS__[
- log_level], fmt='%(asctime)s %(levelname)-7s %(message)s')
- update = __UPDATE_CHOICES__[update]
- if new_version:
- parsed = ZAP_VERSION_RE.match(new_version)
- if not parsed:
- logging.error(
- f"Version '{new_version}' does not seem to parse as a ZAP VERSION")
- sys.exit(1)
- # get the numeric version for zap_execution
- #
- # This makes every group element (date section) to a base 10 integer,
- # so for 'v2023.01.11-nightly' this gets (2023, 1, 11)
- zap_min_version = tuple(map(lambda x: int(x, 10), parsed.groups()))
- files_to_update = []
- if UpdateChoice.USAGE in update:
- files_to_update += USAGE_FILES_DEPENDING_ON_ZAP_VERSION
- for name in files_to_update:
- with open(os.path.join(CHIP_ROOT_DIR, name), 'rt') as f:
- file_data = f.read()
- # Write out any matches. Note that we only write distinct matches as
- # zap versions may occur several times in the same file
- found_versions = set()
- for m in ZAP_VERSION_RE.finditer(file_data):
- version = file_data[m.start():m.end()]
- if version not in found_versions:
- logging.info('%s currently used in %s', version, name)
- found_versions.add(version)
- # If we update, perform the update
- if new_version:
- search_pos = 0
- need_replace = False
- m = ZAP_VERSION_RE.search(file_data, search_pos)
- while m:
- version = file_data[m.start():m.end()]
- if version == new_version:
- logging.warning(
- "Nothing to replace. Version already %s", version)
- break
- file_data = file_data[:m.start()] + \
- new_version + file_data[m.end():]
- need_replace = True
- search_pos = m.end() # generally ok since our versions are fixed length
- m = ZAP_VERSION_RE.search(file_data, search_pos)
- if need_replace:
- logging.info('Replacing with version %s in %s',
- new_version, name)
- with open(os.path.join(CHIP_ROOT_DIR, name), 'wt') as f:
- f.write(file_data)
- # Finally, check zap_execution for any version update
- if UpdateChoice.USAGE in update:
- with open(os.path.join(CHIP_ROOT_DIR, ZAP_EXECUTION_SCRIPT), 'rt') as f:
- file_data = f.read()
- m = ZAP_EXECUTION_MIN_RE.search(file_data)
- logging.info("Min version %s in %s", m.group(2), ZAP_EXECUTION_SCRIPT)
- if new_version:
- new_min_version = ("%d.%d.%d" % zap_min_version)
- file_data = file_data[:m.start()] + m.group(1) + \
- new_min_version + m.group(3) + file_data[m.end():]
- logging.info('Updating min version to %s in %s',
- new_min_version, ZAP_EXECUTION_SCRIPT)
- with open(os.path.join(CHIP_ROOT_DIR, ZAP_EXECUTION_SCRIPT), 'wt') as f:
- f.write(file_data)
- if __name__ == '__main__':
- version_update()
|