board/csky: fixup gdb instructions in readme.txt
[buildroot-gz.git] / support / scripts / getdeveloperlib.py
blob65191073a3b1393ed511c19192d865cb5d32c333
1 import sys
2 import os
3 import re
4 import argparse
5 import glob
6 import subprocess
9 # Patch parsing functions
12 FIND_INFRA_IN_PATCH = re.compile("^\+\$\(eval \$\((host-)?([^-]*)-package\)\)$")
14 def analyze_patch(patch):
15 """Parse one patch and return the list of files modified, added or
16 removed by the patch."""
17 files = set()
18 infras = set()
19 for line in patch:
20 # If the patch is adding a package, find which infra it is
21 m = FIND_INFRA_IN_PATCH.match(line)
22 if m:
23 infras.add(m.group(2))
24 if not line.startswith("+++ "):
25 continue
26 line.strip()
27 fname = line[line.find("/") + 1 : ].strip()
28 if fname == "dev/null":
29 continue
30 files.add(fname)
31 return (files, infras)
33 FIND_INFRA_IN_MK = re.compile("^\$\(eval \$\((host-)?([^-]*)-package\)\)$")
35 def fname_get_package_infra(fname):
36 """Checks whether the file name passed as argument is a Buildroot .mk
37 file describing a package, and find the infrastructure it's using."""
38 if not fname.endswith(".mk"):
39 return None
41 if not os.path.exists(fname):
42 return None
44 with open(fname, "r") as f:
45 for l in f:
46 l = l.strip()
47 m = FIND_INFRA_IN_MK.match(l)
48 if m:
49 return m.group(2)
50 return None
52 def get_infras(files):
53 """Search in the list of files for .mk files, and collect the package
54 infrastructures used by those .mk files."""
55 infras = set()
56 for fname in files:
57 infra = fname_get_package_infra(fname)
58 if infra:
59 infras.add(infra)
60 return infras
62 def analyze_patches(patches):
63 """Parse a list of patches and returns the list of files modified,
64 added or removed by the patches, as well as the list of package
65 infrastructures used by those patches (if any)"""
66 allfiles = set()
67 allinfras = set()
68 for patch in patches:
69 (files, infras) = analyze_patch(patch)
70 allfiles = allfiles | files
71 allinfras = allinfras | infras
72 allinfras = allinfras | get_infras(allfiles)
73 return (allfiles, allinfras)
76 # DEVELOPERS file parsing functions
79 class Developer:
80 def __init__(self, name, files):
81 self.name = name
82 self.files = files
83 self.packages = parse_developer_packages(files)
84 self.architectures = parse_developer_architectures(files)
85 self.infras = parse_developer_infras(files)
87 def hasfile(self, f):
88 f = os.path.abspath(f)
89 for fs in self.files:
90 if f.startswith(fs):
91 return True
92 return False
94 def parse_developer_packages(fnames):
95 """Given a list of file patterns, travel through the Buildroot source
96 tree to find which packages are implemented by those file
97 patterns, and return a list of those packages."""
98 packages = set()
99 for fname in fnames:
100 for root, dirs, files in os.walk(fname):
101 for f in files:
102 path = os.path.join(root, f)
103 if fname_get_package_infra(path):
104 pkg = os.path.splitext(f)[0]
105 packages.add(pkg)
106 return packages
108 def parse_arches_from_config_in(fname):
109 """Given a path to an arch/Config.in.* file, parse it to get the list
110 of BR2_ARCH values for this architecture."""
111 arches = set()
112 with open(fname, "r") as f:
113 parsing_arches = False
114 for l in f:
115 l = l.strip()
116 if l == "config BR2_ARCH":
117 parsing_arches = True
118 continue
119 if parsing_arches:
120 m = re.match("^\s*default \"([^\"]*)\".*", l)
121 if m:
122 arches.add(m.group(1))
123 else:
124 parsing_arches = False
125 return arches
127 def parse_developer_architectures(fnames):
128 """Given a list of file names, find the ones starting by
129 'arch/Config.in.', and use that to determine the architecture a
130 developer is working on."""
131 arches = set()
132 for fname in fnames:
133 if not re.match("^.*/arch/Config\.in\..*$", fname):
134 continue
135 arches = arches | parse_arches_from_config_in(fname)
136 return arches
138 def parse_developer_infras(fnames):
139 infras = set()
140 for fname in fnames:
141 m = re.match("^package/pkg-([^.]*).mk$", fname)
142 if m:
143 infras.add(m.group(1))
144 return infras
146 def parse_developers(basepath=None):
147 """Parse the DEVELOPERS file and return a list of Developer objects."""
148 developers = []
149 linen = 0
150 if basepath == None:
151 basepath = os.getcwd()
152 with open(os.path.join(basepath, "DEVELOPERS"), "r") as f:
153 files = []
154 name = None
155 for l in f:
156 l = l.strip()
157 if l.startswith("#"):
158 continue
159 elif l.startswith("N:"):
160 if name is not None or len(files) != 0:
161 print("Syntax error in DEVELOPERS file, line %d" % linen)
162 name = l[2:].strip()
163 elif l.startswith("F:"):
164 fname = l[2:].strip()
165 dev_files = glob.glob(os.path.join(basepath, fname))
166 if len(dev_files) == 0:
167 print("WARNING: '%s' doesn't match any file" % fname)
168 files += dev_files
169 elif l == "":
170 if not name:
171 continue
172 developers.append(Developer(name, files))
173 files = []
174 name = None
175 else:
176 print("Syntax error in DEVELOPERS file, line %d: '%s'" % (linen, l))
177 return None
178 linen += 1
179 # handle last developer
180 if name is not None:
181 developers.append(Developer(name, files))
182 return developers
184 def check_developers(developers, basepath=None):
185 """Look at the list of files versioned in Buildroot, and returns the
186 list of files that are not handled by any developer"""
187 if basepath == None:
188 basepath = os.getcwd()
189 cmd = ["git", "--git-dir", os.path.join(basepath, ".git"), "ls-files"]
190 files = subprocess.check_output(cmd).strip().split("\n")
191 unhandled_files = []
192 for f in files:
193 handled = False
194 for d in developers:
195 if d.hasfile(os.path.join(basepath, f)):
196 handled = True
197 break
198 if not handled:
199 unhandled_files.append(f)
200 return unhandled_files