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);
        }
Beispiel #2
0
        public bool AddDependency(ProjectDependency dependency)
        {
            // a nuget package can contain multiple assemblies, we need to filter package references so we don't add dups.
            bool addDependency = !_dependencies.Any(d =>
            {
                switch (d.DependencyType)
                {
                case ProjectDependencyType.Package:
                case ProjectDependencyType.Tool:
                    return(d.Name == dependency.Name);

                default:
                    if (d.FullPath == null && dependency.FullPath == null)
                    {
                        goto case ProjectDependencyType.Package;
                    }
                    return(d.FullPath == dependency.FullPath);
                }
            });

            if (addDependency)
            {
                switch (dependency.DependencyType)
                {
                case ProjectDependencyType.Project:
                    this.ProjectReferceGroup.Add(new XElement("ProjectReference", new XAttribute("Include", dependency.FullPath)));
                    break;

                case ProjectDependencyType.Binary:
                    this.ReferenceGroup.Add(new XElement("Reference", new XAttribute("Include", dependency.AssemblyName), new XElement("HintPath", dependency.FullPath)));
                    break;

                case ProjectDependencyType.Package:
                    this.ReferenceGroup.Add(new XElement("PackageReference", new XAttribute("Include", dependency.Name), new XAttribute("Version", dependency.Version)));
                    break;

                case ProjectDependencyType.Tool:
                    this.ReferenceGroup.Add(new XElement("DotNetCliToolReference", new XAttribute("Include", dependency.Name), new XAttribute("Version", dependency.Version)));
                    break;
                }

                _dependencies.Add(dependency);
                _isSaved = false;
            }

            return(addDependency);
        }
Beispiel #3
0
        public SvcutilBootstrapper(SvcutilOptions options)
        {
            this.Options            = options ?? throw new ArgumentNullException(nameof(options));
            this.Options.ProviderId = $"{Tool.ToolName}-bootstrap";
            this.Options.Version    = Tool.PackageVersion;

            // reset options that don't apply to the bootstrapper and that prevent bootstrapping recursion.
            this.Options.NoBootstrapping  = true;
            this.Options.NoLogo           = true;
            this.Options.NoProjectUpdates = true;

            // the operational context has some control over what messages to display on the UI.
            if (this.Options.ToolContext.HasValue && this.Options.ToolContext.Value <= OperationalContext.Global)
            {
                this.Options.ToolContext = OperationalContext.Bootstrapper;
            }

            ProjectDependency.RemoveRedundantReferences(this.Options.References);
        }
Beispiel #4
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);
                }
            }
        }
Beispiel #5
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);
        }
Beispiel #6
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);
        }
Beispiel #7
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);
            }
        }
Beispiel #8
0
        public static TValue ParseValue <TValue>(object value, OptionBase option)
        {
            ThrowInvalidValueIf(value == null, value, option);

            var valueType = typeof(TValue);

            if (value.GetType() != typeof(TValue))
            {
                // parsing is needed, the passed in value must be a string.

                var stringValue = value as string;
                ThrowInvalidValueIf(stringValue == null, value, option);

                if (valueType == typeof(bool))
                {
                    // Special-case boolean values as it is common to specify them as strings in the json file.
                    // { "myFlag" : "True" } will be resolved to {  "MyFlag" : true }
                    ThrowInvalidValueIf(!bool.TryParse(stringValue, out var boolValue), stringValue, option);
                    value = boolValue;
                }
                else if (valueType.GetTypeInfo().IsEnum)
                {
                    value = ParseEnum <TValue>(stringValue, option);
                }
                else if (valueType == typeof(CultureInfo))
                {
                    value = CreateValue <CultureInfo>(() => new CultureInfo(stringValue), option, stringValue);
                }
                else if (valueType == typeof(Uri))
                {
                    value = CreateValue <Uri>(() => new Uri(stringValue, UriKind.RelativeOrAbsolute), option, stringValue);
                }
                else if (valueType == typeof(DirectoryInfo))
                {
                    value = CreateValue <DirectoryInfo>(() => new DirectoryInfo(stringValue), option, stringValue);
                }
                else if (valueType == typeof(FileInfo))
                {
                    value = CreateValue <FileInfo>(() => new FileInfo(stringValue), option, stringValue);
                }
                else if (valueType == typeof(MSBuildProj))
                {
                    value = CreateValue <MSBuildProj>(() => MSBuildProj.FromPathAsync(stringValue, null, System.Threading.CancellationToken.None).Result, option, stringValue);
                }
                else if (valueType == typeof(FrameworkInfo))
                {
                    value = CreateValue <FrameworkInfo>(() => TargetFrameworkHelper.GetValidFrameworkInfo(stringValue), option, stringValue);
                }
                else if (valueType == typeof(ProjectDependency))
                {
                    value = CreateValue <ProjectDependency>(() => ProjectDependency.Parse(stringValue), option, stringValue);
                }
                else if (valueType == typeof(KeyValuePair <string, string>))
                {
                    value = ParseKeyValuePair(stringValue, option);
                }
                else
                {
                    ThrowInvalidValueIf(true, stringValue, option);
                }
            }

            return((TValue)value);
        }
        protected override void OnAfterDeserialize()
        {
            base.OnAfterDeserialize();

            // Synchronize base options (VS2017 format).

            if (this.ReuseTypesinReferencedAssemblies == false)
            {
                this.TypeReuseMode = Svcutil.TypeReuseMode.None;
            }
            else if (this.ReuseTypesinAllReferencedAssemblies.HasValue)
            {
                this.TypeReuseMode = this.ReuseTypesinAllReferencedAssemblies == false ?
                                     Svcutil.TypeReuseMode.Specified : Svcutil.TypeReuseMode.All;
            }

            if (this.CollectionTypeReference.Count > 0)
            {
                this.CollectionTypes.AddRange(this.CollectionTypeReference);
            }

            if (this.DictionaryCollectionTypeReference.Count > 0)
            {
                this.CollectionTypes.AddRange(this.DictionaryCollectionTypeReference);
            }

            // The collections supported by the WCF CS are all part of .NET Core.
            foreach (var packageName in _deserializedCollectionAssemblies.Select(an => ProjectDependency.FromPackage(an, ProjectDependency.NetCoreAppPackageID, "*")))
            {
                if (!this.References.Contains(packageName))
                {
                    this.References.Add(packageName);
                }
            }
        }