Merge branch 'master' of https://github.com/dotnet/cli into publish-tests2
This commit is contained in:
commit
55b9697b74
61 changed files with 1632 additions and 782 deletions
119
Documentation/specs/corehost.md
Normal file
119
Documentation/specs/corehost.md
Normal file
|
@ -0,0 +1,119 @@
|
|||
# corehost runtime/assembly resolution
|
||||
|
||||
The shared host locates assemblies and native libraries using a combination of: Servicing Index, Files in the application folder (aka "app-local") and files from package caches.
|
||||
|
||||
## Definitions and Formats
|
||||
|
||||
### Terms/Notes
|
||||
|
||||
* The term "Library" (Title Case) is used throughout this document to refer to a NuGet Package. We use this term because it is used in the code to represent multiple things: Packages, Projects and Framework Assemblies are all types of "Library".
|
||||
* All of the assembly resolution here refers to setting up the default assembly load context for the runtime. Further dynamic loads (plugins, etc.) can still have custom resolution logic provided by using an `AssemblyLoadContext` in the managed code. Essentially, we are setting up the necessary assemblies to launch the `Program.Main` (and all the assemblies that are statically-referenced by that).
|
||||
|
||||
### Servicing Index
|
||||
|
||||
The servicing index is loaded when the `DOTNET_SERVICING` environment variable is non-empty. When this variable is non-empty, it points to a directory that will be the **Servicing Root**. There may be platform-specific default locations, to be determined later.
|
||||
|
||||
An index file is located at the path defined by `$DOTNET_SERVICING/servicing_index.txt`. In this file are a series of lines of one of the following formats:
|
||||
|
||||
```
|
||||
# Lines starting with a '#' and blank lines are ignored.
|
||||
|
||||
# Identifies an asset from a NuGet Package that has been serviced.
|
||||
package|[Package ID]|[Package Version]|[Original Asset Relative Path]=[New Asset Path, relative to Servicing Root]
|
||||
package|System.Threading.Thread|1.2.3.4|lib/dotnet5.4/System.Threading.Thread.dll=patches/abc123/System.Threading.Thread.dll
|
||||
|
||||
# TBD: Host/Runtime servicing entries.
|
||||
```
|
||||
|
||||
Paths in this file are **always** specified using `/`, even on Windows. They must be converted to platform-specific directory separators.
|
||||
|
||||
This index is loaded when needed during the Resolution Process (see below).
|
||||
|
||||
### Dependencies File
|
||||
|
||||
The `.deps` file is a file located alongside the native host. It is stored in a CSV format, with header, of the following format:
|
||||
|
||||
```
|
||||
LibraryType,LibraryName,LibraryVersion,LibraryHash,AssetType,AssetName,AssetRelativePath,AssetServicable
|
||||
"Package","Microsoft.CodeAnalysis.Common","1.2.0-beta-20151117-04","sha512-4O3f1iRswbWDz70AGTk0tBA1ivslJUuq37FSx4d0+ZuoBFxNO4oY7ReJgndOJYefaxeTMsCVHSVHJMYOJJphtQ==","runtime","Microsoft.CodeAnalysis","lib/portable-net45+win8/Microsoft.CodeAnalysis.dll","true"
|
||||
"Package","Microsoft.CodeAnalysis.Common","1.2.0-beta-20151117-04","sha512-4O3f1iRswbWDz70AGTk0tBA1ivslJUuq37FSx4d0+ZuoBFxNO4oY7ReJgndOJYefaxeTMsCVHSVHJMYOJJphtQ==","resources","Microsoft.CodeAnalysis","lib/portable-net45+win8/fr-FR/Microsoft.CodeAnalysis.resources.dll","false"
|
||||
```
|
||||
|
||||
Fields:
|
||||
|
||||
* `LibraryType` -> The type of Library that provides the Asset. Currently always `Package` (other Library types include Projects and Framework Assemblies but these aren't relevant to `corehost`)
|
||||
* `LibraryName` -> The name of the Library that provides the Asset. For a Package, this is the Package ID
|
||||
* `LibraryVersion` -> The version of the Library that provides the Asset. For a Package, this is the Package Version
|
||||
* `LibraryHash` -> The hash of the Library that provides the Asset. For a Package, this is a hash of the `.nupkg` file. The format is `[algorithm]-[base64-encoded hash]` where `[algorithm]` must always be `sha512` (in the current version)
|
||||
* `AssetType` -> The type of the Asset within the Library. `corehost` recognizes two types: `runtime` and `native`, representing Managed Assemblies and Native Libraries respectively. These names are designed to mirror the names in `project.lock.json`.
|
||||
* `AssetName` -> The base name of the Asset. This is generally just the file name, without the extension (also removing "sub-extensions" like `ni` for native images of managed assemblies)
|
||||
* `AssetRelativePath` -> The relative path to the Asset file within the root of the package in the packages cache. Entries for localized resources will have the culture specific folder as the last directory in the relative path (i.e. `fr-FR/Foo.resources.dll`). See "Satellite Assemblies" below for more details. As with the servicing file, paths in this file **always** use `/` as a directory separator.
|
||||
* `AssetServicable` -> Indicates if the asset is servicable. `true` indicates that it is servicable, `false` indicates that it is not
|
||||
|
||||
A few notes about the format:
|
||||
|
||||
* The current code does not include the header, this is being changed.
|
||||
* All fields MUST be quoted (for simplicity), even if they don't contain a ','
|
||||
|
||||
### Files in the application folder
|
||||
|
||||
Any file with the suffix `.dll` in the same folder as the managed application being loaded (the "Application Base") will be considered a viable assembly during the resolution process. The host **assumes** that the assembly's short name is the same as the file name with the `.dll` suffix removed (yes, this is not technically required by the CLR, but we assume it for use with this host).
|
||||
|
||||
### Files from package caches
|
||||
|
||||
Only assemblies listed in the dependencies file can be resolved from a package cache. To resolve those assemblies, two environment variables are used:
|
||||
|
||||
* `DOTNET_PACKAGES` - The primary package cache. If not set, defaults to `$HOME/.nuget/packages` on Unix or `%LOCALAPPDATA%\NuGet\Packages` (TBD) on Windows. **NOTE**: Currently the host uses different folders as we are still coordinating with NuGet to get the directories right (there are compat considerations). Currently we always use `$HOME/.dnx/packages`(Unix)/`%USERPROFILE%\.dnx\packages`(Win).
|
||||
* `DOTNET_PACKAGES_CACHE` - The secondary cache. This is used by shared hosters (such as Azure) to provide a cache of pre-downloaded common packages on a faster disk. If not set, it is not used.
|
||||
|
||||
Given the Package ID, Package Version, Package Hash and Asset Relative Path provided in the dependencies file, **and the assembly is not serviced** (see the full resolution algorithm below) resolution proceeds as follows (Unix-style paths will be used for convenience but these variables and paths all apply to Windows as well):
|
||||
|
||||
1. If `DOTNET_PACKAGES_CACHE` is non-empty, read the file `$DOTNET_PACKAGES_CACHE/[Package ID]/[Package Version]/[Package Id].[Package Version].nupkg.sha512` if present. If the file is present and the content matches the `[Package Hash]` value from the dependencies file. Use that location as the Package Root and go to 3
|
||||
2. Using `DOTNET_PACKAGES`, or it's default value, use `$DOTNET_PACKAGES/[Package ID]/[Package Version]` as the Package Root
|
||||
3. Concatenate the Package Root and the Asset Relative Path. This is the path to the asset (managed assembly or native library).
|
||||
|
||||
## Assembly Resolution
|
||||
|
||||
During host start-up, the host identifies if a `.deps` file is present and loads it. It also scans the files located in the Application Base and determines the assembly name for each (using the file name). It builds a set of assembly names to be loaded by the union of the assembly names listed in `.deps` file and the assemblies located in the Application Base.
|
||||
|
||||
A `.deps` file is **not** required to successfully launch an application, but without it, all the dependent assemblies must be located within the same folder as the application. Also, since servicing is performed on the basis of packages, an application without a `.deps` file cannot use the servicing index to override the location of assemblies.
|
||||
|
||||
Given the set of assembly names, the host performs the following resolution. In some steps, the Package ID/Version/Relative Path data is required. This is only available if the assembly was listed in the deps file. If the assembly comes from the app-local folder, these resolution steps are skipped.
|
||||
|
||||
1. If there is an entry in the servicing index for the Package ID/Version/Relative Path associated with the assembly, the Servicing Root is concatenated with the New Asset Path from the index and used as the Assembly Path. This occurs **even if the assembly is also located app-local**, as long as it is also in the `.deps` file.
|
||||
2. If there is a file in the Application Base with the file name `[AssemblyName].dll`, `[AssemblyName].ni.dll`, `[AssemblyName].exe`, or `[AssemblyName].ni.exe` (in that order), it its full path is used as the Assembly Path
|
||||
3. The Assembly Path is resolved out of the Package Caches using the algorithm above (in 'Files from package caches').
|
||||
|
||||
A similar process is used to produce a list of Native Library Paths. Native libraries are listed in the `.deps` file (marked with a special `native` type token) and searched in the same way as managed assemblies (Servicing, then app-local, then package caches). The main exception is that the app-local file extensions vary by platform (`.dll` on Windows, `.so` on Linux, `.dylib` on Mac OS X)
|
||||
|
||||
Once a the list of assemblies and native libraries is produced, the host will check for duplicates. If both an `.ni.dll`/`.ni.exe` image and a `.dll`/`.exe` assembly are found for an assembly, the native image will be preferred and the IL-only assembly will be removed. The presence of two different paths for the same assembly name will be considered an error. The managed assemblies are provided in the Trusted Platform Assemblies (TPA) list for the CoreCLR during startup. The folder paths for each native library are deduplicated and provided in the Native Search Paths list for the CoreCLR during startup.
|
||||
|
||||
**NOTE**: The CLR may add support for providing a similar structure as the TPA list for native libraries (i.e. a flat list of full file paths).
|
||||
|
||||
### Satellite Assemblies
|
||||
|
||||
Satellite Assemblies (assemblies containing only embedded resources used in place of the resources provided by an assembly) are detected by path convention in the host. The convention will be to look at the last two segments of the path (the file name and the immediate parent directory name). If the parent directory matches an [IETF Language Tag](https://en.wikipedia.org/wiki/IETF_language_tag) (or more specifically, a value usable in the Culture field for a CLR Assembly Name), then the assembly is considered culture-specific (for the culture specified in that folder name). Upon determining this, the host will place the culture-neutral assemblies on the TPA list and provide the directories containing the assemblies as Platform Resource Roots to the CLR to allow it to locate the assemblies.
|
||||
|
||||
## Runtime Resolution
|
||||
|
||||
Runtime resolution is controlled by two environment variables:
|
||||
|
||||
* `DOTNET_RUNTIME_SERVICING` -> Global override for runtime
|
||||
* `DOTNET_HOME` -> Default location for runtime
|
||||
|
||||
The runtime is located by searching the following paths in order, where `APP_BASE` refers to the directory containing the managed application assembly and `LIBCORECLR` refers to the platform-specific name for the CoreCLR library (`libcoreclr.so` on Unix, `libcoreclr.dylib` on Mac OS X, `coreclr.dll` on Windows). The first path that matches is used as the path to load the CoreCLR from.
|
||||
|
||||
* `$DOTNET_RUNTIME_SERVICING/runtime/coreclr/LIBCORECLR`
|
||||
* `APP_BASE/LIBCORECLR`
|
||||
* `$DOTNET_HOME/runtime/coreclr/LIBCORECLR`
|
||||
* On Unix:
|
||||
* `/usr/local/share/dotnet/runtime/coreclr/LIBCORECLR` [1]
|
||||
* `/usr/share/dotnet/runtime/coreclr/LIBCORECLR`
|
||||
* On Windows:
|
||||
* `%LocalAppData%\dotnet\runtime\coreclr\LIBCORECLR`
|
||||
* `%ProgramFiles%\dotnet\runtime\coreclr\LIBCORECLR` [2]
|
||||
|
||||
Notes:
|
||||
|
||||
1. The Unix paths should be this way but are reversed in the actual code. Generally `/usr/local` is considered to have higher precedence than `/usr`
|
||||
2. Not yet implemented.
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Cli", "src\Microsoft.DotNet.Cli\Microsoft.DotNet.Cli.xproj", "{60CF7E6C-D6C8-439D-B7B7-D8A27E29BE2C}"
|
||||
EndProject
|
||||
|
@ -57,6 +57,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LoadContextTest", "test\Loa
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.New", "src\Microsoft.DotNet.Tools.New\Microsoft.DotNet.Tools.New.xproj", "{BC765FBF-AD7A-4A99-9902-5540C5A74181}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0722D325-24C8-4E83-B5AF-0A083E7F0749}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MultiProjectValidator", "tools\MultiProjectValidator\MultiProjectValidator.xproj", "{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -421,6 +425,22 @@ Global
|
|||
{BC765FBF-AD7A-4A99-9902-5540C5A74181}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{BC765FBF-AD7A-4A99-9902-5540C5A74181}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{BC765FBF-AD7A-4A99-9902-5540C5A74181}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.Release|x64.Build.0 = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -448,5 +468,6 @@ Global
|
|||
{947DD232-8D9B-4B78-9C6A-94F807D2DD58} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
{7A75ACC4-3C2F-44E1-B492-0EC08704E9FF} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
{BC765FBF-AD7A-4A99-9902-5540C5A74181} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{08A68C6A-86F6-4ED2-89A7-B166D33E9F85} = {0722D325-24C8-4E83-B5AF-0A083E7F0749}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -41,9 +41,8 @@ PACKAGE_NAME=$PACKAGE_DIR/dotnet-cli-x64.${DOTNET_BUILD_VERSION}.pkg
|
|||
pkgbuild --root $STAGE2_DIR \
|
||||
--version $DOTNET_BUILD_VERSION \
|
||||
--scripts $DIR/scripts \
|
||||
--ownership preserve \
|
||||
--identifier com.microsoft.dotnet.cli.pkg.dotnet-osx-x64 \
|
||||
--install-location /usr/local/share/dotnet/cli \
|
||||
--install-location /usr/local/share/dotnet \
|
||||
$DIR/dotnet-osx-x64.$DOTNET_BUILD_VERSION.pkg
|
||||
|
||||
cat $DIR/Distribution-Template | sed "/{VERSION}/s//$DOTNET_BUILD_VERSION/g" > $DIR/Dist
|
||||
|
|
|
@ -4,20 +4,27 @@
|
|||
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
#
|
||||
|
||||
ln -s $2/bin/dotnet /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-compile /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-compile-csc /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-new /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-pack /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-publish /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-repl /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-restore /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-resgen /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-run /usr/local/bin/
|
||||
ln -s $2/bin/dotnet-test /usr/local/bin/
|
||||
PACKAGE=$1
|
||||
INSTALL_DESTINATION=$2
|
||||
|
||||
|
||||
# A temporary fix for the permissions issue(s)
|
||||
chmod -R 755 $INSTALL_DESTINATION
|
||||
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-compile /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-compile-csc /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-new /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-pack /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-publish /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-repl /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-restore /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-resgen /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-run /usr/local/bin/
|
||||
ln -s $INSTALL_DESTINATION/bin/dotnet-test /usr/local/bin/
|
||||
|
||||
# A temporary solution to unblock dotnet compile
|
||||
cp $2/bin/corehost /usr/local/bin/
|
||||
cp $INSTALL_DESTINATION/bin/corehost /usr/local/bin/
|
||||
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -79,10 +79,17 @@ if [ -z "$RID" ]; then
|
|||
export RID=osx.10.10-x64
|
||||
export DNX_FLAVOR="dnx-coreclr-darwin-x64"
|
||||
elif [ "$UNAME" == "Linux" ]; then
|
||||
# Detect Distro?
|
||||
export OSNAME=linux
|
||||
export RID=ubuntu.14.04-x64
|
||||
export DNX_FLAVOR="dnx-coreclr-linux-x64"
|
||||
# Detect Distro
|
||||
if [ "$(cat /etc/*-release | grep -cim1 ubuntu)" -eq 1 ]; then
|
||||
export OSNAME=ubuntu
|
||||
export RID=ubuntu.14.04-x64
|
||||
export DNX_FLAVOR="dnx-coreclr-linux-x64"
|
||||
elif [ "$(cat /etc/*-release | grep -cim1 centos)" -eq 1 ]; then
|
||||
export OSNAME=centos
|
||||
export RID=centos.7-x64
|
||||
else
|
||||
error "unknown Linux Distro" 1>&2
|
||||
fi
|
||||
else
|
||||
error "unknown OS: $UNAME" 1>&2
|
||||
exit 1
|
||||
|
|
|
@ -139,6 +139,15 @@ Download it from https://www.cmake.org
|
|||
Exit 1
|
||||
}
|
||||
|
||||
# Run Validation for Project.json dependencies
|
||||
dotnet publish $RepoRoot\tools\MultiProjectValidator -o $Stage2Dir\..\tools
|
||||
& "$Stage2Dir\..\tools\pjvalidate" "$RepoRoot\src"
|
||||
# TODO For release builds, this should be uncommented and fail.
|
||||
# if (!$?) {
|
||||
# Write-Host "Project Validation Failed"
|
||||
# Exit 1
|
||||
# }
|
||||
|
||||
} finally {
|
||||
$env:PATH = $StartPath
|
||||
$env:DOTNET_HOME = $StartDotNetHome
|
||||
|
|
|
@ -48,7 +48,7 @@ DOTNET_PATH=$(which dotnet)
|
|||
PREFIX="$(cd -P "$(dirname "$DOTNET_PATH")/.." && pwd)"
|
||||
|
||||
header "Restoring packages"
|
||||
$DNX_ROOT/dnu restore "$REPOROOT" --quiet --runtime "osx.10.10-x64" --runtime "ubuntu.14.04-x64" --runtime "win7-x64" --no-cache
|
||||
$DNX_ROOT/dnu restore "$REPOROOT" --quiet --runtime "$RID" --no-cache
|
||||
|
||||
header "Building corehost"
|
||||
|
||||
|
@ -111,6 +111,13 @@ DOTNET_HOME=$STAGE2_DIR DOTNET_TOOLS=$STAGE2_DIR $REPOROOT/scripts/build/build_a
|
|||
COMMIT_ID=$(git rev-parse HEAD)
|
||||
echo $COMMIT_ID > $STAGE2_DIR/.commit
|
||||
|
||||
# E2E test on the output
|
||||
# Run tests on the stage2 output
|
||||
header "Testing stage2..."
|
||||
DOTNET_HOME=$STAGE2_DIR DOTNET_TOOLS=$STAGE2_DIR $DIR/test/runtests.sh
|
||||
|
||||
# Run Validation for Project.json dependencies
|
||||
dotnet publish "$REPOROOT/tools/MultiProjectValidator" -o "$STAGE2_DIR/../tools"
|
||||
#TODO for release builds this should fail
|
||||
set +e
|
||||
"$STAGE2_DIR/../tools/pjvalidate" "$REPOROOT/src"
|
||||
set -e
|
||||
|
|
|
@ -9,7 +9,7 @@ set BIN_DIR=%CD%\bin
|
|||
popd
|
||||
|
||||
REM Replace with a robust method for finding the right crossgen.exe
|
||||
set CROSSGEN_UTIL=%UserProfile%\.dnx\packages\runtime.win7-x64.Microsoft.NETCore.Runtime.CoreCLR\1.0.1-beta-23504\tools\crossgen.exe
|
||||
set CROSSGEN_UTIL=%UserProfile%\.dnx\packages\runtime.win7-x64.Microsoft.NETCore.Runtime.CoreCLR\1.0.1-rc2-23616\tools\crossgen.exe
|
||||
|
||||
REM Crossgen currently requires itself to be next to mscorlib
|
||||
copy %CROSSGEN_UTIL% /Y %BIN_DIR% > nul
|
||||
|
|
|
@ -22,7 +22,7 @@ if [ -z "$RID" ]; then
|
|||
fi
|
||||
|
||||
# Replace with a robust method for finding the right crossgen.exe
|
||||
CROSSGEN_UTIL=~/.dnx/packages/runtime.$RID.Microsoft.NETCore.Runtime.CoreCLR/1.0.1-beta-23504/tools/crossgen
|
||||
CROSSGEN_UTIL=$HOME/.dnx/packages/runtime.$RID.Microsoft.NETCore.Runtime.CoreCLR/1.0.1-rc2-23616/tools/crossgen
|
||||
|
||||
cd $BIN_DIR
|
||||
|
||||
|
|
|
@ -4,21 +4,26 @@
|
|||
#
|
||||
|
||||
# Dockerfile that creates a container suitable to build dotnet-cli
|
||||
FROM debian:jessie
|
||||
FROM ubuntu:14.04
|
||||
|
||||
# This could become a "microsoft/coreclr" image, since it just installs the dependencies for CoreCLR (and stdlib)
|
||||
# Install CoreCLR dependencies
|
||||
# Install CoreCLR and CoreFx dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get -qqy install unzip curl libicu-dev libunwind8 gettext libssl-dev libcurl3-gnutls zlib1g
|
||||
apt-get -qqy install unzip curl libicu-dev libunwind8 gettext libssl-dev libcurl3-gnutls zlib1g liblttng-ust-dev lldb-3.6-dev lldb-3.6
|
||||
|
||||
# Install Dotnet CLI dependencies.
|
||||
# clang is required for dotnet-compile-native
|
||||
RUN apt-get -qqy install clang-3.5
|
||||
|
||||
# Install Build Prereqs
|
||||
RUN echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.6 main" | tee /etc/apt/sources.list.d/llvm.list && \
|
||||
curl http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add - && \
|
||||
apt-get update && \
|
||||
apt-get install -y debhelper build-essential devscripts git liblttng-ust-dev lldb-3.6-dev lldb-3.6 clang cmake
|
||||
apt-get install -y debhelper build-essential devscripts git cmake
|
||||
|
||||
# Use clang as c++ compiler
|
||||
RUN update-alternatives --set c++ /usr/bin/clang++
|
||||
RUN update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-3.5 100
|
||||
RUN update-alternatives --set c++ /usr/bin/clang++-3.5
|
||||
|
||||
# Install azure cli. We need this to publish artifacts.
|
||||
RUN apt-get -y install nodejs-legacy && \
|
||||
|
|
|
@ -33,7 +33,7 @@ if (Test-Path $LocalFile)
|
|||
if ($LocalVersion -and $LocalHash)
|
||||
{
|
||||
$RemoteResponse = Invoke-WebRequest -UseBasicParsing "$Feed/$Channel/dnvm/latest.win.version"
|
||||
$RemoteData = @([Text.Encoding]::UTF8.GetString($RemoteResponse.Content).Split());
|
||||
$RemoteData = @([Text.Encoding]::UTF8.GetString($RemoteResponse.Content).Split([char[]]@(), [StringSplitOptions]::RemoveEmptyEntries));
|
||||
$RemoteHash = $RemoteData[0].Trim()
|
||||
$RemoteVersion = $RemoteData[1].Trim()
|
||||
|
||||
|
|
|
@ -87,7 +87,12 @@ current_os()
|
|||
if [ "$uname" = "Darwin" ]; then
|
||||
echo "osx"
|
||||
else
|
||||
echo "linux"
|
||||
# Detect Distro
|
||||
if [ "$(cat /etc/*-release | grep -cim1 ubuntu)" -eq 1 ]; then
|
||||
echo "ubuntu"
|
||||
elif [ "$(cat /etc/*-release | grep -cim1 centos)" -eq 1 ]; then
|
||||
echo "centos"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -107,7 +112,7 @@ check_pre_reqs() {
|
|||
return 0
|
||||
fi
|
||||
|
||||
if [ "$os" = "linux" ]; then
|
||||
if [ "$(uname)" = "Linux" ]; then
|
||||
[ -z "$(ldconfig -p | grep libunwind)" ] && say_err "Unable to locate libunwind. Install libunwind to continue" && _failing=true
|
||||
[ -z "$(ldconfig -p | grep libssl)" ] && say_err "Unable to locate libssl. Install libssl to continue" && _failing=true
|
||||
[ -z "$(ldconfig -p | grep libcurl)" ] && say_err "Unable to locate libcurl. Install libcurl to continue" && _failing=true
|
||||
|
|
|
@ -32,11 +32,10 @@ echo $DOTNET_BUILD_VERSION >> $STAGE2_DIR/.version
|
|||
# Create Dnvm Package
|
||||
$DIR/package-dnvm.sh
|
||||
|
||||
if [[ "$UNAME" == "Linux" ]]; then
|
||||
if [[ "$OSNAME" == "ubuntu" ]]; then
|
||||
# Create Debian package
|
||||
$DIR/package-debian.sh
|
||||
elif [[ "$UNAME" == "Darwin" ]]; then
|
||||
elif [[ "$OSNAME" == "osx" ]]; then
|
||||
# Create OSX PKG
|
||||
$DIR/../../packaging/osx/package-osx.sh
|
||||
fi
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ function UploadFile($Blob, $Uploadfile)
|
|||
|
||||
# use azure cli to upload to blob storage. We cannot use Invoke-WebRequest to do this becuase azure has a max limit of 64mb that can be uploaded using REST
|
||||
#$statusCode = (Invoke-WebRequest -URI "$Upload_URI" -Method PUT -Headers @{"x-ms-blob-type"="BlockBlob"; "x-ms-date"="2015-10-23";"x-ms-version"="2013-08-15"} -InFile $Uploadfile).StatusCode
|
||||
azure storage blob upload --quiet --container $env:STORAGE_CONTAINER --blob $Blob --blobtype block --connection-string "$env:CONNECTION_STRING" --file $Uploadfile
|
||||
azure storage blob upload --quiet --container $env:STORAGE_CONTAINER --blob $Blob --blobtype block --connection-string "$env:CONNECTION_STRING" --file $Uploadfile | Out-Host
|
||||
|
||||
if($LastExitCode -eq 0)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
{
|
||||
internal static class Constants
|
||||
{
|
||||
public static readonly string ProjectFileName = "project.json";
|
||||
public static readonly string ExeSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty;
|
||||
|
||||
// Priority order of runnable suffixes to look for and run
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"shared": "**/*.cs",
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0"
|
||||
},
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
|
|
@ -6,9 +6,9 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Microsoft.Dotnet.Cli.Compiler.Common
|
||||
|
@ -26,7 +26,8 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
[typeof(AssemblyVersionAttribute)] = EscapeCharacters(metadata.AssemblyVersion?.ToString()),
|
||||
[typeof(AssemblyInformationalVersionAttribute)] = EscapeCharacters(metadata.InformationalVersion),
|
||||
[typeof(AssemblyCultureAttribute)] = EscapeCharacters(metadata.Culture),
|
||||
[typeof(NeutralResourcesLanguageAttribute)] = EscapeCharacters(metadata.NeutralLanguage)
|
||||
[typeof(NeutralResourcesLanguageAttribute)] = EscapeCharacters(metadata.NeutralLanguage),
|
||||
[typeof(TargetFrameworkAttribute)] = EscapeCharacters(metadata.TargetFramework)
|
||||
};
|
||||
|
||||
var existingAttributes = new List<Type>();
|
||||
|
|
|
@ -5,6 +5,8 @@ using Microsoft.DotNet.ProjectModel;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.Linq;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.Dotnet.Cli.Compiler.Common
|
||||
{
|
||||
|
@ -26,6 +28,8 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
|
||||
private const string NeutralCultureOptionName = "neutral-language";
|
||||
|
||||
private const string TargetFrameworkOptionName = "target-framework";
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
@ -42,8 +46,22 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
|
||||
public string NeutralLanguage { get; set; }
|
||||
|
||||
public static AssemblyInfoOptions CreateForProject(Project project)
|
||||
public string TargetFramework { get; set; }
|
||||
|
||||
public static AssemblyInfoOptions CreateForProject(ProjectContext context)
|
||||
{
|
||||
var project = context.ProjectFile;
|
||||
NuGetFramework targetFramework = null;
|
||||
// force .NETFramework instead of DNX
|
||||
if (context.TargetFramework.IsDesktop())
|
||||
{
|
||||
targetFramework = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Net, context.TargetFramework.Version);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetFramework = context.TargetFramework;
|
||||
}
|
||||
|
||||
return new AssemblyInfoOptions()
|
||||
{
|
||||
AssemblyVersion = project.Version?.Version.ToString(),
|
||||
|
@ -52,7 +70,8 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
Copyright = project.Copyright,
|
||||
Description = project.Description,
|
||||
Title = project.Title,
|
||||
NeutralLanguage = project.Language
|
||||
NeutralLanguage = project.Language,
|
||||
TargetFramework = targetFramework.DotNetFrameworkName
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -66,22 +85,25 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
string copyright = null;
|
||||
string culture = null;
|
||||
string neutralCulture = null;
|
||||
string targetFramework = null;
|
||||
|
||||
syntax.DefineOption(AssemblyVersionOptionName, ref version, "Assembly version");
|
||||
syntax.DefineOption(AssemblyVersionOptionName, ref version, UnescapeNewlines, "Assembly version");
|
||||
|
||||
syntax.DefineOption(TitleOptionName, ref title, "Assembly title");
|
||||
syntax.DefineOption(TitleOptionName, ref title, UnescapeNewlines, "Assembly title");
|
||||
|
||||
syntax.DefineOption(DescriptionOptionName, ref description, "Assembly description");
|
||||
syntax.DefineOption(DescriptionOptionName, ref description, UnescapeNewlines, "Assembly description");
|
||||
|
||||
syntax.DefineOption(CopyrightOptionName, ref copyright, "Assembly copyright");
|
||||
syntax.DefineOption(CopyrightOptionName, ref copyright, UnescapeNewlines, "Assembly copyright");
|
||||
|
||||
syntax.DefineOption(NeutralCultureOptionName, ref neutralCulture, "Assembly neutral culture");
|
||||
syntax.DefineOption(NeutralCultureOptionName, ref neutralCulture, UnescapeNewlines, "Assembly neutral culture");
|
||||
|
||||
syntax.DefineOption(CultureOptionName, ref culture, "Assembly culture");
|
||||
syntax.DefineOption(CultureOptionName, ref culture, UnescapeNewlines, "Assembly culture");
|
||||
|
||||
syntax.DefineOption(InformationalVersionOptionName, ref informationalVersion, "Assembly informational version");
|
||||
syntax.DefineOption(InformationalVersionOptionName, ref informationalVersion, UnescapeNewlines, "Assembly informational version");
|
||||
|
||||
syntax.DefineOption(AssemblyFileVersionOptionName, ref fileVersion, "Assembly title");
|
||||
syntax.DefineOption(AssemblyFileVersionOptionName, ref fileVersion, UnescapeNewlines, "Assembly title");
|
||||
|
||||
syntax.DefineOption(TargetFrameworkOptionName, ref targetFramework, UnescapeNewlines, "Assembly target framework");
|
||||
|
||||
return new AssemblyInfoOptions()
|
||||
{
|
||||
|
@ -91,7 +113,8 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
NeutralLanguage = neutralCulture,
|
||||
Description = description,
|
||||
InformationalVersion = informationalVersion,
|
||||
Title = title
|
||||
Title = title,
|
||||
TargetFramework = targetFramework
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -131,13 +154,26 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
{
|
||||
options.Add(FormatOption(NeutralCultureOptionName, assemblyInfoOptions.NeutralLanguage));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.TargetFramework))
|
||||
{
|
||||
options.Add(FormatOption(TargetFrameworkOptionName, assemblyInfoOptions.TargetFramework));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static string FormatOption(string optionName, string value)
|
||||
{
|
||||
return $"--{optionName}:{value}";
|
||||
return $"--{optionName}:{EscapeNewlines(value)}";
|
||||
}
|
||||
|
||||
private static string UnescapeNewlines(string text)
|
||||
{
|
||||
return text.Replace("\\r", "\r").Replace("\\n", "\n");
|
||||
}
|
||||
private static string EscapeNewlines(string text)
|
||||
{
|
||||
return text.Replace("\r", "\\r").Replace("\n", "\\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
"version": "1.0.0-*",
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"System.Reflection": "4.0.10-rc2-23608",
|
||||
"System.Reflection": "4.0.10-rc2-23616",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.CommandLine": "0.1.0-*",
|
||||
"Microsoft.CodeAnalysis.CSharp": "1.1.1",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Runtime.Loader": "4.0.0-rc2-23608"
|
||||
"System.Runtime.Loader": "4.0.0-rc2-23616"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.CodeAnalysis.CSharp.Workspaces": "1.1.0-*"
|
||||
},
|
||||
|
|
|
@ -2,17 +2,16 @@
|
|||
"version": "1.0.0-*",
|
||||
"description": "Types to model a .NET Project",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"System.Threading.Thread": "4.0.0-rc2-23608",
|
||||
"System.Runtime.Loader": "4.0.0-rc2-23608",
|
||||
"System.Dynamic.Runtime": "4.0.11-rc2-23608",
|
||||
"System.Security.Cryptography.Algorithms": "4.0.0-rc2-23608",
|
||||
"Microsoft.CSharp": "4.0.1-rc2-23608",
|
||||
"System.Xml.XDocument": "4.0.11-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.Threading.Thread": "4.0.0-rc2-23616",
|
||||
"System.Runtime.Loader": "4.0.0-rc2-23616",
|
||||
"System.Dynamic.Runtime": "4.0.11-rc2-23616",
|
||||
"System.Security.Cryptography.Algorithms": "4.0.0-rc2-23616",
|
||||
"Microsoft.CSharp": "4.0.1-rc2-23616",
|
||||
"System.Xml.XDocument": "4.0.11-rc2-23616",
|
||||
"NuGet.Packaging": "3.3.0-*",
|
||||
|
||||
"Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15791",
|
||||
"Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15882",
|
||||
"Microsoft.Extensions.JsonParser.Sources": {
|
||||
"type": "build",
|
||||
"version": "1.0.0-*"
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
},
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library" : "1.0.0-rc2-23608",
|
||||
"Microsoft.NETCore.Runtime": "1.0.1-beta-23504"
|
||||
"NETStandard.Library" : "1.0.0-rc2-23616"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.Net.Compilers.netcore": "1.2.0-beta-20151117-04",
|
||||
"Microsoft.Net.Compilers.netcore": "1.2.0-beta-20151215-01",
|
||||
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
|
|||
}
|
||||
else if (config.OS == OSMode.Mac)
|
||||
{
|
||||
throw new NotImplementedException("Mac RyuJit not supported");
|
||||
stepList.Add(new MacRyuJitCompileStep(config));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -102,18 +102,6 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
|
|||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
||||
// Needs System.Native.so in output
|
||||
var sharedLibPath = Path.Combine(config.IlcPath, "System.Native.so");
|
||||
var outputSharedLibPath = Path.Combine(config.OutputDirectory, "System.Native.so");
|
||||
try
|
||||
{
|
||||
File.Copy(sharedLibPath, outputSharedLibPath);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Reporter.Error.WriteLine("Unable to copy System.Native.so to output");
|
||||
}
|
||||
|
||||
return result.ExitCode;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler.Native
|
||||
{
|
||||
public class MacLinkStep : IPlatformNativeStep
|
||||
{
|
||||
public int Invoke()
|
||||
{
|
||||
throw new NotImplementedException("Mac linker Not supported yet.");
|
||||
}
|
||||
|
||||
public bool CheckPreReqs()
|
||||
{
|
||||
throw new NotImplementedException("Mac linker Not supported yet.");
|
||||
}
|
||||
|
||||
public string DetermineOutputFile(NativeCompileSettings config)
|
||||
{
|
||||
throw new NotImplementedException("Mac linker Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler.Native
|
||||
{
|
||||
public class MacRyuJitCompileStep : IPlatformNativeStep
|
||||
{
|
||||
private readonly string CompilerName = "clang";
|
||||
private readonly string InputExtension = ".obj";
|
||||
|
||||
private readonly string CompilerOutputExtension = "";
|
||||
|
||||
// TODO: debug/release support
|
||||
private readonly string cflags = "-g -lstdc++ -Wno-invalid-offsetof -pthread -ldl -lm -liconv";
|
||||
|
||||
private readonly string[] libs = new string[]
|
||||
{
|
||||
"libbootstrapper.a",
|
||||
"libRuntime.a",
|
||||
"libSystem.Private.CoreLib.Native.a"
|
||||
};
|
||||
|
||||
private readonly string[] appdeplibs = new string[]
|
||||
{
|
||||
"libSystem.Native.a"
|
||||
};
|
||||
|
||||
|
||||
private string CompilerArgStr { get; set; }
|
||||
private NativeCompileSettings config;
|
||||
|
||||
public MacRyuJitCompileStep(NativeCompileSettings config)
|
||||
{
|
||||
this.config = config;
|
||||
InitializeArgs(config);
|
||||
}
|
||||
|
||||
public int Invoke()
|
||||
{
|
||||
var result = InvokeCompiler();
|
||||
if (result != 0)
|
||||
{
|
||||
Reporter.Error.WriteLine("Compilation of intermediate files failed.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool CheckPreReqs()
|
||||
{
|
||||
// TODO check for clang
|
||||
return true;
|
||||
}
|
||||
|
||||
private void InitializeArgs(NativeCompileSettings config)
|
||||
{
|
||||
var argsList = new List<string>();
|
||||
|
||||
// Flags
|
||||
argsList.Add(cflags);
|
||||
|
||||
// Add Stubs
|
||||
argsList.Add("-I "+Path.Combine(config.AppDepSDKPath, "CPPSdk/osx.10.10"));
|
||||
argsList.Add("-I "+Path.Combine(config.AppDepSDKPath, "CPPSdk"));
|
||||
argsList.Add(Path.Combine(config.AppDepSDKPath, "CPPSdk/osx.10.10/osxstubs.cpp"));
|
||||
|
||||
// Input File
|
||||
var inLibFile = DetermineInFile(config);
|
||||
argsList.Add("-Xlinker "+inLibFile);
|
||||
|
||||
// Libs
|
||||
foreach (var lib in libs)
|
||||
{
|
||||
var libPath = Path.Combine(config.IlcPath, lib);
|
||||
argsList.Add("-Xlinker "+libPath);
|
||||
}
|
||||
|
||||
// AppDep Libs
|
||||
var baseAppDepLibPath = Path.Combine(config.AppDepSDKPath, "CPPSdk/osx.10.10", config.Architecture.ToString());
|
||||
foreach (var lib in appdeplibs)
|
||||
{
|
||||
var appDepLibPath = Path.Combine(baseAppDepLibPath, lib);
|
||||
argsList.Add("-Xlinker "+appDepLibPath);
|
||||
}
|
||||
|
||||
// Output
|
||||
var libOut = DetermineOutputFile(config);
|
||||
argsList.Add($"-o \"{libOut}\"");
|
||||
|
||||
this.CompilerArgStr = string.Join(" ", argsList);
|
||||
}
|
||||
|
||||
private int InvokeCompiler()
|
||||
{
|
||||
var result = Command.Create(CompilerName, CompilerArgStr)
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
||||
return result.ExitCode;
|
||||
}
|
||||
|
||||
private string DetermineInFile(NativeCompileSettings config)
|
||||
{
|
||||
var intermediateDirectory = config.IntermediateDirectory;
|
||||
|
||||
var filename = Path.GetFileNameWithoutExtension(config.InputManagedAssemblyPath);
|
||||
|
||||
var infile = Path.Combine(intermediateDirectory, filename + InputExtension);
|
||||
|
||||
return infile;
|
||||
}
|
||||
|
||||
public string DetermineOutputFile(NativeCompileSettings config)
|
||||
{
|
||||
var intermediateDirectory = config.OutputDirectory;
|
||||
|
||||
var filename = Path.GetFileNameWithoutExtension(config.InputManagedAssemblyPath);
|
||||
|
||||
var outfile = Path.Combine(intermediateDirectory, filename + CompilerOutputExtension);
|
||||
|
||||
return outfile;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,7 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
|
|
@ -279,9 +279,6 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
return false;
|
||||
}
|
||||
|
||||
// Dump dependency data
|
||||
ShowDependencyInfo(dependencies);
|
||||
|
||||
// Get compilation options
|
||||
var outputName = GetProjectOutput(context.ProjectFile, context.TargetFramework, configuration, outputPath);
|
||||
|
||||
|
@ -311,7 +308,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
compilerArgs.AddRange(compilationOptions.SerializeToArgs());
|
||||
|
||||
// Add metadata options
|
||||
compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context.ProjectFile)));
|
||||
compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context)));
|
||||
|
||||
foreach (var dependency in dependencies)
|
||||
{
|
||||
|
@ -825,37 +822,6 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
}
|
||||
}
|
||||
|
||||
private static void ShowDependencyInfo(IEnumerable<LibraryExport> dependencies)
|
||||
{
|
||||
if (CommandContext.IsVerbose())
|
||||
{
|
||||
foreach (var dependency in dependencies)
|
||||
{
|
||||
if (!dependency.Library.Resolved)
|
||||
{
|
||||
Reporter.Verbose.WriteLine($" Unable to resolve dependency {dependency.Library.Identity.ToString().Red().Bold()}");
|
||||
Reporter.Verbose.WriteLine("");
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter.Verbose.WriteLine($" Using {dependency.Library.Identity.Type.Value.Cyan().Bold()} dependency {dependency.Library.Identity.ToString().Cyan().Bold()}");
|
||||
Reporter.Verbose.WriteLine($" Path: {dependency.Library.Path}");
|
||||
|
||||
foreach (var metadataReference in dependency.CompilationAssemblies)
|
||||
{
|
||||
Reporter.Verbose.WriteLine($" Assembly: {metadataReference}");
|
||||
}
|
||||
|
||||
foreach (var sourceReference in dependency.SourceReferences)
|
||||
{
|
||||
Reporter.Verbose.WriteLine($" Source: {sourceReference}");
|
||||
}
|
||||
Reporter.Verbose.WriteLine("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyFiles(IEnumerable<LibraryAsset> files, string outputPath)
|
||||
{
|
||||
foreach (var file in files)
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.Reflection.Metadata": "1.1.0",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
},
|
||||
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Runtime": "1.0.1-beta-*",
|
||||
"System.IO": "4.0.11-beta-*",
|
||||
"System.Console": "4.0.0-beta-*",
|
||||
"System.Runtime": "4.0.21-beta-*"
|
||||
"NETStandard.Library": "1.0.0-rc2-23616"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
|
||||
"System.Linq": "4.0.1-beta-23504",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
|
|
422
src/Microsoft.DotNet.Tools.Pack/PackageGenerator.cs
Normal file
422
src/Microsoft.DotNet.Tools.Pack/PackageGenerator.cs
Normal file
|
@ -0,0 +1,422 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
|
||||
using NuGet;
|
||||
using NuGet.Frameworks;
|
||||
using NuGet.Packaging.Core;
|
||||
using NuGet.Versioning;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
public class PackageGenerator
|
||||
{
|
||||
protected Project Project { get; }
|
||||
|
||||
protected string Configuration { get; }
|
||||
|
||||
protected string OutputPath { get; }
|
||||
|
||||
protected PackageBuilder PackageBuilder { get; private set; }
|
||||
|
||||
public PackageGenerator(Project project, string configuration, string outputPath)
|
||||
{
|
||||
Project = project;
|
||||
Configuration = configuration;
|
||||
OutputPath = outputPath;
|
||||
}
|
||||
|
||||
public bool BuildPackage(IEnumerable<ProjectContext> contexts, List<DiagnosticMessage> packDiagnostics)
|
||||
{
|
||||
|
||||
Reporter.Output.WriteLine($"Producing nuget package \"{GetPackageName()}\" for {Project.Name}");
|
||||
|
||||
PackageBuilder = CreatePackageBuilder(Project);
|
||||
|
||||
// TODO: Report errors for required fields
|
||||
// id
|
||||
// author
|
||||
// description
|
||||
foreach (var context in contexts)
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Processing {context.TargetFramework.ToString().Yellow()}");
|
||||
ProcessContext(context);
|
||||
Reporter.Verbose.WriteLine("");
|
||||
}
|
||||
|
||||
var packageOutputPath = Path.Combine(GetOutputPath(), GetPackageName() + NuGet.Constants.PackageExtension);
|
||||
|
||||
if (GeneratePackage(packageOutputPath, packDiagnostics))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void ProcessContext(ProjectContext context)
|
||||
{
|
||||
PopulateDependencies(context);
|
||||
|
||||
var outputPath = GetOutputPath(context);
|
||||
var outputName = GetProjectOutputName(context.TargetFramework);
|
||||
|
||||
var resourceCultures = context.ProjectFile.Files.ResourceFiles
|
||||
.Select(resourceFile => ResourceUtility.GetResourceCultureName(resourceFile.Key))
|
||||
.Distinct();
|
||||
|
||||
foreach (var culture in resourceCultures)
|
||||
{
|
||||
if (string.IsNullOrEmpty(culture))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var resourceFilePath = Path.Combine(culture, $"{Project.Name}.resources.dll");
|
||||
TryAddOutputFile(context, outputPath, resourceFilePath);
|
||||
}
|
||||
|
||||
TryAddOutputFile(context, outputPath, outputName);
|
||||
TryAddOutputFile(context, outputPath, $"{Project.Name}.xml");
|
||||
}
|
||||
|
||||
protected virtual bool GeneratePackage(string nupkg, List<DiagnosticMessage> packDiagnostics)
|
||||
{
|
||||
foreach (var sharedFile in Project.Files.SharedFiles)
|
||||
{
|
||||
var file = new PhysicalPackageFile();
|
||||
file.SourcePath = sharedFile;
|
||||
file.TargetPath = Path.Combine("shared", Path.GetFileName(sharedFile));
|
||||
PackageBuilder.Files.Add(file);
|
||||
}
|
||||
|
||||
if (Project.Files.PackInclude != null && Project.Files.PackInclude.Any())
|
||||
{
|
||||
AddPackageFiles(Project.Files.PackInclude, packDiagnostics);
|
||||
}
|
||||
|
||||
// Write the packages as long as we're still in a success state.
|
||||
if (!packDiagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error))
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Adding package files");
|
||||
foreach (var file in PackageBuilder.Files.OfType<PhysicalPackageFile>())
|
||||
{
|
||||
if (file.SourcePath != null && File.Exists(file.SourcePath))
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Adding {file.Path.Yellow()}");
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(nupkg));
|
||||
|
||||
using (var fs = File.Create(nupkg))
|
||||
{
|
||||
PackageBuilder.Save(fs);
|
||||
Reporter.Output.WriteLine($"{Project.Name} -> {Path.GetFullPath(nupkg)}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void AddPackageFiles(IEnumerable<PackIncludeEntry> packageFiles, IList<DiagnosticMessage> diagnostics)
|
||||
{
|
||||
var rootDirectory = new DirectoryInfoWrapper(new DirectoryInfo(Project.ProjectDirectory));
|
||||
|
||||
foreach (var match in CollectAdditionalFiles(rootDirectory, packageFiles, Project.ProjectFilePath, diagnostics))
|
||||
{
|
||||
PackageBuilder.Files.Add(match);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<PhysicalPackageFile> CollectAdditionalFiles(DirectoryInfoBase rootDirectory, IEnumerable<PackIncludeEntry> projectFileGlobs, string projectFilePath, IList<DiagnosticMessage> diagnostics)
|
||||
{
|
||||
foreach (var entry in projectFileGlobs)
|
||||
{
|
||||
// Evaluate the globs on the right
|
||||
var matcher = new Matcher();
|
||||
matcher.AddIncludePatterns(entry.SourceGlobs);
|
||||
var results = matcher.Execute(rootDirectory);
|
||||
var files = results.Files.ToList();
|
||||
|
||||
// Check for illegal characters
|
||||
if (string.IsNullOrEmpty(entry.Target))
|
||||
{
|
||||
diagnostics.Add(new DiagnosticMessage(
|
||||
ErrorCodes.NU1003,
|
||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. The target '{entry.Target}' is invalid, " +
|
||||
"targets must either be a file name or a directory suffixed with '/'. " +
|
||||
"The root directory of the package can be specified by using a single '/' character.",
|
||||
projectFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
entry.Line,
|
||||
entry.Column));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.Target.Split('/').Any(s => s.Equals(".") || s.Equals("..")))
|
||||
{
|
||||
diagnostics.Add(new DiagnosticMessage(
|
||||
ErrorCodes.NU1004,
|
||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
|
||||
$"The target '{entry.Target}' contains path-traversal characters ('.' or '..'). " +
|
||||
"These characters are not permitted in target paths.",
|
||||
projectFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
entry.Line,
|
||||
entry.Column));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the arity of the left
|
||||
if (entry.Target.EndsWith("/"))
|
||||
{
|
||||
var dir = entry.Target.Substring(0, entry.Target.Length - 1).Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
yield return new PhysicalPackageFile()
|
||||
{
|
||||
SourcePath = Path.Combine(rootDirectory.FullName, PathUtility.GetPathWithDirectorySeparator(file.Path)),
|
||||
TargetPath = Path.Combine(dir, PathUtility.GetPathWithDirectorySeparator(file.Stem))
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a file. If the glob matched multiple things, we're sad :(
|
||||
if (files.Count > 1)
|
||||
{
|
||||
// Arity mismatch!
|
||||
string sourceValue = entry.SourceGlobs.Length == 1 ?
|
||||
$"\"{entry.SourceGlobs[0]}\"" :
|
||||
("[" + string.Join(",", entry.SourceGlobs.Select(v => $"\"{v}\"")) + "]");
|
||||
diagnostics.Add(new DiagnosticMessage(
|
||||
ErrorCodes.NU1005,
|
||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
|
||||
$"The target '{entry.Target}' refers to a single file, but the pattern {sourceValue} " +
|
||||
"produces multiple files. To mark the target as a directory, suffix it with '/'.",
|
||||
projectFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
entry.Line,
|
||||
entry.Column));
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new PhysicalPackageFile()
|
||||
{
|
||||
SourcePath = Path.Combine(rootDirectory.FullName, files[0].Path),
|
||||
TargetPath = PathUtility.GetPathWithDirectorySeparator(entry.Target)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void TryAddOutputFile(ProjectContext context,
|
||||
string outputPath,
|
||||
string filePath)
|
||||
{
|
||||
var targetPath = Path.Combine("lib", context.TargetFramework.GetTwoDigitShortFolderName(), filePath);
|
||||
var sourcePath = Path.Combine(outputPath, filePath);
|
||||
|
||||
if (!File.Exists(sourcePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PackageBuilder.Files.Add(new PhysicalPackageFile
|
||||
{
|
||||
SourcePath = sourcePath,
|
||||
TargetPath = targetPath
|
||||
});
|
||||
}
|
||||
|
||||
private void PopulateDependencies(ProjectContext context)
|
||||
{
|
||||
var dependencies = new List<PackageDependency>();
|
||||
var project = context.RootProject;
|
||||
|
||||
foreach (var dependency in project.Dependencies)
|
||||
{
|
||||
if (!dependency.HasFlag(LibraryDependencyTypeFlag.BecomesNupkgDependency))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Efficiency
|
||||
var dependencyDescription = context.LibraryManager.GetLibraries().First(l => l.RequestedRanges.Contains(dependency));
|
||||
|
||||
// REVIEW: Can we get this far with unresolved dependencies
|
||||
if (dependencyDescription == null || !dependencyDescription.Resolved)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dependencyDescription.Identity.Type == LibraryType.Project &&
|
||||
((ProjectDescription)dependencyDescription).Project.EmbedInteropTypes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dependency.Target == LibraryType.ReferenceAssembly)
|
||||
{
|
||||
PackageBuilder.FrameworkAssemblies.Add(new FrameworkAssemblyReference(dependency.Name, new[] { context.TargetFramework }));
|
||||
|
||||
Reporter.Verbose.WriteLine($"Adding framework assembly {dependency.Name.Yellow()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionRange dependencyVersion = null;
|
||||
|
||||
if (dependency.VersionRange == null ||
|
||||
dependency.VersionRange.IsFloating)
|
||||
{
|
||||
dependencyVersion = new VersionRange(dependencyDescription.Identity.Version);
|
||||
}
|
||||
else
|
||||
{
|
||||
dependencyVersion = dependency.VersionRange;
|
||||
}
|
||||
|
||||
Reporter.Verbose.WriteLine($"Adding dependency {dependency.Name.Yellow()} {VersionUtility.RenderVersion(dependencyVersion).Yellow()}");
|
||||
|
||||
dependencies.Add(new PackageDependency(dependency.Name, dependencyVersion));
|
||||
}
|
||||
}
|
||||
|
||||
PackageBuilder.DependencySets.Add(new PackageDependencySet(context.TargetFramework, dependencies));
|
||||
}
|
||||
|
||||
protected virtual string GetPackageName()
|
||||
{
|
||||
return $"{Project.Name}.{Project.Version}";
|
||||
}
|
||||
|
||||
private string GetProjectOutputName(NuGetFramework framework)
|
||||
{
|
||||
var compilationOptions = Project.GetCompilerOptions(framework, Configuration);
|
||||
var outputExtension = ".dll";
|
||||
|
||||
if (framework.IsDesktop() && compilationOptions.EmitEntryPoint.GetValueOrDefault())
|
||||
{
|
||||
outputExtension = ".exe";
|
||||
}
|
||||
|
||||
return Project.Name + outputExtension;
|
||||
}
|
||||
|
||||
protected string GetOutputPath()
|
||||
{
|
||||
var outputPath = string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(OutputPath))
|
||||
{
|
||||
outputPath = Path.Combine(
|
||||
GetDefaultRootOutputPath(Project, OutputPath),
|
||||
Cli.Utils.Constants.BinDirectoryName,
|
||||
Configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputPath = OutputPath;
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
protected string GetOutputPath(ProjectContext context)
|
||||
{
|
||||
var outputPath = string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(OutputPath))
|
||||
{
|
||||
outputPath = Path.Combine(
|
||||
GetDefaultRootOutputPath(context.ProjectFile, OutputPath),
|
||||
Cli.Utils.Constants.BinDirectoryName,
|
||||
Configuration,
|
||||
context.TargetFramework.GetTwoDigitShortFolderName());
|
||||
}
|
||||
else
|
||||
{
|
||||
outputPath = OutputPath;
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
private static string GetDefaultRootOutputPath(Project project, string outputOptionValue)
|
||||
{
|
||||
string rootOutputPath = string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(outputOptionValue))
|
||||
{
|
||||
rootOutputPath = project.ProjectDirectory;
|
||||
}
|
||||
|
||||
return rootOutputPath;
|
||||
}
|
||||
|
||||
private static PackageBuilder CreatePackageBuilder(Project project)
|
||||
{
|
||||
var builder = new PackageBuilder();
|
||||
builder.Authors.AddRange(project.Authors);
|
||||
builder.Owners.AddRange(project.Owners);
|
||||
|
||||
if (builder.Authors.Count == 0)
|
||||
{
|
||||
var defaultAuthor = Environment.GetEnvironmentVariable("NUGET_AUTHOR");
|
||||
if (string.IsNullOrEmpty(defaultAuthor))
|
||||
{
|
||||
builder.Authors.Add(project.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Authors.Add(defaultAuthor);
|
||||
}
|
||||
}
|
||||
|
||||
builder.Description = project.Description ?? project.Name;
|
||||
builder.Id = project.Name;
|
||||
builder.Version = project.Version;
|
||||
builder.Title = project.Title;
|
||||
builder.Summary = project.Summary;
|
||||
builder.Copyright = project.Copyright;
|
||||
builder.RequireLicenseAcceptance = project.RequireLicenseAcceptance;
|
||||
builder.ReleaseNotes = project.ReleaseNotes;
|
||||
builder.Language = project.Language;
|
||||
builder.Tags.AddRange(project.Tags);
|
||||
|
||||
if (!string.IsNullOrEmpty(project.IconUrl))
|
||||
{
|
||||
builder.IconUrl = new Uri(project.IconUrl);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(project.ProjectUrl))
|
||||
{
|
||||
builder.ProjectUrl = new Uri(project.ProjectUrl);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(project.LicenseUrl))
|
||||
{
|
||||
builder.LicenseUrl = new Uri(project.LicenseUrl);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -7,17 +7,8 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using NuGet;
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using NuGet.Packaging.Core;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using NuGet.Versioning;
|
||||
using NuGet.Frameworks;
|
||||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
|
@ -121,392 +112,13 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
}
|
||||
}
|
||||
|
||||
Reporter.Output.WriteLine($"Producing nuget package for {project.Name}");
|
||||
|
||||
var packDiagnostics = new List<DiagnosticMessage>();
|
||||
|
||||
// Things compiled now build the package
|
||||
var packageBuilder = CreatePackageBuilder(project);
|
||||
var mainPackageGenerator = new PackageGenerator(project, configuration, outputValue);
|
||||
var symbolsPackageGenerator = new SymbolPackageGenerator(project, configuration, outputValue);
|
||||
|
||||
// TODO: Report errors for required fields
|
||||
// id
|
||||
// author
|
||||
// description
|
||||
foreach (var context in contexts)
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Processing {context.TargetFramework.ToString().Yellow()}");
|
||||
PopulateDependencies(context, packageBuilder);
|
||||
|
||||
var outputPath = GetOutputPath(context, configuration, outputValue);
|
||||
var outputName = GetProjectOutputName(context.ProjectFile, context.TargetFramework, configuration);
|
||||
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, outputName);
|
||||
|
||||
var resourceCultures = context.ProjectFile.Files.ResourceFiles
|
||||
.Select(resourceFile => ResourceUtility.GetResourceCultureName(resourceFile.Key))
|
||||
.Distinct();
|
||||
|
||||
foreach (var culture in resourceCultures)
|
||||
{
|
||||
if (string.IsNullOrEmpty(culture))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var resourceFilePath = Path.Combine(culture, $"{project.Name}.resources.dll");
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, resourceFilePath);
|
||||
}
|
||||
|
||||
// REVIEW: Do we keep making symbols packages?
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.pdb");
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.mdb");
|
||||
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.xml");
|
||||
|
||||
Reporter.Verbose.WriteLine("");
|
||||
}
|
||||
|
||||
var rootOutputPath = GetOutputPath(project, configuration, outputValue);
|
||||
var packageOutputPath = GetPackagePath(project, rootOutputPath);
|
||||
|
||||
if (GeneratePackage(project, packageBuilder, packageOutputPath, packDiagnostics))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool GeneratePackage(Project project, PackageBuilder packageBuilder, string nupkg, List<DiagnosticMessage> packDiagnostics)
|
||||
{
|
||||
foreach (var sharedFile in project.Files.SharedFiles)
|
||||
{
|
||||
var file = new PhysicalPackageFile();
|
||||
file.SourcePath = sharedFile;
|
||||
file.TargetPath = Path.Combine("shared", Path.GetFileName(sharedFile));
|
||||
packageBuilder.Files.Add(file);
|
||||
}
|
||||
|
||||
var root = project.ProjectDirectory;
|
||||
|
||||
if (project.Files.PackInclude != null && project.Files.PackInclude.Any())
|
||||
{
|
||||
AddPackageFiles(project, project.Files.PackInclude, packageBuilder, packDiagnostics);
|
||||
}
|
||||
|
||||
// Write the packages as long as we're still in a success state.
|
||||
if (!packDiagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error))
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Adding package files");
|
||||
foreach (var file in packageBuilder.Files.OfType<PhysicalPackageFile>())
|
||||
{
|
||||
if (file.SourcePath != null && File.Exists(file.SourcePath))
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Adding {file.Path.Yellow()}");
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(nupkg));
|
||||
|
||||
using (var fs = File.Create(nupkg))
|
||||
{
|
||||
packageBuilder.Save(fs);
|
||||
Reporter.Output.WriteLine($"{project.Name} -> {Path.GetFullPath(nupkg)}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void AddPackageFiles(Project project, IEnumerable<PackIncludeEntry> packageFiles, PackageBuilder packageBuilder, IList<DiagnosticMessage> diagnostics)
|
||||
{
|
||||
var rootDirectory = new DirectoryInfoWrapper(new DirectoryInfo(project.ProjectDirectory));
|
||||
|
||||
foreach (var match in CollectAdditionalFiles(rootDirectory, packageFiles, project.ProjectFilePath, diagnostics))
|
||||
{
|
||||
packageBuilder.Files.Add(match);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<PhysicalPackageFile> CollectAdditionalFiles(DirectoryInfoBase rootDirectory, IEnumerable<PackIncludeEntry> projectFileGlobs, string projectFilePath, IList<DiagnosticMessage> diagnostics)
|
||||
{
|
||||
foreach (var entry in projectFileGlobs)
|
||||
{
|
||||
// Evaluate the globs on the right
|
||||
var matcher = new Matcher();
|
||||
matcher.AddIncludePatterns(entry.SourceGlobs);
|
||||
var results = matcher.Execute(rootDirectory);
|
||||
var files = results.Files.ToList();
|
||||
|
||||
// Check for illegal characters
|
||||
if (string.IsNullOrEmpty(entry.Target))
|
||||
{
|
||||
diagnostics.Add(new DiagnosticMessage(
|
||||
ErrorCodes.NU1003,
|
||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. The target '{entry.Target}' is invalid, " +
|
||||
"targets must either be a file name or a directory suffixed with '/'. " +
|
||||
"The root directory of the package can be specified by using a single '/' character.",
|
||||
projectFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
entry.Line,
|
||||
entry.Column));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.Target.Split('/').Any(s => s.Equals(".") || s.Equals("..")))
|
||||
{
|
||||
diagnostics.Add(new DiagnosticMessage(
|
||||
ErrorCodes.NU1004,
|
||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
|
||||
$"The target '{entry.Target}' contains path-traversal characters ('.' or '..'). " +
|
||||
"These characters are not permitted in target paths.",
|
||||
projectFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
entry.Line,
|
||||
entry.Column));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the arity of the left
|
||||
if (entry.Target.EndsWith("/"))
|
||||
{
|
||||
var dir = entry.Target.Substring(0, entry.Target.Length - 1).Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
yield return new PhysicalPackageFile()
|
||||
{
|
||||
SourcePath = Path.Combine(rootDirectory.FullName, PathUtility.GetPathWithDirectorySeparator(file.Path)),
|
||||
TargetPath = Path.Combine(dir, PathUtility.GetPathWithDirectorySeparator(file.Stem))
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a file. If the glob matched multiple things, we're sad :(
|
||||
if (files.Count > 1)
|
||||
{
|
||||
// Arity mismatch!
|
||||
string sourceValue = entry.SourceGlobs.Length == 1 ?
|
||||
$"\"{entry.SourceGlobs[0]}\"" :
|
||||
("[" + string.Join(",", entry.SourceGlobs.Select(v => $"\"{v}\"")) + "]");
|
||||
diagnostics.Add(new DiagnosticMessage(
|
||||
ErrorCodes.NU1005,
|
||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
|
||||
$"The target '{entry.Target}' refers to a single file, but the pattern {sourceValue} " +
|
||||
"produces multiple files. To mark the target as a directory, suffix it with '/'.",
|
||||
projectFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
entry.Line,
|
||||
entry.Column));
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new PhysicalPackageFile()
|
||||
{
|
||||
SourcePath = Path.Combine(rootDirectory.FullName, files[0].Path),
|
||||
TargetPath = PathUtility.GetPathWithDirectorySeparator(entry.Target)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryAddOutputFile(PackageBuilder packageBuilder,
|
||||
ProjectContext context,
|
||||
string outputPath,
|
||||
string filePath)
|
||||
{
|
||||
var targetPath = Path.Combine("lib", context.TargetFramework.GetTwoDigitShortFolderName(), filePath);
|
||||
var sourcePath = Path.Combine(outputPath, filePath);
|
||||
|
||||
if (!File.Exists(sourcePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
packageBuilder.Files.Add(new PhysicalPackageFile
|
||||
{
|
||||
SourcePath = sourcePath,
|
||||
TargetPath = targetPath
|
||||
});
|
||||
}
|
||||
|
||||
public static void PopulateDependencies(ProjectContext context, PackageBuilder packageBuilder)
|
||||
{
|
||||
var dependencies = new List<PackageDependency>();
|
||||
var project = context.RootProject;
|
||||
|
||||
foreach (var dependency in project.Dependencies)
|
||||
{
|
||||
if (!dependency.HasFlag(LibraryDependencyTypeFlag.BecomesNupkgDependency))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Efficiency
|
||||
var dependencyDescription = context.LibraryManager.GetLibraries().First(l => l.RequestedRanges.Contains(dependency));
|
||||
|
||||
// REVIEW: Can we get this far with unresolved dependencies
|
||||
if (dependencyDescription == null || !dependencyDescription.Resolved)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dependencyDescription.Identity.Type == LibraryType.Project &&
|
||||
((ProjectDescription)dependencyDescription).Project.EmbedInteropTypes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dependency.Target == LibraryType.ReferenceAssembly)
|
||||
{
|
||||
packageBuilder.FrameworkAssemblies.Add(new FrameworkAssemblyReference(dependency.Name, new[] { context.TargetFramework }));
|
||||
|
||||
Reporter.Verbose.WriteLine($"Adding framework assembly {dependency.Name.Yellow()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionRange dependencyVersion = null;
|
||||
|
||||
if (dependency.VersionRange == null ||
|
||||
dependency.VersionRange.IsFloating)
|
||||
{
|
||||
dependencyVersion = new VersionRange(dependencyDescription.Identity.Version);
|
||||
}
|
||||
else
|
||||
{
|
||||
dependencyVersion = dependency.VersionRange;
|
||||
}
|
||||
|
||||
Reporter.Verbose.WriteLine($"Adding dependency {dependency.Name.Yellow()} {VersionUtility.RenderVersion(dependencyVersion).Yellow()}");
|
||||
|
||||
dependencies.Add(new PackageDependency(dependency.Name, dependencyVersion));
|
||||
}
|
||||
}
|
||||
|
||||
packageBuilder.DependencySets.Add(new PackageDependencySet(context.TargetFramework, dependencies));
|
||||
}
|
||||
|
||||
private static string GetPackagePath(Project project, string outputPath, bool symbols = false)
|
||||
{
|
||||
string fileName = $"{project.Name}.{project.Version}{(symbols ? ".symbols" : string.Empty)}{NuGet.Constants.PackageExtension}";
|
||||
return Path.Combine(outputPath, fileName);
|
||||
}
|
||||
|
||||
private static PackageBuilder CreatePackageBuilder(Project project)
|
||||
{
|
||||
var builder = new PackageBuilder();
|
||||
builder.Authors.AddRange(project.Authors);
|
||||
builder.Owners.AddRange(project.Owners);
|
||||
|
||||
if (builder.Authors.Count == 0)
|
||||
{
|
||||
var defaultAuthor = Environment.GetEnvironmentVariable("NUGET_AUTHOR");
|
||||
if (string.IsNullOrEmpty(defaultAuthor))
|
||||
{
|
||||
builder.Authors.Add(project.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Authors.Add(defaultAuthor);
|
||||
}
|
||||
}
|
||||
|
||||
builder.Description = project.Description ?? project.Name;
|
||||
builder.Id = project.Name;
|
||||
builder.Version = project.Version;
|
||||
builder.Title = project.Title;
|
||||
builder.Summary = project.Summary;
|
||||
builder.Copyright = project.Copyright;
|
||||
builder.RequireLicenseAcceptance = project.RequireLicenseAcceptance;
|
||||
builder.ReleaseNotes = project.ReleaseNotes;
|
||||
builder.Language = project.Language;
|
||||
builder.Tags.AddRange(project.Tags);
|
||||
|
||||
if (!string.IsNullOrEmpty(project.IconUrl))
|
||||
{
|
||||
builder.IconUrl = new Uri(project.IconUrl);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(project.ProjectUrl))
|
||||
{
|
||||
builder.ProjectUrl = new Uri(project.ProjectUrl);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(project.LicenseUrl))
|
||||
{
|
||||
builder.LicenseUrl = new Uri(project.LicenseUrl);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
// REVIEW: This code copying kinda sucks
|
||||
private static string GetProjectOutputName(Project project, NuGetFramework framework, string configuration)
|
||||
{
|
||||
var compilationOptions = project.GetCompilerOptions(framework, configuration);
|
||||
var outputExtension = ".dll";
|
||||
|
||||
if (framework.IsDesktop() && compilationOptions.EmitEntryPoint.GetValueOrDefault())
|
||||
{
|
||||
outputExtension = ".exe";
|
||||
}
|
||||
|
||||
return project.Name + outputExtension;
|
||||
}
|
||||
|
||||
private static string GetOutputPath(Project project, string configuration, string outputOptionValue)
|
||||
{
|
||||
var outputPath = string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(outputOptionValue))
|
||||
{
|
||||
outputPath = Path.Combine(
|
||||
GetDefaultRootOutputPath(project, outputOptionValue),
|
||||
Cli.Utils.Constants.BinDirectoryName,
|
||||
configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputPath = outputOptionValue;
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
private static string GetOutputPath(ProjectContext context, string configuration, string outputOptionValue)
|
||||
{
|
||||
var outputPath = string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(outputOptionValue))
|
||||
{
|
||||
outputPath = Path.Combine(
|
||||
GetDefaultRootOutputPath(context.ProjectFile, outputOptionValue),
|
||||
Cli.Utils.Constants.BinDirectoryName,
|
||||
configuration,
|
||||
context.TargetFramework.GetTwoDigitShortFolderName());
|
||||
}
|
||||
else
|
||||
{
|
||||
outputPath = outputOptionValue;
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
private static string GetDefaultRootOutputPath(Project project, string outputOptionValue)
|
||||
{
|
||||
string rootOutputPath = string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(outputOptionValue))
|
||||
{
|
||||
rootOutputPath = project.ProjectDirectory;
|
||||
}
|
||||
|
||||
return rootOutputPath;
|
||||
return mainPackageGenerator.BuildPackage(contexts, packDiagnostics) &&
|
||||
symbolsPackageGenerator.BuildPackage(contexts, packDiagnostics);
|
||||
}
|
||||
}
|
||||
}
|
44
src/Microsoft.DotNet.Tools.Pack/SymbolPackageGenerator.cs
Normal file
44
src/Microsoft.DotNet.Tools.Pack/SymbolPackageGenerator.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
using NuGet;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
public class SymbolPackageGenerator: PackageGenerator
|
||||
{
|
||||
public SymbolPackageGenerator(Project project, string configuration, string outputPath) : base(project, configuration, outputPath)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string GetPackageName()
|
||||
{
|
||||
return $"{Project.Name}.{Project.Version}.symbols";
|
||||
}
|
||||
|
||||
protected override void ProcessContext(ProjectContext context)
|
||||
{
|
||||
base.ProcessContext(context);
|
||||
|
||||
var outputPath = GetOutputPath(context);
|
||||
TryAddOutputFile(context, outputPath, $"{Project.Name}.pdb");
|
||||
TryAddOutputFile(context, outputPath, $"{Project.Name}.mdb");
|
||||
}
|
||||
|
||||
protected override bool GeneratePackage(string nupkg, List<DiagnosticMessage> packDiagnostics)
|
||||
{
|
||||
foreach (var path in Project.Files.SourceFiles)
|
||||
{
|
||||
var srcFile = new PhysicalPackageFile();
|
||||
srcFile.SourcePath = path;
|
||||
srcFile.TargetPath = Path.Combine("src", Common.PathUtility.GetRelativePath(Project.ProjectDirectory, path));
|
||||
PackageBuilder.Files.Add(srcFile);
|
||||
}
|
||||
return base.GeneratePackage(nupkg, packDiagnostics);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.IO.Compression.ZipFile": "4.0.1-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.IO.Compression.ZipFile": "4.0.1-rc2-23616",
|
||||
|
||||
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
|
@ -24,8 +24,8 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postcompile": [
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.dll\"",
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.pdb\""
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.dll\"",
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.pdb\""
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using NuGet.Frameworks;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Publish
|
||||
{
|
||||
|
@ -30,58 +25,32 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
var runtime = app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Target runtime to publish for", CommandOptionType.SingleValue);
|
||||
var output = app.Option("-o|--output <OUTPUT_PATH>", "Path in which to publish the app", CommandOptionType.SingleValue);
|
||||
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
|
||||
var project = app.Argument("<PROJECT>", "The project to publish, defaults to the current directory. Can be a path to a project.json or a project directory");
|
||||
var projectPath = app.Argument("<PROJECT>", "The project to publish, defaults to the current directory. Can be a path to a project.json or a project directory");
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
NuGetFramework nugetframework = null;
|
||||
var publish = new PublishCommand();
|
||||
|
||||
if (framework.HasValue())
|
||||
publish.Framework = framework.Value();
|
||||
// TODO: Remove default once xplat publish is enabled.
|
||||
publish.Runtime = runtime.Value() ?? RuntimeIdentifier.Current;
|
||||
publish.OutputPath = output.Value();
|
||||
publish.Configuration = configuration.Value() ?? Constants.DefaultConfiguration;
|
||||
|
||||
publish.ProjectPath = projectPath.Value;
|
||||
if (string.IsNullOrEmpty(publish.ProjectPath))
|
||||
{
|
||||
nugetframework = NuGetFramework.Parse(framework.Value());
|
||||
|
||||
if (nugetframework.IsUnsupported)
|
||||
{
|
||||
Reporter.Output.WriteLine($"Unsupported framework {framework.Value()}.".Red());
|
||||
return 1;
|
||||
}
|
||||
publish.ProjectPath = Directory.GetCurrentDirectory();
|
||||
}
|
||||
|
||||
// TODO: Remove this once xplat publish is enabled.
|
||||
if (!runtime.HasValue())
|
||||
if (!publish.TryPrepareForPublish())
|
||||
{
|
||||
runtime.Values.Add(RuntimeIdentifier.Current);
|
||||
}
|
||||
|
||||
// Locate the project and get the name and full path
|
||||
var path = project.Value;
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
path = Directory.GetCurrentDirectory();
|
||||
}
|
||||
|
||||
var projectContexts = ProjectContext.CreateContextForEachTarget(path);
|
||||
projectContexts = GetMatchingProjectContexts(projectContexts, nugetframework, runtime.Value());
|
||||
|
||||
if (projectContexts.Count() == 0)
|
||||
{
|
||||
string errMsg = $"'{project.Value}' cannot be published";
|
||||
if (framework.HasValue() || runtime.HasValue())
|
||||
{
|
||||
errMsg += $" for '{framework.Value()}' '{runtime.Value()}'";
|
||||
}
|
||||
|
||||
Reporter.Output.WriteLine(errMsg.Red());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
foreach (var projectContext in projectContexts)
|
||||
{
|
||||
result += Publish(projectContext, output.Value(), configuration.Value() ?? Constants.DefaultConfiguration);
|
||||
}
|
||||
|
||||
return result;
|
||||
publish.PublishAllProjects();
|
||||
Reporter.Output.WriteLine($"Published {publish.NumberOfPublishedProjects}/{publish.NumberOfProjects} projects successfully");
|
||||
return (publish.NumberOfPublishedProjects == publish.NumberOfProjects) ? 0 : 1;
|
||||
});
|
||||
|
||||
try
|
||||
|
@ -90,151 +59,10 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(ex);
|
||||
#else
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
#endif
|
||||
Reporter.Error.WriteLine(ex.Message.Red());
|
||||
Reporter.Verbose.WriteLine(ex.ToString().Yellow());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckArg(CommandOption argument)
|
||||
{
|
||||
if (!argument.HasValue())
|
||||
{
|
||||
Reporter.Error.WriteLine($"Missing required argument: {argument.LongName.Red().Bold()}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// return the matching framework/runtime ProjectContext.
|
||||
// if 'nugetframework' or 'runtime' is null or empty then it matches with any.
|
||||
private static IEnumerable<ProjectContext> GetMatchingProjectContexts(IEnumerable<ProjectContext> contexts, NuGetFramework framework, string runtimeIdentifier)
|
||||
{
|
||||
var matchingContexts = contexts.Where(context =>
|
||||
{
|
||||
if (context.TargetFramework == null || string.IsNullOrEmpty(context.RuntimeIdentifier))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(runtimeIdentifier) || runtimeIdentifier.Equals(context.RuntimeIdentifier))
|
||||
{
|
||||
if (framework == null || framework.Equals(context.TargetFramework))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return matchingContexts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publish the project for given 'framework (ex - dnxcore50)' and 'runtimeID (ex - win7-x64)'
|
||||
/// </summary>
|
||||
/// <param name="context">project that is to be published</param>
|
||||
/// <param name="outputPath">Location of published files</param>
|
||||
/// <param name="configuration">Debug or Release</param>
|
||||
/// <returns>Return 0 if successful else return non-zero</returns>
|
||||
private static int Publish(ProjectContext context, string outputPath, string configuration)
|
||||
{
|
||||
Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}");
|
||||
|
||||
var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
|
||||
|
||||
// Generate the output path
|
||||
if (string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
outputPath = Path.Combine(
|
||||
context.ProjectFile.ProjectDirectory,
|
||||
Constants.BinDirectoryName,
|
||||
configuration,
|
||||
context.TargetFramework.GetTwoDigitShortFolderName(),
|
||||
context.RuntimeIdentifier);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(outputPath))
|
||||
{
|
||||
Directory.CreateDirectory(outputPath);
|
||||
}
|
||||
|
||||
// Compile the project (and transitively, all it's dependencies)
|
||||
var result = Command.Create("dotnet-compile",
|
||||
$"--framework \"{context.TargetFramework.DotNetFrameworkName}\" " +
|
||||
$"--output \"{outputPath}\" " +
|
||||
$"--configuration \"{configuration}\" " +
|
||||
"--no-host " +
|
||||
$"\"{context.ProjectFile.ProjectDirectory}\"")
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
return result.ExitCode;
|
||||
}
|
||||
|
||||
// Use a library exporter to collect publish assets
|
||||
var exporter = context.CreateExporter(configuration);
|
||||
|
||||
foreach (var export in exporter.GetAllExports())
|
||||
{
|
||||
// Skip copying project references
|
||||
if (export.Library is ProjectDescription)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ...");
|
||||
|
||||
PublishFiles(export.RuntimeAssemblies, outputPath);
|
||||
PublishFiles(export.NativeLibraries, outputPath);
|
||||
}
|
||||
|
||||
// Publish a host if this is an application
|
||||
if (options.EmitEntryPoint.GetValueOrDefault())
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Making {context.ProjectFile.Name.Cyan()} runnable ...");
|
||||
PublishHost(context, outputPath);
|
||||
}
|
||||
|
||||
Reporter.Output.WriteLine($"Published to {outputPath}".Green().Bold());
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int PublishHost(ProjectContext context, string outputPath)
|
||||
{
|
||||
if (context.TargetFramework.IsDesktop())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var hostPath = Path.Combine(AppContext.BaseDirectory, Constants.HostExecutableName);
|
||||
if (!File.Exists(hostPath))
|
||||
{
|
||||
Reporter.Error.WriteLine($"Cannot find {Constants.HostExecutableName} in the dotnet directory.".Red());
|
||||
return 1;
|
||||
}
|
||||
|
||||
var outputExe = Path.Combine(outputPath, context.ProjectFile.Name + Constants.ExeSuffix);
|
||||
|
||||
// Copy the host
|
||||
File.Copy(hostPath, outputExe, overwrite: true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void PublishFiles(IEnumerable<LibraryAsset> files, string outputPath)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
File.Copy(file.ResolvedPath, Path.Combine(outputPath, Path.GetFileName(file.ResolvedPath)), overwrite: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
195
src/Microsoft.DotNet.Tools.Publish/PublishCommand.cs
Normal file
195
src/Microsoft.DotNet.Tools.Publish/PublishCommand.cs
Normal file
|
@ -0,0 +1,195 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using NuGet.Frameworks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Publish
|
||||
{
|
||||
public class PublishCommand
|
||||
{
|
||||
public string ProjectPath { get; set; }
|
||||
public string Configuration { get; set; }
|
||||
public string OutputPath { get; set; }
|
||||
public string Framework { get; set; }
|
||||
public string Runtime { get; set; }
|
||||
public NuGetFramework NugetFramework { get; set; }
|
||||
public IEnumerable<ProjectContext> ProjectContexts { get; set; }
|
||||
|
||||
public int NumberOfProjects { get; private set; }
|
||||
public int NumberOfPublishedProjects { get; private set; }
|
||||
|
||||
public bool TryPrepareForPublish()
|
||||
{
|
||||
if (Framework != null)
|
||||
{
|
||||
NugetFramework = NuGetFramework.Parse(Framework);
|
||||
|
||||
if (NugetFramework.IsUnsupported)
|
||||
{
|
||||
Reporter.Output.WriteLine($"Unsupported framework {Framework}.".Red());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectContexts = ProjectContext.CreateContextForEachTarget(ProjectPath);
|
||||
ProjectContexts = GetMatchingProjectContexts(ProjectContexts, NugetFramework, Runtime);
|
||||
|
||||
if (ProjectContexts.Count() == 0)
|
||||
{
|
||||
string errMsg = $"'{ProjectPath}' cannot be published for '{Framework ?? "<no framework provided>"}' '{Runtime ?? "<no runtime provided>"}'";
|
||||
Reporter.Output.WriteLine(errMsg.Red());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void PublishAllProjects()
|
||||
{
|
||||
NumberOfPublishedProjects = 0;
|
||||
NumberOfProjects = 0;
|
||||
foreach (var project in ProjectContexts)
|
||||
{
|
||||
if (PublishProjectContext(project, OutputPath, Configuration))
|
||||
{
|
||||
NumberOfPublishedProjects++;
|
||||
}
|
||||
|
||||
NumberOfProjects++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the matching framework/runtime ProjectContext.
|
||||
/// If 'nugetframework' or 'runtime' is null or empty then it matches with any.
|
||||
/// </summary>
|
||||
private static IEnumerable<ProjectContext> GetMatchingProjectContexts(IEnumerable<ProjectContext> contexts, NuGetFramework framework, string runtimeIdentifier)
|
||||
{
|
||||
foreach (var context in contexts)
|
||||
{
|
||||
if (context.TargetFramework == null || string.IsNullOrEmpty(context.RuntimeIdentifier))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(runtimeIdentifier) || runtimeIdentifier.Equals(context.RuntimeIdentifier))
|
||||
{
|
||||
if (framework == null || framework.Equals(context.TargetFramework))
|
||||
{
|
||||
yield return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publish the project for given 'framework (ex - dnxcore50)' and 'runtimeID (ex - win7-x64)'
|
||||
/// </summary>
|
||||
/// <param name="context">project that is to be published</param>
|
||||
/// <param name="outputPath">Location of published files</param>
|
||||
/// <param name="configuration">Debug or Release</param>
|
||||
/// <returns>Return 0 if successful else return non-zero</returns>
|
||||
private static bool PublishProjectContext(ProjectContext context, string outputPath, string configuration)
|
||||
{
|
||||
Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}");
|
||||
|
||||
var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
|
||||
|
||||
// Generate the output path
|
||||
if (string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
outputPath = Path.Combine(
|
||||
context.ProjectFile.ProjectDirectory,
|
||||
Constants.BinDirectoryName,
|
||||
configuration,
|
||||
context.TargetFramework.GetTwoDigitShortFolderName(),
|
||||
context.RuntimeIdentifier);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(outputPath))
|
||||
{
|
||||
Directory.CreateDirectory(outputPath);
|
||||
}
|
||||
|
||||
// Compile the project (and transitively, all it's dependencies)
|
||||
var result = Command.Create("dotnet-compile",
|
||||
$"--framework \"{context.TargetFramework.DotNetFrameworkName}\" " +
|
||||
$"--output \"{outputPath}\" " +
|
||||
$"--configuration \"{configuration}\" " +
|
||||
"--no-host " +
|
||||
$"\"{context.ProjectFile.ProjectDirectory}\"")
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use a library exporter to collect publish assets
|
||||
var exporter = context.CreateExporter(configuration);
|
||||
|
||||
foreach (var export in exporter.GetAllExports())
|
||||
{
|
||||
// Skip copying project references
|
||||
if (export.Library is ProjectDescription)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ...");
|
||||
|
||||
PublishFiles(export.RuntimeAssemblies, outputPath);
|
||||
PublishFiles(export.NativeLibraries, outputPath);
|
||||
}
|
||||
|
||||
// Publish a host if this is an application
|
||||
if (options.EmitEntryPoint.GetValueOrDefault())
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Making {context.ProjectFile.Name.Cyan()} runnable ...");
|
||||
PublishHost(context, outputPath);
|
||||
}
|
||||
|
||||
Reporter.Output.WriteLine($"Published to {outputPath}".Green().Bold());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int PublishHost(ProjectContext context, string outputPath)
|
||||
{
|
||||
if (context.TargetFramework.IsDesktop())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var hostPath = Path.Combine(AppContext.BaseDirectory, Constants.HostExecutableName);
|
||||
if (!File.Exists(hostPath))
|
||||
{
|
||||
Reporter.Error.WriteLine($"Cannot find {Constants.HostExecutableName} in the dotnet directory.".Red());
|
||||
return 1;
|
||||
}
|
||||
|
||||
var outputExe = Path.Combine(outputPath, context.ProjectFile.Name + Constants.ExeSuffix);
|
||||
|
||||
// Copy the host
|
||||
File.Copy(hostPath, outputExe, overwrite: true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void PublishFiles(IEnumerable<LibraryAsset> files, string outputPath)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
File.Copy(file.ResolvedPath, Path.Combine(outputPath, Path.GetFileName(file.ResolvedPath)), overwrite: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,7 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.Net.CSharp.Interactive.netcore": "1.2.0-beta-20151106-02",
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"System.Xml.XDocument": "4.0.11-rc2-23608",
|
||||
"System.Resources.ReaderWriter": "4.0.0-rc2-23608",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.Xml.XDocument": "4.0.11-rc2-23616",
|
||||
"System.Resources.ReaderWriter": "4.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.CodeAnalysis.CSharp": "1.1.1",
|
||||
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-beta-23504",
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
|
||||
"Microsoft.Net.Compilers.netcore": "1.2.0-beta-20151117-04",
|
||||
"Microsoft.Net.Compilers.netcore": "1.2.0-beta-20151215-01",
|
||||
"System.CommandLine" : "0.1.0-d111815-3",
|
||||
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.ConsoleHost": "1.0.0-beta-23409",
|
||||
"Microsoft.NETCore.TestHost": "1.0.0-beta-23409",
|
||||
"Microsoft.NETCore.ConsoleHost": "1.0.0-rc2-23616",
|
||||
"Microsoft.NETCore.TestHost": "1.0.0-rc2-23616",
|
||||
"Microsoft.Extensions.Compilation.Abstractions": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
@ -40,11 +40,11 @@
|
|||
"frameworks": {
|
||||
"dnxcore50": {
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Diagnostics.TextWriterTraceListener": "4.0.0-rc2-23608",
|
||||
"System.Diagnostics.TraceSource": "4.0.0-rc2-23608",
|
||||
"System.Dynamic.Runtime": "4.0.11-rc2-23608",
|
||||
"System.Threading.Thread": "4.0.0-rc2-23608"
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.Diagnostics.TextWriterTraceListener": "4.0.0-rc2-23616",
|
||||
"System.Diagnostics.TraceSource": "4.0.0-rc2-23616",
|
||||
"System.Dynamic.Runtime": "4.0.11-rc2-23616",
|
||||
"System.Threading.Thread": "4.0.0-rc2-23616"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.Extensions.Compilation.Abstractions": "1.0.0-*",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0-*",
|
||||
"System.Runtime.Serialization.Primitives": "4.0.11-rc2-23608"
|
||||
"System.Runtime.Serialization.Primitives": "4.0.11-rc2-23616"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnxcore50": {
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Resources.ResourceManager": "4.0.1-rc2-23608"
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"System.Resources.ResourceManager": "4.0.1-rc2-23616"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace pal
|
|||
typedef std::string string_t;
|
||||
typedef std::stringstream stringstream_t;
|
||||
typedef std::ifstream ifstream_t;
|
||||
typedef long hresult_t;
|
||||
typedef int hresult_t;
|
||||
typedef void* dll_t;
|
||||
typedef void* proc_t;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ bool pal::find_coreclr(pal::string_t& recv)
|
|||
return true;
|
||||
}
|
||||
|
||||
candidate.assign("/usr/local/share/dotnet/cli/runtime/coreclr");
|
||||
candidate.assign("/usr/local/share/dotnet/runtime/coreclr");
|
||||
if (coreclr_exists_in_dir(candidate)) {
|
||||
recv.assign(candidate);
|
||||
return true;
|
||||
|
|
|
@ -53,8 +53,7 @@ namespace ConsoleApplication
|
|||
[Fact]
|
||||
public void TestDotnetCompileNativeRyuJit()
|
||||
{
|
||||
// Skip this test on mac
|
||||
if(SkipForOS(OSPlatform.OSX, "https://github.com/dotnet/cli/issues/246"))
|
||||
if(SkipForOS(OSPlatform.Linux, "https://github.com/dotnet/cli/issues/527"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
},
|
||||
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms":"1.0.1-*",
|
||||
"Microsoft.NETCore.Runtime": "1.0.1-*",
|
||||
"System.Console": "4.0.0-*",
|
||||
"System.Runtime": "4.0.21-*",
|
||||
"System.AppContext": "4.0.1-*",
|
||||
"NETStandard.Library" : "1.0.0-rc2-23616",
|
||||
|
||||
"xunit": "2.1.0",
|
||||
"xunit.console.netcore": "1.0.2-prerelease-00101",
|
||||
|
|
33
tools/MultiProjectValidator/AnalysisResult.cs
Normal file
33
tools/MultiProjectValidator/AnalysisResult.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace MultiProjectValidator
|
||||
{
|
||||
public class AnalysisResult
|
||||
{
|
||||
|
||||
private List<string> _messages;
|
||||
private bool _passed;
|
||||
|
||||
public AnalysisResult(List<string> messages, bool passed)
|
||||
{
|
||||
_messages = messages;
|
||||
_passed = passed;
|
||||
}
|
||||
|
||||
public List<string> Messages
|
||||
{
|
||||
get
|
||||
{
|
||||
return _messages;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Passed
|
||||
{
|
||||
get
|
||||
{
|
||||
return _passed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ProjectSanity.AnalysisRules.DependencyMismatch
|
||||
{
|
||||
internal class DependencyGroup
|
||||
{
|
||||
public static DependencyGroup CreateWithEntry(DependencyInfo dependencyInfo)
|
||||
{
|
||||
var dependencyGroup = new DependencyGroup
|
||||
{
|
||||
DependencyName = dependencyInfo.Name,
|
||||
VersionDependencyInfoMap = new Dictionary<string, List<DependencyInfo>>()
|
||||
};
|
||||
|
||||
dependencyGroup.AddEntry(dependencyInfo);
|
||||
|
||||
return dependencyGroup;
|
||||
}
|
||||
|
||||
public string DependencyName { get; private set; }
|
||||
public Dictionary<string, List<DependencyInfo>> VersionDependencyInfoMap { get; private set; }
|
||||
|
||||
public bool HasConflict
|
||||
{
|
||||
get
|
||||
{
|
||||
return VersionDependencyInfoMap.Count > 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddEntry(DependencyInfo dependencyInfo)
|
||||
{
|
||||
if (!dependencyInfo.Name.Equals(DependencyName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("Added dependency does not match group");
|
||||
}
|
||||
|
||||
if (VersionDependencyInfoMap.ContainsKey(dependencyInfo.Version))
|
||||
{
|
||||
VersionDependencyInfoMap[dependencyInfo.Version].Add(dependencyInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionDependencyInfoMap[dependencyInfo.Version] = new List<DependencyInfo>()
|
||||
{
|
||||
dependencyInfo
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace ProjectSanity.AnalysisRules.DependencyMismatch
|
||||
{
|
||||
internal class DependencyInfo
|
||||
{
|
||||
public static DependencyInfo Create(ProjectContext context, LibraryDescription library)
|
||||
{
|
||||
return new DependencyInfo
|
||||
{
|
||||
ProjectPath = context.ProjectFile.ProjectFilePath,
|
||||
Version = library.Identity.Version.ToString(),
|
||||
Name = library.Identity.Name
|
||||
};
|
||||
}
|
||||
|
||||
public string ProjectPath { get; private set; }
|
||||
public string Version { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using System.Text;
|
||||
using ProjectSanity.AnalysisRules.DependencyMismatch;
|
||||
|
||||
namespace MultiProjectValidator.AnalysisRules
|
||||
{
|
||||
public class DependencyMismatchRule : IAnalysisRule
|
||||
{
|
||||
public AnalysisResult Evaluate(List<ProjectContext> projectContexts)
|
||||
{
|
||||
var targetGroupedContexts = GroupContextsByTarget(projectContexts);
|
||||
|
||||
var failureMessages = EvaluateProjectContextTargetGroups(targetGroupedContexts);
|
||||
var pass = failureMessages.Count == 0;
|
||||
|
||||
var result = new AnalysisResult(failureMessages, pass);
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<string> EvaluateProjectContextTargetGroups(Dictionary<string, List<ProjectContext>> targetGroupedProjectContexts)
|
||||
{
|
||||
var failureMessages = new List<string>();
|
||||
|
||||
foreach (var target in targetGroupedProjectContexts.Keys)
|
||||
{
|
||||
var targetProjectContextGroup = targetGroupedProjectContexts[target];
|
||||
|
||||
var groupFailureMessages = EvaluateProjectContextTargetGroup(targetProjectContextGroup);
|
||||
|
||||
if (groupFailureMessages.Count > 0)
|
||||
{
|
||||
string aggregateFailureMessage = $"Failures for Target {target} {Environment.NewLine}{Environment.NewLine}"
|
||||
+ string.Join("", groupFailureMessages);
|
||||
|
||||
failureMessages.Add(aggregateFailureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return failureMessages;
|
||||
}
|
||||
|
||||
private List<string> EvaluateProjectContextTargetGroup(List<ProjectContext> targetProjectContextGroup)
|
||||
{
|
||||
var failedMessages = new List<string>();
|
||||
|
||||
var dependencyGroups = CreateDependencyGroups(targetProjectContextGroup);
|
||||
|
||||
|
||||
foreach (var dependencyGroup in dependencyGroups)
|
||||
{
|
||||
if(dependencyGroup.HasConflict)
|
||||
{
|
||||
failedMessages.Add(GetDependencyGroupConflictMessage(dependencyGroup));
|
||||
}
|
||||
}
|
||||
|
||||
return failedMessages;
|
||||
}
|
||||
|
||||
private string GetDependencyGroupConflictMessage(DependencyGroup dependencyGroup)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append($"Conflict for {dependencyGroup.DependencyName} in projects:{Environment.NewLine}");
|
||||
|
||||
foreach (var version in dependencyGroup.VersionDependencyInfoMap.Keys)
|
||||
{
|
||||
var dependencyInfoList = dependencyGroup.VersionDependencyInfoMap[version];
|
||||
|
||||
foreach (var dependencyInfo in dependencyInfoList)
|
||||
{
|
||||
sb.Append($"Version: {dependencyInfo.Version} Path: {dependencyInfo.ProjectPath} {Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
sb.Append(Environment.NewLine);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private Dictionary<string, List<ProjectContext>> GroupContextsByTarget(List<ProjectContext> projectContexts)
|
||||
{
|
||||
var targetContextMap = new Dictionary<string, List<ProjectContext>>();
|
||||
foreach (var context in projectContexts)
|
||||
{
|
||||
var target = context.TargetFramework + context.RuntimeIdentifier;
|
||||
|
||||
if (targetContextMap.ContainsKey(target))
|
||||
{
|
||||
targetContextMap[target].Add(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetContextMap[target] = new List<ProjectContext>()
|
||||
{
|
||||
context
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return targetContextMap;
|
||||
}
|
||||
|
||||
private List<DependencyGroup> CreateDependencyGroups(List<ProjectContext> projectContexts)
|
||||
{
|
||||
var libraryNameDependencyGroupMap = new Dictionary<string, DependencyGroup>();
|
||||
|
||||
foreach (var projectContext in projectContexts)
|
||||
{
|
||||
var libraries = projectContext.LibraryManager.GetLibraries();
|
||||
|
||||
foreach (var library in libraries)
|
||||
{
|
||||
var dependencyInfo = DependencyInfo.Create(projectContext, library);
|
||||
|
||||
if (libraryNameDependencyGroupMap.ContainsKey(dependencyInfo.Name))
|
||||
{
|
||||
var dependencyGroup = libraryNameDependencyGroupMap[dependencyInfo.Name];
|
||||
|
||||
dependencyGroup.AddEntry(dependencyInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dependencyGroup = DependencyGroup.CreateWithEntry(dependencyInfo);
|
||||
|
||||
libraryNameDependencyGroupMap[dependencyInfo.Name] = dependencyGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return libraryNameDependencyGroupMap.Values.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
10
tools/MultiProjectValidator/IAnalysisRule.cs
Normal file
10
tools/MultiProjectValidator/IAnalysisRule.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace MultiProjectValidator
|
||||
{
|
||||
public interface IAnalysisRule
|
||||
{
|
||||
AnalysisResult Evaluate(List<ProjectContext> projectContexts);
|
||||
}
|
||||
}
|
18
tools/MultiProjectValidator/MultiProjectValidator.xproj
Normal file
18
tools/MultiProjectValidator/MultiProjectValidator.xproj
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>08a68c6a-86f6-4ed2-89a7-b166d33e9f85</ProjectGuid>
|
||||
<RootNamespace>ProjectSanity</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\tools\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
126
tools/MultiProjectValidator/Program.cs
Normal file
126
tools/MultiProjectValidator/Program.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace MultiProjectValidator
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
|
||||
string rootPath = null;
|
||||
|
||||
try
|
||||
{
|
||||
rootPath = ParseAndValidateArgs(args);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
List<ProjectContext> projects = null;
|
||||
try
|
||||
{
|
||||
projects = ProjectLoader.Load(rootPath);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine("Failed to load projects from path: " + rootPath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
var analyzer = ProjectAnalyzer.Create(projects);
|
||||
var analysisResults = analyzer.DoAnalysis();
|
||||
var failed = analysisResults.Where((a) => !a.Passed).Any();
|
||||
|
||||
PrintAnalysisResults(analysisResults);
|
||||
|
||||
return failed ? 1 : 0;
|
||||
}
|
||||
|
||||
private static void PrintAnalysisResults(List<AnalysisResult> analysisResults)
|
||||
{
|
||||
Console.WriteLine("Project Validation Results");
|
||||
|
||||
var failedCount = analysisResults.Where((a) => !a.Passed).Count();
|
||||
var passedCount = analysisResults.Where((a) => a.Passed).Count();
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine($"{passedCount} Successful Analysis Rules");
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine($"{failedCount} Failed Analysis Rules");
|
||||
|
||||
if (failedCount != 0)
|
||||
{
|
||||
Console.WriteLine("Failure Messages");
|
||||
|
||||
foreach(var result in analysisResults)
|
||||
{
|
||||
if (!result.Passed)
|
||||
{
|
||||
foreach(var message in result.Messages)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
|
||||
private static bool AnyAnalysisFailed(List<AnalysisResult> analysisResults)
|
||||
{
|
||||
foreach (var result in analysisResults)
|
||||
{
|
||||
if (!result.Passed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string ParseAndValidateArgs(string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
PrintHelp();
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
string rootPath = args[0];
|
||||
|
||||
if (!Directory.Exists(rootPath))
|
||||
{
|
||||
Console.WriteLine("Root Directory does not exist: " + rootPath);
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
private static void PrintHelp()
|
||||
{
|
||||
var help = @"
|
||||
Multi-Project Validator
|
||||
|
||||
Description:
|
||||
This tool recursively searches for project.json's from the given root path.
|
||||
It then applies a set of analysis rules, determines whether they pass/fail
|
||||
and then sets exit code to reflect.
|
||||
|
||||
Note:
|
||||
Ensure all analyzed project.json have been restored prior to running this tool.
|
||||
|
||||
Usage:
|
||||
pjvalidate [root path of recursive search]";
|
||||
|
||||
Console.WriteLine(help);
|
||||
}
|
||||
}
|
||||
}
|
43
tools/MultiProjectValidator/ProjectAnalyzer.cs
Normal file
43
tools/MultiProjectValidator/ProjectAnalyzer.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using MultiProjectValidator.AnalysisRules;
|
||||
|
||||
namespace MultiProjectValidator
|
||||
{
|
||||
public class ProjectAnalyzer
|
||||
{
|
||||
|
||||
public static ProjectAnalyzer Create(List<ProjectContext> projectContexts)
|
||||
{
|
||||
// Any Additional rules would be added here
|
||||
var rules = new List<IAnalysisRule>
|
||||
{
|
||||
new DependencyMismatchRule()
|
||||
};
|
||||
|
||||
return new ProjectAnalyzer(rules, projectContexts);
|
||||
}
|
||||
|
||||
private List<ProjectContext> _projectContexts;
|
||||
private List<IAnalysisRule> _rules;
|
||||
|
||||
private ProjectAnalyzer(List<IAnalysisRule> rules, List<ProjectContext> projectContexts)
|
||||
{
|
||||
_rules = rules;
|
||||
_projectContexts = projectContexts;
|
||||
}
|
||||
|
||||
public List<AnalysisResult> DoAnalysis()
|
||||
{
|
||||
var results = new List<AnalysisResult>();
|
||||
|
||||
foreach(var rule in _rules)
|
||||
{
|
||||
results.Add(rule.Evaluate(_projectContexts));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
38
tools/MultiProjectValidator/ProjectLoader.cs
Normal file
38
tools/MultiProjectValidator/ProjectLoader.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace MultiProjectValidator
|
||||
{
|
||||
public class ProjectLoader
|
||||
{
|
||||
private static readonly string PROJECT_FILENAME = "project.json";
|
||||
|
||||
public static List<ProjectContext> Load(string rootPath, bool recursive=true)
|
||||
{
|
||||
var projectFiles = DiscoverProjectFiles(rootPath);
|
||||
var projectContextList = LoadProjectContexts(projectFiles);
|
||||
|
||||
return projectContextList;
|
||||
}
|
||||
|
||||
private static string[] DiscoverProjectFiles(string rootPath)
|
||||
{
|
||||
return Directory.GetFiles(rootPath, PROJECT_FILENAME, SearchOption.AllDirectories);
|
||||
}
|
||||
|
||||
private static List<ProjectContext> LoadProjectContexts(string[] projectFiles)
|
||||
{
|
||||
var projectContexts = new List<ProjectContext>();
|
||||
|
||||
foreach (var file in projectFiles)
|
||||
{
|
||||
var fileTargetContexts = ProjectContext.CreateContextForEachTarget(file);
|
||||
|
||||
projectContexts.AddRange(fileTargetContexts);
|
||||
}
|
||||
|
||||
return projectContexts;
|
||||
}
|
||||
}
|
||||
}
|
17
tools/MultiProjectValidator/project.json
Normal file
17
tools/MultiProjectValidator/project.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"name": "pjvalidate",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23614",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue