示例#1
0
        private async Task <string> ResolveDepsFilePathFromBuildConfigAsync(string outputPath, ILogger logger, CancellationToken cancellationToken)
        {
            // Since we are resolving the deps file path it means the passed in outputPath is built using the default build
            // configuration (debug/release). We need to resolve the configuration by looking at the most recent build in the
            // output path. The output should look something like 'bin\Debug\netcoreapp1.0\HelloSvcutil.deps.json'

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Resolving deps.json file ...").ConfigureAwait(false))
            {
                var fileName = $"{Path.GetFileNameWithoutExtension(this.FileName)}.deps.json";
                var depsFile = string.Empty;

                // find the most recent deps.json files under the project's bin folder built for the project's target framework.
                var binFolder = await PathHelper.TryFindFolderAsync("bin", outputPath, logger, cancellationToken).ConfigureAwait(false);

                if (Directory.Exists(binFolder))
                {
                    var depsFiles = Directory.GetFiles(binFolder, "*", SearchOption.AllDirectories)
                                    .Where(d => Path.GetFileName(d).Equals(fileName, RuntimeEnvironmentHelper.FileStringComparison))
                                    .Where(f => PathHelper.GetFolderName(Path.GetDirectoryName(f)) == this.TargetFramework)
                                    .Select(f => new FileInfo(f))
                                    .OrderByDescending(f => f.CreationTimeUtc);

                    depsFile = depsFiles.FirstOrDefault()?.FullName;
                }

                await safeLogger.WriteMessageAsync($"deps file: {depsFile}", logToUI : false).ConfigureAwait(false);

                return(depsFile);
            }
        }
示例#2
0
        public async Task SaveAsync(ILogger logger, CancellationToken cancellationToken)
        {
            ThrowOnDisposed();

            cancellationToken.ThrowIfCancellationRequested();

            if (!_isSaved)
            {
                using (await SafeLogger.WriteStartOperationAsync(logger, $"Saving project file: \"{this.FullPath}\"").ConfigureAwait(false))
                {
                    if (!Directory.Exists(this.DirectoryPath))
                    {
                        Directory.CreateDirectory(this.DirectoryPath);
                        _ownsDirectory = true;
                    }

                    using (StreamWriter writer = File.CreateText(this.FullPath))
                    {
                        await AsyncHelper.RunAsync(() => ProjectNode.Save(writer), cancellationToken).ConfigureAwait(false);
                    }

                    _isSaved = true;
                }
            }
        }
示例#3
0
        public static async Task <string> GetSdkPathAsync(string workingDirectory, ILogger logger, CancellationToken cancellationToken)
        {
            if (s_sdkPath == null)
            {
                using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving .NETCore SDK path ...").ConfigureAwait(false))
                {
#if NETCORE10
                    var dotnetDir = Path.GetDirectoryName(typeof(int).GetTypeInfo().Assembly.Location);
#else
                    var dotnetDir = Path.GetDirectoryName(typeof(int).Assembly.Location);
#endif

                    while (dotnetDir != null && !(File.Exists(Path.Combine(dotnetDir, "dotnet")) || File.Exists(Path.Combine(dotnetDir, "dotnet.exe"))))
                    {
                        dotnetDir = Path.GetDirectoryName(dotnetDir);
                    }

                    if (dotnetDir != null)
                    {
                        var sdkVersion = await GetSdkVersionAsync(workingDirectory, logger, cancellationToken).ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(sdkVersion))
                        {
                            s_sdkPath = Path.Combine(dotnetDir, "sdk", sdkVersion);
                        }
                    }

                    await safeLogger.WriteMessageAsync($"SDK path: \"{s_sdkPath}\"", logToUI : false).ConfigureAwait(false);
                }
            }

            return(s_sdkPath);
        }
示例#4
0
        public async Task <IEnumerable <ProjectDependency> > ResolveProjectReferencesAsync(IEnumerable <ProjectDependency> excludeDependencies, ILogger logger, CancellationToken cancellationToken)
        {
            ThrowOnDisposed();

            IEnumerable <ProjectDependency> dependencies = null;

            if (excludeDependencies == null)
            {
                excludeDependencies = new List <ProjectDependency>();
            }

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving project references ...").ConfigureAwait(false))
            {
                if (_targetFrameworks.Count == 1 && TargetFrameworkHelper.IsSupportedFramework(this.TargetFramework, out var frameworkInfo) && frameworkInfo.IsDnx)
                {
                    await this.RestoreAsync(logger, cancellationToken).ConfigureAwait(false);

                    var packageReferences = await ResolvePackageReferencesAsync(logger, cancellationToken).ConfigureAwait(false);

                    var assemblyReferences = await ResolveAssemblyReferencesAsync(logger, cancellationToken).ConfigureAwait(false);

                    dependencies = packageReferences.Union(assemblyReferences).Except(excludeDependencies);
                }
                else
                {
                    await safeLogger.WriteWarningAsync(Shared.Resources.WarningMultiFxOrNoSupportedDnxVersion, logToUI : true).ConfigureAwait(false);

                    dependencies = new List <ProjectDependency>();
                }

                await safeLogger.WriteMessageAsync($"Resolved project reference count: {dependencies.Count()}", logToUI : false).ConfigureAwait(false);
            }

            return(dependencies);
        }
