Automated rollback of commit f35e98d96c65ac621bc6c5bd7a7fde44744a7eff.
*** Reason for rollback ***
Add absent logic to handle creating ~/.lldbinit on demand.
PiperOrigin-RevId: 192167030
diff --git a/src/Tulsi.xcodeproj/project.pbxproj b/src/Tulsi.xcodeproj/project.pbxproj
index 9665e33..5f44e6b 100644
--- a/src/Tulsi.xcodeproj/project.pbxproj
+++ b/src/Tulsi.xcodeproj/project.pbxproj
@@ -143,6 +143,7 @@
D3F78C681F391E9700AE0571 /* bazel_options.py in Resources */ = {isa = PBXBuildFile; fileRef = D3F78C671F391E9700AE0571 /* bazel_options.py */; };
E11AFAB02052655500C97875 /* bazel_cache_reader in Copy Utilty resources */ = {isa = PBXBuildFile; fileRef = E1D770EA20523E790026802A /* bazel_cache_reader */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
E135A781205880720082E4D0 /* apfs_clone_copy.py in Resources */ = {isa = PBXBuildFile; fileRef = E135A780205880720082E4D0 /* apfs_clone_copy.py */; };
+ E1542A0E206ED51900D3D339 /* bootstrap_lldbinit.py in Resources */ = {isa = PBXBuildFile; fileRef = E1542A0D206ED51900D3D339 /* bootstrap_lldbinit.py */; };
E155E20C1FCE47DA002B16BB /* BazelBuildSettingsFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = E155E20B1FCE47D9002B16BB /* BazelBuildSettingsFeatures.swift */; };
E19C1C571F5886A000D6E38A /* QueuedLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19C1C561F5886A000D6E38A /* QueuedLogging.swift */; };
E1C0186D2051B65D000580CC /* clean_symbol_cache.py in Resources */ = {isa = PBXBuildFile; fileRef = E1C018692051B65B000580CC /* clean_symbol_cache.py */; };
@@ -358,6 +359,7 @@
D3F78C671F391E9700AE0571 /* bazel_options.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = bazel_options.py; sourceTree = "<group>"; };
E132B8B51F86FA3400DF7F9A /* tulsi_aspects_paths.bzl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = tulsi_aspects_paths.bzl; path = tulsi/tulsi_aspects_paths.bzl; sourceTree = "<group>"; };
E135A780205880720082E4D0 /* apfs_clone_copy.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = apfs_clone_copy.py; sourceTree = "<group>"; };
+ E1542A0D206ED51900D3D339 /* bootstrap_lldbinit.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = bootstrap_lldbinit.py; sourceTree = "<group>"; };
E155E20B1FCE47D9002B16BB /* BazelBuildSettingsFeatures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BazelBuildSettingsFeatures.swift; sourceTree = "<group>"; };
E19C1C561F5886A000D6E38A /* QueuedLogging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueuedLogging.swift; sourceTree = "<group>"; };
E1C018692051B65B000580CC /* clean_symbol_cache.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = clean_symbol_cache.py; sourceTree = "<group>"; };
@@ -527,6 +529,7 @@
3DAC27671C3AD2510040F42C /* Scripts */ = {
isa = PBXGroup;
children = (
+ E1542A0D206ED51900D3D339 /* bootstrap_lldbinit.py */,
5442049B2064156D00EBF343 /* install_genfiles.py */,
E135A780205880720082E4D0 /* apfs_clone_copy.py */,
54EF32091F3E0804009E9C7F /* bazel_build_events.py */,
@@ -877,6 +880,7 @@
5442049C2064156D00EBF343 /* install_genfiles.py in Resources */,
E1C018722051B66C000580CC /* update_symbol_cache.py in Resources */,
3DCFE5D51C80A64600D7F31B /* WORKSPACE in Resources */,
+ E1542A0E206ED51900D3D339 /* bootstrap_lldbinit.py in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/src/TulsiGenerator/Base.lproj/Localizable.strings b/src/TulsiGenerator/Base.lproj/Localizable.strings
index 9e4113d..7be9732 100644
--- a/src/TulsiGenerator/Base.lproj/Localizable.strings
+++ b/src/TulsiGenerator/Base.lproj/Localizable.strings
@@ -44,8 +44,11 @@
/* Error when parsing a Bazel Build Event for BEP when running Bazel. */
"BazelParseBuildEventFailed" = "Failed to parse a Bazel Build Event. This may be a Tulsi bug, please report. Additional Context: %1$@";
+/* Warning when a failure occurred while attempting to bootstrap the user's LLDBInit file. */
+"BootstrapLLDBInitFailed" = "Failed to bootstrap LLDBInit file, bootstrapping script returned error code %1$d, %2$@.";
+
/* Warning when a failure occurred while cleaning dSYMs in the SQLite store used by the DBGShellCommands script. */
-"CleanCachedDsymsFailed" = "Failed to clean cache of dSYMs, clean script returned %1$@.";
+"CleanCachedDsymsFailed" = "Failed to clean cache of dSYMs, clean script returned error code %1$d, %2$@.";
/* Failed to copy an important file resource, the resulting project will most likely be broken. A bug should be reported. */
"CopyingResourceFailed" = "Failed to copy project resource '%1$@' to '%2$@'. The generated project will probably malfunction, please report. Error: %3$@";
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py
index dcd2e89..29c514e 100755
--- a/src/TulsiGenerator/Scripts/bazel_build.py
+++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -29,7 +29,6 @@
import re
import shutil
import signal
-import StringIO
import subprocess
import sys
import textwrap
@@ -39,6 +38,8 @@
from apfs_clone_copy import CopyOnWrite
import bazel_build_events
import bazel_options
+from bootstrap_lldbinit import BootstrapLLDBInit
+from bootstrap_lldbinit import TULSI_LLDBINIT_FILE
from execroot_path import BAZEL_EXECUTION_ROOT
import tulsi_logging
from update_symbol_cache import UpdateSymbolCache
@@ -1445,69 +1446,24 @@
self.codesign_attributes[signed_bundle] = bundle_attributes
return bundle_attributes.Get(attribute)
- _TULSI_LLDBINIT_BLOCK_START = '# <TULSI> LLDB bridge [:\n'
- _TULSI_LLDBINIT_BLOCK_END = '# ]: <TULSI> LLDB bridge\n'
- _TULSI_LLDBINIT_FILE = os.path.expanduser('~/.lldbinit-tulsiproj')
+ # File for custom lldbinit changes.
+ # WARNING: This file will override any dSYM based source remappings AND
+ # ~/.lldbinit-tulsiproj remappings. Use of this file is strongly discouraged.
_TULSI_LLDBINIT_EPILOGUE_FILE = (
os.path.expanduser('~/.lldbinit-tulsiproj-epilogue'))
- def _ExtractLLDBInitContent(self, lldbinit_path):
- """Extracts the non-Tulsi content of the given lldbinit file."""
- if not os.path.isfile(lldbinit_path):
- return []
- content = []
- with open(lldbinit_path) as f:
- ignoring = False
- for line in f:
- if ignoring:
- if line == self._TULSI_LLDBINIT_BLOCK_END:
- ignoring = False
- continue
- if line == self._TULSI_LLDBINIT_BLOCK_START:
- ignoring = True
- continue
- content.append(line)
- return content
-
- def _LinkTulsiLLDBInit(self):
- """Adds a reference to ~/.lldbinit-tulsi to the primary lldbinit file.
-
- Xcode 8+ caches the contents of ~/.lldbinit-Xcode on startup. To get around
- this, an external reference to ~/.lldbinit-tulsi is added, causing LLDB
- itself to load the possibly modified contents on each session.
- """
-
- lldbinit_path = os.path.expanduser('~/.lldbinit-Xcode')
- if not os.path.isfile(lldbinit_path):
- lldbinit_path = os.path.expanduser('~/.lldbinit')
-
- content = self._ExtractLLDBInitContent(lldbinit_path)
- out = StringIO.StringIO()
- for line in content:
- out.write(line)
-
- out.write(self._TULSI_LLDBINIT_BLOCK_START)
- out.write('# This was autogenerated by Tulsi in order to influence LLDB '
- 'source-maps at build time.\n')
- out.write('command source %s\n' % self._TULSI_LLDBINIT_FILE)
- out.write(self._TULSI_LLDBINIT_BLOCK_END)
-
- with open(lldbinit_path, 'w') as outfile:
- out.seek(0)
- # Negative length to make copyfileobj write the whole file at once.
- shutil.copyfileobj(out, outfile, -1)
-
def _LinkTulsiLLDBInitEpilogue(self, outfile):
"""Adds a reference to ~/.lldbinit-tulsi-epilogue if it exists.
This file can be used to append more LLDB commands right after
- .lldbinit-tulsi is sourced.
+ ~/.lldbinit-tulsiproj is loaded.
- Useful for extending or resetting LLDB settings that Tulsi may have set
- automatically
+ Use of this file is strongly discouraged; it will override any other
+ changes made by ~/.lldbinit, ~/.lldbinit-tulsiproj and dSYM bundle path
+ mappings.
Args:
- outfile: a file-type object.
+ outfile: a file-type object, expected to be ~/.lldbinit-tulsiproj.
Returns:
None
@@ -1522,9 +1478,12 @@
if self.product_type == 'com.apple.product-type.application.watchapp2':
return 0
- self._LinkTulsiLLDBInit()
+ # Make sure a reference to ~/.lldbinit-tulsiproj exists in ~/.lldbinit or
+ # ~/.lldbinit-Xcode. Priority is given to ~/.lldbinit-Xcode if it exists,
+ # otherwise the bootstrapping will be written to ~/.lldbinit.
+ BootstrapLLDBInit()
- with open(self._TULSI_LLDBINIT_FILE, 'w') as out:
+ with open(TULSI_LLDBINIT_FILE, 'w') as out:
out.write('# This file is autogenerated by Tulsi and should not be '
'edited.\n')
diff --git a/src/TulsiGenerator/Scripts/bootstrap_lldbinit.py b/src/TulsiGenerator/Scripts/bootstrap_lldbinit.py
new file mode 100755
index 0000000..1af9af8
--- /dev/null
+++ b/src/TulsiGenerator/Scripts/bootstrap_lldbinit.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+# Copyright 2018 The Tulsi Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Bootstraps the presence and setup of ~/.lldbinit-tulsiproj."""
+
+import os
+import shutil
+import StringIO
+import sys
+
+
+TULSI_LLDBINIT_FILE = os.path.expanduser('~/.lldbinit-tulsiproj')
+
+
+class BootstrapLLDBInit(object):
+ """Bootstrap Xcode's preferred lldbinit for Bazel debugging."""
+
+ def _ExtractLLDBInitContent(self, lldbinit_path, source_string):
+ """Extracts non-Tulsi content in a given lldbinit if needed.
+
+ Args:
+ lldbinit_path: Absolute path to the lldbinit we are writing to.
+ source_string: String that we wish to write to lldbinit.
+
+ Returns:
+ (int, [string]): A tuple featuring the status code along with the list
+ of strings representing content to write to lldbinit
+ that does not account for the Tulsi-generated strings.
+ Status code will be 0 if Tulsi-generated strings are
+ not all there. Status code will be 1 if all Tulsi
+ strings were accounted for. Status code will be 2 if
+ the lldbinit file could not be found.
+ """
+ if not os.path.isfile(lldbinit_path):
+ return (2, [])
+ content = []
+ with open(lldbinit_path) as f:
+ ignoring = False
+
+ # Split on the newline. This works as long as the last string isn't
+ # suffixed with \n.
+ source_lines = source_string.split('\n')
+
+ source_idx = 0
+
+ # If the last line was suffixed with \n, last elements would be length
+ # minus 2, accounting for the extra \n.
+ source_last = len(source_lines) - 1
+
+ for line in f:
+
+ # For each line found matching source_string, increment the iterator
+ # and do not append that line to the list.
+ if source_lines[source_idx] in line:
+
+ # If all lines were found, return an error code with empty content.
+ if source_idx == source_last:
+ return (1, [])
+
+ # Increment for each matching line found.
+ source_idx += 1
+ ignoring = True
+ continue
+
+ if ignoring:
+
+ # If the last line was found...
+ if source_lines[source_last] in line:
+ # Stop ignoring lines and continue appending to content.
+ ignoring = False
+ continue
+
+ # If the line could not be found within source_string, append to the
+ # content array.
+ content.append(line)
+
+ return (0, content)
+
+ def _LinkTulsiLLDBInit(self):
+ """Adds a reference to ~/.lldbinit-tulsiproj to the primary lldbinit file.
+
+ Xcode 8+ executes the contents of the first available lldbinit on startup.
+ To help work around this, an external reference to ~/.lldbinit-tulsiproj is
+ added to that lldbinit. This causes Xcode's lldb-rpc-server to load the
+ possibly modified contents between Debug runs of any given app. Note that
+ this only happens after a Debug session terminates; the cache is only fully
+ invalidated after Xcode is relaunched.
+ """
+
+ # ~/.lldbinit-Xcode is the only lldbinit file that Xcode will read if it is
+ # present, therefore it has priority.
+ lldbinit_path = os.path.expanduser('~/.lldbinit-Xcode')
+ if not os.path.isfile(lldbinit_path):
+ # If ~/.lldbinit-Xcode does not exist, write the reference to
+ # ~/.lldbinit-tulsiproj to ~/.lldbinit, the second lldbinit file that
+ # Xcode will attempt to read if ~/.lldbinit-Xcode isn't present.
+ lldbinit_path = os.path.expanduser('~/.lldbinit')
+
+ # String that we plan to inject into this lldbinit.
+ source_string = ('# <TULSI> LLDB bridge [:\n'
+ '# This was autogenerated by Tulsi in order to modify '
+ 'LLDB source-maps at build time.\n'
+ 'command source %s\n' % TULSI_LLDBINIT_FILE +
+ '# ]: <TULSI> LLDB bridge')
+
+ # Retrieve the contents of lldbinit if applicable along with a return code.
+ return_code, content = self._ExtractLLDBInitContent(lldbinit_path,
+ source_string)
+
+ out = StringIO.StringIO()
+
+ if return_code == 0:
+ # Print the existing contents of this ~/.lldbinit without any malformed
+ # tulsi lldbinit block, and add the correct tulsi lldbinit block to the
+ # end of it.
+ for line in content:
+ out.write(line)
+ elif return_code == 1:
+ # If we should ignore the contents of this lldbinit, and it has the
+ # association with ~/.lldbinit-tulsiproj that we want, do not modify it.
+ return
+
+ # Add a newline after the source_string for protection from other elements
+ # within the lldbinit file.
+ out.write(source_string + '\n')
+
+ with open(lldbinit_path, 'w') as outfile:
+ out.seek(0)
+ # Negative length to make copyfileobj write the whole file at once.
+ shutil.copyfileobj(out, outfile, -1)
+
+ def __init__(self):
+ self._LinkTulsiLLDBInit()
+
+
+if __name__ == '__main__':
+ BootstrapLLDBInit()
+ sys.exit(0)
diff --git a/src/TulsiGenerator/TulsiXcodeProjectGenerator.swift b/src/TulsiGenerator/TulsiXcodeProjectGenerator.swift
index 263dd8b..de2f28a 100644
--- a/src/TulsiGenerator/TulsiXcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/TulsiXcodeProjectGenerator.swift
@@ -53,6 +53,7 @@
bundle.url(forResource: "bazel_options", withExtension: "py")!,
bundle.url(forResource: "apfs_clone_copy", withExtension: "py")!,
bundle.url(forResource: "bazel_build_events", withExtension: "py")!,
+ bundle.url(forResource: "bootstrap_lldbinit", withExtension: "py")!,
bundle.url(forResource: "symbol_cache_schema", withExtension: "py")!,
bundle.url(forResource: "update_symbol_cache", withExtension: "py")!,
bundle.url(forResource: "install_genfiles", withExtension: "py")!],
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift
index 6f7ad9d..e5f870b 100644
--- a/src/TulsiGenerator/XcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -70,6 +70,7 @@
private static let CleanScript = "bazel_clean.sh"
private static let ShellCommandsUtil = "bazel_cache_reader"
private static let ShellCommandsCleanScript = "clean_symbol_cache"
+ private static let LLDBInitBootstrapScript = "bootstrap_lldbinit"
private static let WorkspaceFile = "WORKSPACE"
private static let IOSUIRunnerEntitlements = "iOSXCTRunner.entitlements"
private static let MacOSUIRunnerEntitlements = "macOSXCTRunner.entitlements"
@@ -550,6 +551,9 @@
cleanCachedDsymPaths()
}
}
+ profileAction("bootstrapping_lldbinit") {
+ bootstrapLLDBInit()
+ }
return GeneratedProjectInfo(project: xcodeProject,
buildRuleEntries: targetRules,
testSuiteRuleEntries: testSuiteRules,
@@ -1116,30 +1120,48 @@
}
}
- private func cleanCachedDsymPaths() {
- // Execute the script to clean up missing dSYM bundles asynchronously.
+ private func executePythonProcess(_ scriptFileName: String, onError: @escaping (Int32, String) -> Void) {
let bundle = Bundle(for: type(of: self))
- let cleanSymbolsSourceURL = bundle.url(forResource: XcodeProjectGenerator.ShellCommandsCleanScript, withExtension: "py")!
+ let cleanSymbolsSourceURL = bundle.url(forResource: scriptFileName, withExtension: "py")!
let process = ProcessRunner.createProcess(cleanSymbolsSourceURL.path,
arguments: [String]()) {
completionInfo in
- if let stderr = NSString(data: completionInfo.stderr,
- encoding: String.Encoding.utf8.rawValue) {
- guard !stderr.trimmingCharacters(in: .whitespaces).isEmpty else {
- return
- }
- Thread.doOnMainQueue {
- self.localizedMessageLogger.warning("CleanCachedDsymsFailed",
- comment: LocalizedMessageLogger.bugWorthyComment("Failed to clean cached references to existing dSYM bundles."),
- context: self.config.projectName,
- values: stderr)
+ if completionInfo.terminationStatus != 0 {
+ if let stderr = NSString(data: completionInfo.stderr,
+ encoding: String.Encoding.utf8.rawValue) {
+ guard !stderr.trimmingCharacters(in: .whitespaces).isEmpty else {
+ return
+ }
+ onError(completionInfo.terminationStatus, stderr as String)
}
}
}
process.launch()
}
+ private func cleanCachedDsymPaths() {
+ // Execute the script to clean up missing dSYM bundles asynchronously.
+ self.executePythonProcess(XcodeProjectGenerator.ShellCommandsCleanScript) { (returncode, stderr) in
+ self.localizedMessageLogger.warning("CleanCachedDsymsFailed",
+ comment: LocalizedMessageLogger.bugWorthyComment("Failed to clean cached references to existing dSYM bundles."),
+ context: self.config.projectName,
+ values: returncode, stderr)
+ }
+ }
+
+ private func bootstrapLLDBInit() {
+ // Execute the script to bootstrap LLDBInit for path remapping. This needs to be read by Xcode
+ // before Xcode.app launches so that its instance of LLDB can find the file where we do the path
+ // remappings when dSYM bundles aren't present, which is ~/.lldbinit-tulsiproj.
+ self.executePythonProcess(XcodeProjectGenerator.LLDBInitBootstrapScript) { (returncode, stderr) in
+ self.localizedMessageLogger.warning("BootstrapLLDBInitFailed",
+ comment: LocalizedMessageLogger.bugWorthyComment("Failed to bootstrap LLDBInit for debug symbol remapping."),
+ context: self.config.projectName,
+ values: returncode, stderr)
+ }
+ }
+
private func installTulsiScripts(_ projectURL: URL) {
let scriptDirectoryURL = projectURL.appendingPathComponent(XcodeProjectGenerator.ScriptDirectorySubpath,