Applies the `pyupgrade` hook to all files in the repo. Change-Id: I9879c634a65c5fcaa9567c63bc5977ff97d5d3bf
285 lines
8.7 KiB
Python
285 lines
8.7 KiB
Python
# -*- mode:python -*-
|
|
|
|
# Copyright (c) 2018, 2020 ARM Limited
|
|
#
|
|
# The license below extends only to copyright in the software and shall
|
|
# not be construed as granting a license to any other intellectual
|
|
# property including but not limited to intellectual property relating
|
|
# to a hardware implementation of the functionality of the software
|
|
# licensed hereunder. You may use the software subject to the license
|
|
# terms below provided that you ensure that this notice is replicated
|
|
# unmodified and in its entirety in all distributions of the software,
|
|
# modified or unmodified, in source code or in binary form.
|
|
#
|
|
# Copyright (c) 2004-2005 The Regents of The University of Michigan
|
|
# 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 the copyright holders 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.
|
|
|
|
import functools
|
|
|
|
import SCons.Script
|
|
|
|
########################################################################
|
|
# Code for adding source files of various types
|
|
#
|
|
# When specifying a source file of some type, a set of tags can be
|
|
# specified for that file.
|
|
|
|
|
|
def tag_implies(env, tag, tag_list):
|
|
"""
|
|
Associates a tag X to a list of tags which are implied by X.
|
|
|
|
For example, assume:
|
|
- Each file <X>.cc is tagged with the tag "Tag <X>".
|
|
- B.cc refers to symbols from A.cc
|
|
- C.cc refers to symbols from B.cc
|
|
- D.cc refers to symbols from A.cc and C.cc
|
|
|
|
Then:
|
|
- "Tag A" is implied by "Tag B"
|
|
- "Tag B" is implied by "Tag C"
|
|
- "Tag A" is transitively implied by "Tag C" (from "Tag B")
|
|
- "Tag A" and "Tag C" are implied by "Tag D"
|
|
- "Tag B" is transitively implied by "Tag D" (from "Tag C")
|
|
- "Tag A" is transitively implied by "Tag D" (from transitive "Tag B")
|
|
|
|
All of these implications are simply declared as:
|
|
env.TagImplies("Tag B", "Tag A")
|
|
env.TagImplies("Tag C", "Tag B")
|
|
env.TagImplies("Tag D", ["Tag A", "Tag C"])
|
|
|
|
So that any use of a tag will automatically include its transitive tags
|
|
after being resolved.
|
|
"""
|
|
|
|
env.SetDefault(_tag_implies={})
|
|
implications = env["_tag_implies"]
|
|
|
|
if isinstance(tag_list, str):
|
|
tag_list = frozenset([tag_list])
|
|
if not isinstance(tag_list, frozenset):
|
|
tag_list = frozenset(tag_list)
|
|
if tag in implications:
|
|
implications[tag] |= tag_list
|
|
else:
|
|
implications[tag] = tag_list
|
|
|
|
# Check if any of the tags on which the new tag depends on already
|
|
# has a list of implications. If so, add the list to the new tag's
|
|
# implications
|
|
for t in tag_list:
|
|
if t in implications:
|
|
implications[tag] |= implications[t]
|
|
|
|
# Check if another tag depends on this tag. If so, add this tag's
|
|
# implications to that tag.
|
|
for t, implied in implications.items():
|
|
if tag in implied:
|
|
implications[t] |= implications[tag]
|
|
|
|
|
|
def TagImpliesTool(env):
|
|
env.AddMethod(tag_implies, "TagImplies")
|
|
|
|
|
|
def resolve_tags(env, tags):
|
|
"""
|
|
Returns the complete set of tags implied (dependencies) by the
|
|
supplied tags.
|
|
"""
|
|
|
|
implications = env.SetDefault(_tag_implies={})
|
|
implications = env["_tag_implies"]
|
|
|
|
if isinstance(tags, str):
|
|
tags = frozenset([tags])
|
|
if not isinstance(tags, frozenset):
|
|
tags = frozenset(tags)
|
|
|
|
tags = tags.copy()
|
|
for tag in tags:
|
|
if tag in implications:
|
|
tags |= implications[tag]
|
|
return tags
|
|
|
|
|
|
class SourceFilter:
|
|
factories = {}
|
|
|
|
def __init__(self, predicate):
|
|
self.predicate = predicate
|
|
|
|
def __or__(self, other):
|
|
return SourceFilter(
|
|
lambda env, tags: self.predicate(env, tags)
|
|
or other.predicate(env, tags)
|
|
)
|
|
|
|
def __and__(self, other):
|
|
return SourceFilter(
|
|
lambda env, tags: self.predicate(env, tags)
|
|
and other.predicate(env, tags)
|
|
)
|
|
|
|
|
|
def with_any_tags(*tags):
|
|
"""Return a list of sources with any of the supplied tags."""
|
|
return SourceFilter(
|
|
lambda env, stags: len(resolve_tags(env, tags) & stags) > 0
|
|
)
|
|
|
|
|
|
def with_all_tags(*tags):
|
|
"""Return a list of sources with all of the supplied tags."""
|
|
return SourceFilter(lambda env, stags: resolve_tags(env, tags) <= stags)
|
|
|
|
|
|
def with_tag(tag):
|
|
"""Return a list of sources with the supplied tag."""
|
|
return with_any_tags(*[tag])
|
|
|
|
|
|
def without_tags(*tags):
|
|
"""Return a list of sources without any of the supplied tags."""
|
|
return SourceFilter(
|
|
lambda env, stags: len(resolve_tags(env, tags) & stags) == 0
|
|
)
|
|
|
|
|
|
def without_tag(tag):
|
|
"""Return a list of sources without the supplied tag."""
|
|
return without_tags(*[tag])
|
|
|
|
|
|
SourceFilter.factories.update(
|
|
{
|
|
"with_any_tags": with_any_tags,
|
|
"with_all_tags": with_all_tags,
|
|
"with_tag": with_tag,
|
|
"without_tags": without_tags,
|
|
"without_tag": without_tag,
|
|
}
|
|
)
|
|
|
|
|
|
class SourceList(list):
|
|
def apply_filter(self, env, f):
|
|
def match(source):
|
|
return f.predicate(env, resolve_tags(env, source.tags))
|
|
|
|
return SourceList(filter(match, self))
|
|
|
|
def __getattr__(self, name):
|
|
func = SourceFilter.factories.get(name, None)
|
|
if not func:
|
|
raise AttributeError
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(env, *args, **kwargs):
|
|
return self.apply_filter(env, func(*args, **kwargs))
|
|
|
|
return wrapper
|
|
|
|
|
|
class SourceMeta(type):
|
|
"""Meta class for source files that keeps track of all files of a
|
|
particular type."""
|
|
|
|
def __init__(cls, name, bases, dict):
|
|
super().__init__(name, bases, dict)
|
|
cls.all = SourceList()
|
|
|
|
|
|
class SourceItem(metaclass=SourceMeta):
|
|
"""Base object that encapsulates the notion of a source component for
|
|
gem5. This specifies a set of tags which help group components into groups
|
|
based on arbitrary properties."""
|
|
|
|
def __init__(self, source, tags=None, add_tags=None, append=None):
|
|
self.source = source
|
|
|
|
if tags is None:
|
|
tags = "gem5 lib"
|
|
if isinstance(tags, str):
|
|
tags = {tags}
|
|
if not isinstance(tags, set):
|
|
tags = set(tags)
|
|
self.tags = tags.copy()
|
|
|
|
if add_tags:
|
|
if isinstance(add_tags, str):
|
|
add_tags = {add_tags}
|
|
if not isinstance(add_tags, set):
|
|
add_tags = set(add_tags)
|
|
self.tags |= add_tags
|
|
|
|
self.append = append
|
|
|
|
for base in type(self).__mro__:
|
|
if issubclass(base, SourceItem):
|
|
base.all.append(self)
|
|
|
|
|
|
class SourceFile(SourceItem):
|
|
"""Base object that encapsulates the notion of a source file.
|
|
This includes, the source node, target node, various manipulations
|
|
of those."""
|
|
|
|
def __init__(self, source, tags=None, add_tags=None, append=None):
|
|
super().__init__(source, tags=tags, add_tags=add_tags, append=append)
|
|
|
|
tnode = SCons.Script.File(source)
|
|
|
|
self.tnode = tnode
|
|
self.filename = str(self.tnode)
|
|
self.snode = tnode.srcnode()
|
|
|
|
def static(self, env):
|
|
if self.append:
|
|
env = env.Clone()
|
|
env.Append(**self.append)
|
|
return env.StaticObject(self.tnode.abspath)
|
|
|
|
def shared(self, env):
|
|
if self.append:
|
|
env = env.Clone()
|
|
env.Append(**self.append)
|
|
return env.SharedObject(self.tnode.abspath)
|
|
|
|
|
|
__all__ = [
|
|
"TagImpliesTool",
|
|
"SourceFilter",
|
|
"SourceList",
|
|
"SourceFile",
|
|
"SourceItem",
|
|
"with_any_tags",
|
|
"with_all_tags",
|
|
"with_tag",
|
|
"without_tags",
|
|
"without_tag",
|
|
]
|