Chromium Code Reviews| Index: go/clean_goop.py |
| diff --git a/go/clean_goop.py b/go/clean_goop.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..36ae6e81c419bf01a5ae55fac205153a97e7f924 |
| --- /dev/null |
| +++ b/go/clean_goop.py |
| @@ -0,0 +1,104 @@ |
| +#!/usr/bin/env python |
| +# Copyright 2015 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""Suggests what Goop file entries can be removed. |
| + |
| +Horribly slow, but simple. Evaluates recursive dependencies of all packages |
| +in infra/go/... (including github ones) and compares them against Goopfile.lock |
| +entries. |
| + |
| +Supposed to be called under activated go environment. |
| +""" |
| + |
| +import os |
| +import subprocess |
| +import sys |
| + |
| +# For VENDORED_TOOLS. |
| +import bootstrap |
| + |
| + |
| +GO_DIR = os.path.dirname(os.path.abspath(__file__)) |
|
nodir
2015/09/29 16:46:05
You can check that $GOROOT equals this and suggest
Vadim Sh.
2015/09/29 19:49:34
GOROOT points to goland SDK. GOPATH have multiple
|
| + |
| + |
| +# List of Goopfile.lock entries we want to keep because they are imported only |
| +# when building on Windows (and thus detected as unused when script is used |
| +# on Linux). |
| +EXCEPTIONS = [ |
| + 'github.com/mattn/go-isatty', |
| + 'github.com/olekukonko/ts', |
| +] |
| + |
| + |
| +def get_deps(pkg_glob): |
|
tandrii(chromium)
2015/09/29 10:17:27
Add caching of the result, and it'll be so much fa
Vadim Sh.
2015/09/29 19:49:34
Added cache, it doesn't make much difference.
|
| + """Returns a set of imported dependencies.""" |
| + cmd = ['go', 'list', '-f', '{{ join .Deps "\\n" }}', pkg_glob] |
|
nodir
2015/09/29 16:46:05
this must be ran with GO_DIR as current dir, becau
Vadim Sh.
2015/09/29 19:49:34
relpath(...) below builds correct path regardless
nodir
2015/09/29 20:39:13
I just ran go/clean_goop.py from root and it error
|
| + print 'Running ', cmd |
| + deps = subprocess.check_output(cmd).strip() |
| + return sorted(set(deps.splitlines())) |
| + |
| + |
| +def get_all_goop(): |
|
tandrii(chromium)
2015/09/29 10:17:27
and maybe cache this too?
Vadim Sh.
2015/09/29 19:49:33
Done.
|
| + """Returns a list of packages specified in Goopfile.lock.""" |
| + with open(os.path.join(GO_DIR, 'Goopfile.lock'), 'rt') as f: |
|
nodir
2015/09/29 16:46:05
't' mode is unnecessary to specify since it is def
Vadim Sh.
2015/09/29 19:49:34
r is too for that matter
|
| + goop = f.read() |
|
tandrii(chromium)
2015/09/29 10:17:27
nit: return [l.split()[0] for l in f]
Vadim Sh.
2015/09/29 19:49:34
Done.
|
| + return [line.split()[0] for line in goop.splitlines()] |
| + |
| + |
| +def get_used_goop(deps): |
| + """Returns set of packages in Goopfile.lock that cover a dependency list.""" |
| + used = set() |
| + for pkg in get_all_goop(): |
| + for dep in deps: |
| + # If goop pkg covers at least one dependency, it is used. |
| + if dep.startswith(pkg): |
|
nodir
2015/09/29 16:46:05
if dep == pkg or dep.startswith(pkg+'/'):
Vadim Sh.
2015/09/29 19:49:34
Done.
|
| + used.add(pkg) |
| + break |
| + return used |
| + |
| + |
| +def main(): |
| + all_deps = set(EXCEPTIONS) |
| + |
| + # We want to enumerate packages in infra/go/src/... and only them (not all |
| + # packages in GOPAHT, since we don't want to enumerate vendored packages). |
|
nodir
2015/09/29 16:46:05
GOPATH
|
| + # A package glob needs to start with '.' or '..' to be interpreted as file |
| + # system path. See 'go help packages'. |
| + go_dir_rel = os.path.relpath(os.path.join(GO_DIR)) |
|
nodir
2015/09/29 16:46:05
os.path.join(GO_DIR) == GO_DIR ? Am I missing some
Vadim Sh.
2015/09/29 19:49:34
There used to be something else there.
|
| + assert go_dir_rel.startswith('.') |
| + all_deps.update(get_deps(os.path.join(go_dir_rel, 'src', '...'))) |
| + |
| + # Tools build by bootstrap script may not be directly referenced by src/ code. |
| + for tool in bootstrap.VENDORED_TOOLS: |
| + all_deps.add(tool) |
| + all_deps.update(get_deps(tool)) |
| + |
| + # all_deps is all direct dependencies of infra/go/src code. Find what part of |
| + # Goopfile.lock covers them. Then recurse into them. Note that Goopfile |
| + # may specify a parent package of a package used in actual code. So recursing |
| + # into deps of that parent package may reveal more dependencies. |
| + goop_deps = set() |
| + while True: |
| + for pkg in goop_deps: |
|
nodir
2015/09/29 16:46:05
goop_deps is set() in the first iteration. Then it
Vadim Sh.
2015/09/29 19:49:33
Done.
|
| + all_deps.update(get_deps(pkg + '/...')) |
| + new_goop_deps = get_used_goop(all_deps) |
| + if new_goop_deps == goop_deps: |
| + break |
| + goop_deps = new_goop_deps |
| + |
| + # Find what is not used. |
| + unused = [p for p in get_all_goop() if p not in goop_deps] |
| + if unused: |
| + print '-' * 80 |
| + print 'Consider removing from Goopfile following packages:' |
|
tandrii(chromium)
2015/09/29 10:17:27
nit: s/following/the following
Vadim Sh.
2015/09/29 19:49:34
Done.
|
| + print '\n'.join(unused) |
| + else: |
| + print 'Hooray! All Goopfile packages seems to be in use.' |
|
tandrii(chromium)
2015/09/29 10:17:28
s/seems/seem
Vadim Sh.
2015/09/29 19:49:34
Done.
|
| + |
| + return 0 |
| + |
| + |
| +if __name__ == '__main__': |
| + sys.exit(main()) |