9218
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
1
|
#!/usr/bin/env python |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
2
|
# -*- coding: utf-8 -*- |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
3
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
4
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
5
|
Copyright (c) 2015 Vineet Naik (naikvin@gmail.com) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
6
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
7
|
Permission is hereby granted, free of charge, to any person obtaining |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
8
|
a copy of this software and associated documentation files (the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
9
|
"Software"), to deal in the Software without restriction, including |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
10
|
without limitation the rights to use, copy, modify, merge, publish, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
11
|
distribute, sublicense, and/or sell copies of the Software, and to |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
12
|
permit persons to whom the Software is furnished to do so, subject to |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
13
|
the following conditions: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
14
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
15
|
The above copyright notice and this permission notice shall be |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
16
|
included in all copies or substantial portions of the Software. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
17
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
18
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
19
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
20
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
21
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
22
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
23
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
24
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
25
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
26
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
27
|
# |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
28
|
# Modified to be used within the eric-ide project. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
29
|
# |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
30
|
# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
31
|
# |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
32
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
33
|
from __future__ import print_function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
34
|
import os |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
35
|
import inspect |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
36
|
import sys |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
37
|
import subprocess |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
38
|
from itertools import chain |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
39
|
from collections import defaultdict, deque |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
40
|
import argparse |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
41
|
import json |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
42
|
from importlib import import_module |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
43
|
import tempfile |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
44
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
45
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
46
|
from collections import OrderedDict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
47
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
48
|
from ordereddict import OrderedDict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
49
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
50
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
51
|
from collections.abc import Mapping |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
52
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
53
|
from collections import Mapping |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
54
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
55
|
from pip._vendor import pkg_resources |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
56
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
57
|
from pip._internal.operations.freeze import FrozenRequirement |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
58
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
59
|
from pip import FrozenRequirement |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
60
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
61
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
62
|
__version__ = '2.2.1' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
63
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
64
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
65
|
flatten = chain.from_iterable |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
66
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
67
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
68
|
def sorted_tree(tree): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
69
|
"""Sorts the dict representation of the tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
70
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
71
|
The root packages as well as the intermediate packages are sorted |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
72
|
in the alphabetical order of the package names. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
73
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
74
|
:param dict tree: the pkg dependency tree obtained by calling |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
75
|
`construct_tree` function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
76
|
:returns: sorted tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
77
|
:rtype: collections.OrderedDict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
78
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
79
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
80
|
return OrderedDict([(k, sorted(v)) for k, v in sorted(tree.items())]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
81
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
82
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
83
|
def guess_version(pkg_key, default='?'): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
84
|
"""Guess the version of a pkg when pip doesn't provide it |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
85
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
86
|
:param str pkg_key: key of the package |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
87
|
:param str default: default version to return if unable to find |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
88
|
:returns: version |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
89
|
:rtype: string |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
90
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
91
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
92
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
93
|
m = import_module(pkg_key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
94
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
95
|
return default |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
96
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
97
|
v = getattr(m, '__version__', default) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
98
|
if inspect.ismodule(v): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
99
|
return getattr(v, '__version__', default) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
100
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
101
|
return v |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
102
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
103
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
104
|
def frozen_req_from_dist(dist): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
105
|
# The `pip._internal.metadata` modules were introduced in 21.1.1 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
106
|
# and the `pip._internal.operations.freeze.FrozenRequirement` |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
107
|
# class now expects dist to be a subclass of |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
108
|
# `pip._internal.metadata.BaseDistribution`, however the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
109
|
# `pip._internal.utils.misc.get_installed_distributions` continues |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
110
|
# to return objects of type |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
111
|
# pip._vendor.pkg_resources.DistInfoDistribution. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
112
|
# |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
113
|
# This is a hacky backward compatible (with older versions of pip) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
114
|
# fix. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
115
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
116
|
from pip._internal import metadata |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
117
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
118
|
pass |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
119
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
120
|
dist = metadata.pkg_resources.Distribution(dist) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
121
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
122
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
123
|
return FrozenRequirement.from_dist(dist) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
124
|
except TypeError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
125
|
return FrozenRequirement.from_dist(dist, []) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
126
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
127
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
128
|
class Package(object): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
129
|
"""Abstract class for wrappers around objects that pip returns. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
130
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
131
|
This class needs to be subclassed with implementations for |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
132
|
`render_as_root` and `render_as_branch` methods. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
133
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
134
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
135
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
136
|
def __init__(self, obj): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
137
|
self._obj = obj |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
138
|
self.project_name = obj.project_name |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
139
|
self.key = obj.key |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
140
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
141
|
def render_as_root(self, frozen): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
142
|
return NotImplementedError |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
143
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
144
|
def render_as_branch(self, frozen): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
145
|
return NotImplementedError |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
146
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
147
|
def render(self, parent=None, frozen=False): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
148
|
if not parent: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
149
|
return self.render_as_root(frozen) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
150
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
151
|
return self.render_as_branch(frozen) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
152
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
153
|
@staticmethod |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
154
|
def frozen_repr(obj): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
155
|
fr = frozen_req_from_dist(obj) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
156
|
return str(fr).strip() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
157
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
158
|
def __getattr__(self, key): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
159
|
return getattr(self._obj, key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
160
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
161
|
def __repr__(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
162
|
return '<{0}("{1}")>'.format(self.__class__.__name__, self.key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
163
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
164
|
def __lt__(self, rhs): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
165
|
return self.key < rhs.key |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
166
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
167
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
168
|
class DistPackage(Package): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
169
|
"""Wrapper class for pkg_resources.Distribution instances |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
170
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
171
|
:param obj: pkg_resources.Distribution to wrap over |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
172
|
:param req: optional ReqPackage object to associate this |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
173
|
DistPackage with. This is useful for displaying the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
174
|
tree in reverse |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
175
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
176
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
177
|
def __init__(self, obj, req=None): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
178
|
super(DistPackage, self).__init__(obj) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
179
|
self.version_spec = None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
180
|
self.req = req |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
181
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
182
|
def render_as_root(self, frozen): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
183
|
if not frozen: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
184
|
return '{0}=={1}'.format(self.project_name, self.version) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
185
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
186
|
return self.__class__.frozen_repr(self._obj) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
187
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
188
|
def render_as_branch(self, frozen): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
189
|
assert self.req is not None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
190
|
if not frozen: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
191
|
parent_ver_spec = self.req.version_spec |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
192
|
parent_str = self.req.project_name |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
193
|
if parent_ver_spec: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
194
|
parent_str += parent_ver_spec |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
195
|
return ( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
196
|
'{0}=={1} [requires: {2}]' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
197
|
).format(self.project_name, self.version, parent_str) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
198
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
199
|
return self.render_as_root(frozen) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
200
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
201
|
def as_requirement(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
202
|
"""Return a ReqPackage representation of this DistPackage""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
203
|
return ReqPackage(self._obj.as_requirement(), dist=self) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
204
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
205
|
def as_parent_of(self, req): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
206
|
"""Return a DistPackage instance associated to a requirement |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
207
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
208
|
This association is necessary for reversing the PackageDAG. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
209
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
210
|
If `req` is None, and the `req` attribute of the current |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
211
|
instance is also None, then the same instance will be |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
212
|
returned. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
213
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
214
|
:param ReqPackage req: the requirement to associate with |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
215
|
:returns: DistPackage instance |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
216
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
217
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
218
|
if req is None and self.req is None: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
219
|
return self |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
220
|
return self.__class__(self._obj, req) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
221
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
222
|
def as_dict(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
223
|
return {'key': self.key, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
224
|
'package_name': self.project_name, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
225
|
'installed_version': self.version} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
226
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
227
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
228
|
class ReqPackage(Package): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
229
|
"""Wrapper class for Requirements instance |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
230
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
231
|
:param obj: The `Requirements` instance to wrap over |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
232
|
:param dist: optional `pkg_resources.Distribution` instance for |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
233
|
this requirement |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
234
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
235
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
236
|
UNKNOWN_VERSION = '?' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
237
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
238
|
def __init__(self, obj, dist=None): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
239
|
super(ReqPackage, self).__init__(obj) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
240
|
self.dist = dist |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
241
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
242
|
@property |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
243
|
def version_spec(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
244
|
specs = sorted(self._obj.specs, reverse=True) # `reverse` makes '>' prior to '<' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
245
|
return ','.join([''.join(sp) for sp in specs]) if specs else None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
246
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
247
|
@property |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
248
|
def installed_version(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
249
|
if not self.dist: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
250
|
return guess_version(self.key, self.UNKNOWN_VERSION) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
251
|
return self.dist.version |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
252
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
253
|
@property |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
254
|
def is_missing(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
255
|
return self.installed_version == self.UNKNOWN_VERSION |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
256
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
257
|
def is_conflicting(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
258
|
"""If installed version conflicts with required version""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
259
|
# unknown installed version is also considered conflicting |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
260
|
if self.installed_version == self.UNKNOWN_VERSION: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
261
|
return True |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
262
|
ver_spec = (self.version_spec if self.version_spec else '') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
263
|
req_version_str = '{0}{1}'.format(self.project_name, ver_spec) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
264
|
req_obj = pkg_resources.Requirement.parse(req_version_str) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
265
|
return self.installed_version not in req_obj |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
266
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
267
|
def render_as_root(self, frozen): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
268
|
if not frozen: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
269
|
return '{0}=={1}'.format(self.project_name, self.installed_version) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
270
|
elif self.dist: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
271
|
return self.__class__.frozen_repr(self.dist._obj) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
272
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
273
|
return self.project_name |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
274
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
275
|
def render_as_branch(self, frozen): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
276
|
if not frozen: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
277
|
req_ver = self.version_spec if self.version_spec else 'Any' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
278
|
return ( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
279
|
'{0} [required: {1}, installed: {2}]' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
280
|
).format(self.project_name, req_ver, self.installed_version) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
281
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
282
|
return self.render_as_root(frozen) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
283
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
284
|
def as_dict(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
285
|
return {'key': self.key, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
286
|
'package_name': self.project_name, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
287
|
'installed_version': self.installed_version, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
288
|
'required_version': self.version_spec} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
289
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
290
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
291
|
class PackageDAG(Mapping): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
292
|
"""Representation of Package dependencies as directed acyclic graph |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
293
|
using a dict (Mapping) as the underlying datastructure. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
294
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
295
|
The nodes and their relationships (edges) are internally |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
296
|
stored using a map as follows, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
297
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
298
|
{a: [b, c], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
299
|
b: [d], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
300
|
c: [d, e], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
301
|
d: [e], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
302
|
e: [], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
303
|
f: [b], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
304
|
g: [e, f]} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
305
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
306
|
Here, node `a` has 2 children nodes `b` and `c`. Consider edge |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
307
|
direction from `a` -> `b` and `a` -> `c` respectively. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
308
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
309
|
A node is expected to be an instance of a subclass of |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
310
|
`Package`. The keys are must be of class `DistPackage` and each |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
311
|
item in values must be of class `ReqPackage`. (See also |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
312
|
ReversedPackageDAG where the key and value types are |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
313
|
interchanged). |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
314
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
315
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
316
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
317
|
@classmethod |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
318
|
def from_pkgs(cls, pkgs): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
319
|
pkgs = [DistPackage(p) for p in pkgs] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
320
|
idx = {p.key: p for p in pkgs} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
321
|
m = {p: [ReqPackage(r, idx.get(r.key)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
322
|
for r in p.requires()] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
323
|
for p in pkgs} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
324
|
return cls(m) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
325
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
326
|
def __init__(self, m): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
327
|
"""Initialize the PackageDAG object |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
328
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
329
|
:param dict m: dict of node objects (refer class docstring) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
330
|
:returns: None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
331
|
:rtype: NoneType |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
332
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
333
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
334
|
self._obj = m |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
335
|
self._index = {p.key: p for p in list(self._obj)} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
336
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
337
|
def get_node_as_parent(self, node_key): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
338
|
"""Get the node from the keys of the dict representing the DAG. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
339
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
340
|
This method is useful if the dict representing the DAG |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
341
|
contains different kind of objects in keys and values. Use |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
342
|
this method to lookup a node obj as a parent (from the keys of |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
343
|
the dict) given a node key. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
344
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
345
|
:param node_key: identifier corresponding to key attr of node obj |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
346
|
:returns: node obj (as present in the keys of the dict) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
347
|
:rtype: Object |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
348
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
349
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
350
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
351
|
return self._index[node_key] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
352
|
except KeyError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
353
|
return None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
354
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
355
|
def get_children(self, node_key): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
356
|
"""Get child nodes for a node by it's key |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
357
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
358
|
:param str node_key: key of the node to get children of |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
359
|
:returns: list of child nodes |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
360
|
:rtype: ReqPackage[] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
361
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
362
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
363
|
node = self.get_node_as_parent(node_key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
364
|
return self._obj[node] if node else [] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
365
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
366
|
def filter(self, include, exclude): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
367
|
"""Filters nodes in a graph by given parameters |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
368
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
369
|
If a node is included, then all it's children are also |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
370
|
included. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
371
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
372
|
:param set include: set of node keys to include (or None) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
373
|
:param set exclude: set of node keys to exclude (or None) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
374
|
:returns: filtered version of the graph |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
375
|
:rtype: PackageDAG |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
376
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
377
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
378
|
# If neither of the filters are specified, short circuit |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
379
|
if include is None and exclude is None: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
380
|
return self |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
381
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
382
|
# Note: In following comparisons, we use lower cased values so |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
383
|
# that user may specify `key` or `project_name`. As per the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
384
|
# documentation, `key` is simply |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
385
|
# `project_name.lower()`. Refer: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
386
|
# https://setuptools.readthedocs.io/en/latest/pkg_resources.html#distribution-objects |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
387
|
if include: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
388
|
include = set([s.lower() for s in include]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
389
|
if exclude: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
390
|
exclude = set([s.lower() for s in exclude]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
391
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
392
|
exclude = set([]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
393
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
394
|
# Check for mutual exclusion of show_only and exclude sets |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
395
|
# after normalizing the values to lowercase |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
396
|
if include and exclude: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
397
|
assert not (include & exclude) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
398
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
399
|
# Traverse the graph in a depth first manner and filter the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
400
|
# nodes according to `show_only` and `exclude` sets |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
401
|
stack = deque() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
402
|
m = {} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
403
|
seen = set([]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
404
|
for node in self._obj.keys(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
405
|
if node.key in exclude: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
406
|
continue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
407
|
if include is None or node.key in include: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
408
|
stack.append(node) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
409
|
while True: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
410
|
if len(stack) > 0: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
411
|
n = stack.pop() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
412
|
cldn = [c for c in self._obj[n] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
413
|
if c.key not in exclude] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
414
|
m[n] = cldn |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
415
|
seen.add(n.key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
416
|
for c in cldn: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
417
|
if c.key not in seen: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
418
|
cld_node = self.get_node_as_parent(c.key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
419
|
if cld_node: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
420
|
stack.append(cld_node) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
421
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
422
|
# It means there's no root node |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
423
|
# corresponding to the child node |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
424
|
# ie. a dependency is missing |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
425
|
continue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
426
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
427
|
break |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
428
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
429
|
return self.__class__(m) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
430
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
431
|
def reverse(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
432
|
"""Reverse the DAG, or turn it upside-down |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
433
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
434
|
In other words, the directions of edges of the nodes in the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
435
|
DAG will be reversed. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
436
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
437
|
Note that this function purely works on the nodes in the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
438
|
graph. This implies that to perform a combination of filtering |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
439
|
and reversing, the order in which `filter` and `reverse` |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
440
|
methods should be applied is important. For eg. if reverse is |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
441
|
called on a filtered graph, then only the filtered nodes and |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
442
|
it's children will be considered when reversing. On the other |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
443
|
hand, if filter is called on reversed DAG, then the definition |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
444
|
of "child" nodes is as per the reversed DAG. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
445
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
446
|
:returns: DAG in the reversed form |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
447
|
:rtype: ReversedPackageDAG |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
448
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
449
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
450
|
m = defaultdict(list) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
451
|
child_keys = set(r.key for r in flatten(self._obj.values())) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
452
|
for k, vs in self._obj.items(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
453
|
for v in vs: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
454
|
# if v is already added to the dict, then ensure that |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
455
|
# we are using the same object. This check is required |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
456
|
# as we're using array mutation |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
457
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
458
|
node = [p for p in m.keys() if p.key == v.key][0] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
459
|
except IndexError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
460
|
node = v |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
461
|
m[node].append(k.as_parent_of(v)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
462
|
if k.key not in child_keys: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
463
|
m[k.as_requirement()] = [] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
464
|
return ReversedPackageDAG(dict(m)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
465
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
466
|
def sort(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
467
|
"""Return sorted tree in which the underlying _obj dict is an |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
468
|
OrderedDict, sorted alphabetically by the keys |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
469
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
470
|
:returns: Instance of same class with OrderedDict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
471
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
472
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
473
|
return self.__class__(sorted_tree(self._obj)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
474
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
475
|
# Methods required by the abstract base class Mapping |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
476
|
def __getitem__(self, *args): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
477
|
return self._obj.get(*args) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
478
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
479
|
def __iter__(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
480
|
return self._obj.__iter__() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
481
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
482
|
def __len__(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
483
|
return len(self._obj) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
484
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
485
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
486
|
class ReversedPackageDAG(PackageDAG): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
487
|
"""Representation of Package dependencies in the reverse |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
488
|
order. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
489
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
490
|
Similar to it's super class `PackageDAG`, the underlying |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
491
|
datastructure is a dict, but here the keys are expected to be of |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
492
|
type `ReqPackage` and each item in the values of type |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
493
|
`DistPackage`. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
494
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
495
|
Typically, this object will be obtained by calling |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
496
|
`PackageDAG.reverse`. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
497
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
498
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
499
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
500
|
def reverse(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
501
|
"""Reverse the already reversed DAG to get the PackageDAG again |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
502
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
503
|
:returns: reverse of the reversed DAG |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
504
|
:rtype: PackageDAG |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
505
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
506
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
507
|
m = defaultdict(list) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
508
|
child_keys = set(r.key for r in flatten(self._obj.values())) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
509
|
for k, vs in self._obj.items(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
510
|
for v in vs: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
511
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
512
|
node = [p for p in m.keys() if p.key == v.key][0] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
513
|
except IndexError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
514
|
node = v.as_parent_of(None) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
515
|
m[node].append(k) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
516
|
if k.key not in child_keys: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
517
|
m[k.dist] = [] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
518
|
return PackageDAG(dict(m)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
519
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
520
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
521
|
def render_text(tree, list_all=True, frozen=False): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
522
|
"""Print tree as text on console |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
523
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
524
|
:param dict tree: the package tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
525
|
:param bool list_all: whether to list all the pgks at the root |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
526
|
level or only those that are the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
527
|
sub-dependencies |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
528
|
:param bool frozen: whether or not show the names of the pkgs in |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
529
|
the output that's favourable to pip --freeze |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
530
|
:returns: None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
531
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
532
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
533
|
tree = tree.sort() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
534
|
nodes = tree.keys() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
535
|
branch_keys = set(r.key for r in flatten(tree.values())) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
536
|
use_bullets = not frozen |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
537
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
538
|
if not list_all: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
539
|
nodes = [p for p in nodes if p.key not in branch_keys] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
540
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
541
|
def aux(node, parent=None, indent=0, chain=None): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
542
|
chain = chain or [] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
543
|
node_str = node.render(parent, frozen) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
544
|
if parent: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
545
|
prefix = ' '*indent + ('- ' if use_bullets else '') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
546
|
node_str = prefix + node_str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
547
|
result = [node_str] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
548
|
children = [aux(c, node, indent=indent+2, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
549
|
chain=chain+[c.project_name]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
550
|
for c in tree.get_children(node.key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
551
|
if c.project_name not in chain] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
552
|
result += list(flatten(children)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
553
|
return result |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
554
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
555
|
lines = flatten([aux(p) for p in nodes]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
556
|
print('\n'.join(lines)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
557
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
558
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
559
|
def render_json(tree, indent): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
560
|
"""Converts the tree into a flat json representation. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
561
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
562
|
The json repr will be a list of hashes, each hash having 2 fields: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
563
|
- package |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
564
|
- dependencies: list of dependencies |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
565
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
566
|
:param dict tree: dependency tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
567
|
:param int indent: no. of spaces to indent json |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
568
|
:returns: json representation of the tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
569
|
:rtype: str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
570
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
571
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
572
|
tree = tree.sort() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
573
|
return json.dumps([{'package': k.as_dict(), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
574
|
'dependencies': [v.as_dict() for v in vs]} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
575
|
for k, vs in tree.items()], |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
576
|
indent=indent) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
577
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
578
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
579
|
def render_json_tree(tree, indent): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
580
|
"""Converts the tree into a nested json representation. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
581
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
582
|
The json repr will be a list of hashes, each hash having the following fields: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
583
|
- package_name |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
584
|
- key |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
585
|
- required_version |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
586
|
- installed_version |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
587
|
- dependencies: list of dependencies |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
588
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
589
|
:param dict tree: dependency tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
590
|
:param int indent: no. of spaces to indent json |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
591
|
:returns: json representation of the tree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
592
|
:rtype: str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
593
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
594
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
595
|
tree = tree.sort() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
596
|
branch_keys = set(r.key for r in flatten(tree.values())) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
597
|
nodes = [p for p in tree.keys() if p.key not in branch_keys] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
598
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
599
|
def aux(node, parent=None, chain=None): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
600
|
if chain is None: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
601
|
chain = [node.project_name] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
602
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
603
|
d = node.as_dict() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
604
|
if parent: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
605
|
d['required_version'] = node.version_spec if node.version_spec else 'Any' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
606
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
607
|
d['required_version'] = d['installed_version'] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
608
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
609
|
d['dependencies'] = [ |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
610
|
aux(c, parent=node, chain=chain+[c.project_name]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
611
|
for c in tree.get_children(node.key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
612
|
if c.project_name not in chain |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
613
|
] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
614
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
615
|
return d |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
616
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
617
|
return json.dumps([aux(p) for p in nodes], indent=indent) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
618
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
619
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
620
|
def dump_graphviz(tree, output_format='dot', is_reverse=False): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
621
|
"""Output dependency graph as one of the supported GraphViz output formats. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
622
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
623
|
:param dict tree: dependency graph |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
624
|
:param string output_format: output format |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
625
|
:returns: representation of tree in the specified output format |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
626
|
:rtype: str or binary representation depending on the output format |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
627
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
628
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
629
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
630
|
from graphviz import Digraph |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
631
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
632
|
print('graphviz is not available, but necessary for the output ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
633
|
'option. Please install it.', file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
634
|
sys.exit(1) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
635
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
636
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
637
|
from graphviz import parameters |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
638
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
639
|
from graphviz import backend |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
640
|
valid_formats = backend.FORMATS |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
641
|
print('Deprecation warning! Please upgrade graphviz to version >=0.18.0 ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
642
|
'Support for older versions will be removed in upcoming release', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
643
|
file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
644
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
645
|
valid_formats = parameters.FORMATS |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
646
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
647
|
if output_format not in valid_formats: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
648
|
print('{0} is not a supported output format.'.format(output_format), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
649
|
file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
650
|
print('Supported formats are: {0}'.format( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
651
|
', '.join(sorted(valid_formats))), file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
652
|
sys.exit(1) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
653
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
654
|
graph = Digraph(format=output_format) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
655
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
656
|
if not is_reverse: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
657
|
for pkg, deps in tree.items(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
658
|
pkg_label = '{0}\\n{1}'.format(pkg.project_name, pkg.version) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
659
|
graph.node(pkg.key, label=pkg_label) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
660
|
for dep in deps: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
661
|
edge_label = dep.version_spec or 'any' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
662
|
if dep.is_missing: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
663
|
dep_label = '{0}\\n(missing)'.format(dep.project_name) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
664
|
graph.node(dep.key, label=dep_label, style='dashed') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
665
|
graph.edge(pkg.key, dep.key, style='dashed') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
666
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
667
|
graph.edge(pkg.key, dep.key, label=edge_label) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
668
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
669
|
for dep, parents in tree.items(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
670
|
dep_label = '{0}\\n{1}'.format(dep.project_name, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
671
|
dep.installed_version) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
672
|
graph.node(dep.key, label=dep_label) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
673
|
for parent in parents: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
674
|
# req reference of the dep associated with this |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
675
|
# particular parent package |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
676
|
req_ref = parent.req |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
677
|
edge_label = req_ref.version_spec or 'any' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
678
|
graph.edge(dep.key, parent.key, label=edge_label) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
679
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
680
|
# Allow output of dot format, even if GraphViz isn't installed. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
681
|
if output_format == 'dot': |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
682
|
return graph.source |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
683
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
684
|
# As it's unknown if the selected output format is binary or not, try to |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
685
|
# decode it as UTF8 and only print it out in binary if that's not possible. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
686
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
687
|
return graph.pipe().decode('utf-8') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
688
|
except UnicodeDecodeError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
689
|
return graph.pipe() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
690
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
691
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
692
|
def print_graphviz(dump_output): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
693
|
"""Dump the data generated by GraphViz to stdout. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
694
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
695
|
:param dump_output: The output from dump_graphviz |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
696
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
697
|
if hasattr(dump_output, 'encode'): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
698
|
print(dump_output) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
699
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
700
|
with os.fdopen(sys.stdout.fileno(), 'wb') as bytestream: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
701
|
bytestream.write(dump_output) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
702
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
703
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
704
|
def conflicting_deps(tree): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
705
|
"""Returns dependencies which are not present or conflict with the |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
706
|
requirements of other packages. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
707
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
708
|
e.g. will warn if pkg1 requires pkg2==2.0 and pkg2==1.0 is installed |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
709
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
710
|
:param tree: the requirements tree (dict) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
711
|
:returns: dict of DistPackage -> list of unsatisfied/unknown ReqPackage |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
712
|
:rtype: dict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
713
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
714
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
715
|
conflicting = defaultdict(list) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
716
|
for p, rs in tree.items(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
717
|
for req in rs: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
718
|
if req.is_conflicting(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
719
|
conflicting[p].append(req) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
720
|
return conflicting |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
721
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
722
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
723
|
def render_conflicts_text(conflicts): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
724
|
if conflicts: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
725
|
print('Warning!!! Possibly conflicting dependencies found:', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
726
|
file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
727
|
# Enforce alphabetical order when listing conflicts |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
728
|
pkgs = sorted(conflicts.keys()) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
729
|
for p in pkgs: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
730
|
pkg = p.render_as_root(False) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
731
|
print('* {}'.format(pkg), file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
732
|
for req in conflicts[p]: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
733
|
req_str = req.render_as_branch(False) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
734
|
print(' - {}'.format(req_str), file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
735
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
736
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
737
|
def cyclic_deps(tree): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
738
|
"""Return cyclic dependencies as list of tuples |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
739
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
740
|
:param PackageDAG pkgs: package tree/dag |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
741
|
:returns: list of tuples representing cyclic dependencies |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
742
|
:rtype: list |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
743
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
744
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
745
|
index = {p.key: set([r.key for r in rs]) for p, rs in tree.items()} |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
746
|
cyclic = [] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
747
|
for p, rs in tree.items(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
748
|
for r in rs: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
749
|
if p.key in index.get(r.key, []): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
750
|
p_as_dep_of_r = [x for x |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
751
|
in tree.get(tree.get_node_as_parent(r.key)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
752
|
if x.key == p.key][0] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
753
|
cyclic.append((p, r, p_as_dep_of_r)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
754
|
return cyclic |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
755
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
756
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
757
|
def render_cycles_text(cycles): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
758
|
if cycles: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
759
|
print('Warning!! Cyclic dependencies found:', file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
760
|
# List in alphabetical order of the dependency that's cycling |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
761
|
# (2nd item in the tuple) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
762
|
cycles = sorted(cycles, key=lambda xs: xs[1].key) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
763
|
for a, b, c in cycles: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
764
|
print('* {0} => {1} => {2}'.format(a.project_name, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
765
|
b.project_name, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
766
|
c.project_name), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
767
|
file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
768
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
769
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
770
|
def get_parser(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
771
|
parser = argparse.ArgumentParser(description=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
772
|
'Dependency tree of the installed python packages' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
773
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
774
|
parser.add_argument('-v', '--version', action='version', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
775
|
version='{0}'.format(__version__)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
776
|
parser.add_argument('-f', '--freeze', action='store_true', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
777
|
help='Print names so as to write freeze files') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
778
|
parser.add_argument('--python', default=sys.executable, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
779
|
help='Python to use to look for packages in it (default: where' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
780
|
' installed)') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
781
|
parser.add_argument('-a', '--all', action='store_true', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
782
|
help='list all deps at top level') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
783
|
parser.add_argument('-l', '--local-only', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
784
|
action='store_true', help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
785
|
'If in a virtualenv that has global access ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
786
|
'do not show globally installed packages' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
787
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
788
|
parser.add_argument('-u', '--user-only', action='store_true', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
789
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
790
|
'Only show installations in the user site dir' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
791
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
792
|
parser.add_argument('-w', '--warn', action='store', dest='warn', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
793
|
nargs='?', default='suppress', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
794
|
choices=('silence', 'suppress', 'fail'), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
795
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
796
|
'Warning control. "suppress" will show warnings ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
797
|
'but return 0 whether or not they are present. ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
798
|
'"silence" will not show warnings at all and ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
799
|
'always return 0. "fail" will show warnings and ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
800
|
'return 1 if any are present. The default is ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
801
|
'"suppress".' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
802
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
803
|
parser.add_argument('-r', '--reverse', action='store_true', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
804
|
default=False, help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
805
|
'Shows the dependency tree in the reverse fashion ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
806
|
'ie. the sub-dependencies are listed with the ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
807
|
'list of packages that need them under them.' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
808
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
809
|
parser.add_argument('-p', '--packages', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
810
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
811
|
'Comma separated list of select packages to show ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
812
|
'in the output. If set, --all will be ignored.' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
813
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
814
|
parser.add_argument('-e', '--exclude', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
815
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
816
|
'Comma separated list of select packages to exclude ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
817
|
'from the output. If set, --all will be ignored.' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
818
|
), metavar='PACKAGES') |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
819
|
parser.add_argument('-j', '--json', action='store_true', default=False, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
820
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
821
|
'Display dependency tree as json. This will yield ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
822
|
'"raw" output that may be used by external tools. ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
823
|
'This option overrides all other options.' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
824
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
825
|
parser.add_argument('--json-tree', action='store_true', default=False, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
826
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
827
|
'Display dependency tree as json which is nested ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
828
|
'the same way as the plain text output printed by default. ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
829
|
'This option overrides all other options (except --json).' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
830
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
831
|
parser.add_argument('--graph-output', dest='output_format', |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
832
|
help=( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
833
|
'Print a dependency graph in the specified output ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
834
|
'format. Available are all formats supported by ' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
835
|
'GraphViz, e.g.: dot, jpeg, pdf, png, svg' |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
836
|
)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
837
|
return parser |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
838
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
839
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
840
|
def _get_args(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
841
|
parser = get_parser() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
842
|
return parser.parse_args() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
843
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
844
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
845
|
def handle_non_host_target(args): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
846
|
of_python = os.path.abspath(args.python) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
847
|
# if target is not current python re-invoke it under the actual host |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
848
|
if of_python != os.path.abspath(sys.executable): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
849
|
# there's no way to guarantee that graphviz is available, so refuse |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
850
|
if args.output_format: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
851
|
print("graphviz functionality is not supported when querying" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
852
|
" non-host python", file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
853
|
raise SystemExit(1) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
854
|
argv = sys.argv[1:] # remove current python executable |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
855
|
for py_at, value in enumerate(argv): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
856
|
if value == "--python": |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
857
|
del argv[py_at] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
858
|
del argv[py_at] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
859
|
elif value.startswith("--python"): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
860
|
del argv[py_at] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
861
|
# feed the file as argument, instead of file |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
862
|
# to avoid adding the file path to sys.path, that can affect result |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
863
|
file_path = inspect.getsourcefile(sys.modules[__name__]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
864
|
with open(file_path, 'rt') as file_handler: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
865
|
content = file_handler.read() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
866
|
cmd = [of_python, "-c", content] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
867
|
cmd.extend(argv) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
868
|
# invoke from an empty folder to avoid cwd altering sys.path |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
869
|
cwd = tempfile.mkdtemp() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
870
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
871
|
return subprocess.call(cmd, cwd=cwd) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
872
|
finally: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
873
|
os.removedirs(cwd) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
874
|
return None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
875
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
876
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
877
|
def get_installed_distributions(local_only=False, user_only=False): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
878
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
879
|
from pip._internal.metadata import get_environment |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
880
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
881
|
# For backward compatibility with python ver. 2.7 and pip |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
882
|
# version 20.3.4 (latest pip version that works with python |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
883
|
# version 2.7) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
884
|
from pip._internal.utils import misc |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
885
|
return misc.get_installed_distributions( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
886
|
local_only=local_only, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
887
|
user_only=user_only |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
888
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
889
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
890
|
dists = get_environment(None).iter_installed_distributions( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
891
|
local_only=local_only, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
892
|
skip=(), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
893
|
user_only=user_only |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
894
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
895
|
return [d._dist for d in dists] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
896
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
897
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
898
|
def main(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
899
|
os.environ["_PIP_USE_IMPORTLIB_METADATA"] = "False" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
900
|
# patched for 3.11+ compatibility |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
901
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
902
|
args = _get_args() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
903
|
result = handle_non_host_target(args) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
904
|
if result is not None: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
905
|
return result |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
906
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
907
|
pkgs = get_installed_distributions(local_only=args.local_only, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
908
|
user_only=args.user_only) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
909
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
910
|
tree = PackageDAG.from_pkgs(pkgs) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
911
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
912
|
is_text_output = not any([args.json, args.json_tree, args.output_format]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
913
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
914
|
return_code = 0 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
915
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
916
|
# Before any reversing or filtering, show warnings to console |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
917
|
# about possibly conflicting or cyclic deps if found and warnings |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
918
|
# are enabled (ie. only if output is to be printed to console) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
919
|
if is_text_output and args.warn != 'silence': |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
920
|
conflicts = conflicting_deps(tree) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
921
|
if conflicts: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
922
|
render_conflicts_text(conflicts) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
923
|
print('-'*72, file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
924
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
925
|
cycles = cyclic_deps(tree) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
926
|
if cycles: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
927
|
render_cycles_text(cycles) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
928
|
print('-'*72, file=sys.stderr) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
929
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
930
|
if args.warn == 'fail' and (conflicts or cycles): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
931
|
return_code = 1 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
932
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
933
|
# Reverse the tree (if applicable) before filtering, thus ensuring |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
934
|
# that the filter will be applied on ReverseTree |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
935
|
if args.reverse: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
936
|
tree = tree.reverse() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
937
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
938
|
show_only = set(args.packages.split(',')) if args.packages else None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
939
|
exclude = set(args.exclude.split(',')) if args.exclude else None |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
940
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
941
|
if show_only is not None or exclude is not None: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
942
|
tree = tree.filter(show_only, exclude) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
943
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
944
|
if args.json: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
945
|
print(render_json(tree, indent=4)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
946
|
elif args.json_tree: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
947
|
print(render_json_tree(tree, indent=4)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
948
|
elif args.output_format: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
949
|
output = dump_graphviz(tree, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
950
|
output_format=args.output_format, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
951
|
is_reverse=args.reverse) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
952
|
print_graphviz(output) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
953
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
954
|
render_text(tree, args.all, args.freeze) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
955
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
956
|
return return_code |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
957
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
958
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
959
|
if __name__ == '__main__': |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
960
|
sys.exit(main()) |