示例#1
0
        /// <summary>
        /// Adds a file to this project, ignoring dupes
        /// </summary>
        /// <param name="FilePath">Path to the file on disk</param>
        /// <param name="BaseFolder">The directory the path within the project will be relative to</param>
        public void AddFileToProject(FileReference FilePath, DirectoryReference BaseFolder)
        {
            // Check if hasn't already been added as an aliased file
            if (AliasedFilesSet.Contains(FilePath))
            {
                return;
            }

            // Don't add duplicates
            SourceFile ExistingFile = null;

            if (SourceFileMap.TryGetValue(FilePath, out ExistingFile))
            {
                if (ExistingFile.BaseFolder != BaseFolder)
                {
                    throw new BuildException("Trying to add file '" + FilePath + "' to project '" + ProjectFilePath + "' when the file already exists, but with a different relative base folder '" + BaseFolder + "' is different than the current file's '" + ExistingFile.BaseFolder + "'!");
                }
            }
            else
            {
                SourceFile File = AllocSourceFile(FilePath, BaseFolder);
                if (File != null)
                {
                    SourceFileMap[FilePath] = File;
                    SourceFiles.Add(File);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Adds a file to this project, ignoring dupes
        /// </summary>
        /// <param name="FilePath">Path to the file on disk</param>
        /// <param name="RelativeBaseFolder">The directory the path within the project will be relative to</param>
        public void AddFileToProject(string FilePath, string RelativeBaseFolder)
        {
            // Don't add duplicates
            SourceFile ExistingFile = null;

            if (SourceFileMap.TryGetValue(FilePath, out ExistingFile))
            {
                if (ExistingFile.RelativeBaseFolder != RelativeBaseFolder)
                {
                    if ((ExistingFile.RelativeBaseFolder != null) != (RelativeBaseFolder != null) ||
                        !ExistingFile.RelativeBaseFolder.Equals(RelativeBaseFolder, StringComparison.InvariantCultureIgnoreCase))
                    {
                        throw new BuildException("Trying to add file '" + FilePath + "' to project '" + ProjectFilePath + "' when the file already exists, but with a different relative base folder '" + RelativeBaseFolder + "' is different than the current file's '" + ExistingFile.RelativeBaseFolder + "'!");
                    }
                    else
                    {
                        throw new BuildException("Trying to add file '" + FilePath + "' to project '" + ProjectFilePath + "' when the file already exists, but the specified project relative base folder is different than the current file's!");
                    }
                }
            }
            else
            {
                SourceFile File = AllocSourceFile(FilePath, RelativeBaseFolder);
                if (File != null)
                {
                    SourceFileMap[FilePath] = File;
                    SourceFiles.Add(File);
                }
            }
        }
示例#3
0
        private static async Task <bool> DownloadSourceFiles(SourceFileMap map, string pdbCacheDirectory, bool force)
        {
            int countDownloaded           = 0;
            int countPreviouslyDownloaded = 0;
            int countFailed           = 0;
            int countPreviouslyFailed = 0;

            foreach (SourceFileDetails sfd in map.Files)
            {
                string fileCachePath       = Path.Combine(pdbCacheDirectory, sfd.CachedPathSuffix);
                string fileCacheFolderPath = Path.GetDirectoryName(fileCachePath);

                // If the folder where the file would be downloaded exists, stop (that's the marker we tried already)
                if (!force)
                {
                    if (File.Exists(fileCachePath))
                    {
                        countPreviouslyDownloaded++;
                        continue;
                    }

                    if (Directory.Exists(fileCacheFolderPath))
                    {
                        countPreviouslyFailed++;
                        continue;
                    }
                }

                // Try to download the file
                Console.WriteLine("Downloading {0}...", sfd.SourceUrl);

                try
                {
                    await SourceFileMap.Download(map.PdbPath, sfd.SourceUrl, TimeSpan.FromSeconds(5));

                    countDownloaded++;
                }
                catch (WebException ex)
                {
                    countFailed++;

                    // On download failure, create a marker so we know we tried previously
                    Console.WriteLine("Download failed. Writing do not retry marker. Error: {0}", ex.Message);
                    if (!String.IsNullOrEmpty(fileCacheFolderPath))
                    {
                        Directory.CreateDirectory(fileCacheFolderPath);
                    }
                }
            }

            // Log download result
            if (map.Files.Count > 0)
            {
                Console.WriteLine("Source Download completed. {1:n0} newly downloaded, {2:n0} previously downloaded, {3:n0} failed, {4:n0} previously failed.", map.Files.Count, countDownloaded, countPreviouslyDownloaded, countFailed, countPreviouslyFailed);
            }

            return(countFailed == 0);
        }
示例#4
0
        private PdbSymbolProvider(string binaryFilePath, string pdbFilePath = "")
        {
            _binaryFilePath = binaryFilePath;
            _pdbFilePath    = pdbFilePath;
            if (String.IsNullOrEmpty(_pdbFilePath))
            {
                _pdbFilePath = Path.ChangeExtension(binaryFilePath, ".pdb");
            }

            // Create a COM Metadata dispenser
            Guid   dispenserClassID = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); // CLSID_CorMetaDataDispenser
            Guid   dispenserIID     = new Guid(0x809c652e, 0x7396, 0x11d2, 0x97, 0x71, 0x00, 0xa0, 0xc9, 0xb4, 0xd5, 0x0c); // IID_IMetaDataDispenser
            object objDispenser;

            Marshal.ThrowExceptionForHR(NativeMethods.MetaDataGetDispenser(ref dispenserClassID, ref dispenserIID, out objDispenser));
            _metadataDispenser = (IMetaDataDispenser)objDispenser;

            // Create a symbol binder [?]
            Guid   symBinderClassID = new Guid(0x0A29FF9E, 0x7F9C, 0x4437, 0x8B, 0x11, 0xF4, 0x24, 0x49, 0x1E, 0x39, 0x31); // CLSID_CorSymBinder
            Guid   symBinderIID     = new Guid(0xAA544d42, 0x28CB, 0x11d3, 0xbd, 0x22, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd); // IID_ISymUnmanagedBinder
            object objBinder;

            if (NativeMethods.CoCreateInstance(ref symBinderClassID,
                                               IntPtr.Zero, // pUnkOuter
                                               1,           // CLSCTX_INPROC_SERVER
                                               ref symBinderIID,
                                               out objBinder) < 0)
            {
                throw new InvalidComObjectException("PdbSymbolProvider unable to construct an ISymUnmanagedBinder.");
            }
            _symBinder = (ISymUnmanagedBinder)objBinder;

            // Create a symbol reader
            Guid importerIID = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); // IID_IMetaDataImport

            // Open an metadata importer on the given filename. We'll end up passing this importer straight
            // through to the Binder.
            object objImporter;

            Marshal.ThrowExceptionForHR(_metadataDispenser.OpenScope(binaryFilePath, 0x00000010 /* read only */, ref importerIID, out objImporter));

            string pdbFolderPath = Path.GetDirectoryName(pdbFilePath);

            ISymUnmanagedReader reader;

            Marshal.ThrowExceptionForHR(_symBinder.GetReaderForFile(objImporter, binaryFilePath, pdbFolderPath, out reader));

            _symReader = reader;

            // Create a source file map [if we can find the map file]
            _sourceFileMap = SourceFileMap.Load(pdbFilePath);
        }
示例#5
0
        private void OpenSymbol(Symbol matchToOpen)
        {
            string localPath = SourceFileMap.GetLocalPath(matchToOpen);

            if (String.IsNullOrEmpty(localPath))
            {
                Console.WriteLine("ERROR: File Path unknown for '{0}'.", matchToOpen.Name.ToString());
            }
            else
            {
                Console.WriteLine("OPEN: {0}({1})", localPath, matchToOpen.Line);
                VS.OpenFileToLine(localPath, matchToOpen.Line, Options.DatabasePath);
            }
        }
示例#6
0
        public string CacheLocation(string url)
        {
            if (_sourceFileMap == null)
            {
                return(url);
            }

            SourceFileDetails details = _sourceFileMap.Details(url);

            if (details == null)
            {
                return(url);
            }

            return(SourceFileMap.ComputeCachedPath(_pdbFilePath, details.SourceUrl));
        }
示例#7
0
        public SyntaxTree ParseFile(string filePath, string pdbPath)
        {
            // Determine the local path to the file (if it's a URL)
            string localPath = filePath;

            if (filePath.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                localPath = SourceFileMap.ComputeCachedPath(pdbPath, filePath);
            }

            if (!File.Exists(localPath))
            {
                return(null);
            }

            // Much like Roslyn CSharpCompiler.CreateCompilation
            SourceText fileContent = null;

            using (var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 1, options: FileOptions.None))
            {
                fileContent = SourceText.From(stream);
            }

            // Parse the file but keep the original path or URL as the path (so locations from Roslyn point to it)
            string extension = Path.GetExtension(filePath).ToLowerInvariant();

            switch (extension)
            {
            case ".cs":
                return(CSharpSyntaxTree.ParseText(fileContent, path: filePath));

            case ".vb":
                return(VisualBasicSyntaxTree.ParseText(fileContent, path: filePath));

            default:
                return(null);
            }
        }
