summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-oe/classes/socorro-syms.bbclass164
1 files changed, 164 insertions, 0 deletions
diff --git a/meta-oe/classes/socorro-syms.bbclass b/meta-oe/classes/socorro-syms.bbclass
new file mode 100644
index 000000000..766a9e627
--- /dev/null
+++ b/meta-oe/classes/socorro-syms.bbclass
@@ -0,0 +1,164 @@
1# Inherit this class when you want to allow Mozilla Socorro to link Breakpad's
2# stack trace information to the correct source code revision.
3# This class creates a new version of the symbol file (.sym) created by
4# Breakpad. The absolute file paths in the symbol file will be replaced by VCS,
5# branch, file and revision of the source file. That information facilitates the
6# lookup of a particular source code line in the stack trace.
7#
8# Use example:
9#
10# BREAKPAD_BIN = "YourBinary"
11# inherit socorro-syms
12#
13
14# We depend on Breakpad creating the original symbol file.
15inherit breakpad
16
17PACKAGE_PREPROCESS_FUNCS += "symbol_file_preprocess"
18PACKAGES =+ "${PN}-socorro-syms"
19FILES_${PN}-socorro-syms = "/usr/share/socorro-syms"
20
21
22python symbol_file_preprocess() {
23
24 package_dir = d.getVar("PKGD", True)
25 breakpad_bin = d.getVar("BREAKPAD_BIN", True)
26 if not breakpad_bin:
27 package_name = d.getVar("PN", True)
28 bb.error("Package %s depends on Breakpad via socorro-syms. See "
29 "breakpad.bbclass for instructions on setting up the Breakpad "
30 "configuration." % package_name)
31 raise ValueError("BREAKPAD_BIN not defined in %s." % package_name)
32
33 sym_file_name = breakpad_bin + ".sym"
34
35 breakpad_syms_dir = os.path.join(
36 package_dir, "usr", "share", "breakpad-syms")
37 socorro_syms_dir = os.path.join(
38 package_dir, "usr", "share", "socorro-syms")
39 if not os.path.exists(socorro_syms_dir):
40 os.makedirs(socorro_syms_dir)
41
42 breakpad_sym_file_path = os.path.join(breakpad_syms_dir, sym_file_name)
43 socorro_sym_file_path = os.path.join(socorro_syms_dir, sym_file_name)
44
45 # In the symbol file, all source files are referenced like the following.
46 # FILE 123 /path/to/some/File.cpp
47 # Go through all references and replace the file paths with repository
48 # paths.
49 with open(breakpad_sym_file_path, 'r') as breakpad_sym_file, \
50 open(socorro_sym_file_path, 'w') as socorro_sym_file:
51
52 for line in breakpad_sym_file:
53 if line.startswith("FILE "):
54 socorro_sym_file.write(socorro_file_reference(line))
55 else:
56 socorro_sym_file.write(line)
57
58 return
59}
60
61
62def socorro_file_reference(line):
63
64 # The 3rd position is the file path. See example above.
65 source_file_path = line.split()[2]
66 source_file_repo_path = repository_path(os.path.normpath(source_file_path))
67
68 # If the file could be found in any repository then replace it with the
69 # repository's path.
70 if source_file_repo_path:
71 return line.replace(source_file_path, source_file_repo_path)
72
73 return line
74
75
76def repository_path(source_file_path):
77
78 if not os.path.isfile(source_file_path):
79 return None
80
81 # Check which VCS is used and use that to extract repository information.
82 (output, error) = bb.process.run("git status",
83 cwd=os.path.dirname(source_file_path))
84 if not error:
85 return git_repository_path(source_file_path)
86
87 # Here we can add support for other VCSs like hg, svn, cvs, etc.
88
89 # The source file isn't under any VCS so we leave it be.
90 return None
91
92
93def run_command(command, directory):
94
95 (output, error) = bb.process.run(command, cwd=directory)
96 if error:
97 raise bb.process.ExecutionError(command, error)
98
99 return output.rstrip()
100
101
102def git_repository_path(source_file_path):
103
104 import re
105
106 # We need to extract the following.
107 # (1): VCS URL, (2): branch, (3): repo root directory name, (4): repo file,
108 # (5): revision.
109
110 source_file_dir = os.path.dirname(source_file_path)
111
112 # (1) Get the VCS URL and extract the server part, i.e. change the URL from
113 # gitolite@git.someserver.com:SomeRepo.git to just git.someserver.com.
114 source_long_url = run_command(
115 "git config --get remote.origin.url", source_file_dir)
116
117 # The URL could be a local download directory. If so, get the URL again
118 # using the local directory's config file.
119 if os.path.isdir(source_long_url):
120 git_config_file = os.path.join(source_long_url, "config")
121 source_long_url = run_command(
122 "git config --file %s --get remote.origin.url" % git_config_file,
123 source_file_dir)
124
125 # The URL can have several formats. A full list can be found using
126 # git help clone. Extract the server part with a regex.
127 url_match = re.search(".*(://|@)([^:/]*).*", source_long_url)
128 source_server = url_match.group(2)
129
130 # (2) Get the branch for this file. If it's detached and just shows HEAD
131 # then set it to master and hope we can get the correct revision from there.
132 source_branch = run_command(
133 "git rev-parse --abbrev-ref HEAD", source_file_dir)
134 if source_branch == "HEAD":
135 source_branch = "master"
136
137 # (3) Since the repo root directory name can be changed without affecting
138 # git, we need to extract the name from something more reliable.
139 # The git URL has a repo name that we could use. We just need to strip off
140 # everything around it - from gitolite@git.someserver.com:SomeRepo.git/ to
141 # SomeRepo.
142 source_repo_dir = re.sub("/$", "", source_long_url)
143 source_repo_dir = re.sub("\.git$", "", source_repo_dir)
144 source_repo_dir = re.sub(".*[:/]", "", source_repo_dir)
145
146 # (4) We know the file but want to remove all of the build system dependent
147 # path up to and including the repository's root directory, e.g. remove
148 # /home/someuser/dev/repo/projectx/
149 source_toplevel = run_command(
150 "git rev-parse --show-toplevel", source_file_dir)
151 source_toplevel = source_toplevel + os.path.sep
152 source_file = source_file_path.replace(source_toplevel, "")
153
154 # (5) Get the source revision this file is part of.
155 source_revision = run_command("git rev-parse HEAD", source_file_dir)
156
157 # Assemble the repository path according to the Socorro format.
158 socorro_reference = "git:%s/%s:%s/%s:%s" % \
159 (source_server, source_branch,
160 source_repo_dir, source_file,
161 source_revision)
162
163 return socorro_reference
164