mirror of
https://github.com/koalaman/shellcheck.git
synced 2025-09-30 16:59:20 +08:00
Rebase of chromiumos fork
https://chromium.googlesource.com/chromiumos/third_party/shellcheck/
This commit is contained in:
128
portage/get_vars.py
Normal file
128
portage/get_vars.py
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 The ChromiumOS Authors
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# Binary License Terms
|
||||
|
||||
"""Extract eclass variable names into Haskell list format."""
|
||||
from __future__ import print_function
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
# Matches a line that declares a variable in an eclass.
|
||||
VAR_RE = re.compile(r'@(?:ECLASS-)?VARIABLE:\s*(\w+)$')
|
||||
# Matches a line that declares inheritance.
|
||||
INHERIT_RE = re.compile(r'^[^#]*\binherit((?:\s+[\w-]+)+)$')
|
||||
VAR_FILE_HEADER = """module ShellCheck.PortageAutoInternalVariables (
|
||||
portageAutoInternalVariables
|
||||
) where
|
||||
-- This file contains the variables generated by
|
||||
-- portage/get_vars.py"""
|
||||
PORTAGE_AUTO_VAR_NAME = 'portageAutoInternalVariables'
|
||||
class Eclass:
|
||||
"""Container for eclass information"""
|
||||
def __init__(self, name, eclass_vars, inheritances):
|
||||
self.name = name
|
||||
self.vars = eclass_vars
|
||||
self.inheritances = inheritances
|
||||
def calculate_eclass_vars(self, eclasses):
|
||||
while self.inheritances:
|
||||
name = self.inheritances.pop()
|
||||
try:
|
||||
sub_eclass = eclasses[name]
|
||||
new_vars = sub_eclass.calculate_eclass_vars(eclasses).vars
|
||||
self.vars = self.vars.union(new_vars)
|
||||
except Exception:
|
||||
pass
|
||||
return self
|
||||
def print_var_list(eclass, eclass_vars):
|
||||
var_list = ' '.join(['"%s",' % v for v in sorted(eclass_vars)])
|
||||
print(' -- %s\n%s' %
|
||||
(eclass,
|
||||
textwrap.fill(
|
||||
var_list, 80, initial_indent=' ', subsequent_indent=' ')))
|
||||
def process_file(eclass_path):
|
||||
eclass_name = os.path.splitext(os.path.basename(eclass_path))[0]
|
||||
with open(eclass_path, 'r') as f:
|
||||
eclass_vars = set()
|
||||
eclass_inheritances = set()
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
while line[-1] == '\\':
|
||||
line = line[:-1] + next(f).strip()
|
||||
match = VAR_RE.search(line)
|
||||
if match:
|
||||
var_name = match.group(1)
|
||||
eclass_vars.add(var_name.strip())
|
||||
else:
|
||||
match = INHERIT_RE.search(line)
|
||||
if match:
|
||||
for inheritance in re.split(r'\s+', match.group(1)):
|
||||
if inheritance.strip():
|
||||
eclass_inheritances.add(inheritance.strip())
|
||||
return Eclass(eclass_name, eclass_vars, eclass_inheritances)
|
||||
def format_eclasses_as_haskell_map(eclasses):
|
||||
map_entries = []
|
||||
join_string = '", "'
|
||||
for value in sorted(eclasses, key=(lambda x: x.name)):
|
||||
if value.vars:
|
||||
var_list_string = f'"{join_string.join(sorted(list(value.vars)))}"'
|
||||
map_entries.append(
|
||||
textwrap.fill(
|
||||
f'("{value.name}", [{var_list_string}])',
|
||||
80,
|
||||
initial_indent=' ',
|
||||
subsequent_indent=' '))
|
||||
return_string = ',\n\n'.join(map_entries)
|
||||
return_string = f""" Data.Map.fromList
|
||||
[
|
||||
{return_string}
|
||||
]"""
|
||||
return f"""{VAR_FILE_HEADER}\n\n
|
||||
-- Last Generated: {datetime.datetime.now().strftime("%x")}
|
||||
import qualified Data.Map
|
||||
{PORTAGE_AUTO_VAR_NAME} =
|
||||
{return_string}"""
|
||||
def main(argv):
|
||||
eclasses = {}
|
||||
for path in sorted(argv, key=os.path.basename):
|
||||
if not path.endswith('.eclass'):
|
||||
continue
|
||||
new_eclass = process_file(path)
|
||||
eclasses[new_eclass.name] = new_eclass
|
||||
eclasses_list = [
|
||||
value.calculate_eclass_vars(eclasses) for key, value in eclasses.items()
|
||||
]
|
||||
print(format_eclasses_as_haskell_map(eclasses_list))
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
120
portage/get_vars_diff.py
Normal file
120
portage/get_vars_diff.py
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2020 The ChromiumOS Authors
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google LLC nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# Binary License Terms
|
||||
|
||||
"""Generates diff of vars from get_vars.py and those existing in Data.hs."""
|
||||
import itertools
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
SCRIPT = Path(__file__).resolve()
|
||||
THIRD_PARTY = SCRIPT.parent.parent.parent.parent.parent
|
||||
# List of relative directories in which to find the eclasses.
|
||||
eclass_rel_dirs = (
|
||||
THIRD_PARTY / 'chromiumos-overlay' / 'eclass',
|
||||
THIRD_PARTY / 'portage-stable' / 'eclass',
|
||||
THIRD_PARTY / 'eclass-overlay' / 'eclass',
|
||||
)
|
||||
# Runs get_vars.py with the eclass paths and store the output.
|
||||
cmd = [SCRIPT.with_name('get_vars.py')] + list(
|
||||
itertools.chain(*(x.glob('*') for x in eclass_rel_dirs)))
|
||||
new_output = subprocess.check_output(cmd, encoding='utf-8').splitlines()
|
||||
new = []
|
||||
for line in new_output:
|
||||
if '--' in line:
|
||||
new.append(line.strip())
|
||||
elif not line.strip():
|
||||
continue
|
||||
else:
|
||||
new += (line.replace('"', '').replace('\n', '').split(','))
|
||||
# Reads the Data.hs relevant area and store the lines.
|
||||
data_hs = THIRD_PARTY / 'shellcheck' / 'src' / 'ShellCheck' / 'Data.hs'
|
||||
with data_hs.open('r', encoding='utf-8') as fp:
|
||||
record = False
|
||||
old = []
|
||||
for line in fp:
|
||||
if line.strip() == '-- autotest.eclass declared incorrectly':
|
||||
break
|
||||
if line.strip() == '-- generic ebuilds':
|
||||
record = True
|
||||
if record:
|
||||
if '--' in line:
|
||||
old.append(line.strip())
|
||||
elif not line.strip():
|
||||
continue
|
||||
else:
|
||||
old += line.replace('"', '').replace('\n', '').split(',')
|
||||
# Cleans up empty bits as a result of parsing difficulties.
|
||||
new = [x.strip() for x in new if x.strip()]
|
||||
old = [x.strip() for x in old if x.strip()]
|
||||
all_eclasses = set()
|
||||
old_vars = {}
|
||||
new_vars = {}
|
||||
current_eclass = ''
|
||||
for item in old:
|
||||
if '--' in item:
|
||||
# It's an eclass comment line.
|
||||
current_eclass = item[3:]
|
||||
all_eclasses.add(current_eclass)
|
||||
continue
|
||||
else:
|
||||
# It's a var, so add it to the dict of the current eclass.
|
||||
old_vars.setdefault(current_eclass, []).append(item)
|
||||
for item in new:
|
||||
if '--' in item:
|
||||
# It's an eclass comment line.
|
||||
current_eclass = item[3:]
|
||||
all_eclasses.add(current_eclass)
|
||||
continue
|
||||
else:
|
||||
# It's a var, so add it to the dict of the current eclass.
|
||||
new_vars.setdefault(current_eclass, []).append(item)
|
||||
for eclass in sorted(all_eclasses):
|
||||
if eclass in old_vars:
|
||||
if eclass not in new_vars:
|
||||
# Checks if the entire eclass is removed.
|
||||
print(f'{eclass} not present in new variables.')
|
||||
for var in old_vars[eclass]:
|
||||
print(f'\t-{var}')
|
||||
print()
|
||||
else:
|
||||
# Eclass isn't removed, so check for added or removed vars.
|
||||
toprint = '\n'.join(
|
||||
[f'\t-{x}' for x in old_vars[eclass] if x not in new_vars[eclass]] +
|
||||
[f'\t+{x}' for x in new_vars[eclass] if x not in old_vars[eclass]])
|
||||
if toprint:
|
||||
print(eclass)
|
||||
print(toprint)
|
||||
if eclass in new_vars:
|
||||
if eclass not in old_vars:
|
||||
# Checks if entire eclass is new.
|
||||
print(f'{eclass} added in new variables.')
|
||||
for var in new_vars[eclass]:
|
||||
print(f'\t+{var}')
|
||||
print()
|
Reference in New Issue
Block a user