-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
1,479 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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:])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.