1"""Contains helper functions to compute checksums for LLVM checkouts.
2"""
3from __future__ import absolute_import
4from __future__ import division
5from __future__ import print_function
6
7import logging
8import os
9import os.path
10import sys
11
12
13class LLVMProject(object):
14  """An LLVM project with a descriptive name and a relative checkout path.
15  """
16
17  def __init__(self, name, relpath):
18    self.name = name
19    self.relpath = relpath
20
21  def is_subproject(self, other_project):
22    """ Check if self is checked out as a subdirectory of other_project.
23    """
24    return self.relpath.startswith(other_project.relpath)
25
26
27def WalkProjectFiles(checkout_root, all_projects, project, visitor):
28  """ Walk over all files inside a project without recursing into subprojects, '.git' and '.svn' subfolders.
29
30    checkout_root: root of the LLVM checkout.
31    all_projects: projects in the LLVM checkout.
32    project: a project to walk the files of. Must be inside all_projects.
33    visitor: a function called on each visited file.
34  """
35  assert project in all_projects
36
37  ignored_paths = set()
38  for other_project in all_projects:
39    if other_project != project and other_project.is_subproject(project):
40      ignored_paths.add(os.path.join(checkout_root, other_project.relpath))
41
42  def raise_error(err):
43    raise err
44
45  project_root = os.path.join(checkout_root, project.relpath)
46  for root, dirs, files in os.walk(project_root, onerror=raise_error):
47    dirs[:] = [
48        d for d in dirs
49        if d != ".svn" and d != ".git" and
50        os.path.join(root, d) not in ignored_paths
51    ]
52    for f in files:
53      visitor(os.path.join(root, f))
54
55
56def CreateLLVMProjects(single_tree_checkout):
57  """Returns a list of LLVMProject instances, describing relative paths of a typical LLVM checkout.
58
59  Args:
60    single_tree_checkout:
61      When True, relative paths for each project points to a typical single
62        source tree checkout.
63      When False, relative paths for each projects points to a separate
64        directory. However, clang-tools-extra is an exception, its relative path
65        will always be 'clang/tools/extra'.
66  """
67  # FIXME: cover all of llvm projects.
68
69  # Projects that reside inside 'projects/' in a single source tree checkout.
70  ORDINARY_PROJECTS = [
71      "compiler-rt", "dragonegg", "libcxx", "libcxxabi", "libunwind",
72      "parallel-libs", "test-suite"
73  ]
74  # Projects that reside inside 'tools/' in a single source tree checkout.
75  TOOLS_PROJECTS = ["clang", "lld", "lldb"]
76
77  if single_tree_checkout:
78    projects = [LLVMProject("llvm", "")]
79    projects += [
80        LLVMProject(p, os.path.join("projects", p)) for p in ORDINARY_PROJECTS
81    ]
82    projects += [
83        LLVMProject(p, os.path.join("tools", p)) for p in TOOLS_PROJECTS
84    ]
85    projects.append(
86        LLVMProject("clang-tools-extra",
87                    os.path.join("tools", "clang", "tools", "extra")))
88  else:
89    projects = [LLVMProject("llvm", "llvm")]
90    projects += [LLVMProject(p, p) for p in ORDINARY_PROJECTS]
91    projects += [LLVMProject(p, p) for p in TOOLS_PROJECTS]
92    projects.append(
93        LLVMProject("clang-tools-extra", os.path.join("clang", "tools",
94                                                      "extra")))
95  return projects
96