summaryrefslogtreecommitdiffstats
path: root/meta-oe/classes
diff options
context:
space:
mode:
authorDaniel Markus <daniel.markus@leica-geosystems.com>2015-02-26 14:00:12 +0100
committerMartin Jansa <Martin.Jansa@gmail.com>2015-03-03 08:36:00 +0100
commit7fe80db1df7a43e57cd7807052fbefdcbdbceb5d (patch)
tree6e5a673cceca5d6550c08274178d172c819ce8af /meta-oe/classes
parent339c3053fc94f6d6047a34c03120898dbe908e4b (diff)
downloadmeta-openembedded-7fe80db1df7a43e57cd7807052fbefdcbdbceb5d.tar.gz
socorro-syms: Add Breakpad symbol generation adapted for Socorro
https://github.com/mozilla/socorro Mozilla Socorro is a downloadable crash dump server that handles Breakpad crash dumps coming from own applications. In order for Socorro to create clickable links into your source code repository, Breakpad's symbol files must be copied and modified to contain VCS information for each file reference. This class reads the symbol file generated by Breakpad and creates a new symbol file with that VCS information contained. Signed-off-by: Daniel Markus <daniel.markus@leica-geosystems.com>
Diffstat (limited to 'meta-oe/classes')
-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