-
Notifications
You must be signed in to change notification settings - Fork 96
/
Copy pathcodebase.py
146 lines (117 loc) · 5.22 KB
/
codebase.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# SPDX-License-Identifier: Apache-2.0
#
# http://nexb.com and https://github.com/aboutcode-org/scancode.io
# The ScanCode.io software is licensed under the Apache License version 2.0.
# Data generated with ScanCode.io is provided as-is without warranties.
# ScanCode is a trademark of nexB Inc.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at: http://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.
#
# Data Generated with ScanCode.io is provided on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
# ScanCode.io should be considered or used as legal advice. Consult an Attorney
# for any legal advice.
#
# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/aboutcode-org/scancode.io for support and download.
from commoncode.resource import VirtualCodebase
from scanpipe.models import Project
def sort_by_lower_name(resource):
return resource["name"].lower()
def get_resource_fields(resource, fields):
"""Return a mapping of fields from `fields` and values from `resource`"""
return {field: getattr(resource, field) for field in fields}
def get_resource_tree(resource, fields, codebase=None, seen_resources=set()):
"""
Return a tree as a dictionary structure starting from the provided `resource`.
The following classes are supported for the input `resource` object:
- scanpipe.models.CodebaseResource
- commoncode.resource.Resource
The data included for each child is controlled with the `fields` argument.
The `codebase` is only required in the context of a commoncode `Resource`
input.
`seen_resources` is used when get_resource_tree() is used in the context of
get_codebase_tree(). We keep track of child Resources we visit in
`seen_resources`, so we don't visit them again in get_codebase_tree().
"""
resource_dict = get_resource_fields(resource, fields)
if resource.is_dir:
children = []
for child in resource.children(codebase):
seen_resources.add(child.path)
children.append(get_resource_tree(child, fields, codebase, seen_resources))
if children:
resource_dict["children"] = sorted(children, key=sort_by_lower_name)
return resource_dict
def get_codebase_tree(codebase, fields):
"""
Return a tree as a dictionary structure starting from the root resources of
the provided `codebase`.
The following classes are supported for the input `codebase` object:
- scanpipe.pipes.codebase.ProjectCodebase
- commoncode.resource.Codebase
- commoncode.resource.VirtualCodebase
The data included for each child is controlled with the `fields` argument.
"""
seen_resources = set()
codebase_dict = dict(children=[])
for resource in codebase.walk():
path = resource.path
if path in seen_resources:
continue
else:
seen_resources.add(path)
resource_dict = get_resource_fields(resource, fields)
if resource.is_dir:
children = []
for child in resource.children(codebase):
seen_resources.add(child.path)
children.append(
get_resource_tree(child, fields, codebase, seen_resources)
)
if children:
resource_dict["children"] = sorted(children, key=sort_by_lower_name)
codebase_dict["children"].append(resource_dict)
return codebase_dict
def get_basic_virtual_codebase(resources_qs):
"""
Return a VirtualCodebase created from CodebaseResources in `resources_qs`.
The only Resource fields that are populated are path, sha1, size, and
is_file. This is intended for use with
scanpipe.pipes.matchcode.fingerprint_codebase_directories
"""
resources = [
{"path": r.path, "sha1": r.sha1, "size": r.size, "is_file": r.is_file}
for r in resources_qs
]
return VirtualCodebase(location={"files": resources})
class ProjectCodebase:
"""
Represents the codebase of a project stored in the database.
A Codebase is a tree of Resources.
"""
project = None
def __init__(self, project):
if not isinstance(project, Project):
raise ValueError("Provided value for project is not a Project instance.")
self.project = project
@property
def root_resources(self):
return self.project.codebaseresources.exclude(path__contains="/")
@property
def resources(self):
return self.project.codebaseresources.all()
def walk(self, topdown=True):
for root_resource in self.root_resources:
if topdown:
yield root_resource
yield from root_resource.walk(topdown=topdown)
if not topdown:
yield root_resource
def get_tree(self):
return get_codebase_tree(self, fields=["name", "path"])