public void BeforeCompile(IBeforeCompileContext context)
        {
            string keyPath = Environment.GetEnvironmentVariable("NUGET_BUILD_KEY_PATH");
            string delaySignString = Environment.GetEnvironmentVariable("NUGET_BUILD_DELAY_SIGN");

            if (!string.IsNullOrEmpty(keyPath))
            {
                FileInfo keyFile = new FileInfo(keyPath);

                if (keyFile.Exists)
                {
                    bool delaySign = delaySignString != null && StringComparer.OrdinalIgnoreCase.Equals("true", delaySignString);

                    // Console.WriteLine("Signing assembly with: {0} Delay sign: {1}", keyFile.FullName, delaySign ? "true" : "false");

                    var parms = new CspParameters();
                    parms.KeyNumber = 2;

                    var provider = new RSACryptoServiceProvider(parms);
                    byte[] array = provider.ExportCspBlob(!provider.PublicOnly);

                    var strongNameProvider = new DesktopStrongNameProvider();


                    var options = context.Compilation.Options.WithStrongNameProvider(strongNameProvider)
                                                                   .WithCryptoKeyFile(keyFile.FullName)
                                                                   .WithDelaySign(delaySign);

                    // Enfore viral strong naming
                    var specificDiagnosticOptions = new Dictionary<string, ReportDiagnostic>(options.SpecificDiagnosticOptions);
                    specificDiagnosticOptions["CS8002"] = ReportDiagnostic.Error;
                    options = options.WithSpecificDiagnosticOptions(specificDiagnosticOptions);

                    context.Compilation = context.Compilation.WithOptions(options);
                }
                else
                {
                    // The key was not found. Throw a compile error.
                    var descriptor = new DiagnosticDescriptor(
                    id: "SN1001",
                    title: "Missing key file",
                    messageFormat: "Key file '{0}' could not be found",
                    category: "CA1001: \"StrongNaming\"",
                    defaultSeverity: DiagnosticSeverity.Error,
                    isEnabledByDefault: true);

                    // TODO: what should this reference for the location?
                    var textSpan = new TextSpan();
                    var position = new LinePosition(0, 0);
                    var span = new LinePositionSpan(position, position);

                    var location = Location.Create(context.ProjectContext.ProjectFilePath, textSpan, span);

                    var diagnsotic = Diagnostic.Create(descriptor, location, keyPath);

                    context.Diagnostics.Add(diagnsotic);
                }
            }
        }
        public override bool Equals(object obj)
        {
            // Explicitly check that we're not comparing against a derived type
            if (obj == null || GetType() != obj.GetType())
            {
                return(false);
            }

            DesktopStrongNameProvider other = (DesktopStrongNameProvider)obj;

            return(_keyFileSearchPaths.SequenceEqual(other._keyFileSearchPaths, StringComparer.Ordinal));
        }
        private unsafe static void InstallKey(byte[] keyBlob, string keyName)
        {
            try
            {
                IClrStrongName strongName = new DesktopStrongNameProvider().GetStrongNameInterface();

                //EDMAURER use marshal to be safe?
                fixed (byte* p = keyBlob)
                {
                    strongName.StrongNameKeyInstall(keyName, (IntPtr)p, keyBlob.Length);
                }
            }
            catch (COMException ex)
            {
                if (unchecked((uint)ex.ErrorCode) != 0x8009000F)
                    throw;
            }
        }
        /// <summary>
        /// Create a <see cref="ProjectInfo"/> structure initialized from a compilers command line arguments.
        /// </summary>
        public static ProjectInfo CreateProjectInfo(string projectName, string language, IEnumerable<string> commandLineArgs, string projectDirectory, Workspace workspace = null)
        {
            // TODO (tomat): the method may throw all sorts of exceptions.
            var tmpWorkspace = workspace ?? new AdhocWorkspace(DesktopMefHostServices.DefaultServices);
            var languageServices = tmpWorkspace.Services.GetLanguageServices(language);
            if (languageServices == null)
            {
                throw new ArgumentException(WorkspacesResources.UnrecognizedLanguageName);
            }

            var commandLineParser = languageServices.GetRequiredService<ICommandLineParserService>();
            var commandLineArguments = commandLineParser.Parse(commandLineArgs, projectDirectory, isInteractive: false, sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO (tomat): to match csc.exe/vbc.exe we should use CommonCommandLineCompiler.ExistingReferencesResolver to deal with #r's
            var referenceResolver = new RelativePathReferenceResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory);
            var referenceProvider = tmpWorkspace.Services.GetRequiredService<IMetadataService>().GetProvider();
            var analyzerLoader = tmpWorkspace.Services.GetRequiredService<IAnalyzerService>().GetLoader();
            var xmlFileResolver = new XmlFileResolver(commandLineArguments.BaseDirectory);
            var strongNameProvider = new DesktopStrongNameProvider(commandLineArguments.KeyFileSearchPaths);

            // resolve all metadata references.
            var boundMetadataReferences = commandLineArguments.ResolveMetadataReferences(new AssemblyReferenceResolver(referenceResolver, referenceProvider));
            var unresolvedMetadataReferences = boundMetadataReferences.FirstOrDefault(r => r is UnresolvedMetadataReference);
            if (unresolvedMetadataReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.CantResolveMetadataReference, ((UnresolvedMetadataReference)unresolvedMetadataReferences).Reference));
            }

            // resolve all analyzer references.
            foreach (var path in commandLineArguments.AnalyzerReferences.Select(r => r.FilePath))
            {
                analyzerLoader.AddDependencyLocation(path);
            }
            var boundAnalyzerReferences = commandLineArguments.ResolveAnalyzerReferences(analyzerLoader);
            var unresolvedAnalyzerReferences = boundAnalyzerReferences.FirstOrDefault(r => r is UnresolvedAnalyzerReference);
            if (unresolvedAnalyzerReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.CantResolveAnalyzerReference, ((UnresolvedAnalyzerReference)unresolvedAnalyzerReferences).Display));
            }

            AssemblyIdentityComparer assemblyIdentityComparer;
            if (commandLineArguments.AppConfigPath != null)
            {
                try
                {
                    using (var appConfigStream = new FileStream(commandLineArguments.AppConfigPath, FileMode.Open, FileAccess.Read))
                    {
                        assemblyIdentityComparer = DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream);
                    }
                }
                catch (Exception e)
                {
                    throw new ArgumentException(string.Format(WorkspacesResources.ErrorWhileReadingSpecifiedConfigFile, e.Message));
                }
            }
            else
            {
                assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default;
            }

            var projectId = ProjectId.CreateNewId(debugName: projectName);

            // construct file infos
            var docs = new List<DocumentInfo>();
            foreach (var fileArg in commandLineArguments.SourceFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                    ? Path.GetFullPath(fileArg.Path)
                    : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath = FilePathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = FilePathUtilities.IsNestedPath(projectDirectory, absolutePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders = isWithinProject ? GetFolders(relativePath) : null;
                var name = Path.GetFileName(relativePath);
                var id = DocumentId.CreateNewId(projectId, absolutePath);

                var doc = DocumentInfo.Create(
                   id: id,
                   name: name,
                   folders: folders,
                   sourceCodeKind: fileArg.IsScript ? SourceCodeKind.Script : SourceCodeKind.Regular,
                   loader: new FileTextLoader(absolutePath, commandLineArguments.Encoding),
                   filePath: absolutePath);

                docs.Add(doc);
            }

            // construct file infos for additional files.
            var additionalDocs = new List<DocumentInfo>();
            foreach (var fileArg in commandLineArguments.AdditionalFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                        ? Path.GetFullPath(fileArg.Path)
                        : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath = FilePathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = FilePathUtilities.IsNestedPath(projectDirectory, absolutePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders = isWithinProject ? GetFolders(relativePath) : null;
                var name = Path.GetFileName(relativePath);
                var id = DocumentId.CreateNewId(projectId, absolutePath);

                var doc = DocumentInfo.Create(
                   id: id,
                   name: name,
                   folders: folders,
                   sourceCodeKind: SourceCodeKind.Regular,
                   loader: new FileTextLoader(absolutePath, commandLineArguments.Encoding),
                   filePath: absolutePath);

                additionalDocs.Add(doc);
            }

            // If /out is not specified and the project is a console app the csc.exe finds out the Main method
            // and names the compilation after the file that contains it. We don't want to create a compilation, 
            // bind Mains etc. here. Besides the msbuild always includes /out in the command line it produces.
            // So if we don't have the /out argument we name the compilation "<anonymous>".
            string assemblyName = (commandLineArguments.OutputFileName != null) ?
                Path.GetFileNameWithoutExtension(commandLineArguments.OutputFileName) : "<anonymous>";

            // TODO (tomat): what should be the assemblyName when compiling a netmodule? Should it be /moduleassemblyname

            var projectInfo = ProjectInfo.Create(
                projectId,
                VersionStamp.Create(),
                projectName,
                assemblyName,
                language: language,
                compilationOptions: commandLineArguments.CompilationOptions
                    .WithXmlReferenceResolver(xmlFileResolver)
                    .WithAssemblyIdentityComparer(assemblyIdentityComparer)
                    .WithStrongNameProvider(strongNameProvider)
                    .WithMetadataReferenceResolver(new AssemblyReferenceResolver(referenceResolver, referenceProvider)),
                parseOptions: commandLineArguments.ParseOptions,
                documents: docs,
                additionalDocuments: additionalDocs,
                metadataReferences: boundMetadataReferences,
                analyzerReferences: boundAnalyzerReferences);

            return projectInfo;
        }
        /// <summary>
        /// Create a ProjectInfo structure initialized from a compilers command line arguments.
        /// </summary>
        public static ProjectInfo CreateProjectInfo(Workspace workspace, string projectName, string language, IEnumerable <string> commandLineArgs, string projectDirectory)
        {
            // TODO (tomat): the method may throw all sorts of exceptions.

            var languageServices = workspace.Services.GetLanguageServices(language);

            if (languageServices == null)
            {
                throw new ArgumentException(WorkspacesResources.UnrecognizedLanguageName);
            }

            var commandLineArgumentsFactory = languageServices.GetService <ICommandLineArgumentsFactoryService>();
            var commandLineArguments        = commandLineArgumentsFactory.CreateCommandLineArguments(commandLineArgs, projectDirectory, isInteractive: false);

            // TODO (tomat): to match csc.exe/vbc.exe we should use CommonCommandLineCompiler.ExistingReferencesResolver to deal with #r's
            var referenceResolver  = new MetadataFileReferenceResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory);
            var referenceProvider  = MetadataFileReferenceProvider.Default;
            var xmlFileResolver    = new XmlFileResolver(commandLineArguments.BaseDirectory);
            var strongNameProvider = new DesktopStrongNameProvider(commandLineArguments.KeyFileSearchPaths);

            // resolve all metadata references.
            var boundMetadataReferences      = commandLineArguments.ResolveMetadataReferences(referenceResolver, referenceProvider);
            var unresolvedMetadataReferences = boundMetadataReferences.FirstOrDefault(r => r is UnresolvedMetadataReference);

            if (unresolvedMetadataReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.CantResolveMetadataReference, ((UnresolvedMetadataReference)unresolvedMetadataReferences).Reference));
            }

            // resolve all analyzer references.
            var boundAnalyzerReferences      = commandLineArguments.ResolveAnalyzerReferences();
            var unresolvedAnalyzerReferences = boundAnalyzerReferences.FirstOrDefault(r => r is UnresolvedAnalyzerReference);

            if (unresolvedAnalyzerReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.CantResolveAnalyzerReference, ((UnresolvedAnalyzerReference)unresolvedAnalyzerReferences).Display));
            }

            AssemblyIdentityComparer assemblyIdentityComparer;

            if (commandLineArguments.AppConfigPath != null)
            {
                try
                {
                    using (var appConfigStream = new FileStream(commandLineArguments.AppConfigPath, FileMode.Open, FileAccess.Read))
                    {
                        assemblyIdentityComparer = DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream);
                    }
                }
                catch (Exception e)
                {
                    throw new ArgumentException(string.Format(WorkspacesResources.ErrorWhileReadingSpecifiedConfigFile, e.Message));
                }
            }
            else
            {
                assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default;
            }

            var projectId = ProjectId.CreateNewId(debugName: projectName);

            // construct file infos
            var docs = new List <DocumentInfo>();
            var ids  = new HashSet <DocumentId>();

            foreach (var fileArg in commandLineArguments.SourceFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                    ? Path.GetFullPath(fileArg.Path)
                    : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath    = FilePathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = !Path.IsPathRooted(relativePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders    = isWithinProject ? GetFolders(relativePath) : null;
                var name       = Path.GetFileName(relativePath);
                var id         = GetUniqueDocumentId(projectId, name, folderRoot, ids);

                var doc = DocumentInfo.Create(
                    id: id,
                    name: name,
                    folders: folders,
                    sourceCodeKind: fileArg.IsScript ? SourceCodeKind.Script : SourceCodeKind.Regular,
                    loader: new FileTextLoader(absolutePath),
                    filePath: absolutePath);

                docs.Add(doc);
            }

            // If /out is not specified and the project is a console app the csc.exe finds out the Main method
            // and names the compilation after the file that contains it. We don't want to create a compilation,
            // bind Mains etc. here. Besides the msbuild always includes /out in the command line it produces.
            // So if we don't have the /out argument we name the compilation "<anonymous>".
            string assemblyName = (commandLineArguments.OutputFileName != null) ?
                                  Path.GetFileNameWithoutExtension(commandLineArguments.OutputFileName) : "<anonymous>";

            // TODO (tomat): what should be the assemblyName when compiling a netmodule? Should it be /moduleassemblyname

            var projectInfo = ProjectInfo.Create(
                projectId,
                VersionStamp.Create(),
                projectName,
                assemblyName,
                language: language,
                compilationOptions: commandLineArguments.CompilationOptions
                .WithXmlReferenceResolver(xmlFileResolver)
                .WithAssemblyIdentityComparer(assemblyIdentityComparer)
                .WithStrongNameProvider(strongNameProvider)
                .WithMetadataReferenceResolver(referenceResolver)
                .WithMetadataReferenceProvider(referenceProvider),
                parseOptions: commandLineArguments.ParseOptions,
                documents: docs,
                metadataReferences: boundMetadataReferences,
                analyzerReferences: boundAnalyzerReferences);

            return(projectInfo);
        }
