我一直在使用MS调试工具安装中的MS Source Server。
目前,我正在通过Subversion索引命令运行我的代码/ pdbs,该命令现在正在按预期运行。它为给定的pdb文件创建流并将其写入pdb文件。
然而,当我在visual studio 2008中使用该DLL和相关的pdb时,它说无法检索源代码。
如果我检查pdb对srctool说没有包含所有源文件的索引,这很奇怪,因为之前的进程运行正常。
如果我检查从pv的svnindex.cmd运行生成的流,则srctool表示所有源文件都已编入索引。
为什么会有差异?
我已经在文本编辑器中打开了pdb文件,我可以看到我机器上的源文件的原始引用(也在srcsrv头名称下),新的“注入”源服务器链接到我的subversion存储库)。
两个引用是否仍然存在于pdb中?我本以为要删除一个?
无论哪种方式,visual studio 2008都不会拿起我的源代码引用,所以我对于接下来要尝试什么感到有点迷茫。据我所知,我已经做了我应该做的一切。
有没有类似的经历?
非常感谢。
答案 0 :(得分:2)
我已经解决了我的问题 - 在构建期间写入PDB的源文件路径与作为Subversion源索引任务的一部分写入的路径略有不同。
这必须使Visual Studio中的源搜索无效,因为两条路径不匹配。
还将我自己的简化源索引流从自定义的NAnt任务写入我的PDB文件,该任务连接到我们的SCM系统Vault。
答案 1 :(得分:1)
Visual Studio的Options \ Debugging \ Symbols中有一个选项可以发出源服务器的日志 您还需要最新版本的srcsrv.dll,只需从该处下载最新的WinDBG复制DLL,并确保Visual Studio使用它。
答案 2 :(得分:0)
很久没多久了,抱歉。这完全符合我们公司的需求。应该足以显示正在发生的事情。
以下代码段:
<强> PdbFile.cs 强>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Code.Integration.SourceIndex
{
public class PdbFile
{
private FileInfo _pdbFile;
public FileInfo Pdb
{
get { return _pdbFile; }
}
public PdbFile(FileInfo pdbFile)
{
if (pdbFile == null)
throw new ArgumentNullException("pdbFile");
if (!pdbFile.Exists)
throw new ArgumentException(string.Format("Pdb file specified \"{0}\" does not exist.", pdbFile.FullName), "pdbFile");
_pdbFile = pdbFile;
}
// Read source files
// Write source stream
}
}
<强> PdbUtil.cs 强>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
namespace Code.Integration.SourceIndex
{
public static class PdbUtil
{
private static readonly string SRCTOOL_PATH_1 = @"C:\Program Files\Debugging Tools for Windows\srcsrv\srctool.exe";
private static readonly string SRCTOOL_PATH_2 = @"C:\Program Files\Debugging Tools for Windows (x86)\srcsrv\srctool.exe";
private static readonly string PDBSTR_PATH_1 = @"C:\Program Files\Debugging Tools for Windows\srcsrv\pdbstr.exe";
private static readonly string PDBSTR_PATH_2 = @"C:\Program Files\Debugging Tools for Windows (x86)\srcsrv\pdbstr.exe";
private static string SRCTOOL = "";
private static string PDBSTR = "";
static PdbUtil()
{
if (File.Exists(SRCTOOL_PATH_1))
SRCTOOL = SRCTOOL_PATH_1;
else if (File.Exists(SRCTOOL_PATH_2))
SRCTOOL = SRCTOOL_PATH_2;
if (File.Exists(PDBSTR_PATH_1))
PDBSTR = PDBSTR_PATH_1;
else if (File.Exists(PDBSTR_PATH_2))
PDBSTR = PDBSTR_PATH_2;
}
private static void EnsureToolsExist()
{
if (string.IsNullOrEmpty(SRCTOOL))
throw new ApplicationException(string.Format("SRCTOOL does not exist. Is it installed?", SRCTOOL));
if (string.IsNullOrEmpty(PDBSTR))
throw new ApplicationException(string.Format("PDBSTR does not exist. Is it installed?", PDBSTR));
}
public static List<string> ReadSourceFiles(PdbFile pdb)
{
EnsureToolsExist();
ProcessStartInfo info = new ProcessStartInfo(SRCTOOL);
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.Arguments = string.Format("-r \"{0}\"", pdb.Pdb.FullName);
string output;
string errors;
using (Process p = Process.Start(info))
{
output = p.StandardOutput.ReadToEnd();
errors = p.StandardError.ReadToEnd();
p.WaitForExit();
}
if (!string.IsNullOrEmpty(errors))
throw new ApplicationException(string.Format("Error reading pdb source files \"{0}\".", errors));
List<string> result = new List<string>();
if (!string.IsNullOrEmpty(output))
{
foreach (string item in output.Split('\r', '\n'))
{
string sourceFile = item.Trim();
if (string.IsNullOrEmpty(sourceFile))
continue;
result.Add(sourceFile);
}
}
return result;
}
public static void WriteSourceFileStream(PdbFile pdb, FileInfo stream)
{
EnsureToolsExist();
ProcessStartInfo info = new ProcessStartInfo(PDBSTR);
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.Arguments = string.Format("-w -s:srcsrv -p:\"{0}\" -i:\"{1}\"", pdb.Pdb.FullName, stream.FullName);
string output;
string errors;
using (Process p = Process.Start(info))
{
output = p.StandardOutput.ReadToEnd();
errors = p.StandardError.ReadToEnd();
p.WaitForExit();
}
if (!string.IsNullOrEmpty(errors))
throw new ApplicationException(string.Format("Error writing to pdb \"{0}\".", errors));
}
}
}
<强> SourceIndexTask.cs 强>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using NAnt.Core;
using NAnt.Core.Attributes;
using NAnt.Core.Types;
using Code.Integration.SourceIndex;
namespace Code.Integration.NAnt.Tasks.SourceIndex
{
[TaskName("codesourceindex")]
public class SourceIndexTask : Task
{
private FileSet _pdbs = new FileSet();
private string _build = "0.0.0.0";
private string _repositoryName = "";
private string _repositoryProjectStart = "";
private string _user = "";
private string _password = "";
private string _server = "";
#region Properties
/// <summary>
/// FileSet of pdbs to process.
/// </summary>
[BuildElement("pdbs")]
public FileSet Pdbs
{
get { return _pdbs; }
set { _pdbs = value; }
}
/// <summary>
/// Build label to extract.
/// Default is "0.0.0.0".
/// </summary>
[TaskAttribute("build", Required = true)]
[StringValidator(AllowEmpty = false)]
public string Build
{
get { return _build; }
set { _build = value; }
}
/// <summary>
/// Name of repository we are working on.
/// </summary>
[TaskAttribute("reponame", Required = true)]
[StringValidator(AllowEmpty = false)]
public string RepositoryName
{
get { return _repositoryName; }
set { _repositoryName = value; }
}
/// <summary>
/// Name of start folder within project we are working on. i.e. if the
/// repository was "Code 2-0" then the repository project start could be "/Code/Trunk"
/// or "/Code/Branches/1.0.0.123/"
/// </summary>
[TaskAttribute("repoprojectstart", Required = true)]
[StringValidator(AllowEmpty = false)]
public string RepositoryProjectStart
{
get { return _repositoryProjectStart; }
set { _repositoryProjectStart = value; }
}
/// <summary>
/// Vault user with repository access.
/// </summary>
[TaskAttribute("user", Required = true)]
[StringValidator(AllowEmpty = false)]
public string User
{
get { return _user; }
set { _user = value; }
}
/// <summary>
/// Vault user password.
/// </summary>
[TaskAttribute("password", Required = true)]
[StringValidator(AllowEmpty = false)]
public string Password
{
get { return _password; }
set { _password = value; }
}
/// <summary>
/// Location of Vault server.
/// </summary>
[TaskAttribute("server", Required = true)]
[StringValidator(AllowEmpty = false)]
public string Server
{
get { return _server; }
set { _server = value; }
}
#endregion
protected override void ExecuteTask()
{
try
{
WriteFiles();
}
catch (Exception exception)
{
throw new BuildException("Source indexing could not be completed.", Location, exception);
}
}
private void WriteFiles()
{
foreach (string fileName in Pdbs.FileNames)
{
Log(Level.Info, string.Format("Processing '{0}'.", fileName));
PdbFile pdb = new PdbFile(new FileInfo(fileName));
List<string> sourceFiles = PdbUtil.ReadSourceFiles(pdb);
string tmpFile = Path.GetFullPath(Path.GetTempFileName());
try
{
using (StreamWriter sw = new StreamWriter(tmpFile))
{
sw.WriteLine("SRCSRV: ini ------------------------------------------------");
sw.WriteLine("VERSION=1");
sw.WriteLine("VERCTRL=VAULT");
sw.WriteLine("DATETIME=" + DateTime.Now.ToUniversalTime().ToString("u"));
sw.WriteLine("SRCSRV: variables ------------------------------------------");
sw.WriteLine("VAULT_USER=" + User);
sw.WriteLine("VAULT_PASS=" + Password);
sw.WriteLine("VAULT_SRV=" + Server);
sw.WriteLine("VAULT_EXTRACT_TARGET=%targ%%fnbksl%(%var3%)\\%var4%\\%fnfile%(%var1%)");
sw.WriteLine("VAULT_EXTRACT_FOLDER=%targ%%fnbksl%(%var3%)\\%var4%");
sw.WriteLine("VAULT_EXTRACT_CMD=\"C:\\Program Files\\SourceGear\\Vault Client\\vault.exe\" getlabel -host %vault_srv% -user %vault_user% -password %vault_pass% -repository \"%var2%\" \"$%var3%\" %var4% -nonworkingfolder \"%vault_extract_folder%\" > \"%vault_extract_target%.log\"");
sw.WriteLine("SRCSRVTRG=%vault_extract_target%");
sw.WriteLine("SRCSRVCMD=%vault_extract_cmd%");
sw.WriteLine("SRCSRV: source files ---------------------------------------");
foreach (string sourceFile in sourceFiles)
{
// Will build against something like:
// D:\CruiseControl.NET.Working\Solutions 2.0\Code\Code\Trunk\Working\Solution\..
// Don't want "Working" folder name in there either.
// Need to generate Vault repo path to asset:
// /Code/Trunk/Solution/..
// 1. Pass in repo start - /Code/Trunk
// 2. Redirect slashes and search for \Code\Trunk
// 3. Find first index and split at index to get - \Code\Trunk\Working\Solution\..
// 4. Remove "Working\"
// 5. Flip slashes again to get - /Code/Trunk/Solution/..
// Problems:
// 1. Passing in "Trunk" - would need to work that out dynamically over time
string repositoryPath = sourceFile;
int index = sourceFile.IndexOf(RepositoryProjectStart.Replace("/", @"\"));
if (index != -1)
repositoryPath = sourceFile.Substring(index);
repositoryPath = repositoryPath.Replace(@"Working\", "");
repositoryPath = repositoryPath.Replace(@"\", "/");
sw.Write(sourceFile);
sw.Write("*");
sw.Write(RepositoryName);
sw.Write("*");
sw.Write(repositoryPath);
sw.Write("*");
sw.Write(Build);
sw.WriteLine();
}
sw.WriteLine("SRCSRV: end ------------------------------------------------");
}
Log(Level.Debug, string.Format("Generated stream '{0}'.", File.ReadAllText(tmpFile)));
// Write the stream to the pdb file
PdbUtil.WriteSourceFileStream(pdb, new FileInfo(tmpFile));
Log(Level.Info, "Written stream to pdb.");
}
finally
{
if (File.Exists(tmpFile))
File.Delete(tmpFile);
}
}
}
}
}