staticer 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- staticer/__init__.py +1 -0
- staticer/common/__init__.py +0 -0
- staticer/common/depgraph.py +116 -0
- staticer/elf_embedder.py +2142 -0
- staticer/pe_embedder.py +1097 -0
- staticer/staticer.py +72 -0
- staticer/stubs/__init__.py +0 -0
- staticer/stubs/linux/__init__.py +0 -0
- staticer/stubs/linux/elf_stub.py +374 -0
- staticer/stubs/windows/__init__.py +0 -0
- staticer/stubs/windows/pe_stub.py +228 -0
- staticer-0.0.1.dist-info/METADATA +170 -0
- staticer-0.0.1.dist-info/RECORD +16 -0
- staticer-0.0.1.dist-info/WHEEL +5 -0
- staticer-0.0.1.dist-info/entry_points.txt +2 -0
- staticer-0.0.1.dist-info/top_level.txt +1 -0
staticer/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .staticer import main
|
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Format-agnostic dependency graph: resolution, transitive exclusion, and
|
|
2
|
+
dependency-first init order, driven entirely by caller-supplied
|
|
3
|
+
``list_imports``/``resolve`` callables.
|
|
4
|
+
|
|
5
|
+
This module knows nothing about PE or ELF; those formats supply their own
|
|
6
|
+
``list_imports``/``resolve`` implementations (see ``pe_embedder``/
|
|
7
|
+
``elf_embedder``) and call into ``build_dependency_graph``/``embed_order``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from dataclasses import field
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Callable, Dict, List, Optional, Set
|
|
13
|
+
|
|
14
|
+
from firstclass import firstclass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@firstclass
|
|
18
|
+
class DependencyNode:
|
|
19
|
+
name: str
|
|
20
|
+
path: Path
|
|
21
|
+
embeddable: bool
|
|
22
|
+
# Names of this node's own resolved imports (edges), keyed the same
|
|
23
|
+
# way as the graph dict. Populated by build_dependency_graph;
|
|
24
|
+
# embed_order walks it to produce a dependencies-first order. Not
|
|
25
|
+
# part of the original interface's three fields, but required for
|
|
26
|
+
# embed_order to have any edge information to sort over, since the
|
|
27
|
+
# graph dict is its only input.
|
|
28
|
+
imports: List[str] = field(default_factory=list)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CyclicDependencyError(Exception):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_dependency_graph(
|
|
36
|
+
root_path: Path,
|
|
37
|
+
list_imports: Callable[[Path], List[str]],
|
|
38
|
+
resolve: Callable[[str, List[Path]], Optional[Path]],
|
|
39
|
+
search_dirs: List[Path],
|
|
40
|
+
lib_dir: Optional[Path],
|
|
41
|
+
exclude: Set[str],
|
|
42
|
+
) -> Dict[str, DependencyNode]:
|
|
43
|
+
nodes: Dict[str, DependencyNode] = {}
|
|
44
|
+
|
|
45
|
+
def in_scope(path: Path) -> bool:
|
|
46
|
+
return lib_dir is None or path.is_relative_to(lib_dir)
|
|
47
|
+
|
|
48
|
+
def visit(name: str, path: Path, force_excluded: bool) -> None:
|
|
49
|
+
is_excluded = force_excluded or (name in exclude) or not in_scope(path)
|
|
50
|
+
if name in nodes:
|
|
51
|
+
node = nodes[name]
|
|
52
|
+
# Only cascade when this visit newly excludes the node (guards
|
|
53
|
+
# against both redundant re-cascading on repeat revisits and,
|
|
54
|
+
# critically, infinite recursion around cycles: once a node is
|
|
55
|
+
# already False, re-walking its recorded imports again is a
|
|
56
|
+
# no-op).
|
|
57
|
+
if is_excluded and node.embeddable:
|
|
58
|
+
node.embeddable = False
|
|
59
|
+
for child_name in node.imports:
|
|
60
|
+
child = nodes.get(child_name)
|
|
61
|
+
if child is not None:
|
|
62
|
+
visit(child_name, child.path, force_excluded=True)
|
|
63
|
+
return
|
|
64
|
+
node = DependencyNode(name=name, path=path, embeddable=not is_excluded)
|
|
65
|
+
nodes[name] = node
|
|
66
|
+
for imp_name in list_imports(path):
|
|
67
|
+
resolved = resolve(imp_name, search_dirs)
|
|
68
|
+
if resolved is None:
|
|
69
|
+
continue
|
|
70
|
+
node.imports.append(imp_name)
|
|
71
|
+
visit(imp_name, resolved, force_excluded=is_excluded)
|
|
72
|
+
|
|
73
|
+
for imp_name in list_imports(root_path):
|
|
74
|
+
resolved = resolve(imp_name, search_dirs)
|
|
75
|
+
if resolved is not None:
|
|
76
|
+
visit(imp_name, resolved, force_excluded=False)
|
|
77
|
+
return nodes
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def embed_order(graph: Dict[str, DependencyNode]) -> List[DependencyNode]:
|
|
81
|
+
"""Dependencies-first topological order over the embeddable subset of
|
|
82
|
+
``graph``. Raises CyclicDependencyError, naming the cycle, if a cycle
|
|
83
|
+
exists among embeddable nodes."""
|
|
84
|
+
order: List[DependencyNode] = []
|
|
85
|
+
visited: Set[str] = set()
|
|
86
|
+
in_progress: List[str] = []
|
|
87
|
+
in_progress_set: Set[str] = set()
|
|
88
|
+
|
|
89
|
+
def visit(name: str) -> None:
|
|
90
|
+
if name in visited:
|
|
91
|
+
return
|
|
92
|
+
if name in in_progress_set:
|
|
93
|
+
cycle = in_progress[in_progress.index(name):] + [name]
|
|
94
|
+
raise CyclicDependencyError(
|
|
95
|
+
"cyclic dependency detected: " + " -> ".join(cycle)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
node = graph[name]
|
|
99
|
+
in_progress.append(name)
|
|
100
|
+
in_progress_set.add(name)
|
|
101
|
+
|
|
102
|
+
for imp_name in node.imports:
|
|
103
|
+
dep = graph.get(imp_name)
|
|
104
|
+
if dep is not None and dep.embeddable:
|
|
105
|
+
visit(imp_name)
|
|
106
|
+
|
|
107
|
+
in_progress.pop()
|
|
108
|
+
in_progress_set.discard(name)
|
|
109
|
+
visited.add(name)
|
|
110
|
+
order.append(node)
|
|
111
|
+
|
|
112
|
+
for name, node in graph.items():
|
|
113
|
+
if node.embeddable:
|
|
114
|
+
visit(name)
|
|
115
|
+
|
|
116
|
+
return order
|