示例#5
0
        private async Task GenerateProjectAsync(bool keepBootstrapperDir, ILogger logger, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var projectFullPath = Path.Combine(this.Options.BootstrapPath.FullName, nameof(SvcutilBootstrapper), SvcutilBootstrapper.ProjectName);

            if (keepBootstrapperDir)
            {
                // creating the directory prevents the bootstrapper project from deleting it as it doesn't own it, files will not be deleted either.
                Directory.CreateDirectory(Path.GetDirectoryName(projectFullPath));
            }

            // If the target framework was provided, it was validated already when processing params.
            // Bootstrapping is enabled only for netcoreapp or netstandard TFM, let's check.

            bool isSupportedTFM = TargetFrameworkHelper.IsSupportedFramework(this.Options.TargetFramework.FullName, out var frameworkInfo);

            Debug.Assert(frameworkInfo.IsDnx, "The bootstrapper has been enabled for a non-DNX platform!");

            ToolConsole.WriteLineIf(ToolConsole.Verbosity >= Verbosity.Verbose, Resource.CreatingProjectMsg);

            using (await SafeLogger.WriteStartOperationAsync(logger, $"Creating project file: \"{projectFullPath}\"").ConfigureAwait(false))
            {
                var svcutilPkgRef = ProjectDependency.FromAssembly(Path.Combine(Path.GetDirectoryName(Tool.FullPath), Tool.AssemblyName + ".dll"));

                this.MSBuildProj = await MSBuildProj.DotNetNewAsync(projectFullPath, logger, cancellationToken).ConfigureAwait(false);

                this.MSBuildProj.AddDependency(svcutilPkgRef);

                // NOTE: If post v2.0 NetStandard ships a different version from NetCore the table below needs to be updated!
                var targetFramework = frameworkInfo.FullName;
                if (isSupportedTFM && frameworkInfo.IsKnownDnx)
                {
                    if (frameworkInfo.Name == FrameworkInfo.Netstandard)
                    {
                        targetFramework = FrameworkInfo.Netcoreapp + TargetFrameworkHelper.NetStandardToNetCoreVersionMap[frameworkInfo.Version];
                    }
                    this.MSBuildProj.TargetFramework = targetFramework;
                }
                // else
                // The TFM is unknown: either, it was not provided or it is a version not yet known to the tool,
                // we will use the default TF from the generated project.
            }

            foreach (ProjectDependency dependency in this.Options.References)
            {
                this.MSBuildProj.AddDependency(dependency);
            }

            if (!string.IsNullOrEmpty(this.Options.RuntimeIdentifier))
            {
                this.MSBuildProj.RuntimeIdentifier = this.Options.RuntimeIdentifier;
            }

            // Don't treat warnings as errors so the bootstrapper will succeed as often as possible.
            this.MSBuildProj.ClearWarningsAsErrors();

            await this.MSBuildProj.SaveAsync(logger, cancellationToken).ConfigureAwait(false);
        }
示例#6
0
        public static async Task <SafeLogger> WriteStartOperationAsync(ILogger logger, string message, bool logToUI = false)
        {
            var safeLogger = new SafeLogger(logger);

            safeLogger._startTime = await safeLogger.WriteStartOperationAsync(message, logToUI).ConfigureAwait(false);

            return(safeLogger);
        }
示例#7
0
 internal async Task GenerateProgramFileAsync(ILogger logger, CancellationToken cancellationToken)
 {
     using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Generating Program.cs ...").ConfigureAwait(false))
     {
         string programFilePath = Path.Combine(this.MSBuildProj.DirectoryPath, "Program.cs");
         File.WriteAllText(programFilePath, s_programClass);
     }
 }
