PR-URL: https://github.com/nodejs/node/pull/58070 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
151 lines
5.1 KiB
Python
Executable File
151 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright 2025 the V8 project authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can
|
|
# be found in the LICENSE file.
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
TEST_ROOT = Path(__file__).absolute().parent.parent.parent / 'test'
|
|
TEST_SUITES = [
|
|
'mjsunit', 'debugger', 'inspector', 'message', 'js-perf-test', 'webkit'
|
|
]
|
|
TEST_EXTENSIONS = ('.js', '.mjs')
|
|
HAS_FLAGS_RE = re.compile("//\\s*Flags:.*\n")
|
|
EXTRACT_FLAGS_RE = re.compile("//\\s*Flags:\\s+((--[A-z0-9-_=]+\\s*)+).*")
|
|
FEATURE_FLAG_PREFIXES = {
|
|
'js': ('--js-', '--js_'),
|
|
'harmony': ('--harmony-', '--harmony_'),
|
|
'wasm': ('--experimental-wasm-', '--experimental_wasm_')
|
|
}
|
|
NEG_FEATURE_FLAG_PREFIXES = {
|
|
'js': ('--no-js-', '--no_js_'),
|
|
'harmony': ('--no-harmony-', '--no_harmony_'),
|
|
'wasm': ('--no-experimental-wasm-', '--no_experimental_wasm_')
|
|
}
|
|
STAGING_FLAGS = {
|
|
'js': '--js-staging',
|
|
'harmony': '--harmony',
|
|
'wasm': '--wasm-staging'
|
|
}
|
|
SHIPPING_FLAGS = {
|
|
'js': '--js-shipping',
|
|
'harmony': '--harmony-shipping',
|
|
'wasm': '' # Wasm doesn't have a shipping flag
|
|
}
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'--outdir', required=True, type=Path, help='build directory with d8')
|
|
args = parser.parse_args()
|
|
|
|
D8 = os.path.join(args.outdir, 'd8')
|
|
|
|
|
|
def raw_flags_to_cli_flags(raw_flags_for_lang):
|
|
return {
|
|
kind:
|
|
set([f'--{flag}' for flag in raw_flags] +
|
|
[f"--{flag.replace('_', '-')}" for flag in raw_flags])
|
|
for kind, raw_flags in raw_flags_for_lang.items()
|
|
}
|
|
|
|
|
|
def get_feature_flags():
|
|
p = subprocess.run([D8, '--print-feature-flags-json'],
|
|
stdin=subprocess.PIPE,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
raw_flags = json.loads(p.stdout)
|
|
return {key: raw_flags_to_cli_flags(val) for key, val in raw_flags.items()}
|
|
|
|
|
|
def clean_up_feature_flags(contents, all_flags_by_lang):
|
|
# Returns a (bool, string) pair, where the bool says whether the contents
|
|
# changed due to a flag being cleaned up.
|
|
|
|
if not re.search(HAS_FLAGS_RE, contents):
|
|
return (False, contents)
|
|
|
|
dirty = False
|
|
cleaned_contents = []
|
|
emitted_staging_flags = set()
|
|
for line in contents.splitlines():
|
|
match = re.search(EXTRACT_FLAGS_RE, line)
|
|
if match:
|
|
inprogress_flags = set(match.group(1).split())
|
|
original_flags = inprogress_flags.copy()
|
|
for (lang, lang_flags) in all_flags_by_lang.items():
|
|
# Remove staged flags.
|
|
inprogress_flags_no_staged = inprogress_flags - lang_flags['staged']
|
|
# If any staged flags were removed, emit the staging flag instead. Only
|
|
# do so once per file.
|
|
if (inprogress_flags_no_staged
|
|
!= inprogress_flags) and (lang not in emitted_staging_flags):
|
|
inprogress_flags_no_staged.add(STAGING_FLAGS[lang])
|
|
emitted_staging_flags.add(lang)
|
|
inprogress_flags = inprogress_flags_no_staged
|
|
# Remove flags that are shipping.
|
|
inprogress_flags -= lang_flags['shipping']
|
|
# Heuristically remove flags that look like feature flags (prefixed by
|
|
# one of the known prefixes) that don't exist anymore.
|
|
for flag in inprogress_flags.copy():
|
|
if flag == STAGING_FLAGS[lang] or flag == SHIPPING_FLAGS[lang]:
|
|
continue
|
|
if flag.startswith(FEATURE_FLAG_PREFIXES[lang]) and (
|
|
flag not in lang_flags['in-progress']):
|
|
inprogress_flags.remove(flag)
|
|
elif flag.startswith(NEG_FEATURE_FLAG_PREFIXES[lang]) and (
|
|
f"--{flag[5:]}" not in lang_flags['in-progress']):
|
|
inprogress_flags.remove(flag)
|
|
|
|
if inprogress_flags != original_flags:
|
|
dirty = True
|
|
if len(inprogress_flags) > 0:
|
|
cleaned_contents.append(f"// Flags: {' '.join(inprogress_flags)}")
|
|
else:
|
|
cleaned_contents.append(line)
|
|
else:
|
|
cleaned_contents.append(line)
|
|
|
|
if not dirty:
|
|
return (False, contents)
|
|
else:
|
|
return (True, "\n".join(cleaned_contents) + "\n")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
flags = get_feature_flags()
|
|
|
|
# Walk test files.
|
|
for suite_dir in TEST_SUITES:
|
|
suite_path = TEST_ROOT / suite_dir
|
|
for dirname, dirs, files in os.walk(suite_path, followlinks=True):
|
|
for filename in files:
|
|
if not filename.endswith(TEST_EXTENSIONS):
|
|
continue
|
|
abspath = Path(dirname) / filename
|
|
encoding = 'utf-8'
|
|
with open(abspath, 'rb') as fh:
|
|
# We still have some test files that aren't valid UTF-8. But we also
|
|
# can't unconditionally use ISO-8859-1, because we also have tests
|
|
# that can only be encoded in UTF-8.
|
|
try:
|
|
contents = fh.read().decode(encoding)
|
|
except:
|
|
encoding = 'ISO-8859-1'
|
|
contents = fh.read().decode(encoding)
|
|
contents_changed, contents = clean_up_feature_flags(contents, flags)
|
|
if contents_changed:
|
|
with open(abspath, 'w', encoding=encoding) as fh:
|
|
fh.write(contents)
|
|
print(f"Changed flags in {abspath}")
|
|
|
|
sys.exit(0)
|