示例#8
0
        private static int Run(Options arguments)
        {
            if (!String.IsNullOrEmpty(arguments.SymbolCachePath))
            {
                SymbolCache.Path = arguments.SymbolCachePath;
            }

            if (!File.Exists(arguments.BinaryPath))
            {
                Console.WriteLine("Error: Unable to find \"{0}\". Stopping.", arguments.BinaryPath);
                return(ExitCodes.BinaryNotFound);
            }

            // Get Hash of Binary
            RsDsSignature signature = Assembly.ReadRsDsSignature(arguments.BinaryPath);

            if (signature == null)
            {
                Console.WriteLine("Unable to read binary signature. It may not be a managed binary.");
                return(ExitCodes.BinarySignatureNotFound);
            }

            Console.WriteLine("Signature: {0}", signature);

            // File Structure Map:
            //  C:\SymbolCache\Elfie.pdb									=> All known Elfie.pdb copies
            //			\671497fb11a04a8f9fc2c64bd82b4a201\Elfie.pdb		=> All content related to Elfie.dll with debug signature 671...201
            //				Elfie.pdb										=> Elfie.pdb matching Elfie.dll with debug signature 671...201
            //				FilePaths.map									=> Tab delimited file with source file path in PDB, download URL, cached path under \SymbolCache\Elfie.pdb
            //			\src\fc2c64bd\Program.cs							=> Source Code 'Program.cs' with remote URL hash fc2c64bd
            string pdbFileName          = Path.ChangeExtension(Path.GetFileName(arguments.BinaryPath), ".pdb");
            string pdbNameDirectory     = Path.Combine(Environment.ExpandEnvironmentVariables(SymbolCache.Path), pdbFileName);
            string pdbCacheDirectory    = Path.Combine(pdbNameDirectory, signature.ToString());
            string pdbPath              = Path.Combine(pdbCacheDirectory, pdbFileName);
            string sourceCacheDirectory = Path.Combine(pdbNameDirectory, "src");

            if (File.Exists(pdbPath))
            {
                Console.WriteLine("PDB: {0}", pdbPath);
            }
            else if (File.Exists(Path.ChangeExtension(arguments.BinaryPath, ".pdb")))
            {
                pdbPath = Path.GetFullPath(Path.ChangeExtension(arguments.BinaryPath, ".pdb"));
                Console.WriteLine("PDB: {0}", pdbPath);
            }
            else if (Directory.Exists(pdbCacheDirectory) && !arguments.Force)
            {
                Console.WriteLine("PDB download previously failed. Stopping. Use '-f' to force retry.");
                return(ExitCodes.SymbolsNotFoundAtAnySymbolServer);
            }
            else
            {
                // Get symbols, if we haven't previously tried
                DownloadSymbols(arguments, pdbPath);

                if (!File.Exists(pdbPath))
                {
                    // TODO: Ping the symbol servers; don't write the "don't try again" if we couldn't reach the server at all

                    // Create a stub indicating we tried but could not download the PDB
                    if (!String.IsNullOrEmpty(pdbCacheDirectory))
                    {
                        Directory.CreateDirectory(pdbCacheDirectory);
                    }

                    Console.WriteLine("No configured symbol server had symbols. Stopping. Use '-f' to force retry.");
                    return(ExitCodes.SymbolsNotFoundAtAnySymbolServer);
                }
            }

            // Extract or reload the PDB path to source URL map
            SourceFileMap map = SourceFileMap.BuildOrLoad(pdbPath);

            // Write map next to binary as well as PDB [so either can be indexed safely]
            map.Save(Path.ChangeExtension(arguments.BinaryPath, ".map"));

            if (map.Files.Count == 0)
            {
                Console.WriteLine("No Source File URLs found in PDB. It may not be source server registered.");
                return(ExitCodes.SourceUrlsNotFoundInPdb);
            }
            else
            {
                Console.WriteLine("PDB references {0:n0} source file URLs.", map.Files.Count);
            }

            // Download source files not already downloaded (or failed)
            bool allFilesDownloaded = DownloadSourceFiles(map, sourceCacheDirectory, arguments.Force).Result;

            return(allFilesDownloaded ? ExitCodes.Success : ExitCodes.FailedDownloadingSomeSourceFiles);
        }
示例#9
0
 public string RenderCoverageReport(SourceFileMap sourceFileMap)
 {
     return(_viewRender.Render("CoveragePage", sourceFileMap));
 }