示例#8
0
        public async Task <DateTime> WriteStartOperationAsync(string message, bool logToUI = false)
        {
            var startTime = DateTime.Now;

            await WriteMessageAsync(SafeLogger.GetStartOperationMessage(message, startTime), logToUI);

            return(startTime);
        }
        public static async Task <bool> TryAddSvcutilNuGetFeedAsync(string nugetConfigPath, string packageFeed, ILogger logger, CancellationToken cancellationToken)
        {
            bool?added = false;

            if (File.Exists(nugetConfigPath))
            {
                using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Adding svcutil NuGet feed to existing nuget.config file ...").ConfigureAwait(false))
                {
                    try
                    {
                        using (var stream = File.Open(nugetConfigPath, FileMode.Open, FileAccess.ReadWrite))
                        {
                            var doc            = XDocument.Parse(new StreamReader(stream).ReadToEnd());
                            var pkgSourcesNode = doc.Element("configuration")?.Element("packageSources");

                            if (pkgSourcesNode != null)
                            {
                                added = pkgSourcesNode.Elements("add")?
                                        .Select(e => e.Attribute("value").Value.TrimEnd(Path.DirectorySeparatorChar))
                                        .Any(v => v != null && packageFeed.Equals(v, RuntimeEnvironmentHelper.FileStringComparison));

                                if (added != true)
                                {
                                    var feedName = "SvcutilNuGetFeed";
                                    var count    = 1;

                                    while (pkgSourcesNode.Elements("add").Any(e => StringComparer.OrdinalIgnoreCase.Compare(e.Attribute("key").Value, feedName) == 0))
                                    {
                                        feedName += count++;
                                    }

                                    var addElement = new XElement("add");
                                    addElement.Add(new XAttribute("key", feedName), new XAttribute("value", packageFeed));

                                    pkgSourcesNode.Add(addElement);

                                    stream.Seek(0, SeekOrigin.Begin);
                                    doc.Save(stream);
                                    added = true;
                                }
                                else
                                {
                                    await safeLogger.WriteMessageAsync("Feed entry already exists.", logToUI : false);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        await safeLogger.WriteErrorAsync(ex.Message, logToUI : false);
                    }

                    await safeLogger.WriteMessageAsync($"Feed entry added/exists: {added == true}", logToUI : false);
                }
            }

            return(added == true);
        }
示例#10
0
        internal async Task <string> GenerateParamsFileAsync(ILogger logger, CancellationToken cancellationToken)
        {
            var paramsFilePath = Path.Combine(this.MSBuildProj.DirectoryPath, s_bootstrapperParamsFileName);

            using (await SafeLogger.WriteStartOperationAsync(logger, $"Generating {paramsFilePath} params file ...").ConfigureAwait(false))
            {
                await AsyncHelper.RunAsync(() => this.Options.Save(paramsFilePath), cancellationToken).ConfigureAwait(false);

                return(paramsFilePath);
            }
        }
示例#11
0
        public static async Task <string> GetSdkVersionAsync(string workingDirectory, ILogger logger, CancellationToken cancellationToken)
        {
            if (s_sdkVersion == null)
            {
                using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving dotnet sdk version ...").ConfigureAwait(false))
                {
                    var procResult = await ProcessRunner.TryRunAsync("dotnet", "--version", workingDirectory, logger, cancellationToken).ConfigureAwait(false);

                    if (procResult.ExitCode == 0)
                    {
                        s_sdkVersion = procResult.OutputText.Trim();
                    }

                    await safeLogger.WriteMessageAsync($"dotnet sdk version:{s_sdkVersion}", logToUI : false).ConfigureAwait(false);
                }
            }
            return(s_sdkVersion);
        }
示例#12
0
        internal async Task <ProcessRunner.ProcessResult> BoostrapSvcutilAsync(bool keepBootstrapperDir, ILogger logger, CancellationToken cancellationToken)
        {
            bool redirectOutput = false;

            if (this.Options.ToolContext == OperationalContext.Infrastructure)
            {
                redirectOutput = true;
            }

            ProcessRunner.ProcessResult result = null;

            using (await SafeLogger.WriteStartOperationAsync(logger, "Bootstrapping svcutil ...").ConfigureAwait(false))
            {
                // guard against bootstrapping recursion.
                if (this.Options.NoBootstrapping != true)
                {
                    Debug.Fail($"The NoBootstrapping property is not set, this would cause infinite bootstrapping recursion!");
                    return(null);
                }

                if (this.Options.Project != null && StringComparer.OrdinalIgnoreCase.Compare(this.Options.Project.FileName, SvcutilBootstrapper.ProjectName) == 0)
                {
                    Debug.Fail("Bootstrapping is enabled for the bootstrapper! This would cause an infinite bootstrapping recursion!");
                    return(null);
                }

                // When in Infrastructure mode (WCF CS) it is assumed the initial progress message is to be presented by the calling tool.
                ToolConsole.WriteLineIf(ToolConsole.ToolModeLevel != OperationalContext.Infrastructure, Resource.BootstrappingApplicationMsg);

                await GenerateProjectAsync(keepBootstrapperDir, logger, cancellationToken).ConfigureAwait(false);
                await GenerateProgramFileAsync(logger, cancellationToken).ConfigureAwait(false);

                var paramsFilePath = await GenerateParamsFileAsync(logger, cancellationToken).ConfigureAwait(false);

                await BuildBootstrapProjectAsync(logger, cancellationToken).ConfigureAwait(false);

                ToolConsole.WriteLineIf(ToolConsole.Verbosity >= Verbosity.Verbose, Resource.InvokingProjectMsg);
                result = await ProcessRunner.RunAsync("dotnet", $"run \"{paramsFilePath}\"", this.MSBuildProj.DirectoryPath, redirectOutput, logger, cancellationToken).ConfigureAwait(false);

                MarkupTelemetryHelper.TelemetryPostOperation(result.ExitCode == 0, "Invoke svcutil bootstrapper");
            }

            return(result);
        }
示例#13
0
        private static async Task GenerateParamsFileAsync(CommandProcessorOptions options, ILogger logger, CancellationToken cancellationToken)
        {
            // params file is generated on first run, never on update and never by the bootstrapper.

            if (!(options.IsUpdateOperation || options.NoProjectUpdates == true))
            {
                using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Generating svcutil params file ...").ConfigureAwait(false))
                {
                    var updateOptions = options.CloneAs <UpdateOptions>();
                    updateOptions.ProviderId = Tool.ToolName;
                    updateOptions.Version    = Tool.PackageVersion;

                    ProjectDependency.RemoveRedundantReferences(updateOptions.References);

                    updateOptions.MakePathsRelativeTo(options.OutputDir);

                    var paramsFile = Path.Combine(options.OutputDir.FullName, CommandProcessorOptions.SvcutilParamsFileName);
                    await AsyncHelper.RunAsync(() => updateOptions.Save(paramsFile), cancellationToken).ConfigureAwait(false);
                }
            }
        }
示例#14
0
        private static async Task <string> TryFindItemAsync(Func <string, IEnumerable <string> > EnumerateItems, string itemName, string workingDir, ILogger logger, CancellationToken cancellationToken)
        {
            // Look up the file in the folder structure starting from the specified working directory.
            cancellationToken.ThrowIfCancellationRequested();

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Looking for '{itemName}' up from '{workingDir}' dir ...").ConfigureAwait(false))
            {
                var fullPath = string.Empty;

                try
                {
                    if (!string.IsNullOrEmpty(itemName) && !string.IsNullOrEmpty(workingDir) && Directory.Exists(workingDir))
                    {
                        while (string.IsNullOrEmpty(fullPath))
                        {
                            fullPath = EnumerateItems(workingDir).Where(item => Path.GetFileName(item).Equals(itemName, RuntimeEnvironmentHelper.FileStringComparison)).FirstOrDefault();
                            if (!string.IsNullOrEmpty(fullPath))
                            {
                                break;
                            }

                            workingDir = Path.GetDirectoryName(workingDir);
                            if (string.IsNullOrEmpty(workingDir))
                            {
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    await safeLogger.WriteMessageAsync($"Error: {ex.Message}", logToUI : false).ConfigureAwait(false);
                }

                await safeLogger.WriteMessageAsync($"Item found: {!string.IsNullOrEmpty(fullPath)}", logToUI : false).ConfigureAwait(false);

                return(fullPath);
            }
        }
示例#15
0
        private async Task <Assembly> LoadMSBuildAssembliesAsync(string sdkPath, ILogger logger, CancellationToken cancellationToken)
        {
#if !NETCORE10
            Assembly msbuildAssembly = null;

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Loading MSBuild assemblies ...").ConfigureAwait(false))
            {
                if (Directory.Exists(sdkPath))
                {
                    foreach (var assemblyPath in Directory.GetFiles(sdkPath, "Microsoft.Build.*", SearchOption.TopDirectoryOnly))
                    {
                        var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
                        if (Path.GetFileNameWithoutExtension(assemblyPath) == "Microsoft.Build")
                        {
                            msbuildAssembly = assembly;
                        }
                    }
                }
            }
            return(msbuildAssembly);
#else
            return(await Task.FromResult <Assembly>(null));
#endif
        }
示例#16
0
        public static async Task <string> TryCopyFileIfFoundAsync(string fileName, string workingDirectory, string destinationDir, ILogger logger, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var filePath = await TryFindFileAsync(fileName, workingDirectory, logger, cancellationToken).ConfigureAwait(false);

            if (File.Exists(filePath))
            {
                using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Copying {fileName} to {destinationDir} ...").ConfigureAwait(false))
                {
                    try
                    {
                        var dstFilePath = Path.Combine(destinationDir, fileName);
                        File.Copy(filePath, dstFilePath, overwrite: true);
                        return(dstFilePath);
                    }
                    catch (Exception ex)
                    {
                        await safeLogger.WriteErrorAsync(ex.Message, logToUI : false).ConfigureAwait(false);
                    }
                }
            }
            return(null);
        }
示例#17
0
        internal static async Task <ToolExitCode> RunAsync(CommandProcessorOptions options, CancellationToken cancellationToken)
        {
            ImportModule importModule  = null;
            var          credsProvicer = new CmdCredentialsProvider();

            ServiceDescriptor serviceDescriptor = options.Inputs.Count == 1 ?
                                                  new ServiceDescriptor(options.Inputs[0].ToString(), credsProvicer, credsProvicer, credsProvicer) :
                                                  new ServiceDescriptor(options.Inputs.Select(i => i.ToString()).ToList(), credsProvicer, credsProvicer, credsProvicer);

            // When in Infrastructure mode (WCF CS) it is assumed the metadata docs have been downloaded and passed in as wsdl files.
            if (options.ToolContext != OperationalContext.Infrastructure)
            {
                if (serviceDescriptor.MetadataUrl != null)
                {
                    ToolConsole.WriteLine(string.Format(SR.RetreivingMetadataMsgFormat, serviceDescriptor.MetadataUrl.AbsoluteUri));
                }
                else
                {
                    var displayUri = serviceDescriptor.MetadataFiles.Count() == 1 ? serviceDescriptor.MetadataFiles.First().LocalPath : SR.WsdlOrSchemaFilesMsg;
                    ToolConsole.WriteLine(string.Format(SR.ReadingMetadataMessageFormat, displayUri));
                }
            }

            using (await SafeLogger.WriteStartOperationAsync(options.Logger, "Importing metadata ...").ConfigureAwait(false))
            {
                try
                {
                    await serviceDescriptor.ImportMetadataAsync(
                        (wi) => importModule = new ImportModule(options, serviceDescriptor, wi),
                        (sd) => importModule.BeforeImportMetadata(sd),
                        (sd) => importModule.AfterImportMetadata(sd),
                        cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    if (Utils.IsFatalOrUnexpected(ex))
                    {
                        throw;
                    }
                    var exception = new ToolInputException(Utils.GetExceptionMessage(ex), ex);
                    if (serviceDescriptor.MetadataUrl != null)
                    {
                        exception = new ToolMexException(exception, serviceDescriptor.MetadataUrl);
                    }
                    throw exception;
                }
            }

            using (await SafeLogger.WriteStartOperationAsync(options.Logger, "Processing Code DOM ...").ConfigureAwait(false))
            {
                ToolConsole.WriteLine(SR.GeneratingFiles);

                CodeSerializer codeSerializer = new CodeSerializer(options, serviceDescriptor.MetadataDocuments);
                var            filePath       = codeSerializer.Save(importModule.CodeCompileUnit);

                // When in Infrastructure mode (WCF CS) it is assumed the output file path have been provided so no need to display it.
                ToolConsole.WriteLineIf(options.ToolContext != OperationalContext.Infrastructure, filePath, LogTag.Important);
            }

            return(ToolConsole.ExitCode);
        }
示例#18
0
        public async Task <Dictionary <string, string> > EvaluateProjectPropertiesAsync(string projectPath, string targetFramework, IEnumerable <string> propertyNames, IDictionary <string, string> globalProperties, ILogger logger, CancellationToken cancellationToken)
        {
            var propertyTable = new Dictionary <string, string>();

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Resolving {propertyNames.Count()} project properties ...").ConfigureAwait(false))
            {
                ValidatePropertyNames(propertyNames);
                ValidatePropertyNames(globalProperties);

                var workingDirectory = Path.GetDirectoryName(projectPath);
                var sdkVersion       = await GetSdkVersionAsync(workingDirectory, logger, cancellationToken).ConfigureAwait(false);

                var sdkPath = await GetSdkPathAsync(workingDirectory, logger, cancellationToken).ConfigureAwait(false);

                try
                {
#if NETCORE
                    var propertiesResolved = false;

                    try
                    {
                        // In order for the MSBuild project evaluation API to work in .NET Core, the code must be executed directly from the .NET Core SDK assemblies.
                        // MSBuild libraries need to be explicitly loaded from the right SDK path (the one that corresponds to the runtime executing the project) as
                        // dependencies must be loaded from the executing runtime. This is not always possible, a newer SDK can load an older runtime; also, msbuild
                        // scripts from a newer SDK may not be supported by an older SDKs.
                        // Consider: A project created with the command 'dotnet new console' will target the right platform for the current SDK.

                        Assembly msbuildAssembly = await LoadMSBuildAssembliesAsync(sdkPath, logger, cancellationToken).ConfigureAwait(false);

                        if (msbuildAssembly != null)
                        {
                            var projType         = msbuildAssembly.GetType("Microsoft.Build.Evaluation.Project", true, false);
                            var projInstance     = Activator.CreateInstance(projType, new object[] { projectPath, globalProperties, /*toolsVersion*/ null });
                            var getPropertyValue = projType.GetMethod("GetPropertyValue");

                            if (getPropertyValue != null)
                            {
                                foreach (var propertyName in propertyNames)
                                {
                                    var propertyValue = getPropertyValue.Invoke(projInstance, new object[] { propertyName }).ToString();
                                    propertyTable[propertyName] = propertyValue;
                                    await safeLogger.WriteMessageAsync($"Evaluated '{propertyName}={propertyValue}'", logToUI : false).ConfigureAwait(false);
                                }
                                propertiesResolved = true;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        await safeLogger.WriteMessageAsync(ex.Message, logToUI : false).ConfigureAwait(false);
                    }

                    if (!propertiesResolved)
                    {
                        foreach (var propertyName in propertyNames)
                        {
                            var propertyValue = GetDefaultPropertyValue(projectPath, targetFramework, propertyName);
                            propertyTable[propertyName] = propertyValue;
                            await safeLogger.WriteMessageAsync($"Resolved '{propertyName}={propertyValue}'", logToUI : false).ConfigureAwait(false);
                        }
                    }
#else
                    // don't use GlobalProjectCollection as once a project is loaded into memory changes to the project file won't take effect until the solution is reloaded.
                    var projCollection = new Microsoft.Build.Evaluation.ProjectCollection(globalProperties);
                    var project        = projCollection.LoadProject(projectPath);

                    foreach (var propertyName in propertyNames)
                    {
                        var propertyValue = project.GetPropertyValue(propertyName);
                        propertyTable[propertyName] = propertyValue;
                        await safeLogger.WriteMessageAsync($"Evaluated '{propertyName}={propertyValue}'", logToUI : false).ConfigureAwait(false);
                    }
#endif // NETCORE
                }
                catch (Exception ex)
                {
                    if (Utils.IsFatalOrUnexpected(ex))
                    {
                        throw;
                    }
                    await safeLogger.WriteErrorAsync($"{ex.Message}{Environment.NewLine}{ex.StackTrace}", logToUI : false);
                }
                finally
                {
                    // Ensure the dictionary is populated in any case, the client needs to validate the values but not the collection.
                    foreach (var propertyName in propertyNames)
                    {
                        if (!propertyTable.ContainsKey(propertyName))
                        {
                            propertyTable[propertyName] = string.Empty;
                        }
                    }
                }
            }

            return(propertyTable);
        }
示例#19
0
        public static async Task <MSBuildProj> ParseAsync(string projectText, string projectFullPath, ILogger logger, CancellationToken cancellationToken)
        {
            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Parsing project {Path.GetFileName(projectFullPath)}").ConfigureAwait(false))
            {
                projectFullPath = Path.GetFullPath(projectFullPath);

                MSBuildProj msbuildProj = new MSBuildProj
                {
                    FileName      = Path.GetFileName(projectFullPath),
                    DirectoryPath = Path.GetDirectoryName(projectFullPath)
                };

                XDocument projDefinition = XDocument.Parse(projectText);

                var msbuildNS = XNamespace.None;
                if (projDefinition.Root != null && projDefinition.Root.Name != null)
                {
                    msbuildNS = projDefinition.Root.Name.Namespace;
                }

                msbuildProj._msbuildNS  = msbuildNS;
                msbuildProj.ProjectNode = projDefinition.Element(msbuildNS + "Project");
                if (msbuildProj.ProjectNode == null)
                {
                    throw new Exception(Shared.Resources.ErrorInvalidProjectFormat);
                }

                // The user project can declare TargetFramework and/or TargetFrameworks property. If both are provided, TargetFramework wins.
                // When TargetFrameworks is provided, the project is built for every entry specified in the TargetFramework property.

                IEnumerable <XElement> targetFrameworkElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "PropertyGroup", "TargetFramework");
                if (targetFrameworkElements.Count() > 0)
                {
                    // If property is specified more than once, MSBuild will resolve it by overwriting it with the last value.
                    var targetFramework = targetFrameworkElements.Last().Value.Trim();
                    if (!string.IsNullOrWhiteSpace(targetFramework))
                    {
                        if (targetFramework.StartsWith("net5.0-"))
                        {
                            targetFramework = "net5.0";
                        }

                        msbuildProj._targetFrameworks.Add(targetFramework);
                    }
                }

                if (msbuildProj._targetFrameworks.Count == 0)
                {
                    // TargetFramework was not provided, check TargetFrameworks property.
                    IEnumerable <XElement> targetFrameworksElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "PropertyGroup", "TargetFrameworks");
                    if (targetFrameworksElements.Count() > 0)
                    {
                        var targetFrameworks = targetFrameworksElements.Last().Value;
                        foreach (var targetFx in targetFrameworks.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()))
                        {
                            if (!string.IsNullOrWhiteSpace(targetFx))
                            {
                                msbuildProj._targetFrameworks.Add(targetFx);
                            }
                        }
                    }
                }

                msbuildProj._targetFramework = TargetFrameworkHelper.GetBestFitTargetFramework(msbuildProj._targetFrameworks);

                // Ensure target framework is valid.
                FrameworkInfo frameworkInfo = TargetFrameworkHelper.GetValidFrameworkInfo(msbuildProj.TargetFramework);

                IEnumerable <XElement> runtimeIdentifierElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "PropertyGroup", "RuntimeIdentifier");
                if (runtimeIdentifierElements.Count() > 0)
                {
                    msbuildProj.RuntimeIdentifier = runtimeIdentifierElements.Last().Value.Trim();
                }

                IEnumerable <XElement> packageReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "PackageReference");
                foreach (XElement reference in packageReferenceElements)
                {
                    if (!TryGetItemIdentity(reference, out var packageName))
                    {
                        continue;
                    }

                    string version = GetItemValue(reference, "Version");

                    ProjectDependency packageDep = ProjectDependency.FromPackage(packageName, version);

                    msbuildProj._dependencies.Add(packageDep);
                }

                IEnumerable <XElement> toolReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "DotNetCliToolReference");
                foreach (XElement reference in toolReferenceElements)
                {
                    if (!TryGetItemIdentity(reference, out var packageName))
                    {
                        continue;
                    }

                    string version = GetItemValue(reference, "Version");

                    ProjectDependency packageDep = ProjectDependency.FromCliTool(packageName, version);

                    msbuildProj._dependencies.Add(packageDep);
                }

                IEnumerable <XElement> projectReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "ProjectReference");
                foreach (XElement reference in projectReferenceElements)
                {
                    string projectPath = GetItemValue(reference, "Include", throwIfMissing: true);

                    ProjectDependency projectDep = ProjectDependency.FromProject(projectPath);

                    msbuildProj._dependencies.Add(projectDep);
                }

                IEnumerable <XElement> binReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "Reference");
                foreach (XElement reference in binReferenceElements)
                {
                    //Find hint path or path
                    string binReference = GetItemIdentity(reference);

                    if (!Path.IsPathRooted(binReference))
                    {
                        string fullPath      = null;
                        bool   fullPathFound = true;

                        XElement hintPath = reference.Element("HintPath");
                        XElement path     = reference.Element("Path");
                        if (path != null)
                        {
                            fullPath = path.Value;
                        }
                        else if (hintPath != null)
                        {
                            fullPath = hintPath.Value;
                        }
                        else
                        {
                            try
                            {
                                fullPath = new FileInfo(Path.Combine(msbuildProj.DirectoryPath, binReference)).FullName;
                            }
                            catch
                            {
                            }

                            if (fullPath == null || !File.Exists(fullPath))
                            {
                                fullPathFound = false;

                                // If we're only targeting .NET Core or .NET Standard projects we throw if we can't find the full path to the assembly.
                                if (!TargetFrameworkHelper.ContainsFullFrameworkTarget(msbuildProj._targetFrameworks))
                                {
                                    throw new Exception(string.Format(CultureInfo.CurrentCulture, Shared.Resources.ErrorProjectReferenceMissingFilePathFormat, binReference));
                                }
                            }
                        }

                        if (fullPathFound)
                        {
                            if (System.IO.Directory.Exists(fullPath)) // IsDir?
                            {
                                fullPath = Path.Combine(fullPath, binReference);
                            }
                            else if (Directory.Exists(Path.Combine(msbuildProj.DirectoryPath, fullPath)))
                            {
                                fullPath = Path.Combine(msbuildProj.DirectoryPath, fullPath, binReference);
                            }

                            binReference = fullPath;
                        }
                    }

                    ProjectDependency projectDep = ProjectDependency.FromAssembly(binReference);

                    msbuildProj._dependencies.Add(projectDep);
                }

                // ensure we have a working directory for the ProcessRunner (ProjectPropertyResolver)..
                if (!Directory.Exists(msbuildProj.DirectoryPath))
                {
                    Directory.CreateDirectory(msbuildProj.DirectoryPath);
                    msbuildProj._ownsDirectory = true;
                }

                var sdkVersion = await ProjectPropertyResolver.GetSdkVersionAsync(msbuildProj.DirectoryPath, logger, cancellationToken).ConfigureAwait(false);

                msbuildProj.SdkVersion = sdkVersion ?? string.Empty;

                return(msbuildProj);
            }
        }
示例#20
0
        public static async Task <ProcessResult> RunAsync(string processName, string processArgs, string currentDir, bool redirectOutput, bool throwOnError, IDictionary <string, string> environmentVariables, ILogger logger, CancellationToken cancellationToken)
        {
            bool isErrorLogged  = false;
            var  errorTextBldr  = new StringBuilder();
            var  outputTextBldr = new StringBuilder();

            cancellationToken.ThrowIfCancellationRequested();

            if (string.IsNullOrWhiteSpace(currentDir))
            {
                currentDir = Directory.GetCurrentDirectory();
            }

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Executing command [\"{currentDir}\"]{Environment.NewLine}>{processName} {processArgs}").ConfigureAwait(false))
            {
                using (var proc = new Process())
                {
                    proc.StartInfo.WorkingDirectory       = Path.GetFullPath(currentDir);
                    proc.StartInfo.UseShellExecute        = false;
                    proc.StartInfo.CreateNoWindow         = redirectOutput;
                    proc.StartInfo.RedirectStandardError  = redirectOutput;
                    proc.StartInfo.RedirectStandardOutput = redirectOutput;
                    proc.StartInfo.FileName  = processName;
                    proc.StartInfo.Arguments = processArgs;
                    proc.EnableRaisingEvents = true;

                    foreach (var environmentVar in environmentVariables.Where(e => !string.IsNullOrWhiteSpace(e.Key)))
                    {
                        proc.StartInfo.Environment.Add(environmentVar);
                    }

                    if (redirectOutput)
                    {
                        // The default encoding might not work while redirecting non-ANSI characters.
                        // Standard error encoding is only supported when standard error is redirected.
                        proc.StartInfo.StandardErrorEncoding  = Encoding.UTF8;
                        proc.StartInfo.StandardOutputEncoding = Encoding.UTF8;
                    }

                    proc.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e)
                    {
                        if (!string.IsNullOrWhiteSpace(e.Data))
                        {
                            errorTextBldr.AppendLine(e.Data);
                            safeLogger.WriteErrorAsync(e.Data, false).ConfigureAwait(false);
                            isErrorLogged = true;
                        }
                    };

                    proc.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
                    {
                        outputTextBldr.AppendLine(e.Data);
                        safeLogger.WriteMessageAsync(e.Data, false).ConfigureAwait(false);
                    };

                    proc.Start();
#if DEBUG
                    if (DebugUtils.SvcutilDebug == 1)
                    {
                        try
                        {
                            Console.WriteLine($"Starting process in the background: {Path.GetFileName(proc.ProcessName)}, ID: {proc.Id}.");
                            Console.WriteLine($"{Path.GetFileName(currentDir)}>{processName} {processArgs}{Environment.NewLine}");
                        }
                        catch
                        {
                        }
                    }
#endif
                    if (redirectOutput)
                    {
                        proc.BeginErrorReadLine();
                        proc.BeginOutputReadLine();
                    }

                    await AsyncHelper.RunAsync(() => proc.WaitForExit(), () => { try { proc.Kill(); } catch { } }, cancellationToken).ConfigureAwait(false);

                    if (!cancellationToken.IsCancellationRequested)
                    {
                        // allow for processing message packets a few more times as they can keep coming after the process has finished.
                        int waitCount = 3;
                        while (waitCount-- > 0)
                        {
                            proc.WaitForExit();
                            await Task.Delay(100);
                        }
                    }
                    cancellationToken.ThrowIfCancellationRequested();

                    var outputText = outputTextBldr.ToString().Trim();
                    var errorText  = errorTextBldr.ToString().Trim();

                    await safeLogger.WriteMessageAsync($"Exit code: {proc.ExitCode}", false).ConfigureAwait(false);

                    if (throwOnError && (isErrorLogged || proc.ExitCode != 0))
                    {
                        // avoid reporting a foreign tool's exit code.
                        var exitCode = Path.GetFileName(processName) == Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName) ? proc.ExitCode : -1;
                        throw new ProcessException(string.IsNullOrWhiteSpace(errorText) ? outputText : errorText, exitCode);
                    }
                    else if (string.IsNullOrWhiteSpace(outputText))
                    {
                        outputText = errorText;
                    }

                    return(new ProcessResult(proc.ExitCode, outputText));
                }
            }
        }
