# HG changeset patch
# User Evgeniy.Koshkin
# Date 1374147268 -14400
# Node ID c6ca0a26d93eee5844bc8230f67cee38f1f3035b
# Parent 33e8cf5b2d57d39c6290b1f8e77c3b8486d0c421
initial implementation of agent-side symbol indexer
diff -r 33e8cf5b2d57 -r c6ca0a26d93e agent/agent.iml
--- a/agent/agent.iml Tue Jul 16 20:17:11 2013 +0400
+++ b/agent/agent.iml Thu Jul 18 15:34:28 2013 +0400
@@ -8,6 +8,7 @@
jar://$TeamCityDistribution$/buildAgent/lib/agent.jar!/META-INF/buildAgentSpring.xml
jar://$TeamCityDistribution$/buildAgent/lib/agent.jar!/META-INF/buildAgentPlugins.xml
file://$MODULE_DIR$/fake-teamcity-agent-plugin-context.xml
+ file://$MODULE_DIR$/src/META-INF/build-agent-plugin-symbol-server.xml
@@ -24,6 +25,7 @@
+
diff -r 33e8cf5b2d57 -r c6ca0a26d93e agent/src/META-INF/build-agent-plugin-symbol-server.xml
--- a/agent/src/META-INF/build-agent-plugin-symbol-server.xml Tue Jul 16 20:17:11 2013 +0400
+++ b/agent/src/META-INF/build-agent-plugin-symbol-server.xml Thu Jul 18 15:34:28 2013 +0400
@@ -6,12 +6,6 @@
default-autowire="constructor"
>
-
-
-
-
-
+
\ No newline at end of file
diff -r 33e8cf5b2d57 -r c6ca0a26d93e agent/src/jetbrains/buildServer/symbols/SymbolsIndexer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/jetbrains/buildServer/symbols/SymbolsIndexer.java Thu Jul 18 15:34:28 2013 +0400
@@ -0,0 +1,130 @@
+package jetbrains.buildServer.symbols;
+
+import com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.SimpleCommandLineProcessRunner;
+import jetbrains.buildServer.agent.AgentLifeCycleAdapter;
+import jetbrains.buildServer.agent.AgentLifeCycleListener;
+import jetbrains.buildServer.agent.AgentRunningBuild;
+import jetbrains.buildServer.agent.BuildFinishedStatus;
+import jetbrains.buildServer.agent.artifacts.ArtifactsWatcher;
+import jetbrains.buildServer.agent.impl.artifacts.ArtifactsBuilderAdapter;
+import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
+import jetbrains.buildServer.agent.plugins.beans.PluginDescriptor;
+import jetbrains.buildServer.util.EventDispatcher;
+import jetbrains.buildServer.util.FileUtil;
+import org.apache.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author Evgeniy.Koshkin
+ */
+public class SymbolsIndexer extends ArtifactsBuilderAdapter {
+
+ public static final Logger LOG = Logger.getLogger(SymbolsIndexer.class);
+
+ public static final String PDB_FILE_EXTENSION = "pdb";
+ public static final String EXE_FILE_EXTENSION = "exe";
+ public static final String DLL_FILE_EXTENSION = "dll";
+
+ public static final String SYMBOLS_EXE = "symbols.exe";
+ public static final String DUMP_SYMBOL_SIGN_CMD = "dumpSymbolSign";
+ public static final String DUMP_BIN_SIGN_CMD = "dumpBinSign";
+
+ @NotNull private final ArtifactsWatcher myArtifactsWatcher;
+ @NotNull private final File myNativeToolPath;
+ @Nullable private AgentRunningBuild myBuild;
+ @Nullable private Collection myBinariesToProcess;
+ @Nullable private Collection mySymbolsToProcess;
+
+ public SymbolsIndexer(@NotNull final PluginDescriptor pluginDescriptor, @NotNull final EventDispatcher agentDispatcher, @NotNull final ArtifactsWatcher artifactsWatcher) {
+ myNativeToolPath = new File(new File(pluginDescriptor.getPluginRoot(), "bin"), SYMBOLS_EXE);
+ myArtifactsWatcher = artifactsWatcher;
+ agentDispatcher.addListener(new AgentLifeCycleAdapter() {
+ @Override
+ public void buildStarted(@NotNull final AgentRunningBuild runningBuild) {
+ myBuild = runningBuild;
+ myBinariesToProcess = new HashSet();
+ mySymbolsToProcess = new HashSet();
+ }
+
+ @Override
+ public void beforeBuildFinish(@NotNull AgentRunningBuild build, @NotNull BuildFinishedStatus buildStatus) {
+ super.beforeBuildFinish(build, buildStatus);
+ if (myBuild == null || mySymbolsToProcess == null || myBinariesToProcess == null) return;
+ if (mySymbolsToProcess.isEmpty()) {
+ LOG.debug("Symbols weren't found in artifacts to be published.");
+ } else {
+ final File targetDir = myBuild.getBuildTempDirectory();
+ try {
+ final File symbolSignaturesFile = dumpSymbolSignatures(mySymbolsToProcess, targetDir);
+ myArtifactsWatcher.addNewArtifactsPath(symbolSignaturesFile + "=>" + ".teamcity/symbols/symbol-signatures.xml");
+ final File binariesSignaturesFile = dumpBinarySignatures(myBinariesToProcess, targetDir);
+ myArtifactsWatcher.addNewArtifactsPath(binariesSignaturesFile + "=>" + ".teamcity/symbols/binary-signatures.xml");
+ } catch (IOException e) {
+ LOG.error("Error while dumping symbols/binaries signatures.", e);
+ }
+ }
+ mySymbolsToProcess = null;
+ myBinariesToProcess = null;
+ myBuild = null;
+ }
+ });
+ }
+
+ @Override
+ public void afterCollectingFiles(@NotNull List artifacts) {
+ super.afterCollectingFiles(artifacts);
+ if(myBuild == null || mySymbolsToProcess == null || myBinariesToProcess == null) return;
+ if(myBuild.getBuildFeaturesOfType(SymbolsConstants.BUILD_FEATURE_TYPE).isEmpty()){
+ LOG.debug(SymbolsConstants.BUILD_FEATURE_TYPE + " build feature disabled. No indexing performed.");
+ return;
+ }
+ LOG.debug(SymbolsConstants.BUILD_FEATURE_TYPE + " build feature enabled. Searching for symbol files.");
+ mySymbolsToProcess.addAll(getArtifactPathsByFileExtension(artifacts, PDB_FILE_EXTENSION));
+ myBinariesToProcess.addAll(getArtifactPathsByFileExtension(artifacts, EXE_FILE_EXTENSION));
+ myBinariesToProcess.addAll(getArtifactPathsByFileExtension(artifacts, DLL_FILE_EXTENSION));
+ }
+
+ private Collection getArtifactPathsByFileExtension(List artifactsCollections, String fileExtension){
+ final Collection result = new HashSet();
+ for(ArtifactsCollection artifactsCollection : artifactsCollections){
+ if(artifactsCollection.isEmpty()) continue;
+ for (File artifact : artifactsCollection.getFilePathMap().keySet()){
+ if(FileUtil.getExtension(artifact.getPath()).equalsIgnoreCase(fileExtension))
+ result.add(artifact);
+ }
+ }
+ return result;
+ }
+
+ private File dumpSymbolSignatures(Collection files, File targetDir) throws IOException {
+ final File tempFile = FileUtil.createTempFile(targetDir, "symbol-signatures-", ".xml", false);
+ runTool(DUMP_SYMBOL_SIGN_CMD, files, tempFile);
+ return tempFile;
+ }
+
+ private File dumpBinarySignatures(Collection files, File targetDir) throws IOException {
+ final File tempFile = FileUtil.createTempFile(targetDir, "binary-signatures-", ".xml", false);
+ runTool(DUMP_BIN_SIGN_CMD, files, tempFile);
+ return tempFile;
+ }
+
+ private void runTool(String cmd, Collection files, File output){
+ final GeneralCommandLine commandLine = new GeneralCommandLine();
+ commandLine.setExePath(myNativeToolPath.getPath());
+ commandLine.addParameter(cmd);
+ commandLine.addParameter(String.format("/o=\"%s\"", output.getPath()));
+ for(File file : files){
+ commandLine.addParameter(file.getPath());
+ }
+ final ExecResult execResult = SimpleCommandLineProcessRunner.runCommand(commandLine, null);
+ if (execResult.getExitCode() == 0) return;
+ LOG.warn(String.format("%s ends with non-zero exit code.", SYMBOLS_EXE));
+ }
+}
diff -r 33e8cf5b2d57 -r c6ca0a26d93e common/src/jetbrains/buildServer/symbols/SymbolsConstants.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/jetbrains/buildServer/symbols/SymbolsConstants.java Thu Jul 18 15:34:28 2013 +0400
@@ -0,0 +1,8 @@
+package jetbrains.buildServer.symbols;
+
+/**
+ * @author Evgeniy.Koshkin
+ */
+public class SymbolsConstants {
+ public static final String BUILD_FEATURE_TYPE = "symbol-indexer";
+}
diff -r 33e8cf5b2d57 -r c6ca0a26d93e server/server.iml
--- a/server/server.iml Tue Jul 16 20:17:11 2013 +0400
+++ b/server/server.iml Thu Jul 18 15:34:28 2013 +0400
@@ -18,6 +18,7 @@
jar://$TeamCityDistribution$/buildAgent/lib/common-impl.jar!/META-INF/per-plugin-shared-spring.xml
jar://$TeamCityDistribution$/buildAgent/lib/common-impl.jar!/META-INF/plugin-model-shared-spring.xml
jar://$TeamCityDistribution$/buildAgent/lib/common-impl.jar!/META-INF/shared-spring-sub-container.xml
+ file://$MODULE_DIR$/src/META-INF/build-server-plugin-symbol-server.xml
diff -r 33e8cf5b2d57 -r c6ca0a26d93e server/src/META-INF/build-server-plugin-symbol-server.xml
--- a/server/src/META-INF/build-server-plugin-symbol-server.xml Tue Jul 16 20:17:11 2013 +0400
+++ b/server/src/META-INF/build-server-plugin-symbol-server.xml Thu Jul 18 15:34:28 2013 +0400
@@ -5,11 +5,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-autowire="constructor"
>
-
-
-
+
diff -r 33e8cf5b2d57 -r c6ca0a26d93e server/src/jetbrains/buildServer/symbols/IndexSymbolsBuildFeature.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/jetbrains/buildServer/symbols/IndexSymbolsBuildFeature.java Thu Jul 18 15:34:28 2013 +0400
@@ -0,0 +1,29 @@
+package jetbrains.buildServer.symbols;
+
+import jetbrains.buildServer.serverSide.BuildFeature;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Evgeniy.Koshkin
+ */
+public class IndexSymbolsBuildFeature extends BuildFeature {
+
+ @NotNull
+ @Override
+ public String getType() {
+ return SymbolsConstants.BUILD_FEATURE_TYPE;
+ }
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return "Symbol files (.pdb) indexer";
+ }
+
+ @Nullable
+ @Override
+ public String getEditParametersUrl() {
+ return null;
+ }
+}