Mercurial > hg
annotate contrib/import-checker.py @ 25018:93e015a3d1ea
commit: add ui.allowemptycommit config option
This adds a config flag that enables a user to make empty commits.
This is useful in a number of cases.
For instance, automation that creates release branches via
bookmarks may want to make empty commits to that release bookmark so that it
can't be fast-forwarded and so it can record information about the release
bookmark's creation. This is already possible with named branches, so making it
possible for bookmarks makes sense.
Another case we've wanted it is for mirroring repositories into Mercurial. We
have automation that syncs commits into hg by running things from the command
line. The ability to produce empty commits is useful for syncing unusual commits
from other VCS's.
In general, allowing the user to create the DAG as they see fit seems useful,
and when I mentioned this in IRC more than one person piped up and said they
were already hacking around this limitation by using mq, import, and
commit-dummy-change-then-amend-the-content-away style solutions.
author | Durham Goode <durham@fb.com> |
---|---|
date | Mon, 11 May 2015 16:18:28 -0700 |
parents | fbdbff1b486a |
children | 723e364488f4 |
rev | line source |
---|---|
20036 | 1 import ast |
2 import os | |
3 import sys | |
4 | |
20198
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
5 # Import a minimal set of stdlib modules needed for list_stdlib_modules() |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
6 # to work when run from a virtualenv. The modules were chosen empirically |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
7 # so that the return value matches the return value without virtualenv. |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
8 import BaseHTTPServer |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
9 import zlib |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
10 |
22975
461342e1c8aa
import-checker: check modules for pure Python build correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
22974
diff
changeset
|
11 def dotted_name_of_path(path, trimpure=False): |
20036 | 12 """Given a relative path to a source file, return its dotted module name. |
13 | |
14 >>> dotted_name_of_path('mercurial/error.py') | |
15 'mercurial.error' | |
22975
461342e1c8aa
import-checker: check modules for pure Python build correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
22974
diff
changeset
|
16 >>> dotted_name_of_path('mercurial/pure/parsers.py', trimpure=True) |
461342e1c8aa
import-checker: check modules for pure Python build correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
22974
diff
changeset
|
17 'mercurial.parsers' |
20383
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
18 >>> dotted_name_of_path('zlibmodule.so') |
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
19 'zlib' |
20036 | 20 """ |
21 parts = path.split('/') | |
20391
466e4c574db0
import-checker: handle standard modules with arch in the filename
Mads Kiilerich <madski@unity3d.com>
parents:
20386
diff
changeset
|
22 parts[-1] = parts[-1].split('.', 1)[0] # remove .py and .so and .ARCH.so |
20383
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
23 if parts[-1].endswith('module'): |
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
24 parts[-1] = parts[-1][:-6] |
22975
461342e1c8aa
import-checker: check modules for pure Python build correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
22974
diff
changeset
|
25 if trimpure: |
461342e1c8aa
import-checker: check modules for pure Python build correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
22974
diff
changeset
|
26 return '.'.join(p for p in parts if p != 'pure') |
20036 | 27 return '.'.join(parts) |
28 | |
29 | |
30 def list_stdlib_modules(): | |
31 """List the modules present in the stdlib. | |
32 | |
33 >>> mods = set(list_stdlib_modules()) | |
34 >>> 'BaseHTTPServer' in mods | |
35 True | |
36 | |
37 os.path isn't really a module, so it's missing: | |
38 | |
39 >>> 'os.path' in mods | |
40 False | |
41 | |
42 sys requires special treatment, because it's baked into the | |
43 interpreter, but it should still appear: | |
44 | |
45 >>> 'sys' in mods | |
46 True | |
47 | |
48 >>> 'collections' in mods | |
49 True | |
50 | |
51 >>> 'cStringIO' in mods | |
52 True | |
53 """ | |
54 for m in sys.builtin_module_names: | |
55 yield m | |
56 # These modules only exist on windows, but we should always | |
57 # consider them stdlib. | |
58 for m in ['msvcrt', '_winreg']: | |
59 yield m | |
60 # These get missed too | |
61 for m in 'ctypes', 'email': | |
62 yield m | |
63 yield 'builtins' # python3 only | |
24669
fbdbff1b486a
import-checker: force 'fcntl', 'grp', 'pwd', and 'termios' to stdlib modules
Matt Harbison <matt_harbison@yahoo.com>
parents:
24668
diff
changeset
|
64 for m in 'fcntl', 'grp', 'pwd', 'termios': # Unix only |
fbdbff1b486a
import-checker: force 'fcntl', 'grp', 'pwd', and 'termios' to stdlib modules
Matt Harbison <matt_harbison@yahoo.com>
parents:
24668
diff
changeset
|
65 yield m |
20197
761f2929a6ad
import-checker: refactor sys.path prefix check (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20038
diff
changeset
|
66 stdlib_prefixes = set([sys.prefix, sys.exec_prefix]) |
20198
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
67 # We need to supplement the list of prefixes for the search to work |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
68 # when run from within a virtualenv. |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
69 for mod in (BaseHTTPServer, zlib): |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
70 try: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
71 # Not all module objects have a __file__ attribute. |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
72 filename = mod.__file__ |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
73 except AttributeError: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
74 continue |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
75 dirname = os.path.dirname(filename) |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
76 for prefix in stdlib_prefixes: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
77 if dirname.startswith(prefix): |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
78 # Then this directory is redundant. |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
79 break |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
80 else: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
81 stdlib_prefixes.add(dirname) |
20036 | 82 for libpath in sys.path: |
20201
bc3b48b0f5c8
import-checker: suppress check-code about any()
Augie Fackler <raf@durin42.com>
parents:
20200
diff
changeset
|
83 # We want to walk everything in sys.path that starts with |
bc3b48b0f5c8
import-checker: suppress check-code about any()
Augie Fackler <raf@durin42.com>
parents:
20200
diff
changeset
|
84 # something in stdlib_prefixes. check-code suppressed because |
bc3b48b0f5c8
import-checker: suppress check-code about any()
Augie Fackler <raf@durin42.com>
parents:
20200
diff
changeset
|
85 # the ast module used by this script implies the availability |
bc3b48b0f5c8
import-checker: suppress check-code about any()
Augie Fackler <raf@durin42.com>
parents:
20200
diff
changeset
|
86 # of any(). |
20238
81e905790b30
check-code: do not skip entire file, skip only one match instead
Simon Heimberg <simohe@besonet.ch>
parents:
20201
diff
changeset
|
87 if not any(libpath.startswith(p) for p in stdlib_prefixes): # no-py24 |
20036 | 88 continue |
89 if 'site-packages' in libpath: | |
90 continue | |
91 for top, dirs, files in os.walk(libpath): | |
92 for name in files: | |
93 if name == '__init__.py': | |
94 continue | |
24668
81873bb2a01d
import-checker: allow *.pyd based stdlib modules
Matt Harbison <matt_harbison@yahoo.com>
parents:
24491
diff
changeset
|
95 if not (name.endswith('.py') or name.endswith('.so') |
81873bb2a01d
import-checker: allow *.pyd based stdlib modules
Matt Harbison <matt_harbison@yahoo.com>
parents:
24491
diff
changeset
|
96 or name.endswith('.pyd')): |
20036 | 97 continue |
98 full_path = os.path.join(top, name) | |
99 if 'site-packages' in full_path: | |
100 continue | |
101 rel_path = full_path[len(libpath) + 1:] | |
102 mod = dotted_name_of_path(rel_path) | |
103 yield mod | |
104 | |
105 stdlib_modules = set(list_stdlib_modules()) | |
106 | |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
107 def imported_modules(source, ignore_nested=False): |
20036 | 108 """Given the source of a file as a string, yield the names |
109 imported by that file. | |
110 | |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
111 Args: |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
112 source: The python source to examine as a string. |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
113 ignore_nested: If true, import statements that do not start in |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
114 column zero will be ignored. |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
115 |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
116 Returns: |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
117 A list of module names imported by the given source. |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
118 |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
119 >>> sorted(imported_modules( |
20036 | 120 ... 'import foo ; from baz import bar; import foo.qux')) |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
121 ['baz.bar', 'foo', 'foo.qux'] |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
122 >>> sorted(imported_modules( |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
123 ... '''import foo |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
124 ... def wat(): |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
125 ... import bar |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
126 ... ''', ignore_nested=True)) |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
127 ['foo'] |
20036 | 128 """ |
129 for node in ast.walk(ast.parse(source)): | |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
130 if ignore_nested and getattr(node, 'col_offset', 0) > 0: |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
131 continue |
20036 | 132 if isinstance(node, ast.Import): |
133 for n in node.names: | |
134 yield n.name | |
135 elif isinstance(node, ast.ImportFrom): | |
136 prefix = node.module + '.' | |
137 for n in node.names: | |
138 yield prefix + n.name | |
139 | |
140 def verify_stdlib_on_own_line(source): | |
141 """Given some python source, verify that stdlib imports are done | |
142 in separate statements from relative local module imports. | |
143 | |
144 Observing this limitation is important as it works around an | |
145 annoying lib2to3 bug in relative import rewrites: | |
146 http://bugs.python.org/issue19510. | |
147 | |
148 >>> list(verify_stdlib_on_own_line('import sys, foo')) | |
20386
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
149 ['mixed imports\\n stdlib: sys\\n relative: foo'] |
20036 | 150 >>> list(verify_stdlib_on_own_line('import sys, os')) |
151 [] | |
152 >>> list(verify_stdlib_on_own_line('import foo, bar')) | |
153 [] | |
154 """ | |
155 for node in ast.walk(ast.parse(source)): | |
156 if isinstance(node, ast.Import): | |
20386
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
157 from_stdlib = {False: [], True: []} |
20036 | 158 for n in node.names: |
20386
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
159 from_stdlib[n.name in stdlib_modules].append(n.name) |
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
160 if from_stdlib[True] and from_stdlib[False]: |
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
161 yield ('mixed imports\n stdlib: %s\n relative: %s' % |
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
162 (', '.join(sorted(from_stdlib[True])), |
a05d31b040d7
import-checker: show stdlib and relative imports separately
Mads Kiilerich <madski@unity3d.com>
parents:
20383
diff
changeset
|
163 ', '.join(sorted(from_stdlib[False])))) |
20036 | 164 |
165 class CircularImport(Exception): | |
166 pass | |
167 | |
24490
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
168 def checkmod(mod, imports): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
169 shortest = {} |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
170 visit = [[mod]] |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
171 while visit: |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
172 path = visit.pop(0) |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
173 for i in sorted(imports.get(path[-1], [])): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
174 if i not in stdlib_modules and not i.startswith('mercurial.'): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
175 i = mod.rsplit('.', 1)[0] + '.' + i |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
176 if len(path) < shortest.get(i, 1000): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
177 shortest[i] = len(path) |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
178 if i in path: |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
179 if i == path[0]: |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
180 raise CircularImport(path) |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
181 continue |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
182 visit.append(path + [i]) |
20036 | 183 |
20038
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
184 def rotatecycle(cycle): |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
185 """arrange a cycle so that the lexicographically first module listed first |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
186 |
24488
4b3fc46097f7
import-checker: drop duplicate element from cycle
Matt Mackall <mpm@selenic.com>
parents:
24487
diff
changeset
|
187 >>> rotatecycle(['foo', 'bar']) |
20038
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
188 ['bar', 'foo', 'bar'] |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
189 """ |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
190 lowest = min(cycle) |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
191 idx = cycle.index(lowest) |
24488
4b3fc46097f7
import-checker: drop duplicate element from cycle
Matt Mackall <mpm@selenic.com>
parents:
24487
diff
changeset
|
192 return cycle[idx:] + cycle[:idx] + [lowest] |
20036 | 193 |
194 def find_cycles(imports): | |
195 """Find cycles in an already-loaded import graph. | |
196 | |
197 >>> imports = {'top.foo': ['bar', 'os.path', 'qux'], | |
198 ... 'top.bar': ['baz', 'sys'], | |
199 ... 'top.baz': ['foo'], | |
200 ... 'top.qux': ['foo']} | |
201 >>> print '\\n'.join(sorted(find_cycles(imports))) | |
24487
642d245ff537
import-checker: fix rotatecycle
Matt Mackall <mpm@selenic.com>
parents:
22975
diff
changeset
|
202 top.bar -> top.baz -> top.foo -> top.bar |
642d245ff537
import-checker: fix rotatecycle
Matt Mackall <mpm@selenic.com>
parents:
22975
diff
changeset
|
203 top.foo -> top.qux -> top.foo |
20036 | 204 """ |
24491
784b278b349c
import-checker: rotatecycle is actually the canonical cycle key
Matt Mackall <mpm@selenic.com>
parents:
24490
diff
changeset
|
205 cycles = set() |
20036 | 206 for mod in sorted(imports.iterkeys()): |
207 try: | |
24490
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
208 checkmod(mod, imports) |
20036 | 209 except CircularImport, e: |
210 cycle = e.args[0] | |
24491
784b278b349c
import-checker: rotatecycle is actually the canonical cycle key
Matt Mackall <mpm@selenic.com>
parents:
24490
diff
changeset
|
211 cycles.add(" -> ".join(rotatecycle(cycle))) |
784b278b349c
import-checker: rotatecycle is actually the canonical cycle key
Matt Mackall <mpm@selenic.com>
parents:
24490
diff
changeset
|
212 return cycles |
20036 | 213 |
214 def _cycle_sortkey(c): | |
215 return len(c), c | |
216 | |
217 def main(argv): | |
218 if len(argv) < 2: | |
219 print 'Usage: %s file [file] [file] ...' | |
220 return 1 | |
221 used_imports = {} | |
222 any_errors = False | |
223 for source_path in argv[1:]: | |
224 f = open(source_path) | |
22975
461342e1c8aa
import-checker: check modules for pure Python build correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
22974
diff
changeset
|
225 modname = dotted_name_of_path(source_path, trimpure=True) |
20036 | 226 src = f.read() |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
227 used_imports[modname] = sorted( |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
228 imported_modules(src, ignore_nested=True)) |
20036 | 229 for error in verify_stdlib_on_own_line(src): |
230 any_errors = True | |
231 print source_path, error | |
232 f.close() | |
233 cycles = find_cycles(used_imports) | |
234 if cycles: | |
235 firstmods = set() | |
236 for c in sorted(cycles, key=_cycle_sortkey): | |
237 first = c.split()[0] | |
238 # As a rough cut, ignore any cycle that starts with the | |
239 # same module as some other cycle. Otherwise we see lots | |
240 # of cycles that are effectively duplicates. | |
241 if first in firstmods: | |
242 continue | |
243 print 'Import cycle:', c | |
244 firstmods.add(first) | |
245 any_errors = True | |
246 return not any_errors | |
247 | |
248 if __name__ == '__main__': | |
249 sys.exit(int(main(sys.argv))) |