示例#21
0
        internal static async Task <int> MainAsync(string[] args, ILogger logger, CancellationToken cancellationToken)
        {
            int result = -1;
            CommandProcessorOptions options = null;

            WaitForDebugger();

            try
            {
                options = await CommandProcessorOptions.ParseArgumentsAsync(args, logger, cancellationToken);

                ValidateUICulture(options);

                if (options.NoTelemetry == true)
                {
                    AppInsightsTelemetryClient.IsUserOptedIn = false;
                }

                ToolConsole.Init(options);
                ToolConsole.WriteHeaderIf(options.NoLogo != true);

                ThrowOnValidationErrors(options);

                if (options.Help == true)
                {
                    ToolConsole.WriteHelp();
                    result = (int)ToolExitCode.Success;
                }
                else
                {
                    // Show early warnings
                    var earlyWarnings = options.Warnings;
                    foreach (string warning in earlyWarnings.Distinct())
                    {
                        ToolConsole.WriteWarning(warning);
                    }

                    var operationMessage = (options.IsUpdateOperation ? "Update" : "Add") + " web service reference operation started!";
                    using (var safeLogger = await SafeLogger.WriteStartOperationAsync(options.Logger, operationMessage).ConfigureAwait(false))
                    {
                        await options.ResolveAsync(cancellationToken).ConfigureAwait(false);

                        ThrowOnValidationErrors(options);

                        options.ProviderId = Tool.ToolName;
                        options.Version    = Tool.PackageVersion;

                        foreach (string warning in options.Warnings.Distinct().Except(earlyWarnings))
                        {
                            ToolConsole.WriteWarning(warning);
                        }

                        if (options.RequiresBoostrapping)
                        {
                            using (var bootstrapper = new SvcutilBootstrapper(options.CloneAs <SvcutilOptions>()))
                            {
                                await options.SetupBootstrappingDirectoryAsync(options.Logger, cancellationToken).ConfigureAwait(false);

                                var bootstrapResult = await bootstrapper.BoostrapSvcutilAsync(options.KeepBootstrapDir, options.Logger, cancellationToken).ConfigureAwait(false);

                                ToolConsole.WriteLine(bootstrapResult.OutputText);
                                result = bootstrapResult.ExitCode;
                            }
                        }
                        else
                        {
                            result = (int) await RunAsync(options, cancellationToken).ConfigureAwait(false);
                        }

                        if (IsSuccess(result))
                        {
                            if (!File.Exists(options.OutputFile.FullName))
                            {
                                await safeLogger.WriteMessageAsync("The process completed successfully but no proxy file was found!", logToUI : false);

                                throw new ToolArgumentException(SR.ErrUnexpectedError);
                            }
                            else
                            {
                                await GenerateParamsFileAsync(options, options.Logger, cancellationToken);

                                if (CanAddProjectReferences(options) && !await AddProjectReferencesAsync(options.Project, options, cancellationToken).ConfigureAwait(false))
                                {
                                    result = (int)ToolExitCode.InputError;
                                }
                            }

                            // clean up only on success to allow to troubleshoot any problems on failure.
                            options?.Cleanup();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                result = await ProcessExceptionAsync(e, options);
            }
            finally
            {
                try
                {
                    // Don't log telemetry if we're running from bootstrapper or connected service.
                    if (options?.ToolContext <= OperationalContext.Global)
                    {
                        var properties = new Dictionary <string, string>()
                        {
                            { "IsUpdate", (options?.IsUpdateOperation).ToString() },
                            { "TargetFramework", options?.TargetFramework?.FullName },
                            { "Parameters", options?.ToTelemetryString() },
                            { "ExitCode", result.ToString() },
                            { "RequiresBootstrapping", options?.RequiresBoostrapping.ToString() },
                        };

                        var telemetryClient = await AppInsightsTelemetryClient.GetInstanceAsync(cancellationToken).ConfigureAwait(false);

                        telemetryClient.TrackEvent("ToolRun", properties);
                    }
                }
                catch
                {
                }
            }

            return(result);
        }
示例#22
0
        private async Task <List <ProjectDependency> > ResolvePackageReferencesAsync(ILogger logger, CancellationToken cancellationToken)
        {
            ThrowOnDisposed();

            cancellationToken.ThrowIfCancellationRequested();

            var packageDependencies = new List <ProjectDependency>();

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving package references ...").ConfigureAwait(false))
            {
                await AsyncHelper.RunAsync(async() =>
                {
                    try
                    {
                        var assetsFile = new FileInfo(Path.Combine(this.DirectoryPath, "obj", "project.assets.json")).FullName;
                        if (File.Exists(assetsFile))
                        {
                            LockFile lockFile = LockFileUtilities.GetLockFile(assetsFile, logger as NuGet.Common.ILogger);

                            if (lockFile != null)
                            {
                                if (lockFile.Targets.Count == 1)
                                {
                                    foreach (var lib in lockFile.Targets[0].Libraries)
                                    {
                                        bool isPackage = StringComparer.OrdinalIgnoreCase.Compare(lib.Type, "package") == 0;

                                        if (isPackage)
                                        {
                                            foreach (var compiletimeAssembly in lib.CompileTimeAssemblies)
                                            {
                                                if (Path.GetExtension(compiletimeAssembly.Path) == ".dll")
                                                {
                                                    var dependency = ProjectDependency.FromPackage(Path.GetFileNameWithoutExtension(compiletimeAssembly.Path), lib.Name, lib.Version.ToNormalizedString());
                                                    var itemIdx    = packageDependencies.IndexOf(dependency);

                                                    if (itemIdx == -1)
                                                    {
                                                        packageDependencies.Add(dependency);
                                                    }
                                                    else if (dependency.IsFramework)
                                                    {
                                                        // packages can be described individually and/or as part of a platform metapackage in the lock file; for instance: Microsoft.CSharp is a package that is part of Microsoft.NetCore.
                                                        packageDependencies[itemIdx] = dependency;
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    packageDependencies.Sort();
                                }
                                else
                                {
                                    await safeLogger.WriteWarningAsync(Shared.Resources.WarningMultiFxOrNoSupportedDnxVersion, logToUI: true).ConfigureAwait(false);
                                }
                            }
                            else
                            {
                                await safeLogger.WriteWarningAsync(Shared.Resources.WarningCannotResolveProjectReferences, logToUI: true).ConfigureAwait(false);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (Utils.IsFatalOrUnexpected(ex))
                        {
                            throw;
                        }
                        await safeLogger.WriteWarningAsync(ex.Message, logToUI: false).ConfigureAwait(false);
                    }
                }, cancellationToken).ConfigureAwait(false);

                await safeLogger.WriteMessageAsync($"Package reference count: {packageDependencies.Count}", logToUI : false).ConfigureAwait(false);
            }

            return(packageDependencies);
        }
示例#23
0
 public Task WriteEndOperationAsync(DateTime startTime, bool logToUI = false)
 {
     return(WriteMessageAsync(SafeLogger.GetEndOperationMessage(startTime), logToUI));
 }
示例#24
0
        private async Task <List <ProjectDependency> > ResolveAssemblyReferencesAsync(ILogger logger, CancellationToken cancellationToken)
        {
            ThrowOnDisposed();

            cancellationToken.ThrowIfCancellationRequested();

            var assemblyDependencies = new List <ProjectDependency>();

            using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Resolving assembly references for {this.TargetFramework} target framework ...").ConfigureAwait(false))
            {
                await ResolveProperyValuesAsync(new string[] { "OutputPath", "TargetPath" }, logger, cancellationToken).ConfigureAwait(false);

                var outputPath = this._resolvedProperties["OutputPath"];
                if (!Path.IsPathRooted(outputPath))
                {
                    outputPath = Path.Combine(this.DirectoryPath, outputPath.Trim(new char[] { '\"' }));
                }

                var depsFile = this.GlobalProperties.TryGetValue("Configuration", out var activeConfiguration) && !string.IsNullOrWhiteSpace(activeConfiguration) ?
                               Path.Combine(outputPath, $"{Path.GetFileNameWithoutExtension(this.FileName)}.deps.json") :
                               await ResolveDepsFilePathFromBuildConfigAsync(outputPath, logger, cancellationToken).ConfigureAwait(false);

                if (File.Exists(depsFile))
                {
                    await AsyncHelper.RunAsync(async() =>
                    {
                        try
                        {
                            DependencyContext depContext = null;
                            using (var stream = File.OpenRead(depsFile))
                            {
                                depContext = new DependencyContextJsonReader().Read(stream);
                            }

                            var targetLib = Path.GetFileName(this._resolvedProperties["TargetPath"].Trim('\"'));
                            if (string.IsNullOrEmpty(targetLib))
                            {
                                targetLib = $"{Path.ChangeExtension(this.FileName, ".dll")}";
                            }

                            foreach (var rtLib in depContext.RuntimeLibraries.Where(l => l.NativeLibraryGroups.Count == 0))
                            {
                                ProjectDependency dependency = null;
                                switch (rtLib.Type)
                                {
                                case "project":
                                case "reference":
                                    foreach (var assemblyGroup in rtLib.RuntimeAssemblyGroups)
                                    {
                                        foreach (var assetPath in assemblyGroup.AssetPaths)
                                        {
                                            if (!Path.GetFileName(assetPath).Equals(targetLib, RuntimeEnvironmentHelper.FileStringComparison))
                                            {
                                                dependency = ProjectDependency.FromAssembly(Path.Combine(outputPath, assetPath));
                                                if (File.Exists(dependency.FullPath) && !assemblyDependencies.Contains(dependency))
                                                {
                                                    assemblyDependencies.Add(dependency);
                                                }
                                            }
                                        }
                                    }
                                    break;

                                //case "package":
                                default:
                                    break;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            if (Utils.IsFatalOrUnexpected(ex))
                            {
                                throw;
                            }
                            await safeLogger.WriteWarningAsync(ex.Message, logToUI: false).ConfigureAwait(false);
                        }
                    }, cancellationToken).ConfigureAwait(false);

                    assemblyDependencies.Sort();
                }
                else
                {
                    await safeLogger.WriteWarningAsync("Deps file not found (project not built), unable to resolve assembly/project dependencies!", logToUI : false).ConfigureAwait(false);
                }

                await safeLogger.WriteMessageAsync($"Assembly reference count: {assemblyDependencies.Count}", logToUI : false).ConfigureAwait(false);
            }

            return(assemblyDependencies);
        }