예제 #1
0
        private static int Main(string[] args)
        {
#if DEBUG
            LogManager.AddDebugListener(true);
#endif

            var consoleLogListener = new OutputLogListener();
            LogManager.AddListener(consoleLogListener);

            Uri        remoteGitUrl  = null;
            string     commitId      = null;
            string     baseDir       = null;
            string     pdbPath       = null;
            bool       skipVerify    = false;
            bool       allDepotFiles = false;
            LinkMethod method        = LinkMethod.Http;
            var        arguments     = ArgumentSyntax.Parse(args, syntax =>
            {
                syntax.DefineOption("m|method", ref method, v => (LinkMethod)Enum.Parse(typeof(LinkMethod), v, true), "The method for SRCSRV to retrieve source code. One of <" + string.Join("|", Enum.GetNames(typeof(LinkMethod))) + ">. Default is " + method + ".");
                syntax.DefineOption("u|url", ref remoteGitUrl, s => new Uri(s, UriKind.Absolute), "Url to remote git repository.");
                syntax.DefineOption("commit", ref commitId, "The git ref to assume all the source code belongs to.");
                syntax.DefineOption("baseDir", ref baseDir, "The path to the root of the git repo.");
                syntax.DefineOption("s|skipVerify", ref skipVerify, "Verify all source files are available in source control.");
                syntax.DefineOption("a|allDepotFiles", ref allDepotFiles, "Index all source files from depot. Add this option for native PDBs (C++).");
                syntax.DefineParameter("pdb", ref pdbPath, "The PDB to add source indexing to.");

                if (!string.IsNullOrEmpty(pdbPath) && !File.Exists(pdbPath))
                {
                    syntax.ReportError($"File not found: \"{pdbPath}\"");
                }

                if (!string.IsNullOrEmpty(baseDir) && !Directory.Exists(baseDir))
                {
                    syntax.ReportError($"Directory not found: \"{baseDir}\"");
                }
            });

            if (string.IsNullOrEmpty(pdbPath))
            {
                Log.Info(arguments.GetHelpText());
                return(1);
            }

            var options = new LinkOptions
            {
                GitRemoteUrl        = remoteGitUrl,
                GitWorkingDirectory = baseDir != null?Catel.IO.Path.GetFullPath(baseDir, Environment.CurrentDirectory) : null,
                                          CommitId           = commitId,
                                          SkipVerify         = skipVerify,
                                          Method             = method,
                                          IndexAllDepotFiles = allDepotFiles,
            };

            if (!Linker.Link(pdbPath, options))
            {
                return(1);
            }

            WaitForKeyPressWhenDebugging();
            return(0);
        }
