depfile.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. # Copyright 2019 Red Hat, Inc.
  2. # Licensed under the Apache License, Version 2.0 (the "License");
  3. # you may not use this file except in compliance with the License.
  4. # You may obtain a copy of the License at
  5. # http://www.apache.org/licenses/LICENSE-2.0
  6. # Unless required by applicable law or agreed to in writing, software
  7. # distributed under the License is distributed on an "AS IS" BASIS,
  8. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. # See the License for the specific language governing permissions and
  10. # limitations under the License.
  11. import collections
  12. def parse(lines):
  13. rules = []
  14. targets = []
  15. deps = []
  16. in_deps = False
  17. out = ''
  18. for line in lines:
  19. if not line.endswith('\n'):
  20. line += '\n'
  21. escape = None
  22. for c in line:
  23. if escape:
  24. if escape == '$' and c != '$':
  25. out += '$'
  26. if escape == '\\' and c == '\n':
  27. continue
  28. out += c
  29. escape = None
  30. continue
  31. if c == '\\' or c == '$':
  32. escape = c
  33. continue
  34. elif c in (' ', '\n'):
  35. if out != '':
  36. if in_deps:
  37. deps.append(out)
  38. else:
  39. targets.append(out)
  40. out = ''
  41. if c == '\n':
  42. rules.append((targets, deps))
  43. targets = []
  44. deps = []
  45. in_deps = False
  46. continue
  47. elif c == ':':
  48. targets.append(out)
  49. out = ''
  50. in_deps = True
  51. continue
  52. out += c
  53. return rules
  54. Target = collections.namedtuple('Target', ['deps'])
  55. class DepFile:
  56. def __init__(self, lines):
  57. rules = parse(lines)
  58. depfile = {}
  59. for (targets, deps) in rules:
  60. for target in targets:
  61. t = depfile.setdefault(target, Target(deps=set()))
  62. for dep in deps:
  63. t.deps.add(dep)
  64. self.depfile = depfile
  65. def get_all_dependencies(self, target, visited=None):
  66. deps = set()
  67. if not visited:
  68. visited = set()
  69. if target in visited:
  70. return set()
  71. visited.add(target)
  72. target = self.depfile.get(target)
  73. if not target:
  74. return set()
  75. deps.update(target.deps)
  76. for dep in target.deps:
  77. deps.update(self.get_all_dependencies(dep, visited))
  78. return deps