Exemple #6
0
        /// <summary>
        /// Create a <see cref="ProjectInfo"/> structure initialized from a compilers command line arguments.
        /// </summary>
        public static ProjectInfo CreateProjectInfo(string projectName, string language, IEnumerable <string> commandLineArgs, string projectDirectory, Workspace workspace = null)
        {
            // TODO (tomat): the method may throw all sorts of exceptions.
            var tmpWorkspace     = workspace ?? new AdhocWorkspace(DesktopMefHostServices.DefaultServices);
            var languageServices = tmpWorkspace.Services.GetLanguageServices(language);

            if (languageServices == null)
            {
                throw new ArgumentException(WorkspacesResources.Unrecognized_language_name);
            }

            var commandLineParser    = languageServices.GetRequiredService <ICommandLineParserService>();
            var commandLineArguments = commandLineParser.Parse(commandLineArgs, projectDirectory, isInteractive: false, sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            var metadataService = tmpWorkspace.Services.GetRequiredService <IMetadataService>();

            // we only support file paths in /r command line arguments
            var commandLineMetadataReferenceResolver = new WorkspaceMetadataFileReferenceResolver(
                metadataService, new RelativePathResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory));

            var analyzerLoader     = tmpWorkspace.Services.GetRequiredService <IAnalyzerService>().GetLoader();
            var xmlFileResolver    = new XmlFileResolver(commandLineArguments.BaseDirectory);
            var strongNameProvider = new DesktopStrongNameProvider(commandLineArguments.KeyFileSearchPaths);

            // resolve all metadata references.
            var boundMetadataReferences      = commandLineArguments.ResolveMetadataReferences(commandLineMetadataReferenceResolver);
            var unresolvedMetadataReferences = boundMetadataReferences.FirstOrDefault(r => r is UnresolvedMetadataReference);

            if (unresolvedMetadataReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.Can_t_resolve_metadata_reference_colon_0, ((UnresolvedMetadataReference)unresolvedMetadataReferences).Reference));
            }

            // resolve all analyzer references.
            foreach (var path in commandLineArguments.AnalyzerReferences.Select(r => r.FilePath))
            {
                analyzerLoader.AddDependencyLocation(path);
            }

            var boundAnalyzerReferences      = commandLineArguments.ResolveAnalyzerReferences(analyzerLoader);
            var unresolvedAnalyzerReferences = boundAnalyzerReferences.FirstOrDefault(r => r is UnresolvedAnalyzerReference);

            if (unresolvedAnalyzerReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.Can_t_resolve_analyzer_reference_colon_0, ((UnresolvedAnalyzerReference)unresolvedAnalyzerReferences).Display));
            }

            AssemblyIdentityComparer assemblyIdentityComparer;

            if (commandLineArguments.AppConfigPath != null)
            {
                try
                {
                    using (var appConfigStream = new FileStream(commandLineArguments.AppConfigPath, FileMode.Open, FileAccess.Read))
                    {
                        assemblyIdentityComparer = DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream);
                    }
                }
                catch (Exception e)
                {
                    throw new ArgumentException(string.Format(WorkspacesResources.An_error_occurred_while_reading_the_specified_configuration_file_colon_0, e.Message));
                }
            }
            else
            {
                assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default;
            }

            var projectId = ProjectId.CreateNewId(debugName: projectName);

            // construct file infos
            var docs = new List <DocumentInfo>();

            foreach (var fileArg in commandLineArguments.SourceFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                    ? Path.GetFullPath(fileArg.Path)
                    : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath    = FilePathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = FilePathUtilities.IsNestedPath(projectDirectory, absolutePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders    = isWithinProject ? GetFolders(relativePath) : null;
                var name       = Path.GetFileName(relativePath);
                var id         = DocumentId.CreateNewId(projectId, absolutePath);

                var doc = DocumentInfo.Create(
                    id: id,
                    name: name,
                    folders: folders,
                    sourceCodeKind: fileArg.IsScript ? SourceCodeKind.Script : SourceCodeKind.Regular,
                    loader: new FileTextLoader(absolutePath, commandLineArguments.Encoding),
                    filePath: absolutePath);

                docs.Add(doc);
            }

            // construct file infos for additional files.
            var additionalDocs = new List <DocumentInfo>();

            foreach (var fileArg in commandLineArguments.AdditionalFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                        ? Path.GetFullPath(fileArg.Path)
                        : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath    = FilePathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = FilePathUtilities.IsNestedPath(projectDirectory, absolutePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders    = isWithinProject ? GetFolders(relativePath) : null;
                var name       = Path.GetFileName(relativePath);
                var id         = DocumentId.CreateNewId(projectId, absolutePath);

                var doc = DocumentInfo.Create(
                    id: id,
                    name: name,
                    folders: folders,
                    sourceCodeKind: SourceCodeKind.Regular,
                    loader: new FileTextLoader(absolutePath, commandLineArguments.Encoding),
                    filePath: absolutePath);

                additionalDocs.Add(doc);
            }

            // If /out is not specified and the project is a console app the csc.exe finds out the Main method
            // and names the compilation after the file that contains it. We don't want to create a compilation,
            // bind Mains etc. here. Besides the msbuild always includes /out in the command line it produces.
            // So if we don't have the /out argument we name the compilation "<anonymous>".
            string assemblyName = (commandLineArguments.OutputFileName != null) ?
                                  Path.GetFileNameWithoutExtension(commandLineArguments.OutputFileName) : "<anonymous>";

            // TODO (tomat): what should be the assemblyName when compiling a netmodule? Should it be /moduleassemblyname

            var projectInfo = ProjectInfo.Create(
                projectId,
                VersionStamp.Create(),
                projectName,
                assemblyName,
                language: language,
                compilationOptions: commandLineArguments.CompilationOptions
                .WithXmlReferenceResolver(xmlFileResolver)
                .WithAssemblyIdentityComparer(assemblyIdentityComparer)
                .WithStrongNameProvider(strongNameProvider)
                // TODO (https://github.com/dotnet/roslyn/issues/4967):
                .WithMetadataReferenceResolver(new WorkspaceMetadataFileReferenceResolver(metadataService, new RelativePathResolver(ImmutableArray <string> .Empty, projectDirectory))),
                parseOptions: commandLineArguments.ParseOptions,
                documents: docs,
                additionalDocuments: additionalDocs,
                metadataReferences: boundMetadataReferences,
                analyzerReferences: boundAnalyzerReferences);

            return(projectInfo);
        }
Exemple #7
0
        private void AddStrongNameProvider(CompilationContext compilationContext)
        {
            if (!string.IsNullOrEmpty(compilationContext.Compilation.Options.CryptoKeyFile))
            {
                var strongNameProvider =
                    new DesktopStrongNameProvider(ImmutableArray.Create(compilationContext.Project.ProjectDirectory));

                compilationContext.Compilation =
                    compilationContext.Compilation.WithOptions(
                        compilationContext.Compilation.Options.WithStrongNameProvider(strongNameProvider));
            }
        }
        private void ApplyStrongNameSettings(CompilationContext compilationContext)
        {
            var keyFile =
                Environment.GetEnvironmentVariable(EnvironmentNames.BuildKeyFile) ??
                compilationContext.Compilation.Options.CryptoKeyFile;

            if (!string.IsNullOrEmpty(keyFile) && !RuntimeEnvironmentHelper.IsMono) {
            #if DNX451
                var delaySignString = Environment.GetEnvironmentVariable(EnvironmentNames.BuildDelaySign);
                var delaySign =
                    delaySignString == null
                        ? compilationContext.Compilation.Options.DelaySign
                        : string.Equals(delaySignString, "true", StringComparison.OrdinalIgnoreCase) ||
                          string.Equals(delaySignString, "1", StringComparison.OrdinalIgnoreCase);

                var strongNameProvider = new DesktopStrongNameProvider(
                    ImmutableArray.Create(compilationContext.Project.ProjectDirectory));
                var newOptions = compilationContext.Compilation.Options
                    .WithStrongNameProvider(strongNameProvider)
                    .WithCryptoKeyFile(keyFile)
                    .WithDelaySign(delaySign);
                compilationContext.Compilation = compilationContext.Compilation.WithOptions(newOptions);
            #else
                var diag = Diagnostic.Create(
                    RoslynDiagnostics.StrongNamingNotSupported,
                    null);
                compilationContext.Diagnostics.Add(diag);
            #endif
            }

            // If both CryptoPublicKey and CryptoKeyFile compilation will fail so we don't need a check
            if (compilationContext.Compilation.Options.CryptoPublicKey != null) {
                var options = compilationContext.Compilation.Options
                    .WithCryptoPublicKey(compilationContext.Compilation.Options.CryptoPublicKey);
                compilationContext.Compilation = compilationContext.Compilation.WithOptions(options);
            }
        }
        public static ProjectInfo CreateProjectInfo(string projectName, string language, IEnumerable <string> commandLineArgs, string projectDirectory, Workspace workspace = null)
#pragma warning restore RS0026 // Type is forwarded from MS.CA.Workspaces.Desktop.
        {
            // TODO (tomat): the method may throw all sorts of exceptions.
            var tmpWorkspace     = workspace ?? new AdhocWorkspace();
            var languageServices = tmpWorkspace.Services.GetLanguageServices(language);

            if (languageServices == null)
            {
                throw new ArgumentException(WorkspacesResources.Unrecognized_language_name);
            }

            var commandLineParser    = languageServices.GetRequiredService <ICommandLineParserService>();
            var commandLineArguments = commandLineParser.Parse(commandLineArgs, projectDirectory, isInteractive: false, sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            var metadataService = tmpWorkspace.Services.GetRequiredService <IMetadataService>();

            // we only support file paths in /r command line arguments
            var relativePathResolver =
                new RelativePathResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory);
            var commandLineMetadataReferenceResolver = new WorkspaceMetadataFileReferenceResolver(
                metadataService, relativePathResolver);

            var analyzerLoader     = tmpWorkspace.Services.GetRequiredService <IAnalyzerService>().GetLoader();
            var xmlFileResolver    = new XmlFileResolver(commandLineArguments.BaseDirectory);
            var strongNameProvider = new DesktopStrongNameProvider(commandLineArguments.KeyFileSearchPaths);

            // Resolve all metadata references.
            //
            // In the command line compiler, it's entirely possible that duplicate reference paths may appear in this list; in the compiler
            // each MetadataReference object is a distinct instance, and the deduplication is ultimately performed in the ReferenceManager
            // once the Compilation actually starts to read metadata. In this code however,  we're resolving with the IMetadataService, which
            // has a default implementation to cache and return the same MetadataReference instance for a duplicate. This means duplicate
            // reference path will create duplicate MetadataReference objects, which is disallowed by ProjectInfo.Create -- even though the
            // compiler eventually would have dealt with it just fine. It's reasonable the Workspace APIs disallow duplicate reference objects
            // since it makes the semantics of APIs like Add/RemoveMetadataReference tricky. But since we want to not break for command lines
            // with duplicate references, we'll do a .Distinct() here, and let the Compilation do any further deduplication
            // that isn't handled by this explicit instance check. This does mean that the Compilations produced through this API
            // won't produce the "duplicate metadata reference" diagnostic like the real command line compiler would, but that's probably fine.
            //
            // Alternately, we could change the IMetadataService behavior to simply not cache, but that could theoretically break other
            // callers that would now see references across projects not be the same, or hurt performance for users of MSBuildWorkspace. Given
            // this is an edge case, it's not worth the larger fix here.
            var boundMetadataReferences      = commandLineArguments.ResolveMetadataReferences(commandLineMetadataReferenceResolver).Distinct().ToList();
            var unresolvedMetadataReferences = boundMetadataReferences.FirstOrDefault(r => r is UnresolvedMetadataReference);

            if (unresolvedMetadataReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.Can_t_resolve_metadata_reference_colon_0, ((UnresolvedMetadataReference)unresolvedMetadataReferences).Reference));
            }

            // resolve all analyzer references.
            foreach (var path in commandLineArguments.AnalyzerReferences.Select(r => r.FilePath))
            {
                analyzerLoader.AddDependencyLocation(relativePathResolver.ResolvePath(path, baseFilePath: null));
            }

            var boundAnalyzerReferences      = commandLineArguments.ResolveAnalyzerReferences(analyzerLoader);
            var unresolvedAnalyzerReferences = boundAnalyzerReferences.FirstOrDefault(r => r is UnresolvedAnalyzerReference);

            if (unresolvedAnalyzerReferences != null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.Can_t_resolve_analyzer_reference_colon_0, ((UnresolvedAnalyzerReference)unresolvedAnalyzerReferences).Display));
            }

            AssemblyIdentityComparer assemblyIdentityComparer;

            if (commandLineArguments.AppConfigPath != null)
            {
                try
                {
                    using var appConfigStream = new FileStream(commandLineArguments.AppConfigPath, FileMode.Open, FileAccess.Read);

                    assemblyIdentityComparer = DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream);
                }
                catch (Exception e)
                {
                    throw new ArgumentException(string.Format(WorkspacesResources.An_error_occurred_while_reading_the_specified_configuration_file_colon_0, e.Message));
                }
            }
            else
            {
                assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default;
            }

            var projectId = ProjectId.CreateNewId(debugName: projectName);

            // construct file infos
            var docs = new List <DocumentInfo>();

            foreach (var fileArg in commandLineArguments.SourceFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                    ? Path.GetFullPath(fileArg.Path)
                    : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath    = PathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = PathUtilities.IsChildPath(projectDirectory, absolutePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders    = isWithinProject ? GetFolders(relativePath) : null;
                var name       = Path.GetFileName(relativePath);
                var id         = DocumentId.CreateNewId(projectId, absolutePath);

                var doc = DocumentInfo.Create(
                    id: id,
                    name: name,
                    folders: folders,
                    sourceCodeKind: fileArg.IsScript ? SourceCodeKind.Script : SourceCodeKind.Regular,
                    loader: new FileTextLoader(absolutePath, commandLineArguments.Encoding),
                    filePath: absolutePath);

                docs.Add(doc);
            }

            // construct file infos for additional files.
            var additionalDocs = new List <DocumentInfo>();

            foreach (var fileArg in commandLineArguments.AdditionalFiles)
            {
                var absolutePath = Path.IsPathRooted(fileArg.Path) || string.IsNullOrEmpty(projectDirectory)
                        ? Path.GetFullPath(fileArg.Path)
                        : Path.GetFullPath(Path.Combine(projectDirectory, fileArg.Path));

                var relativePath    = PathUtilities.GetRelativePath(projectDirectory, absolutePath);
                var isWithinProject = PathUtilities.IsChildPath(projectDirectory, absolutePath);

                var folderRoot = isWithinProject ? Path.GetDirectoryName(relativePath) : "";
                var folders    = isWithinProject ? GetFolders(relativePath) : null;
                var name       = Path.GetFileName(relativePath);
                var id         = DocumentId.CreateNewId(projectId, absolutePath);

                var doc = DocumentInfo.Create(
                    id: id,
                    name: name,
                    folders: folders,
                    sourceCodeKind: SourceCodeKind.Regular,
                    loader: new FileTextLoader(absolutePath, commandLineArguments.Encoding),
                    filePath: absolutePath);

                additionalDocs.Add(doc);
            }

            // If /out is not specified and the project is a console app the csc.exe finds out the Main method
            // and names the compilation after the file that contains it. We don't want to create a compilation,
            // bind Mains etc. here. Besides the msbuild always includes /out in the command line it produces.
            // So if we don't have the /out argument we name the compilation "<anonymous>".
            var assemblyName = (commandLineArguments.OutputFileName != null) ?
                               Path.GetFileNameWithoutExtension(commandLineArguments.OutputFileName) : "<anonymous>";

            // TODO (tomat): what should be the assemblyName when compiling a netmodule? Should it be /moduleassemblyname

            var projectInfo = ProjectInfo.Create(
                projectId,
                VersionStamp.Create(),
                projectName,
                assemblyName,
                language: language,
                compilationOptions: commandLineArguments.CompilationOptions
                .WithXmlReferenceResolver(xmlFileResolver)
                .WithAssemblyIdentityComparer(assemblyIdentityComparer)
                .WithStrongNameProvider(strongNameProvider)
                // TODO (https://github.com/dotnet/roslyn/issues/4967):
                .WithMetadataReferenceResolver(new WorkspaceMetadataFileReferenceResolver(metadataService, new RelativePathResolver(ImmutableArray <string> .Empty, projectDirectory))),
                parseOptions: commandLineArguments.ParseOptions,
                documents: docs,
                additionalDocuments: additionalDocs,
                metadataReferences: boundMetadataReferences,
                analyzerReferences: boundAnalyzerReferences);

            return(projectInfo);
        }
        private void UpdateCompilationOption(ProjectState state)
        {
            var context = state.ProjectContext;
            var project = context.ProjectFile;
            var option = project.GetCompilerOptions(context.TargetFramework, _compilationConfiguration);

            var outputKind = option.EmitEntryPoint.GetValueOrDefault() ? OutputKind.ConsoleApplication :
                                                                         OutputKind.DynamicallyLinkedLibrary;

            var generalDiagnosticOpt = (option.WarningsAsErrors ?? false) ? ReportDiagnostic.Error :
                                                                            ReportDiagnostic.Default;

            var optimize = (option.Optimize ?? false) ? OptimizationLevel.Release : OptimizationLevel.Debug;

            var csharpOptions = new CSharpCompilationOptions(outputKind)
                .WithAllowUnsafe(option.AllowUnsafe ?? false)
                .WithPlatform(ParsePlatfrom(option.Platform))
                .WithGeneralDiagnosticOption(generalDiagnosticOpt)
                .WithOptimizationLevel(optimize)
                .WithSpecificDiagnosticOptions(new Dictionary<string, ReportDiagnostic> {
                    { "CS1701", ReportDiagnostic.Suppress },
                    { "CS1702", ReportDiagnostic.Suppress },
                    { "CS1705", ReportDiagnostic.Suppress },
                })
                .WithConcurrentBuild(false); // TODO: actually just need to disable on mono

            if (!string.IsNullOrEmpty(option.KeyFile))
            {
                var cryptoKeyFile = Path.GetFullPath(Path.Combine(project.ProjectDirectory, option.KeyFile));
                if (File.Exists(cryptoKeyFile))
                {
                    var strongNameProvider = new DesktopStrongNameProvider(ImmutableArray.Create(project.ProjectDirectory));
                    csharpOptions = csharpOptions
                        .WithStrongNameProvider(strongNameProvider)
                        .WithCryptoPublicKey(SnkUtils.ExtractPublicKey(File.ReadAllBytes(cryptoKeyFile)));
                }
            }

            var parseOptions = new CSharpParseOptions(languageVersion: ParseLanguageVersion(option.LanguageVersion),
                                                      preprocessorSymbols: option.Defines);

            _omnisharpWorkspace.SetCompilationOptions(state.Id, csharpOptions);
            _omnisharpWorkspace.SetParseOptions(state.Id, parseOptions);
        }
Exemple #11
0
        private void ApplyStrongNameSettings(CompilationContext compilationContext)
        {
            // This is temporary, eventually we'll want a project.json feature for this
            var keyFile = Environment.GetEnvironmentVariable(EnvironmentNames.BuildKeyFile);
            if(!string.IsNullOrEmpty(keyFile))
            {
            #if DNX451
                var delaySignString = Environment.GetEnvironmentVariable(EnvironmentNames.BuildDelaySign);
                var delaySign = !string.IsNullOrEmpty(delaySignString) && (
                    string.Equals(delaySignString, "true", StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(delaySignString, "1", StringComparison.OrdinalIgnoreCase));

                var strongNameProvider = new DesktopStrongNameProvider();
                var newOptions = compilationContext.Compilation.Options
                    .WithStrongNameProvider(strongNameProvider)
                    .WithCryptoKeyFile(keyFile)
                    .WithDelaySign(delaySign);
                compilationContext.Compilation = compilationContext.Compilation.WithOptions(newOptions);
            #else
                var diag = Diagnostic.Create(
                    RoslynDiagnostics.StrongNamingNotSupported,
                    null);
                compilationContext.Diagnostics.Add(diag);
            #endif
            }
        }