예제 #2
0
        public static bool Link(string pdbPath, LinkOptions options = default(LinkOptions))
        {
            Argument.IsNotNullOrEmpty(() => pdbPath);

            var    projectSrcSrvFile = pdbPath + ".srcsrv";
            string repositoryDirectory;
            IReadOnlyCollection <string>         sourceFiles;
            IReadOnlyDictionary <string, string> repoSourceFiles;

            using (var pdb = new PdbFile(pdbPath))
            {
                sourceFiles = pdb.GetFilesAndChecksums().Keys.ToList();

                if (options.GitWorkingDirectory != null)
                {
                    repositoryDirectory = Path.Combine(options.GitWorkingDirectory, ".git");
                }
                else
                {
                    string someSourceFile = sourceFiles.FirstOrDefault();
                    if (someSourceFile == null)
                    {
                        Log.Error("No source files were found in the PDB.");
                        return(false);
                    }

                    repositoryDirectory = GitDirFinder.TreeWalkForGitDir(Path.GetDirectoryName(someSourceFile));
                    if (repositoryDirectory == null)
                    {
                        Log.Error("No source files found that are tracked in a git repo.");
                        return(false);
                    }
                }

                string workingDirectory = Path.GetDirectoryName(repositoryDirectory);

                var repository = new Lazy <Repository>(() => new Repository(repositoryDirectory));
                try
                {
                    string commitId = options.CommitId ?? repository.Value.Head.Commits.FirstOrDefault()?.Sha;
                    if (commitId == null)
                    {
                        Log.Error("No commit is checked out to HEAD. Have you committed yet?");
                        return(false);
                    }

                    var providerManager = new Providers.ProviderManager();
                    Providers.IProvider provider;
                    if (options.GitRemoteUrl == null)
                    {
                        var candidateProviders = from remote in repository.Value.Network.Remotes
                                                 let p = providerManager.GetProvider(remote.Url)
                                                         where p != null
                                                         select p;
                        provider = candidateProviders.FirstOrDefault();
                    }
                    else
                    {
                        provider = providerManager.GetProvider(options.GitRemoteUrl.AbsoluteUri);
                    }

                    if (provider == null)
                    {
                        Log.Error("Unable to detect the remote git service.");
                        return(false);
                    }

                    try
                    {
                        Repository repo = repository.Value;
                        repoSourceFiles = sourceFiles.ToDictionary(e => e, e => repo.GetNormalizedPath(e));
                    }
                    catch (RepositoryNotFoundException)
                    {
                        // Normalize using file system since we can't find the git repo.
                        Log.Warning($"Unable to find git repo at \"{options.GitWorkingDirectory}\". Using file system to find canonical capitalization of file paths.");
                        repoSourceFiles = sourceFiles.ToDictionary(e => e, e => GetNormalizedPath(e, workingDirectory));
                    }

                    if (!options.SkipVerify)
                    {
                        Log.Debug("Verifying pdb file");

                        var missingFiles = pdb.FindMissingOrChangedSourceFiles();
                        foreach (var missingFile in missingFiles)
                        {
                            Log.Warning($"File \"{missingFile}\" missing or changed since the PDB was compiled.");
                        }
                    }

                    string rawUrl = provider.RawGitUrl;
                    if (rawUrl.Contains(RevisionPlaceholder) || rawUrl.Contains(FilenamePlaceholder))
                    {
                        if (!rawUrl.Contains(RevisionPlaceholder) || !rawUrl.Contains(FilenamePlaceholder))
                        {
                            Log.Error("Supplied custom URL pattern must contain both a revision and a filename placeholder.");
                            return(false);
                        }

                        rawUrl = rawUrl
                                 .Replace(RevisionPlaceholder, "{0}")
                                 .Replace(FilenamePlaceholder, "%var2%");
                    }
                    else
                    {
                        rawUrl = $"{rawUrl}/{{0}}/%var2%";
                    }

                    Log.Info($"Using {string.Format(rawUrl, commitId)} for source server URLs.");
                    var srcSrvContext = new SrcSrvContext
                    {
                        RawUrl = rawUrl,
                        DownloadWithPowershell = options.Method == LinkMethod.Powershell,
                        Revision = commitId,
                    };
                    foreach (var sourceFile in repoSourceFiles)
                    {
                        // Skip files that aren't tracked by source control.
                        if (sourceFile.Value != null)
                        {
                            string relativePathForUrl = ReplaceSlashes(provider, sourceFile.Value);
                            srcSrvContext.Paths.Add(Tuple.Create(sourceFile.Key, relativePathForUrl));
                        }
                    }

                    // When using the VisualStudioTeamServicesProvider, add extra infomration to dictionary with VSTS-specific data
                    if (provider is Providers.VisualStudioTeamServicesProvider)
                    {
                        srcSrvContext.VstsData["TFS_COLLECTION"]   = provider.CompanyUrl;
                        srcSrvContext.VstsData["TFS_TEAM_PROJECT"] = provider.ProjectName;
                        srcSrvContext.VstsData["TFS_REPO"]         = provider.ProjectUrl;
                    }

                    CreateSrcSrv(projectSrcSrvFile, srcSrvContext);
                }
                catch (RepositoryNotFoundException)
                {
                    Log.Error($"Unable to find git repo at \"{options.GitWorkingDirectory}\".");
                    return(false);
                }
                finally
                {
                    if (repository.IsValueCreated)
                    {
                        repository.Value.Dispose();
                    }
                }
            }

            Log.Debug("Created source server link file, updating pdb file \"{0}\"", Catel.IO.Path.GetRelativePath(pdbPath, repositoryDirectory));
            PdbStrHelper.Execute(PdbStrExePath, pdbPath, projectSrcSrvFile);
            var indexedFilesCount = repoSourceFiles.Values.Count(v => v != null);

            Log.Info($"Remote git source information for {indexedFilesCount}/{sourceFiles.Count} files written to pdb: \"{pdbPath}\"");

            return(true);
        }