2015-10-13 14:31:29 -07:00
|
|
|
|
// Copyright (c) .NET Foundation. All rights reserved.
|
|
|
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2015-10-15 15:09:37 -07:00
|
|
|
|
using Microsoft.Extensions.JsonParser.Sources;
|
2015-10-17 08:55:06 -07:00
|
|
|
|
using Microsoft.Extensions.ProjectModel.Files;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
using Microsoft.Extensions.ProjectModel.Graph;
|
2015-10-17 22:42:50 -07:00
|
|
|
|
using Microsoft.Extensions.ProjectModel.Utilities;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
using NuGet.Frameworks;
|
|
|
|
|
using NuGet.Versioning;
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.Extensions.ProjectModel
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
public class ProjectReader
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-17 22:42:50 -07:00
|
|
|
|
public static bool TryGetProject(string path, out Project project, ICollection<DiagnosticMessage> diagnostics = null)
|
|
|
|
|
{
|
|
|
|
|
project = null;
|
|
|
|
|
|
|
|
|
|
string projectPath = null;
|
|
|
|
|
|
|
|
|
|
if (string.Equals(Path.GetFileName(path), Project.FileName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
projectPath = path;
|
|
|
|
|
path = Path.GetDirectoryName(path);
|
|
|
|
|
}
|
|
|
|
|
else if (!HasProjectFile(path))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
projectPath = Path.Combine(path, Project.FileName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assume the directory name is the project name if none was specified
|
|
|
|
|
var projectName = PathUtility.GetDirectoryName(Path.GetFullPath(path));
|
|
|
|
|
projectPath = Path.GetFullPath(projectPath);
|
|
|
|
|
|
|
|
|
|
if (!File.Exists(projectPath))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var stream = File.OpenRead(projectPath))
|
|
|
|
|
{
|
|
|
|
|
var reader = new ProjectReader();
|
|
|
|
|
project = reader.ReadProject(stream, projectName, projectPath, diagnostics);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
throw FileFormatException.Create(ex, projectPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-13 14:31:29 -07:00
|
|
|
|
public static Project GetProject(string projectFile)
|
|
|
|
|
{
|
|
|
|
|
return GetProject(projectFile, new List<DiagnosticMessage>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Project GetProject(string projectFile, ICollection<DiagnosticMessage> diagnostics)
|
|
|
|
|
{
|
|
|
|
|
var name = Path.GetFileName(Path.GetDirectoryName(projectFile));
|
|
|
|
|
using (var stream = new FileStream(projectFile, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
|
|
|
{
|
|
|
|
|
return new ProjectReader().ReadProject(stream, name, projectFile, diagnostics);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Project ReadProject(Stream stream, string projectName, string projectPath, ICollection<DiagnosticMessage> diagnostics)
|
|
|
|
|
{
|
|
|
|
|
var project = new Project();
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var reader = new StreamReader(stream);
|
|
|
|
|
var rawProject = JsonDeserializer.Deserialize(reader) as JsonObject;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (rawProject == null)
|
|
|
|
|
{
|
|
|
|
|
throw FileFormatException.Create(
|
|
|
|
|
"The JSON file can't be deserialized to a JSON object.",
|
|
|
|
|
projectPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Meta-data properties
|
2015-10-18 00:35:56 -07:00
|
|
|
|
project.Name = rawProject.ValueAsString("name") ?? projectName;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
project.ProjectFilePath = Path.GetFullPath(projectPath);
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var version = rawProject.Value("version") as JsonString;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (version == null)
|
|
|
|
|
{
|
|
|
|
|
project.Version = new NuGetVersion("1.0.0");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2015-10-30 10:34:02 -07:00
|
|
|
|
var buildVersion = Environment.GetEnvironmentVariable("DOTNET_BUILD_VERSION");
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.Version = SpecifySnapshot(version, buildVersion);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
throw FileFormatException.Create(ex, version, project.ProjectFilePath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-17 07:20:56 -07:00
|
|
|
|
var fileVersion = Environment.GetEnvironmentVariable("DOTNET_ASSEMBLY_FILE_VERSION");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (string.IsNullOrWhiteSpace(fileVersion))
|
|
|
|
|
{
|
|
|
|
|
project.AssemblyFileVersion = project.Version.Version;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var simpleVersion = project.Version.Version;
|
|
|
|
|
project.AssemblyFileVersion = new Version(simpleVersion.Major,
|
|
|
|
|
simpleVersion.Minor,
|
|
|
|
|
simpleVersion.Build,
|
|
|
|
|
int.Parse(fileVersion));
|
|
|
|
|
}
|
|
|
|
|
catch (FormatException ex)
|
|
|
|
|
{
|
|
|
|
|
throw new FormatException("The assembly file version is invalid: " + fileVersion, ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.Description = rawProject.ValueAsString("description");
|
|
|
|
|
project.Summary = rawProject.ValueAsString("summary");
|
|
|
|
|
project.Copyright = rawProject.ValueAsString("copyright");
|
|
|
|
|
project.Title = rawProject.ValueAsString("title");
|
|
|
|
|
project.EntryPoint = rawProject.ValueAsString("entryPoint");
|
|
|
|
|
project.ProjectUrl = rawProject.ValueAsString("projectUrl");
|
|
|
|
|
project.LicenseUrl = rawProject.ValueAsString("licenseUrl");
|
|
|
|
|
project.IconUrl = rawProject.ValueAsString("iconUrl");
|
2015-10-23 15:21:49 -07:00
|
|
|
|
project.CompilerName = rawProject.ValueAsString("compilerName");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
2015-10-17 07:20:56 -07:00
|
|
|
|
project.Authors = rawProject.ValueAsStringArray("authors") ?? Array.Empty<string>();
|
|
|
|
|
project.Owners = rawProject.ValueAsStringArray("owners") ?? Array.Empty<string>();
|
|
|
|
|
project.Tags = rawProject.ValueAsStringArray("tags") ?? Array.Empty<string>();
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.Language = rawProject.ValueAsString("language");
|
|
|
|
|
project.ReleaseNotes = rawProject.ValueAsString("releaseNotes");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.RequireLicenseAcceptance = rawProject.ValueAsBoolean("requireLicenseAcceptance", defaultValue: false);
|
2015-10-17 22:42:50 -07:00
|
|
|
|
|
2015-10-17 08:05:35 -07:00
|
|
|
|
// REVIEW: Move this to the dependencies node?
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.EmbedInteropTypes = rawProject.ValueAsBoolean("embedInteropTypes", defaultValue: false);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
|
|
|
|
project.Dependencies = new List<LibraryRange>();
|
|
|
|
|
|
|
|
|
|
// Project files
|
|
|
|
|
project.Files = new ProjectFilesCollection(rawProject, project.ProjectDirectory, project.ProjectFilePath);
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var commands = rawProject.Value("commands") as JsonObject;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (commands != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
foreach (var key in commands.Keys)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var value = commands.ValueAsString(key);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (value != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.Commands[key] = value;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var scripts = rawProject.Value("scripts") as JsonObject;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (scripts != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
foreach (var key in scripts.Keys)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var stringValue = scripts.ValueAsString(key);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (stringValue != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.Scripts[key] = new string[] { stringValue };
|
2015-10-13 14:31:29 -07:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var arrayValue = scripts.ValueAsStringArray(key);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (arrayValue != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project.Scripts[key] = arrayValue;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw FileFormatException.Create(
|
|
|
|
|
string.Format("The value of a script in {0} can only be a string or an array of strings", Project.FileName),
|
2015-10-15 15:09:37 -07:00
|
|
|
|
scripts.Value(key),
|
2015-10-13 14:31:29 -07:00
|
|
|
|
project.ProjectFilePath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BuildTargetFrameworksAndConfigurations(project, rawProject, diagnostics);
|
|
|
|
|
|
|
|
|
|
PopulateDependencies(
|
|
|
|
|
project.ProjectFilePath,
|
|
|
|
|
project.Dependencies,
|
|
|
|
|
rawProject,
|
|
|
|
|
"dependencies",
|
|
|
|
|
isGacOrFrameworkReference: false);
|
|
|
|
|
|
|
|
|
|
return project;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static NuGetVersion SpecifySnapshot(string version, string snapshotValue)
|
|
|
|
|
{
|
|
|
|
|
if (version.EndsWith("-*"))
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(snapshotValue))
|
|
|
|
|
{
|
|
|
|
|
version = version.Substring(0, version.Length - 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
version = version.Substring(0, version.Length - 1) + snapshotValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
return new NuGetVersion(version);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void PopulateDependencies(
|
|
|
|
|
string projectPath,
|
|
|
|
|
IList<LibraryRange> results,
|
2015-10-15 15:09:37 -07:00
|
|
|
|
JsonObject settings,
|
2015-10-13 14:31:29 -07:00
|
|
|
|
string propertyName,
|
|
|
|
|
bool isGacOrFrameworkReference)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var dependencies = settings.ValueAsJsonObject(propertyName);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (dependencies != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
foreach (var dependencyKey in dependencies.Keys)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
if (string.IsNullOrEmpty(dependencyKey))
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
throw FileFormatException.Create(
|
|
|
|
|
"Unable to resolve dependency ''.",
|
2015-10-15 15:09:37 -07:00
|
|
|
|
dependencies.Value(dependencyKey),
|
2015-10-13 14:31:29 -07:00
|
|
|
|
projectPath);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var dependencyValue = dependencies.Value(dependencyKey);
|
|
|
|
|
var dependencyTypeValue = LibraryDependencyType.Default;
|
|
|
|
|
JsonString dependencyVersionAsString = null;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
LibraryType target = isGacOrFrameworkReference ? LibraryType.ReferenceAssembly : LibraryType.Unspecified;
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
if (dependencyValue is JsonObject)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
// "dependencies" : { "Name" : { "version": "1.0", "type": "build", "target": "project" } }
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var dependencyValueAsObject = (JsonObject)dependencyValue;
|
|
|
|
|
dependencyVersionAsString = dependencyValueAsObject.ValueAsString("version");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var type = dependencyValueAsObject.ValueAsString("type");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (type != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
dependencyTypeValue = LibraryDependencyType.Parse(type.Value);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read the target if specified
|
|
|
|
|
if (!isGacOrFrameworkReference)
|
|
|
|
|
{
|
|
|
|
|
LibraryType parsedTarget;
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var targetStr = dependencyValueAsObject.ValueAsString("target");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (!string.IsNullOrEmpty(targetStr) && LibraryType.TryParse(targetStr, out parsedTarget))
|
|
|
|
|
{
|
|
|
|
|
target = parsedTarget;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-15 15:09:37 -07:00
|
|
|
|
else if (dependencyValue is JsonString)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
// "dependencies" : { "Name" : "1.0" }
|
2015-10-15 15:09:37 -07:00
|
|
|
|
dependencyVersionAsString = (JsonString)dependencyValue;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw FileFormatException.Create(
|
|
|
|
|
string.Format("Invalid dependency version: {0}. The format is not recognizable.", dependencyKey),
|
|
|
|
|
dependencyValue,
|
|
|
|
|
projectPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VersionRange dependencyVersionRange = null;
|
2015-10-15 15:09:37 -07:00
|
|
|
|
if (!string.IsNullOrEmpty(dependencyVersionAsString?.Value))
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
dependencyVersionRange = VersionRange.Parse(dependencyVersionAsString.Value);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
throw FileFormatException.Create(
|
|
|
|
|
ex,
|
|
|
|
|
dependencyValue,
|
|
|
|
|
projectPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
results.Add(new LibraryRange(
|
2015-10-15 15:09:37 -07:00
|
|
|
|
dependencyKey,
|
2015-10-13 14:31:29 -07:00
|
|
|
|
dependencyVersionRange,
|
|
|
|
|
target,
|
|
|
|
|
dependencyTypeValue,
|
|
|
|
|
projectPath,
|
2015-10-15 15:09:37 -07:00
|
|
|
|
dependencies.Value(dependencyKey).Line,
|
|
|
|
|
dependencies.Value(dependencyKey).Column));
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
private static bool TryGetStringEnumerable(JsonObject parent, string property, out IEnumerable<string> result)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
var collection = new List<string>();
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var valueInString = parent.ValueAsString(property);
|
|
|
|
|
if (valueInString != null)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
collection.Add(valueInString);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var valueInArray = parent.ValueAsStringArray(property);
|
|
|
|
|
if (valueInArray != null)
|
|
|
|
|
{
|
|
|
|
|
collection.AddRange(valueInArray);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = null;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
result = collection.SelectMany(value => value.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries));
|
2015-10-13 14:31:29 -07:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
private void BuildTargetFrameworksAndConfigurations(Project project, JsonObject projectJsonObject, ICollection<DiagnosticMessage> diagnostics)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
// Get the shared compilationOptions
|
2015-10-20 13:27:56 -07:00
|
|
|
|
project._defaultCompilerOptions = GetCompilationOptions(projectJsonObject) ?? new CommonCompilerOptions();
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
|
|
|
|
project._defaultTargetFrameworkConfiguration = new TargetFrameworkInformation
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
Dependencies = new List<LibraryRange>()
|
2015-10-13 14:31:29 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Add default configurations
|
2015-10-20 13:27:56 -07:00
|
|
|
|
project._compilerOptionsByConfiguration["Debug"] = new CommonCompilerOptions
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
Defines = new[] { "DEBUG", "TRACE" },
|
|
|
|
|
Optimize = false
|
|
|
|
|
};
|
|
|
|
|
|
2015-10-20 13:27:56 -07:00
|
|
|
|
project._compilerOptionsByConfiguration["Release"] = new CommonCompilerOptions
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
Defines = new[] { "RELEASE", "TRACE" },
|
|
|
|
|
Optimize = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// The configuration node has things like debug/release compiler settings
|
|
|
|
|
/*
|
|
|
|
|
{
|
|
|
|
|
"configurations": {
|
|
|
|
|
"Debug": {
|
|
|
|
|
},
|
|
|
|
|
"Release": {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var configurationsSection = projectJsonObject.ValueAsJsonObject("configurations");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (configurationsSection != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
foreach (var configKey in configurationsSection.Keys)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var compilerOptions = GetCompilationOptions(configurationsSection.ValueAsJsonObject(configKey));
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
|
|
|
|
// Only use this as a configuration if it's not a target framework
|
2015-10-15 15:09:37 -07:00
|
|
|
|
project._compilerOptionsByConfiguration[configKey] = compilerOptions;
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The frameworks node is where target frameworks go
|
|
|
|
|
/*
|
|
|
|
|
{
|
|
|
|
|
"frameworks": {
|
|
|
|
|
"net45": {
|
|
|
|
|
},
|
|
|
|
|
"dnxcore50": {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var frameworks = projectJsonObject.ValueAsJsonObject("frameworks");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (frameworks != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
foreach (var frameworkKey in frameworks.Keys)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var frameworkToken = frameworks.ValueAsJsonObject(frameworkKey);
|
|
|
|
|
var success = BuildTargetFrameworkNode(project, frameworkKey, frameworkToken);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
diagnostics?.Add(
|
|
|
|
|
new DiagnosticMessage(
|
|
|
|
|
ErrorCodes.NU1008,
|
|
|
|
|
$"\"{frameworkKey}\" is an unsupported framework.",
|
|
|
|
|
project.ProjectFilePath,
|
|
|
|
|
DiagnosticMessageSeverity.Error,
|
2015-10-15 15:09:37 -07:00
|
|
|
|
frameworkToken.Line,
|
|
|
|
|
frameworkToken.Column));
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
throw FileFormatException.Create(ex, frameworks.Value(frameworkKey), project.ProjectFilePath);
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Json object which represents project configuration for a specified framework
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="frameworkKey">The name of the framework</param>
|
|
|
|
|
/// <param name="frameworkValue">The Json object represent the settings</param>
|
|
|
|
|
/// <returns>Returns true if it successes.</returns>
|
2015-10-15 15:09:37 -07:00
|
|
|
|
private bool BuildTargetFrameworkNode(Project project, string frameworkKey, JsonObject frameworkValue)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
// If no compilation options are provided then figure them out from the node
|
|
|
|
|
var compilerOptions = GetCompilationOptions(frameworkValue) ??
|
2015-10-20 13:27:56 -07:00
|
|
|
|
new CommonCompilerOptions();
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
|
|
|
|
var frameworkName = NuGetFramework.Parse(frameworkKey);
|
|
|
|
|
|
|
|
|
|
// If it's not unsupported then keep it
|
|
|
|
|
if (frameworkName.IsUnsupported)
|
|
|
|
|
{
|
|
|
|
|
// REVIEW: Should we skip unsupported target frameworks
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the target framework specific define
|
|
|
|
|
var defines = new HashSet<string>(compilerOptions.Defines ?? Enumerable.Empty<string>());
|
|
|
|
|
var frameworkDefine = MakeDefaultTargetFrameworkDefine(frameworkName);
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(frameworkDefine))
|
|
|
|
|
{
|
|
|
|
|
defines.Add(frameworkDefine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
compilerOptions.Defines = defines;
|
|
|
|
|
|
|
|
|
|
var targetFrameworkInformation = new TargetFrameworkInformation
|
|
|
|
|
{
|
|
|
|
|
FrameworkName = frameworkName,
|
2015-10-17 08:36:22 -07:00
|
|
|
|
Dependencies = new List<LibraryRange>(),
|
2015-10-28 02:21:00 -07:00
|
|
|
|
CompilerOptions = compilerOptions,
|
|
|
|
|
Line = frameworkValue.Line,
|
|
|
|
|
Column = frameworkValue.Column
|
2015-10-13 14:31:29 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var frameworkDependencies = new List<LibraryRange>();
|
|
|
|
|
|
|
|
|
|
PopulateDependencies(
|
|
|
|
|
project.ProjectFilePath,
|
|
|
|
|
frameworkDependencies,
|
|
|
|
|
frameworkValue,
|
|
|
|
|
"dependencies",
|
|
|
|
|
isGacOrFrameworkReference: false);
|
|
|
|
|
|
|
|
|
|
var frameworkAssemblies = new List<LibraryRange>();
|
|
|
|
|
PopulateDependencies(
|
|
|
|
|
project.ProjectFilePath,
|
|
|
|
|
frameworkAssemblies,
|
|
|
|
|
frameworkValue,
|
|
|
|
|
"frameworkAssemblies",
|
|
|
|
|
isGacOrFrameworkReference: true);
|
|
|
|
|
|
|
|
|
|
frameworkDependencies.AddRange(frameworkAssemblies);
|
|
|
|
|
targetFrameworkInformation.Dependencies = frameworkDependencies;
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
targetFrameworkInformation.WrappedProject = frameworkValue.ValueAsString("wrappedProject");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var binNode = frameworkValue.ValueAsJsonObject("bin");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (binNode != null)
|
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
targetFrameworkInformation.AssemblyPath = binNode.ValueAsString("assembly");
|
|
|
|
|
targetFrameworkInformation.PdbPath = binNode.ValueAsString("pdb");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
project._targetFrameworks[frameworkName] = targetFrameworkInformation;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-20 13:27:56 -07:00
|
|
|
|
private static CommonCompilerOptions GetCompilationOptions(JsonObject rawObject)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
var rawOptions = rawObject.ValueAsJsonObject("compilationOptions");
|
2015-10-13 14:31:29 -07:00
|
|
|
|
if (rawOptions == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-20 13:27:56 -07:00
|
|
|
|
return new CommonCompilerOptions
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
2015-10-15 15:09:37 -07:00
|
|
|
|
Defines = rawOptions.ValueAsStringArray("define"),
|
|
|
|
|
LanguageVersion = rawOptions.ValueAsString("languageVersion"),
|
|
|
|
|
AllowUnsafe = rawOptions.ValueAsNullableBoolean("allowUnsafe"),
|
|
|
|
|
Platform = rawOptions.ValueAsString("platform"),
|
|
|
|
|
WarningsAsErrors = rawOptions.ValueAsNullableBoolean("warningsAsErrors"),
|
|
|
|
|
Optimize = rawOptions.ValueAsNullableBoolean("optimize"),
|
|
|
|
|
KeyFile = rawOptions.ValueAsString("keyFile"),
|
|
|
|
|
DelaySign = rawOptions.ValueAsNullableBoolean("delaySign"),
|
2015-11-09 00:19:39 -08:00
|
|
|
|
UseOssSigning = rawOptions.ValueAsNullableBoolean("useOssSigning"),
|
2015-10-15 15:09:37 -07:00
|
|
|
|
EmitEntryPoint = rawOptions.ValueAsNullableBoolean("emitEntryPoint")
|
2015-10-13 14:31:29 -07:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 15:09:37 -07:00
|
|
|
|
private static string MakeDefaultTargetFrameworkDefine(NuGetFramework targetFramework)
|
2015-10-13 14:31:29 -07:00
|
|
|
|
{
|
|
|
|
|
var shortName = targetFramework.GetTwoDigitShortFolderName();
|
|
|
|
|
|
|
|
|
|
if (targetFramework.IsPCL)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var candidateName = shortName.ToUpperInvariant();
|
|
|
|
|
|
|
|
|
|
// Replace '-', '.', and '+' in the candidate name with '_' because TFMs with profiles use those (like "net40-client")
|
|
|
|
|
// and we want them representable as defines (i.e. "NET40_CLIENT")
|
|
|
|
|
candidateName = candidateName.Replace('-', '_').Replace('+', '_').Replace('.', '_');
|
|
|
|
|
|
|
|
|
|
// We require the following from our Target Framework Define names
|
|
|
|
|
// Starts with A-Z or _
|
|
|
|
|
// Contains only A-Z, 0-9 and _
|
|
|
|
|
if (!string.IsNullOrEmpty(candidateName) &&
|
|
|
|
|
(char.IsLetter(candidateName[0]) || candidateName[0] == '_') &&
|
|
|
|
|
candidateName.All(c => Char.IsLetterOrDigit(c) || c == '_'))
|
|
|
|
|
{
|
|
|
|
|
return candidateName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2015-10-17 22:42:50 -07:00
|
|
|
|
|
|
|
|
|
private static bool HasProjectFile(string path)
|
|
|
|
|
{
|
|
|
|
|
string projectPath = Path.Combine(path, Project.FileName);
|
|
|
|
|
|
|
|
|
|
return File.Exists(projectPath);
|
|
|
|
|
}
|
2015-10-13 14:31:29 -07:00
|
|
|
|
}
|
|
|
|
|
}
|