diff --git a/.gitattributes b/.gitattributes index bdaa5ba982..c2f0f84273 100644 --- a/.gitattributes +++ b/.gitattributes @@ -48,3 +48,5 @@ *.fsproj text=auto *.dbproj text=auto *.sln text=auto eol=crlf + +*.sh eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index ac82da7568..10779cb569 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ nuget.exe *.ipch *.sln.ide project.lock.json +.testPublish/ +.build/ diff --git a/.travis.yml b/.travis.yml index 2019384e19..e8f77f0f14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,14 +10,11 @@ addons: - libssl-dev - libunwind8 - zlib1g -before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install icu4c; fi -env: - - KOREBUILD_DNU_RESTORE_CORECLR=true MONO_THREADS_PER_CPU=2000 mono: - 4.0.5 os: - linux - osx +osx_image: xcode7.1 script: - - ./build.sh --quiet verify + - ./build.sh --quiet verify \ No newline at end of file diff --git a/NuGet.config b/NuGet.config index 03704957e8..52bf414192 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - \ No newline at end of file + diff --git a/build.cmd b/build.cmd index 553e3929a0..65fb3e3353 100644 --- a/build.cmd +++ b/build.cmd @@ -1,40 +1,40 @@ -@echo off -cd %~dp0 - +@ECHO off SETLOCAL + +SET REPO_FOLDER=%~dp0 +CD "%REPO_FOLDER%" + +SET BUILD_FOLDER=.build +SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet +SET KOREBUILD_VERSION= + +SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION= -SET BUILDCMD_DNX_VERSION= -IF EXIST %CACHED_NUGET% goto copynuget -echo Downloading latest version of NuGet.exe... -IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - -:copynuget -IF EXIST .nuget\nuget.exe goto restore -md .nuget -copy %CACHED_NUGET% .nuget\nuget.exe > nul - -:restore -IF EXIST packages\Sake goto getdnx -IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre -) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre -) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages - -:getdnx -IF "%BUILDCMD_DNX_VERSION%"=="" ( - SET BUILDCMD_DNX_VERSION=latest -) -IF "%SKIP_DNX_INSTALL%"=="" ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default - CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default -) ELSE ( - CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +IF NOT EXIST %BUILD_FOLDER% ( + md %BUILD_FOLDER% ) -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +IF NOT EXIST %NUGET_PATH% ( + IF NOT EXIST %CACHED_NUGET% ( + echo Downloading latest version of NuGet.exe... + IF NOT EXIST %LocalAppData%\NuGet ( + md %LocalAppData%\NuGet + ) + @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + ) + + copy %CACHED_NUGET% %NUGET_PATH% > nul +) + +IF NOT EXIST %KOREBUILD_FOLDER% ( + SET KOREBUILD_DOWNLOAD_ARGS= + IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% + ) + + %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% +) + +"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* diff --git a/build.sh b/build.sh index da4e3fcd1c..263fb667a8 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,10 @@ #!/usr/bin/env bash +buildFolder=.build +koreBuildFolder=$buildFolder/KoreBuild-dotnet + +nugetPath=$buildFolder/nuget.exe + if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild else @@ -11,33 +16,30 @@ else fi mkdir -p $cachedir nugetVersion=latest -cachePath=$cachedir/nuget.$nugetVersion.exe +cacheNuget=$cachedir/nuget.$nugetVersion.exe -url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachePath; then - wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +if test ! -d $buildFolder; then + mkdir $buildFolder fi -if test ! -e .nuget; then - mkdir .nuget - cp $cachePath .nuget/nuget.exe +if test ! -f $nugetPath; then + if test ! -f $cacheNuget; then + wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + fi + + cp $cacheNuget $nugetPath fi -if test ! -d packages/Sake; then - mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +if test ! -d $koreBuildFolder; then + mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre + chmod +x $koreBuildFolder/build/KoreBuild.sh fi -if ! type dnvm > /dev/null 2>&1; then - source packages/KoreBuild/build/dnvm.sh +makeFile=makefile.shade +if [ ! -e $makeFile ]; then + makeFile=$koreBuildFolder/build/makefile.shade fi -if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then - dnvm install latest -runtime coreclr -alias default - dnvm install default -runtime mono -alias default -else - dnvm use default -runtime mono -fi - -mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" +./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" diff --git a/dnx-watch.sln b/dotnet-watch.sln similarity index 64% rename from dnx-watch.sln rename to dotnet-watch.sln index 6b01701d71..3c8e1e6bbb 100644 --- a/dnx-watch.sln +++ b/dotnet-watch.sln @@ -5,9 +5,9 @@ VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{66517987-2A5A-4330-B130-207039378FD4}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.Watcher", "src\Microsoft.Dnx.Watcher\Microsoft.Dnx.Watcher.xproj", "{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-watch", "src\dotnet-watch\dotnet-watch.xproj", "{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.Watcher.Core", "src\Microsoft.Dnx.Watcher.Core\Microsoft.Dnx.Watcher.Core.xproj", "{D3DA3BBB-E206-404F-AEE6-17FB9B6F1221}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Watcher.Core", "src\Microsoft.DotNet.Watcher.Core\Microsoft.DotNet.Watcher.Core.xproj", "{D3DA3BBB-E206-404F-AEE6-17FB9B6F1221}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8321E0D1-9A47-4D2F-AED8-3AE636D44E35}" ProjectSection(SolutionItems) = preProject @@ -15,10 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NuGet.Config = NuGet.Config EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{442A6A17-4C5A-4E11-B547-A554063FD338}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.Watcher.Tests", "test\Microsoft.Dnx.Watcher.Tests\Microsoft.Dnx.Watcher.Tests.xproj", "{640D190B-26DB-4DDE-88EE-55814C86C43E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,10 +29,6 @@ Global {D3DA3BBB-E206-404F-AEE6-17FB9B6F1221}.Debug|Any CPU.Build.0 = Debug|Any CPU {D3DA3BBB-E206-404F-AEE6-17FB9B6F1221}.Release|Any CPU.ActiveCfg = Release|Any CPU {D3DA3BBB-E206-404F-AEE6-17FB9B6F1221}.Release|Any CPU.Build.0 = Release|Any CPU - {640D190B-26DB-4DDE-88EE-55814C86C43E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {640D190B-26DB-4DDE-88EE-55814C86C43E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {640D190B-26DB-4DDE-88EE-55814C86C43E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {640D190B-26DB-4DDE-88EE-55814C86C43E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -44,6 +36,5 @@ Global GlobalSection(NestedProjects) = preSolution {8A8CEABC-AC47-43FF-A5DF-69224F7E1F46} = {66517987-2A5A-4330-B130-207039378FD4} {D3DA3BBB-E206-404F-AEE6-17FB9B6F1221} = {66517987-2A5A-4330-B130-207039378FD4} - {640D190B-26DB-4DDE-88EE-55814C86C43E} = {442A6A17-4C5A-4E11-B547-A554063FD338} EndGlobalSection EndGlobal diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/Constants.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/Constants.cs deleted file mode 100644 index 9c2e502b02..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/Constants.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Dnx.Runtime -{ - internal static class Constants - { - public const string BootstrapperExeName = "dnx"; - public const string BootstrapperFullName = "Microsoft .NET Execution environment"; - public const string DefaultLocalRuntimeHomeDir = ".dnx"; - public const string RuntimeShortName = "dnx"; - public const string RuntimeLongName = "Microsoft DNX"; - public const string RuntimeNamePrefix = RuntimeShortName + "-"; - public const string WebConfigRuntimeVersion = RuntimeNamePrefix + "version"; - public const string WebConfigRuntimeFlavor = RuntimeNamePrefix + "clr"; - public const string WebConfigRuntimeAppBase = RuntimeNamePrefix + "app-base"; - public const string WebConfigBootstrapperVersion = "bootstrapper-version"; - public const string WebConfigRuntimePath = "runtime-path"; - public const string BootstrapperHostName = RuntimeShortName + ".host"; - public const string BootstrapperClrName = RuntimeShortName + ".clr"; - - public const int LockFileVersion = 2; - - public static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10); - public static readonly string AppConfigurationFileName = "app.config"; - - public static readonly Version Version35 = new Version(3, 5); - public static readonly Version Version40 = new Version(4, 0); - public static readonly Version Version50 = new Version(5, 0); - public static readonly Version Version10_0 = new Version(10, 0); - } -} diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/FileFormatException.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/FileFormatException.cs deleted file mode 100644 index 0efa1871d1..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/FileFormatException.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.JsonParser.Sources; - -namespace Microsoft.Dnx.Runtime -{ - internal sealed class FileFormatException : Exception - { - private FileFormatException(string message) : - base(message) - { - } - - private FileFormatException(string message, Exception innerException) : - base(message, innerException) - { - } - - public string Path { get; private set; } - public int Line { get; private set; } - public int Column { get; private set; } - - public override string ToString() - { - return $"{Path}({Line},{Column}): Error: {base.ToString()}"; - } - - internal static FileFormatException Create(Exception exception, string filePath) - { - if (exception is JsonDeserializerException) - { - return new FileFormatException(exception.Message, exception) - .WithFilePath(filePath) - .WithLineInfo((JsonDeserializerException)exception); - } - else - { - return new FileFormatException(exception.Message, exception) - .WithFilePath(filePath); - } - } - - internal static FileFormatException Create(Exception exception, JsonValue jsonValue, string filePath) - { - var result = Create(exception, jsonValue) - .WithFilePath(filePath); - - return result; - } - - internal static FileFormatException Create(Exception exception, JsonValue jsonValue) - { - var result = new FileFormatException(exception.Message, exception) - .WithLineInfo(jsonValue); - - return result; - } - - internal static FileFormatException Create(string message, JsonValue jsonValue, string filePath) - { - var result = Create(message, jsonValue) - .WithFilePath(filePath); - - return result; - } - - internal static FileFormatException Create(string message, string filePath) - { - var result = new FileFormatException(message) - .WithFilePath(filePath); - - return result; - } - - internal static FileFormatException Create(string message, JsonValue jsonValue) - { - var result = new FileFormatException(message) - .WithLineInfo(jsonValue); - - return result; - } - - internal FileFormatException WithFilePath(string path) - { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - - Path = path; - - return this; - } - - private FileFormatException WithLineInfo(JsonValue value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - Line = value.Line; - Column = value.Column; - - return this; - } - - private FileFormatException WithLineInfo(JsonDeserializerException exception) - { - if (exception == null) - { - throw new ArgumentNullException(nameof(exception)); - } - - Line = exception.Line; - Column = exception.Column; - - return this; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFile.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFile.cs deleted file mode 100644 index 8f07a5f54c..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFile.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.Dnx.Runtime -{ - public class LockFile - { - public int Version { get; set; } - - public IList ProjectLibraries { get; set; } = new List(); - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFileProjectLibrary.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFileProjectLibrary.cs deleted file mode 100644 index a131fa32ce..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFileProjectLibrary.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.Dnx.Runtime -{ - public class LockFileProjectLibrary - { - public string Name { get; set; } - - public string Path { get; set; } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFileReader.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFileReader.cs deleted file mode 100644 index 5cc3821fd9..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/LockFileReader.cs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using Microsoft.Extensions.JsonParser.Sources; -using NuGet; - -namespace Microsoft.Dnx.Runtime -{ - internal class LockFileReader - { - public const string LockFileName = "project.lock.json"; - - public LockFile Read(string filePath) - { - using (var stream = OpenFileStream(filePath)) - { - try - { - return Read(stream); - } - catch (FileFormatException ex) - { - throw ex.WithFilePath(filePath); - } - catch (Exception ex) - { - throw FileFormatException.Create(ex, filePath); - } - } - } - - private static FileStream OpenFileStream(string filePath) - { - // Retry 3 times before re-throw the exception. - // It mitigates the race condition when DTH read lock file while VS is restoring projects. - - int retry = 3; - while (true) - { - try - { - return new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); - } - catch (Exception) - { - if (retry > 0) - { - retry--; - Thread.Sleep(100); - } - else - { - throw; - } - } - } - - } - - internal LockFile Read(Stream stream) - { - try - { - var reader = new StreamReader(stream); - var jobject = JsonDeserializer.Deserialize(reader) as JsonObject; - - if (jobject != null) - { - return ReadLockFile(jobject); - } - else - { - throw new InvalidDataException(); - } - } - catch - { - // Ran into parsing errors, mark it as unlocked and out-of-date - return new LockFile - { - Version = int.MinValue - }; - } - } - - private LockFile ReadLockFile(JsonObject cursor) - { - var lockFile = new LockFile(); - lockFile.Version = ReadInt(cursor, "version", defaultValue: int.MinValue); - ReadLibrary(cursor.ValueAsJsonObject("libraries"), lockFile); - - return lockFile; - } - - private void ReadLibrary(JsonObject json, LockFile lockFile) - { - if (json == null) - { - return; - } - - foreach (var key in json.Keys) - { - var value = json.ValueAsJsonObject(key); - if (value == null) - { - throw FileFormatException.Create("The value type is not object.", json.Value(key)); - } - - var parts = key.Split(new[] { '/' }, 2); - var name = parts[0]; - var version = parts.Length == 2 ? SemanticVersion.Parse(parts[1]) : null; - - var type = value.ValueAsString("type")?.Value; - - if (type == "project") - { - lockFile.ProjectLibraries.Add(new LockFileProjectLibrary - { - Name = name, - Path = ReadString(value.Value("path")) - }); - } - } - } - - private string ReadFrameworkAssemblyReference(JsonValue json) - { - return ReadString(json); - } - - private IList ReadArray(JsonValue json, Func readItem) - { - if (json == null) - { - return new List(); - } - - var jarray = json as JsonArray; - if (jarray == null) - { - throw FileFormatException.Create("The value type is not array.", json); - } - - var items = new List(); - for (int i = 0; i < jarray.Length; ++i) - { - items.Add(readItem(jarray[i])); - } - return items; - } - - private IList ReadObject(JsonObject json, Func readItem) - { - if (json == null) - { - return new List(); - } - var items = new List(); - foreach (var childKey in json.Keys) - { - items.Add(readItem(childKey, json.Value(childKey))); - } - return items; - } - - private bool ReadBool(JsonObject cursor, string property, bool defaultValue) - { - var valueToken = cursor.Value(property) as JsonBoolean; - if (valueToken == null) - { - return defaultValue; - } - - return valueToken.Value; - } - - private int ReadInt(JsonObject cursor, string property, int defaultValue) - { - var number = cursor.Value(property) as JsonNumber; - if (number == null) - { - return defaultValue; - } - - try - { - var resultInInt = Convert.ToInt32(number.Raw); - return resultInInt; - } - catch (Exception ex) - { - // FormatException or OverflowException - throw FileFormatException.Create(ex, cursor); - } - } - - private string ReadString(JsonValue json) - { - if (json is JsonString) - { - return (json as JsonString).Value; - } - else if (json is JsonNull) - { - return null; - } - else - { - throw FileFormatException.Create("The value type is not string.", json); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/NamedResourceReader.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/NamedResourceReader.cs deleted file mode 100644 index 54bfed296b..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/NamedResourceReader.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.JsonParser.Sources; - -namespace Microsoft.Dnx.Runtime -{ - internal static class NamedResourceReader - { - public static IDictionary ReadNamedResources(JsonObject rawProject, string projectFilePath) - { - if (!rawProject.Keys.Contains("namedResource")) - { - return new Dictionary(); - } - - var namedResourceToken = rawProject.ValueAsJsonObject("namedResource"); - if (namedResourceToken == null) - { - throw FileFormatException.Create("Value must be object.", rawProject.Value("namedResource"), projectFilePath); - } - - var namedResources = new Dictionary(); - - foreach (var namedResourceKey in namedResourceToken.Keys) - { - var resourcePath = namedResourceToken.ValueAsString(namedResourceKey); - if (resourcePath == null) - { - throw FileFormatException.Create("Value must be string.", namedResourceToken.Value(namedResourceKey), projectFilePath); - } - - if (resourcePath.Value.Contains("*")) - { - throw FileFormatException.Create("Value cannot contain wildcards.", resourcePath, projectFilePath); - } - - var resourceFileFullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(projectFilePath), resourcePath)); - - if (namedResources.ContainsKey(namedResourceKey)) - { - throw FileFormatException.Create( - string.Format("The named resource {0} already exists.", namedResourceKey), - resourcePath, - projectFilePath); - } - - namedResources.Add( - namedResourceKey, - resourceFileFullPath); - } - - return namedResources; - } - - public static void ApplyNamedResources(IDictionary namedResources, IDictionary resources) - { - foreach (var namedResource in namedResources) - { - // The named resources dictionary is like the project file - // key = name, value = path to resource - if (resources.ContainsKey(namedResource.Value)) - { - resources[namedResource.Value] = namedResource.Key; - } - else - { - resources.Add(namedResource.Value, namedResource.Key); - } - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PackIncludeEntry.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PackIncludeEntry.cs deleted file mode 100644 index 8ba9c19515..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PackIncludeEntry.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Linq; -using Microsoft.Extensions.JsonParser.Sources; - -namespace Microsoft.Dnx.Runtime -{ - public class PackIncludeEntry - { - public string Target { get; } - public string[] SourceGlobs { get; } - public int Line { get; } - public int Column { get; } - - internal PackIncludeEntry(string target, JsonValue json) - : this(target, ExtractValues(json), json.Line, json.Column) - { - } - - public PackIncludeEntry(string target, string[] sourceGlobs, int line, int column) - { - Target = target; - SourceGlobs = sourceGlobs; - Line = line; - Column = column; - } - - private static string[] ExtractValues(JsonValue json) - { - var valueAsString = json as JsonString; - if (valueAsString != null) - { - return new string[] { valueAsString.Value }; - } - - var valueAsArray = json as JsonArray; - if(valueAsArray != null) - { - return valueAsArray.Values.Select(v => v.ToString()).ToArray(); - } - return new string[0]; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PathUtility.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PathUtility.cs deleted file mode 100644 index 9546881690..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PathUtility.cs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; - -namespace NuGet -{ - internal static class PathUtility - { - public static bool IsChildOfDirectory(string dir, string candidate) - { - if (dir == null) - { - throw new ArgumentNullException(nameof(dir)); - } - if (candidate == null) - { - throw new ArgumentNullException(nameof(candidate)); - } - dir = Path.GetFullPath(dir); - dir = EnsureTrailingSlash(dir); - candidate = Path.GetFullPath(candidate); - return candidate.StartsWith(dir, StringComparison.OrdinalIgnoreCase); - } - - public static string EnsureTrailingSlash(string path) - { - return EnsureTrailingCharacter(path, Path.DirectorySeparatorChar); - } - - public static string EnsureTrailingForwardSlash(string path) - { - return EnsureTrailingCharacter(path, '/'); - } - - private static string EnsureTrailingCharacter(string path, char trailingCharacter) - { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - - // if the path is empty, we want to return the original string instead of a single trailing character. - if (path.Length == 0 || path[path.Length - 1] == trailingCharacter) - { - return path; - } - - return path + trailingCharacter; - } - - public static void EnsureParentDirectory(string filePath) - { - string directory = Path.GetDirectoryName(filePath); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - } - - /// - /// Returns path2 relative to path1, with Path.DirectorySeparatorChar as separator - /// - public static string GetRelativePath(string path1, string path2) - { - return GetRelativePath(path1, path2, Path.DirectorySeparatorChar); - } - - /// - /// Returns path2 relative to path1, with given path separator - /// - public static string GetRelativePath(string path1, string path2, char separator) - { - if (string.IsNullOrEmpty(path1)) - { - throw new ArgumentException("Path must have a value", nameof(path1)); - } - - if (string.IsNullOrEmpty(path2)) - { - throw new ArgumentException("Path must have a value", nameof(path2)); - } - - StringComparison compare; - if (Microsoft.Dnx.Runtime.RuntimeEnvironmentHelper.IsWindows) - { - compare = StringComparison.OrdinalIgnoreCase; - // check if paths are on the same volume - if (!string.Equals(Path.GetPathRoot(path1), Path.GetPathRoot(path2))) - { - // on different volumes, "relative" path is just path2 - return path2; - } - } - else - { - compare = StringComparison.Ordinal; - } - - var index = 0; - var path1Segments = path1.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - var path2Segments = path2.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - // if path1 does not end with / it is assumed the end is not a directory - // we will assume that is isn't a directory by ignoring the last split - var len1 = path1Segments.Length - 1; - var len2 = path2Segments.Length; - - // find largest common absolute path between both paths - var min = Math.Min(len1, len2); - while (min > index) - { - if (!string.Equals(path1Segments[index], path2Segments[index], compare)) - { - break; - } - // Handle scenarios where folder and file have same name (only if os supports same name for file and directory) - // e.g. /file/name /file/name/app - else if ((len1 == index && len2 > index + 1) || (len1 > index && len2 == index + 1)) - { - break; - } - ++index; - } - - var path = ""; - - // check if path2 ends with a non-directory separator and if path1 has the same non-directory at the end - if (len1 + 1 == len2 && !string.IsNullOrEmpty(path1Segments[index]) && - string.Equals(path1Segments[index], path2Segments[index], compare)) - { - return path; - } - - for (var i = index; len1 > i; ++i) - { - path += ".." + separator; - } - for (var i = index; len2 - 1 > i; ++i) - { - path += path2Segments[i] + separator; - } - // if path2 doesn't end with an empty string it means it ended with a non-directory name, so we add it back - if (!string.IsNullOrEmpty(path2Segments[len2 - 1])) - { - path += path2Segments[len2 - 1]; - } - - return path; - } - - public static string GetAbsolutePath(string basePath, string relativePath) - { - if (basePath == null) - { - throw new ArgumentNullException(nameof(basePath)); - } - - if (relativePath == null) - { - throw new ArgumentNullException(nameof(relativePath)); - } - - Uri resultUri = new Uri(new Uri(basePath), new Uri(relativePath, UriKind.Relative)); - return resultUri.LocalPath; - } - - public static string GetDirectoryName(string path) - { - path = path.TrimEnd(Path.DirectorySeparatorChar); - return path.Substring(Path.GetDirectoryName(path).Length).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - } - - public static string GetPathWithForwardSlashes(string path) - { - return path.Replace('\\', '/'); - } - - public static string GetPathWithBackSlashes(string path) - { - return path.Replace('/', '\\'); - } - - public static string GetPathWithDirectorySeparator(string path) - { - if (Path.DirectorySeparatorChar == '/') - { - return GetPathWithForwardSlashes(path); - } - else - { - return GetPathWithBackSlashes(path); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PatternGroup.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PatternGroup.cs deleted file mode 100644 index b7abecd809..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PatternGroup.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Extensions.CompilationAbstractions; -using Microsoft.Extensions.FileSystemGlobbing; -using Microsoft.Extensions.JsonParser.Sources; - -namespace Microsoft.Dnx.Runtime -{ - public class PatternGroup - { - private readonly List _excludeGroups = new List(); - private readonly Matcher _matcher = new Matcher(); - - internal PatternGroup(IEnumerable includePatterns) - { - IncludeLiterals = Enumerable.Empty(); - IncludePatterns = includePatterns; - ExcludePatterns = Enumerable.Empty(); - _matcher.AddIncludePatterns(IncludePatterns); - } - - internal PatternGroup(IEnumerable includePatterns, IEnumerable excludePatterns, IEnumerable includeLiterals) - { - IncludeLiterals = includeLiterals; - IncludePatterns = includePatterns; - ExcludePatterns = excludePatterns; - - _matcher.AddIncludePatterns(IncludePatterns); - _matcher.AddExcludePatterns(ExcludePatterns); - } - - internal static PatternGroup Build( - JsonObject rawProject, - string projectDirectory, - string projectFilePath, - string name, - IEnumerable fallbackIncluding = null, - IEnumerable additionalIncluding = null, - IEnumerable additionalExcluding = null, - bool includePatternsOnly = false, - ICollection warnings = null) - { - string includePropertyName = name; - additionalIncluding = additionalIncluding ?? Enumerable.Empty(); - var includePatterns = PatternsCollectionHelper.GetPatternsCollection(rawProject, projectDirectory, projectFilePath, includePropertyName, defaultPatterns: fallbackIncluding) - .Concat(additionalIncluding) - .Distinct(); - - if (includePatternsOnly) - { - return new PatternGroup(includePatterns); - } - - additionalExcluding = additionalExcluding ?? Enumerable.Empty(); - var excludePatterns = PatternsCollectionHelper.GetPatternsCollection(rawProject, projectDirectory, projectFilePath, propertyName: name + "Exclude") - .Concat(additionalExcluding) - .Distinct(); - - var includeLiterals = PatternsCollectionHelper.GetPatternsCollection(rawProject, projectDirectory, projectFilePath, propertyName: name + "Files", literalPath: true) - .Distinct(); - - return new PatternGroup(includePatterns, excludePatterns, includeLiterals); - } - - public IEnumerable IncludeLiterals { get; } - - public IEnumerable IncludePatterns { get; } - - public IEnumerable ExcludePatterns { get; } - - public IEnumerable ExcludePatternsGroup { get { return _excludeGroups; } } - - public PatternGroup ExcludeGroup(PatternGroup group) - { - _excludeGroups.Add(group); - - return this; - } - - public IEnumerable SearchFiles(string rootPath) - { - // literal included files are added at the last, but the search happens early - // so as to make the process fail early in case there is missing file. fail early - // helps to avoid unnecessary globing for performance optimization - var literalIncludedFiles = new List(); - foreach (var literalRelativePath in IncludeLiterals) - { - var fullPath = Path.GetFullPath(Path.Combine(rootPath, literalRelativePath)); - - if (!File.Exists(fullPath)) - { - throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath)); - } - - // TODO: extract utility like NuGet.PathUtility.GetPathWithForwardSlashes() - literalIncludedFiles.Add(fullPath.Replace('\\', '/')); - } - - // globing files - var globbingResults = _matcher.GetResultsInFullPath(rootPath); - - // if there is no results generated in globing, skip excluding other groups - // for performance optimization. - if (globbingResults.Any()) - { - foreach (var group in _excludeGroups) - { - globbingResults = globbingResults.Except(group.SearchFiles(rootPath)); - } - } - - return globbingResults.Concat(literalIncludedFiles).Distinct(); - } - - public override string ToString() - { - return string.Format("Pattern group: Literals [{0}] Includes [{1}] Excludes [{2}]", string.Join(", ", IncludeLiterals), string.Join(", ", IncludePatterns), string.Join(", ", ExcludePatterns)); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PatternsCollectionHelper.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PatternsCollectionHelper.cs deleted file mode 100644 index ed3bb607b3..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/PatternsCollectionHelper.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Extensions.JsonParser.Sources; - -namespace Microsoft.Dnx.Runtime -{ - internal static class PatternsCollectionHelper - { - private static readonly char[] PatternSeparator = new[] { ';' }; - - public static IEnumerable GetPatternsCollection( - JsonObject rawProject, - string projectDirectory, - string projectFilePath, - string propertyName, - IEnumerable defaultPatterns = null, - bool literalPath = false) - { - defaultPatterns = defaultPatterns ?? Enumerable.Empty(); - - try - { - if (!rawProject.Keys.Contains(propertyName)) - { - return CreateCollection(projectDirectory, propertyName, defaultPatterns, literalPath); - } - - var valueInString = rawProject.ValueAsString(propertyName); - if (valueInString != null) - { - return CreateCollection(projectDirectory, propertyName, new string[] { valueInString }, literalPath); - } - - var valuesInArray = rawProject.ValueAsStringArray(propertyName); - if (valuesInArray != null) - { - return CreateCollection(projectDirectory, propertyName, valuesInArray.Select(s => s.ToString()), literalPath); - } - } - catch (Exception ex) - { - throw FileFormatException.Create(ex, rawProject.Value(propertyName), projectFilePath); - } - - throw FileFormatException.Create("Value must be either string or array.", rawProject.Value(propertyName), projectFilePath); - } - - private static IEnumerable CreateCollection(string projectDirectory, string propertyName, IEnumerable patternsStrings, bool literalPath) - { - var patterns = patternsStrings.SelectMany(patternsString => GetSourcesSplit(patternsString)) - .Select(patternString => patternString.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar)); - - foreach (var pattern in patterns) - { - if (Path.IsPathRooted(pattern)) - { - throw new InvalidOperationException($"The '{propertyName}' property cannot be a rooted path."); - } - - if (literalPath && pattern.Contains('*')) - { - throw new InvalidOperationException($"The '{propertyName}' property cannot contain wildcard characters."); - } - } - - return new List(patterns.Select(pattern => FolderToPattern(pattern, projectDirectory))); - } - - private static IEnumerable GetSourcesSplit(string sourceDescription) - { - if (string.IsNullOrEmpty(sourceDescription)) - { - return Enumerable.Empty(); - } - - return sourceDescription.Split(PatternSeparator, StringSplitOptions.RemoveEmptyEntries); - } - - private static string FolderToPattern(string candidate, string projectDir) - { - // This conversion is needed to support current template - - // If it's already a pattern, no change is needed - if (candidate.Contains('*')) - { - return candidate; - } - - // If the given string ends with a path separator, or it is an existing directory - // we convert this folder name to a pattern matching all files in the folder - if (candidate.EndsWith(@"\") || - candidate.EndsWith("/") || - Directory.Exists(Path.Combine(projectDir, candidate))) - { - return Path.Combine(candidate, "**", "*"); - } - - // Otherwise, it represents a single file - return candidate; - } - } -} diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/Project.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/Project.cs deleted file mode 100644 index 1b8ddd07d5..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/Project.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.CompilationAbstractions; -using NuGet; - -namespace Microsoft.Dnx.Runtime -{ - public class Project - { - public const string ProjectFileName = "project.json"; - - public Project() - { - } - - public string ProjectFilePath { get; set; } - - public string ProjectDirectory - { - get - { - return Path.GetDirectoryName(ProjectFilePath); - } - } - - public string Name { get; set; } - - public string Title { get; set; } - - public string Description { get; set; } - - public string Copyright { get; set; } - - public string Summary { get; set; } - - public string Language { get; set; } - - public string ReleaseNotes { get; set; } - - public string[] Authors { get; set; } - - public string[] Owners { get; set; } - - public bool EmbedInteropTypes { get; set; } - - public Version AssemblyFileVersion { get; set; } - public string WebRoot { get; set; } - - public string EntryPoint { get; set; } - - public string ProjectUrl { get; set; } - - public string LicenseUrl { get; set; } - - public string IconUrl { get; set; } - - public bool RequireLicenseAcceptance { get; set; } - - public string[] Tags { get; set; } - - public bool IsLoadable { get; set; } - - public ProjectFilesCollection Files { get; set; } - - public IDictionary Commands { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public IDictionary> Scripts { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); - - public static bool HasProjectFile(string path) - { - string projectPath = Path.Combine(path, ProjectFileName); - - return File.Exists(projectPath); - } - - public static bool TryGetProject(string path, out Project project, ICollection diagnostics = null) - { - project = null; - - string projectPath = null; - - if (string.Equals(Path.GetFileName(path), ProjectFileName, StringComparison.OrdinalIgnoreCase)) - { - projectPath = path; - path = Path.GetDirectoryName(path); - } - else if (!HasProjectFile(path)) - { - return false; - } - else - { - projectPath = Path.Combine(path, ProjectFileName); - } - - // Assume the directory name is the project name if none was specified - var projectName = PathUtility.GetDirectoryName(path); - projectPath = Path.GetFullPath(projectPath); - - if (!File.Exists(projectPath)) - { - return false; - } - - try - { - using (var stream = File.OpenRead(projectPath)) - { - var reader = new ProjectReader(); - project = reader.ReadProject(stream, projectName, projectPath, diagnostics); - } - } - catch (Exception ex) - { - throw FileFormatException.Create(ex, projectPath); - } - - return true; - } - } -} diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/ProjectFilesCollection.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/ProjectFilesCollection.cs deleted file mode 100644 index 2fe99407b3..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/ProjectFilesCollection.cs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.JsonParser.Sources; - -namespace Microsoft.Dnx.Runtime -{ - public class ProjectFilesCollection - { - public static readonly string[] DefaultCompileBuiltInPatterns = new[] { @"**/*.cs" }; - public static readonly string[] DefaultPublishExcludePatterns = new[] { @"obj/**/*.*", @"bin/**/*.*", @"**/.*/**", @"**/global.json" }; - public static readonly string[] DefaultPreprocessPatterns = new[] { @"compiler/preprocess/**/*.cs" }; - public static readonly string[] DefaultSharedPatterns = new[] { @"compiler/shared/**/*.cs" }; - public static readonly string[] DefaultResourcesBuiltInPatterns = new[] { @"compiler/resources/**/*", "**/*.resx" }; - public static readonly string[] DefaultContentsBuiltInPatterns = new[] { @"**/*" }; - - public static readonly string[] DefaultBuiltInExcludePatterns = new[] { "bin/**", "obj/**", "**/*.xproj" }; - - public static readonly string PackIncludePropertyName = "packInclude"; - - private PatternGroup _sharedPatternsGroup; - private PatternGroup _resourcePatternsGroup; - private PatternGroup _preprocessPatternsGroup; - private PatternGroup _compilePatternsGroup; - private PatternGroup _contentPatternsGroup; - private IDictionary _namedResources; - private IEnumerable _publishExcludePatterns; - private IEnumerable _packInclude; - - private readonly string _projectDirectory; - private readonly string _projectFilePath; - - private JsonObject _rawProject; - private bool _initialized; - - internal ProjectFilesCollection(JsonObject rawProject, string projectDirectory, string projectFilePath) - { - _projectDirectory = projectDirectory; - _projectFilePath = projectFilePath; - _rawProject = rawProject; - } - - internal void EnsureInitialized() - { - if (_initialized) - { - return; - } - - var excludeBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "excludeBuiltIn", DefaultBuiltInExcludePatterns); - var excludePatterns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "exclude") - .Concat(excludeBuiltIns); - var contentBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "contentBuiltIn", DefaultContentsBuiltInPatterns); - var compileBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "compileBuiltIn", DefaultCompileBuiltInPatterns); - var resourceBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "resourceBuiltIn", DefaultResourcesBuiltInPatterns); - - _publishExcludePatterns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "publishExclude", DefaultPublishExcludePatterns); - - _sharedPatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "shared", fallbackIncluding: DefaultSharedPatterns, additionalExcluding: excludePatterns); - - _resourcePatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "resource", additionalIncluding: resourceBuiltIns, additionalExcluding: excludePatterns); - - _preprocessPatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "preprocess", fallbackIncluding: DefaultPreprocessPatterns, additionalExcluding: excludePatterns) - .ExcludeGroup(_sharedPatternsGroup) - .ExcludeGroup(_resourcePatternsGroup); - - _compilePatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "compile", additionalIncluding: compileBuiltIns, additionalExcluding: excludePatterns) - .ExcludeGroup(_sharedPatternsGroup) - .ExcludeGroup(_preprocessPatternsGroup) - .ExcludeGroup(_resourcePatternsGroup); - - _contentPatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "content", additionalIncluding: contentBuiltIns, additionalExcluding: excludePatterns.Concat(_publishExcludePatterns)) - .ExcludeGroup(_compilePatternsGroup) - .ExcludeGroup(_preprocessPatternsGroup) - .ExcludeGroup(_sharedPatternsGroup) - .ExcludeGroup(_resourcePatternsGroup); - - _namedResources = NamedResourceReader.ReadNamedResources(_rawProject, _projectFilePath); - - // Files to be packed along with the project - var packIncludeJson = _rawProject.ValueAsJsonObject(PackIncludePropertyName); - if (packIncludeJson != null) - { - _packInclude = packIncludeJson - .Keys - .Select(k => new PackIncludeEntry(k, packIncludeJson.Value(k))) - .ToList(); - } - else - { - _packInclude = new List(); - } - - _initialized = true; - _rawProject = null; - } - - public IEnumerable PackInclude - { - get - { - EnsureInitialized(); - return _packInclude; - } - } - - public IEnumerable SourceFiles - { - get { return CompilePatternsGroup.SearchFiles(_projectDirectory).Distinct(); } - } - - public IEnumerable PreprocessSourceFiles - { - get { return PreprocessPatternsGroup.SearchFiles(_projectDirectory).Distinct(); } - } - - public IDictionary ResourceFiles - { - get - { - var resources = ResourcePatternsGroup - .SearchFiles(_projectDirectory) - .Distinct() - .ToDictionary(res => res, res => (string)null); - - NamedResourceReader.ApplyNamedResources(_namedResources, resources); - - return resources; - } - } - - public IEnumerable SharedFiles - { - get { return SharedPatternsGroup.SearchFiles(_projectDirectory).Distinct(); } - } - - public IEnumerable GetFilesForBundling(bool includeSource, IEnumerable additionalExcludePatterns) - { - var patternGroup = new PatternGroup(ContentPatternsGroup.IncludePatterns, - ContentPatternsGroup.ExcludePatterns.Concat(additionalExcludePatterns), - ContentPatternsGroup.IncludeLiterals); - if (!includeSource) - { - foreach (var excludedGroup in ContentPatternsGroup.ExcludePatternsGroup) - { - patternGroup.ExcludeGroup(excludedGroup); - } - } - - return patternGroup.SearchFiles(_projectDirectory); - } - - internal PatternGroup CompilePatternsGroup - { - get - { - EnsureInitialized(); - return _compilePatternsGroup; - } - } - - internal PatternGroup SharedPatternsGroup - { - get - { - EnsureInitialized(); - return _sharedPatternsGroup; - } - } - - internal PatternGroup ResourcePatternsGroup - { - get - { - EnsureInitialized(); - return _resourcePatternsGroup; - } - } - - internal PatternGroup PreprocessPatternsGroup - { - get - { - EnsureInitialized(); - return _preprocessPatternsGroup; - } - } - - internal PatternGroup ContentPatternsGroup - { - get - { - EnsureInitialized(); - return _contentPatternsGroup; - } - } - } -} diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/ProjectReader.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/ProjectReader.cs deleted file mode 100644 index 1eafcc90a9..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/ProjectReader.cs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Extensions.CompilationAbstractions; -using Microsoft.Extensions.JsonParser.Sources; -using NuGet; - -namespace Microsoft.Dnx.Runtime -{ - public class ProjectReader - { - public Project ReadProject(Stream stream, string projectName, string projectPath, ICollection diagnostics) - { - var project = new Project(); - - var reader = new StreamReader(stream); - var rawProject = JsonDeserializer.Deserialize(reader) as JsonObject; - if (rawProject == null) - { - throw FileFormatException.Create( - "The JSON file can't be deserialized to a JSON object.", - projectPath); - } - - // Meta-data properties - project.Name = projectName; - project.ProjectFilePath = Path.GetFullPath(projectPath); - - var version = rawProject.Value("version") as JsonString; - - project.Description = rawProject.ValueAsString("description"); - project.Summary = rawProject.ValueAsString("summary"); - project.Copyright = rawProject.ValueAsString("copyright"); - project.Title = rawProject.ValueAsString("title"); - project.WebRoot = rawProject.ValueAsString("webroot"); - project.EntryPoint = rawProject.ValueAsString("entryPoint"); - project.ProjectUrl = rawProject.ValueAsString("projectUrl"); - project.LicenseUrl = rawProject.ValueAsString("licenseUrl"); - project.IconUrl = rawProject.ValueAsString("iconUrl"); - - project.Authors = rawProject.ValueAsStringArray("authors") ?? new string[] { }; - project.Owners = rawProject.ValueAsStringArray("owners") ?? new string[] { }; - project.Tags = rawProject.ValueAsStringArray("tags") ?? new string[] { }; - - project.Language = rawProject.ValueAsString("language"); - project.ReleaseNotes = rawProject.ValueAsString("releaseNotes"); - - project.RequireLicenseAcceptance = rawProject.ValueAsBoolean("requireLicenseAcceptance", defaultValue: false); - project.IsLoadable = rawProject.ValueAsBoolean("loadable", defaultValue: true); - // TODO: Move this to the dependencies node - project.EmbedInteropTypes = rawProject.ValueAsBoolean("embedInteropTypes", defaultValue: false); - - // Project files - project.Files = new ProjectFilesCollection(rawProject, project.ProjectDirectory, project.ProjectFilePath); - - var commands = rawProject.Value("commands") as JsonObject; - if (commands != null) - { - foreach (var key in commands.Keys) - { - var value = commands.ValueAsString(key); - if (value != null) - { - project.Commands[key] = value; - } - } - } - - var scripts = rawProject.Value("scripts") as JsonObject; - if (scripts != null) - { - foreach (var key in scripts.Keys) - { - var stringValue = scripts.ValueAsString(key); - if (stringValue != null) - { - project.Scripts[key] = new string[] { stringValue }; - continue; - } - - var arrayValue = scripts.ValueAsStringArray(key); - if (arrayValue != null) - { - project.Scripts[key] = arrayValue; - continue; - } - - throw FileFormatException.Create( - string.Format("The value of a script in {0} can only be a string or an array of strings", Project.ProjectFileName), - scripts.Value(key), - project.ProjectFilePath); - } - } - - return project; - } - - private static SemanticVersion SpecifySnapshot(string version, string snapshotValue) - { - if (version.EndsWith("-*")) - { - if (string.IsNullOrEmpty(snapshotValue)) - { - version = version.Substring(0, version.Length - 2); - } - else - { - version = version.Substring(0, version.Length - 1) + snapshotValue; - } - } - - return new SemanticVersion(version); - } - - private static bool TryGetStringEnumerable(JsonObject parent, string property, out IEnumerable result) - { - var collection = new List(); - var valueInString = parent.ValueAsString(property); - if (valueInString != null) - { - collection.Add(valueInString); - } - else - { - var valueInArray = parent.ValueAsStringArray(property); - if (valueInArray != null) - { - collection.AddRange(valueInArray); - } - else - { - result = null; - return false; - } - } - - result = collection.SelectMany(value => value.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries)); - return true; - } - } -} diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/RuntimeEnvironmentHelper.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/RuntimeEnvironmentHelper.cs deleted file mode 100644 index 27ea21b458..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/RuntimeEnvironmentHelper.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.PlatformAbstractions; - -namespace Microsoft.Dnx.Runtime -{ - internal static class RuntimeEnvironmentHelper - { - private static Lazy _isMono = new Lazy(() => - _runtimeEnv.Value.RuntimeType == "Mono"); - - private static Lazy _isWindows = new Lazy(() => - _runtimeEnv.Value.OperatingSystem == "Windows"); - - private static Lazy _runtimeEnv = new Lazy(() => - GetRuntimeEnvironment()); - - private static IRuntimeEnvironment GetRuntimeEnvironment() - { - var environment = PlatformServices.Default.Runtime; - - if (environment == null) - { - throw new InvalidOperationException("Failed to resolve IRuntimeEnvironment"); - } - - return environment; - } - - public static IRuntimeEnvironment RuntimeEnvironment - { - get - { - return _runtimeEnv.Value; - } - } - - public static bool IsWindows - { - get { return _isWindows.Value; } - } - - public static bool IsMono - { - get { return _isMono.Value; } - } - } -} diff --git a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/SemanticVersion.cs b/src/Microsoft.Dnx.Watcher.Core/External/Runtime/SemanticVersion.cs deleted file mode 100644 index 59846a2cf9..0000000000 --- a/src/Microsoft.Dnx.Watcher.Core/External/Runtime/SemanticVersion.cs +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text; - -namespace NuGet -{ - /// - /// A hybrid implementation of SemVer that supports semantic versioning as described at http://semver.org while not strictly enforcing it to - /// allow older 4-digit versioning schemes to continue working. - /// - internal sealed class SemanticVersion : IComparable, IComparable, IEquatable - { - private string _normalizedVersionString; - - public SemanticVersion(string version) - : this(Parse(version)) - { - } - - public SemanticVersion(int major, int minor, int build, int revision) - : this(new Version(major, minor, build, revision)) - { - } - - public SemanticVersion(int major, int minor, int build, string specialVersion) - : this(new Version(major, minor, build), specialVersion) - { - } - - public SemanticVersion(Version version) - : this(version, string.Empty) - { - } - - public SemanticVersion(Version version, string specialVersion) - { - if (version == null) - { - throw new ArgumentNullException(nameof(version)); - } - Version = NormalizeVersionValue(version); - SpecialVersion = specialVersion ?? string.Empty; - } - - internal SemanticVersion(SemanticVersion semVer) - { - Version = semVer.Version; - SpecialVersion = semVer.SpecialVersion; - } - - /// - /// Gets the normalized version portion. - /// - public Version Version - { - get; - private set; - } - - /// - /// Gets the optional special version. - /// - public string SpecialVersion - { - get; - private set; - } - - private static string[] SplitAndPadVersionString(string version) - { - string[] a = version.Split('.'); - if (a.Length == 4) - { - return a; - } - else - { - // if 'a' has less than 4 elements, we pad the '0' at the end - // to make it 4. - var b = new string[4] { "0", "0", "0", "0" }; - Array.Copy(a, 0, b, 0, a.Length); - return b; - } - } - - /// - /// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version. - /// - public static SemanticVersion Parse(string version) - { - if (string.IsNullOrEmpty(version)) - { - throw new ArgumentNullException(nameof(version)); - } - - SemanticVersion semVer; - if (!TryParse(version, out semVer)) - { - throw new ArgumentException(nameof(version)); - } - return semVer; - } - - /// - /// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version. - /// - public static bool TryParse(string version, out SemanticVersion value) - { - return TryParseInternal(version, strict: false, semVer: out value); - } - - /// - /// Parses a version string using strict semantic versioning rules that allows exactly 3 components and an optional special version. - /// - public static bool TryParseStrict(string version, out SemanticVersion value) - { - return TryParseInternal(version, strict: true, semVer: out value); - } - - private static bool TryParseInternal(string version, bool strict, out SemanticVersion semVer) - { - semVer = null; - if (string.IsNullOrEmpty(version)) - { - return false; - } - - version = version.Trim(); - var versionPart = version; - - string specialVersion = string.Empty; - if (version.IndexOf('-') != -1) - { - var parts = version.Split(new char[] { '-' }, 2, StringSplitOptions.RemoveEmptyEntries); - if (parts.Length != 2) - { - return false; - } - - versionPart = parts[0]; - specialVersion = parts[1]; - } - - Version versionValue; - if (!Version.TryParse(versionPart, out versionValue)) - { - return false; - } - - if (strict) - { - // Must have major, minor and build only. - if (versionValue.Major == -1 || - versionValue.Minor == -1 || - versionValue.Build == -1 || - versionValue.Revision != -1) - { - return false; - } - } - - semVer = new SemanticVersion(NormalizeVersionValue(versionValue), specialVersion); - return true; - } - - /// - /// Attempts to parse the version token as a SemanticVersion. - /// - /// An instance of SemanticVersion if it parses correctly, null otherwise. - public static SemanticVersion ParseOptionalVersion(string version) - { - SemanticVersion semVer; - TryParse(version, out semVer); - return semVer; - } - - private static Version NormalizeVersionValue(Version version) - { - return new Version(version.Major, - version.Minor, - Math.Max(version.Build, 0), - Math.Max(version.Revision, 0)); - } - - public int CompareTo(object obj) - { - if (Object.ReferenceEquals(obj, null)) - { - return 1; - } - SemanticVersion other = obj as SemanticVersion; - if (other == null) - { - throw new ArgumentException(nameof(obj)); - } - return CompareTo(other); - } - - public int CompareTo(SemanticVersion other) - { - if (Object.ReferenceEquals(other, null)) - { - return 1; - } - - int result = Version.CompareTo(other.Version); - - if (result != 0) - { - return result; - } - - bool empty = string.IsNullOrEmpty(SpecialVersion); - bool otherEmpty = string.IsNullOrEmpty(other.SpecialVersion); - if (empty && otherEmpty) - { - return 0; - } - else if (empty) - { - return 1; - } - else if (otherEmpty) - { - return -1; - } - return StringComparer.OrdinalIgnoreCase.Compare(SpecialVersion, other.SpecialVersion); - } - - public static bool operator ==(SemanticVersion version1, SemanticVersion version2) - { - if (Object.ReferenceEquals(version1, null)) - { - return Object.ReferenceEquals(version2, null); - } - return version1.Equals(version2); - } - - public static bool operator !=(SemanticVersion version1, SemanticVersion version2) - { - return !(version1 == version2); - } - - public static bool operator <(SemanticVersion version1, SemanticVersion version2) - { - if (version1 == null) - { - throw new ArgumentNullException(nameof(version1)); - } - return version1.CompareTo(version2) < 0; - } - - public static bool operator <=(SemanticVersion version1, SemanticVersion version2) - { - return (version1 == version2) || (version1 < version2); - } - - public static bool operator >(SemanticVersion version1, SemanticVersion version2) - { - if (version1 == null) - { - throw new ArgumentNullException(nameof(version1)); - } - return version2 < version1; - } - - public static bool operator >=(SemanticVersion version1, SemanticVersion version2) - { - return (version1 == version2) || (version1 > version2); - } - - public override string ToString() - { - if (_normalizedVersionString == null) - { - var builder = new StringBuilder(); - builder - .Append(Version.Major) - .Append('.') - .Append(Version.Minor) - .Append('.') - .Append(Math.Max(0, Version.Build)); - - if (Version.Revision > 0) - { - builder - .Append('.') - .Append(Version.Revision); - } - - if (!string.IsNullOrEmpty(SpecialVersion)) - { - builder - .Append('-') - .Append(SpecialVersion); - } - - _normalizedVersionString = builder.ToString(); - } - - return _normalizedVersionString; - } - - public bool Equals(SemanticVersion other) - { - return !Object.ReferenceEquals(null, other) && - Version.Equals(other.Version) && - SpecialVersion.Equals(other.SpecialVersion, StringComparison.OrdinalIgnoreCase); - } - - public override bool Equals(object obj) - { - SemanticVersion semVer = obj as SemanticVersion; - return !Object.ReferenceEquals(null, semVer) && Equals(semVer); - } - - public override int GetHashCode() - { - int hashCode = Version.GetHashCode(); - if (SpecialVersion != null) - { - hashCode = hashCode * 4567 + SpecialVersion.GetHashCode(); - } - - return hashCode; - } - } -} diff --git a/src/Microsoft.Dnx.Watcher/Program.cs b/src/Microsoft.Dnx.Watcher/Program.cs deleted file mode 100644 index f2b2d9c104..0000000000 --- a/src/Microsoft.Dnx.Watcher/Program.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.CommandLineUtils; -using Microsoft.Extensions.PlatformAbstractions; -using Microsoft.Dnx.Watcher.Core; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Dnx.Watcher -{ - public class Program - { - private const string DnxWatchArgumentSeparator = "--dnx-args"; - - private readonly ILoggerFactory _loggerFactory; - - public Program() - { - _loggerFactory = new LoggerFactory(); - - var commandProvider = new CommandOutputProvider(PlatformServices.Default.Runtime); - _loggerFactory.AddProvider(commandProvider); - } - - public static int Main(string[] args) - { - using (CancellationTokenSource ctrlCTokenSource = new CancellationTokenSource()) - { - Console.CancelKeyPress += (sender, ev) => - { - ctrlCTokenSource.Cancel(); - ev.Cancel = false; - }; - - string[] watchArgs, dnxArgs; - SeparateWatchArguments(args, out watchArgs, out dnxArgs); - - return new Program().MainInternal(watchArgs, dnxArgs, ctrlCTokenSource.Token); - } - } - - internal static void SeparateWatchArguments(string[] args, out string[] watchArgs, out string[] dnxArgs) - { - int argsIndex = -1; - watchArgs = args.TakeWhile((arg, idx) => - { - argsIndex = idx; - return !string.Equals(arg, DnxWatchArgumentSeparator, StringComparison.OrdinalIgnoreCase); - }).ToArray(); - - dnxArgs = args.Skip(argsIndex + 1).ToArray(); - - if (dnxArgs.Length == 0) - { - // If no explicit dnx arguments then all arguments get passed to dnx - dnxArgs = watchArgs; - watchArgs = new string[0]; - } - } - - private int MainInternal(string[] watchArgs, string[] dnxArgs, CancellationToken cancellationToken) - { - var app = new CommandLineApplication(); - app.Name = "dnx-watch"; - app.FullName = "Microsoft .NET DNX File Watcher"; - - app.HelpOption("-?|-h|--help"); - - var projectArg = app.Option( - "--project ", - "Path to the project.json file or the application folder. Defaults to the current folder if not provided. Will be passed to DNX.", - CommandOptionType.SingleValue); - - var workingDirArg = app.Option( - "--working-dir ", - "The working directory for DNX. Defaults to the current directory.", - CommandOptionType.SingleValue); - - var exitOnChangeArg = app.Option( - "--exit-on-change", - "The watcher will exit when a file change is detected instead of restarting the process.", - CommandOptionType.NoValue); - - // This option is here just to be displayed in help - // it will not be parsed because it is removed before the code is executed - app.Option( - $"{DnxWatchArgumentSeparator} ", - "Marks the arguments that will be passed to DNX. Anything following this option is passed. If not specified, all the arguments are passed to DNX.", - CommandOptionType.SingleValue); - - app.OnExecute(() => - { - var projectToRun = projectArg.HasValue() ? - projectArg.Value() : - Directory.GetCurrentDirectory(); - - if (!projectToRun.EndsWith("project.json", StringComparison.Ordinal)) - { - projectToRun = Path.Combine(projectToRun, "project.json"); - } - - var workingDir = workingDirArg.HasValue() ? - workingDirArg.Value() : - Directory.GetCurrentDirectory(); - - var watcher = DnxWatcher.CreateDefault(_loggerFactory); - watcher.ExitOnChange = exitOnChangeArg.HasValue(); - - try - { - watcher.WatchAsync(projectToRun, dnxArgs, workingDir, cancellationToken).Wait(); - } - catch (AggregateException ex) - { - if (ex.InnerExceptions.Count != 1 || !(ex.InnerException is TaskCanceledException)) - { - throw; - } - } - - - return 1; - }); - - return app.Execute(watchArgs); - } - } -} diff --git a/src/Microsoft.Dnx.Watcher/Properties/AssemblyInfo.cs b/src/Microsoft.Dnx.Watcher/Properties/AssemblyInfo.cs deleted file mode 100644 index 64dbfc69d0..0000000000 --- a/src/Microsoft.Dnx.Watcher/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; - -[assembly:InternalsVisibleTo("Microsoft.Dnx.Watcher.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-US")] diff --git a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IFileWatcher.cs b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IFileWatcher.cs similarity index 91% rename from src/Microsoft.Dnx.Watcher.Core/Abstractions/IFileWatcher.cs rename to src/Microsoft.DotNet.Watcher.Core/Abstractions/IFileWatcher.cs index 8dfd44f1e5..c5f01a6399 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IFileWatcher.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IFileWatcher.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public interface IFileWatcher : IDisposable { diff --git a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IProcessWatcher.cs b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IProcessWatcher.cs similarity index 88% rename from src/Microsoft.Dnx.Watcher.Core/Abstractions/IProcessWatcher.cs rename to src/Microsoft.DotNet.Watcher.Core/Abstractions/IProcessWatcher.cs index d075bd519a..ad975f3a12 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IProcessWatcher.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IProcessWatcher.cs @@ -1,10 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public interface IProcessWatcher { diff --git a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IProject.cs b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IProject.cs similarity index 90% rename from src/Microsoft.Dnx.Watcher.Core/Abstractions/IProject.cs rename to src/Microsoft.DotNet.Watcher.Core/Abstractions/IProject.cs index cad54e0997..fc4556c570 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IProject.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IProject.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public interface IProject { diff --git a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IProjectProvider.cs b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IProjectProvider.cs similarity index 88% rename from src/Microsoft.Dnx.Watcher.Core/Abstractions/IProjectProvider.cs rename to src/Microsoft.DotNet.Watcher.Core/Abstractions/IProjectProvider.cs index 77abc7bbb1..44e46cd91e 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Abstractions/IProjectProvider.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Abstractions/IProjectProvider.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public interface IProjectProvider { diff --git a/src/Microsoft.Dnx.Watcher.Core/DictionaryExtensions.cs b/src/Microsoft.DotNet.Watcher.Core/DictionaryExtensions.cs similarity index 100% rename from src/Microsoft.Dnx.Watcher.Core/DictionaryExtensions.cs rename to src/Microsoft.DotNet.Watcher.Core/DictionaryExtensions.cs diff --git a/src/Microsoft.Dnx.Watcher.Core/DnxWatcher.cs b/src/Microsoft.DotNet.Watcher.Core/DotNetWatcher.cs similarity index 71% rename from src/Microsoft.Dnx.Watcher.Core/DnxWatcher.cs rename to src/Microsoft.DotNet.Watcher.Core/DotNetWatcher.cs index b4a27a9afb..f105727329 100644 --- a/src/Microsoft.Dnx.Watcher.Core/DnxWatcher.cs +++ b/src/Microsoft.DotNet.Watcher.Core/DotNetWatcher.cs @@ -8,9 +8,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { - public class DnxWatcher + public class DotNetWatcher { private readonly Func _fileWatcherFactory; private readonly Func _processWatcherFactory; @@ -21,7 +21,7 @@ namespace Microsoft.Dnx.Watcher.Core public bool ExitOnChange { get; set; } - public DnxWatcher( + public DotNetWatcher( Func fileWatcherFactory, Func processWatcherFactory, IProjectProvider projectProvider, @@ -32,12 +32,44 @@ namespace Microsoft.Dnx.Watcher.Core _projectProvider = projectProvider; _loggerFactory = loggerFactory; - _logger = _loggerFactory.CreateLogger(nameof(DnxWatcher)); + _logger = _loggerFactory.CreateLogger(nameof(DotNetWatcher)); } - public async Task WatchAsync(string projectFile, string[] dnxArguments, string workingDir, CancellationToken cancellationToken) + + public async Task WatchAsync(string projectFile, string command, string[] dotnetArguments, string workingDir, CancellationToken cancellationToken) { - dnxArguments = new string[] { "--project", projectFile } - .Concat(dnxArguments) + if (string.IsNullOrEmpty(projectFile)) + { + throw new ArgumentNullException(nameof(projectFile)); + } + if (string.IsNullOrEmpty(command)) + { + throw new ArgumentNullException(nameof(command)); + } + if (dotnetArguments == null) + { + throw new ArgumentNullException(nameof(dotnetArguments)); + } + if (string.IsNullOrEmpty(workingDir)) + { + throw new ArgumentNullException(nameof(workingDir)); + } + if (cancellationToken == null) + { + throw new ArgumentNullException(nameof(cancellationToken)); + } + + if (dotnetArguments.Length > 0) + { + dotnetArguments = new string[] { command, "--" } + .Concat(dotnetArguments) + .ToArray(); + } + else + { + dotnetArguments = new string[] { command }; + } + + dotnetArguments = dotnetArguments .Select(arg => { // If the argument has spaces, make sure we quote it @@ -50,7 +82,7 @@ namespace Microsoft.Dnx.Watcher.Core }) .ToArray(); - var dnxArgumentsAsString = string.Join(" ", dnxArguments); + var dotnetArgumentsAsString = string.Join(" ", dotnetArguments); while (true) { @@ -63,14 +95,14 @@ namespace Microsoft.Dnx.Watcher.Core currentRunCancellationSource.Token)) { var fileWatchingTask = WaitForProjectFileToChangeAsync(project, combinedCancellationSource.Token); - var dnxTask = WaitForDnxToExitAsync(dnxArgumentsAsString, workingDir, combinedCancellationSource.Token); + var dotnetTask = WaitForDotnetToExitAsync(dotnetArgumentsAsString, workingDir, combinedCancellationSource.Token); - var tasksToWait = new Task[] { dnxTask, fileWatchingTask }; + var tasksToWait = new Task[] { dotnetTask, fileWatchingTask }; int finishedTaskIndex = Task.WaitAny(tasksToWait, cancellationToken); // Regardless of the outcome, make sure everything is cancelled - // and wait for dnx to exit. We don't want orphan processes + // and wait for dotnet to exit. We don't want orphan processes currentRunCancellationSource.Cancel(); Task.WaitAll(tasksToWait); @@ -78,16 +110,16 @@ namespace Microsoft.Dnx.Watcher.Core if (finishedTaskIndex == 0) { - // This is the dnx task - var dnxExitCode = dnxTask.Result; + // This is the dotnet task + var dotnetExitCode = dotnetTask.Result; - if (dnxExitCode == 0) + if (dotnetExitCode == 0) { - _logger.LogInformation($"dnx exit code: {dnxExitCode}"); + _logger.LogInformation($"dotnet exit code: {dotnetExitCode}"); } else { - _logger.LogError($"dnx exit code: {dnxExitCode}"); + _logger.LogError($"dotnet exit code: {dotnetExitCode}"); } if (ExitOnChange) @@ -95,8 +127,8 @@ namespace Microsoft.Dnx.Watcher.Core break; } - _logger.LogInformation("Waiting for a file to change before restarting dnx..."); - // Now wait for a file to change before restarting dnx + _logger.LogInformation("Waiting for a file to change before restarting dotnet..."); + // Now wait for a file to change before restarting dotnet await WaitForProjectFileToChangeAsync(project, cancellationToken); } else @@ -123,15 +155,15 @@ namespace Microsoft.Dnx.Watcher.Core } } - private Task WaitForDnxToExitAsync(string dnxArguments, string workingDir, CancellationToken cancellationToken) + private Task WaitForDotnetToExitAsync(string dotnetArguments, string workingDir, CancellationToken cancellationToken) { - _logger.LogInformation($"Running dnx with the following arguments: {dnxArguments}"); + _logger.LogInformation($"Running dotnet with the following arguments: {dotnetArguments}"); - var dnxWatcher = _processWatcherFactory(); - int dnxProcessId = dnxWatcher.Start("dnx", dnxArguments, workingDir); - _logger.LogInformation($"dnx process id: {dnxProcessId}"); + var dotnetWatcher = _processWatcherFactory(); + int dotnetProcessId = dotnetWatcher.Start("dotnet", dotnetArguments, workingDir); + _logger.LogInformation($"dotnet run process id: {dotnetProcessId}"); - return dnxWatcher.WaitForExitAsync(cancellationToken); + return dotnetWatcher.WaitForExitAsync(cancellationToken); } private async Task WaitForValidProjectJsonAsync(string projectFile, CancellationToken cancellationToken) @@ -219,9 +251,9 @@ namespace Microsoft.Dnx.Watcher.Core return changedPath; } - public static DnxWatcher CreateDefault(ILoggerFactory loggerFactory) + public static DotNetWatcher CreateDefault(ILoggerFactory loggerFactory) { - return new DnxWatcher( + return new DotNetWatcher( fileWatcherFactory: root => new FileWatcher(root), processWatcherFactory: () => new ProcessWatcher(), projectProvider: new ProjectProvider(), diff --git a/src/Microsoft.Dnx.Watcher.Core/FileSystem/FileSystemWatcherRoot.cs b/src/Microsoft.DotNet.Watcher.Core/FileSystem/FileSystemWatcherRoot.cs similarity index 93% rename from src/Microsoft.Dnx.Watcher.Core/FileSystem/FileSystemWatcherRoot.cs rename to src/Microsoft.DotNet.Watcher.Core/FileSystem/FileSystemWatcherRoot.cs index 3c4fb517c1..ff8534bc37 100644 --- a/src/Microsoft.Dnx.Watcher.Core/FileSystem/FileSystemWatcherRoot.cs +++ b/src/Microsoft.DotNet.Watcher.Core/FileSystem/FileSystemWatcherRoot.cs @@ -3,7 +3,7 @@ using System.IO; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { internal class FileSystemWatcherRoot : IWatcherRoot { diff --git a/src/Microsoft.Dnx.Watcher.Core/FileSystem/FileWatcher.cs b/src/Microsoft.DotNet.Watcher.Core/FileSystem/FileWatcher.cs similarity index 99% rename from src/Microsoft.Dnx.Watcher.Core/FileSystem/FileWatcher.cs rename to src/Microsoft.DotNet.Watcher.Core/FileSystem/FileWatcher.cs index fe9921336e..e3d3abd442 100644 --- a/src/Microsoft.Dnx.Watcher.Core/FileSystem/FileWatcher.cs +++ b/src/Microsoft.DotNet.Watcher.Core/FileSystem/FileWatcher.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.IO; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public class FileWatcher : IFileWatcher { diff --git a/src/Microsoft.Dnx.Watcher.Core/FileSystem/IWatcherRoot.cs b/src/Microsoft.DotNet.Watcher.Core/FileSystem/IWatcherRoot.cs similarity index 87% rename from src/Microsoft.Dnx.Watcher.Core/FileSystem/IWatcherRoot.cs rename to src/Microsoft.DotNet.Watcher.Core/FileSystem/IWatcherRoot.cs index ffc7a86f6b..eaf0e66bd0 100644 --- a/src/Microsoft.Dnx.Watcher.Core/FileSystem/IWatcherRoot.cs +++ b/src/Microsoft.DotNet.Watcher.Core/FileSystem/IWatcherRoot.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { internal interface IWatcherRoot : IDisposable { diff --git a/src/Microsoft.Dnx.Watcher.Core/Impl/ProcessWatcher.cs b/src/Microsoft.DotNet.Watcher.Core/Impl/ProcessWatcher.cs similarity index 55% rename from src/Microsoft.Dnx.Watcher.Core/Impl/ProcessWatcher.cs rename to src/Microsoft.DotNet.Watcher.Core/Impl/ProcessWatcher.cs index 153979d659..91e7d72653 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Impl/ProcessWatcher.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Impl/ProcessWatcher.cs @@ -3,14 +3,16 @@ using System; using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.PlatformAbstractions; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public class ProcessWatcher : IProcessWatcher { + private static readonly bool _isWindows = PlatformServices.Default.Runtime.OperatingSystem.Equals("Windows", StringComparison.OrdinalIgnoreCase); + private Process _runningProcess; public int Start(string executable, string arguments, string workingDir) @@ -30,8 +32,6 @@ namespace Microsoft.Dnx.Watcher.Core WorkingDirectory = workingDir }; - RemoveCompilationPortEnvironmentVariable(_runningProcess.StartInfo); - _runningProcess.Start(); return _runningProcess.Id; @@ -39,9 +39,9 @@ namespace Microsoft.Dnx.Watcher.Core public Task WaitForExitAsync(CancellationToken cancellationToken) { - cancellationToken.Register(() => _runningProcess?.Kill()); - - return Task.Run(() => + cancellationToken.Register(() => KillProcess(_runningProcess?.Id)); + + return Task.Run(() => { _runningProcess.WaitForExit(); @@ -52,32 +52,33 @@ namespace Microsoft.Dnx.Watcher.Core }); } - private static void RemoveCompilationPortEnvironmentVariable(ProcessStartInfo procStartInfo) + private void KillProcess(int? processId) { - string[] _environmentVariablesToRemove = new string[] + if (processId == null) { - "DNX_COMPILATION_SERVER_PORT", - }; - -#if DNX451 - var environmentVariables = procStartInfo.EnvironmentVariables.Keys.Cast(); -#else - var environmentVariables = procStartInfo.Environment.Keys; -#endif - - var envVarsToRemove = environmentVariables - .Where(envVar => _environmentVariablesToRemove.Contains(envVar, StringComparer.OrdinalIgnoreCase)) - .ToArray(); - - // Workaround for the DNX start issue (it passes some environment variables that it shouldn't) - foreach (var envVar in envVarsToRemove) - { -#if DNX451 - procStartInfo.EnvironmentVariables.Remove(envVar); -#else - procStartInfo.Environment.Remove(envVar); -#endif + return; } + + ProcessStartInfo startInfo; + + if (_isWindows) + { + startInfo = new ProcessStartInfo() + { + FileName = "taskkill", + Arguments = $"/T /F /PID {processId}", + }; + } + else + { + startInfo = new ProcessStartInfo() + { + FileName = "pkill", + Arguments = $"-TERM -P {processId}", + }; + } + var killProcess = Process.Start(startInfo); + killProcess.WaitForExit(); } } } \ No newline at end of file diff --git a/src/Microsoft.Dnx.Watcher.Core/Impl/Project.cs b/src/Microsoft.DotNet.Watcher.Core/Impl/Project.cs similarity index 82% rename from src/Microsoft.Dnx.Watcher.Core/Impl/Project.cs rename to src/Microsoft.DotNet.Watcher.Core/Impl/Project.cs index 04d667c95a..a4e2423206 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Impl/Project.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Impl/Project.cs @@ -4,14 +4,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Dnx.Runtime; -using Microsoft.Extensions.CompilationAbstractions; +using Microsoft.DotNet.ProjectModel.Graph; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { internal class Project : IProject { - public Project(Runtime.Project runtimeProject) + public Project(ProjectModel.Project runtimeProject) { ProjectFile = runtimeProject.ProjectFilePath; ProjectDirectory = runtimeProject.ProjectDirectory; @@ -23,12 +22,11 @@ namespace Microsoft.Dnx.Watcher.Core new string[] { runtimeProject.ProjectFilePath }) .ToList(); - var projectLockJsonPath = Path.Combine(runtimeProject.ProjectDirectory, LockFileReader.LockFileName); - var lockFileReader = new LockFileReader(); - + var projectLockJsonPath = Path.Combine(runtimeProject.ProjectDirectory, "project.lock.json"); + if (File.Exists(projectLockJsonPath)) { - var lockFile = lockFileReader.Read(projectLockJsonPath); + var lockFile = LockFileReader.Read(projectLockJsonPath); ProjectDependencies = lockFile.ProjectLibraries.Select(dep => GetProjectRelativeFullPath(dep.Path)).ToList(); } else diff --git a/src/Microsoft.Dnx.Watcher.Core/Impl/ProjectProvider.cs b/src/Microsoft.DotNet.Watcher.Core/Impl/ProjectProvider.cs similarity index 87% rename from src/Microsoft.Dnx.Watcher.Core/Impl/ProjectProvider.cs rename to src/Microsoft.DotNet.Watcher.Core/Impl/ProjectProvider.cs index 73005c5d15..1336f50829 100644 --- a/src/Microsoft.Dnx.Watcher.Core/Impl/ProjectProvider.cs +++ b/src/Microsoft.DotNet.Watcher.Core/Impl/ProjectProvider.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; -using Microsoft.Extensions.CompilationAbstractions; +using Microsoft.DotNet.ProjectModel; -namespace Microsoft.Dnx.Watcher.Core +namespace Microsoft.DotNet.Watcher.Core { public class ProjectProvider : IProjectProvider { @@ -16,7 +16,7 @@ namespace Microsoft.Dnx.Watcher.Core errors = null; project = null; - Runtime.Project runtimeProject; + ProjectModel.Project runtimeProject; if (!TryGetProject(projectFile, out runtimeProject, out errors)) { return false; @@ -36,12 +36,12 @@ namespace Microsoft.Dnx.Watcher.Core } // Same as TryGetProject but it doesn't throw - private bool TryGetProject(string projectFile, out Runtime.Project project, out string errorMessage) + private bool TryGetProject(string projectFile, out ProjectModel.Project project, out string errorMessage) { try { var errors = new List(); - if (!Runtime.Project.TryGetProject(projectFile, out project, errors)) + if (!ProjectReader.TryGetProject(projectFile, out project, errors)) { errorMessage = string.Join(Environment.NewLine, errors.Select(e => e.ToString())); } diff --git a/src/Microsoft.Dnx.Watcher.Core/Microsoft.Dnx.Watcher.Core.xproj b/src/Microsoft.DotNet.Watcher.Core/Microsoft.DotNet.Watcher.Core.xproj similarity index 100% rename from src/Microsoft.Dnx.Watcher.Core/Microsoft.Dnx.Watcher.Core.xproj rename to src/Microsoft.DotNet.Watcher.Core/Microsoft.DotNet.Watcher.Core.xproj diff --git a/src/Microsoft.Dnx.Watcher.Core/Properties/AssemblyInfo.cs b/src/Microsoft.DotNet.Watcher.Core/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.Dnx.Watcher.Core/Properties/AssemblyInfo.cs rename to src/Microsoft.DotNet.Watcher.Core/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.Dnx.Watcher.Core/project.json b/src/Microsoft.DotNet.Watcher.Core/project.json similarity index 71% rename from src/Microsoft.Dnx.Watcher.Core/project.json rename to src/Microsoft.DotNet.Watcher.Core/project.json index b0b659a01b..cb07bfea11 100644 --- a/src/Microsoft.Dnx.Watcher.Core/project.json +++ b/src/Microsoft.DotNet.Watcher.Core/project.json @@ -5,6 +5,7 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { + "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*", "Microsoft.Extensions.FileProviders.Physical": "1.0.0-*", "Microsoft.Extensions.PlatformAbstractions": "1.0.0-*", @@ -18,18 +19,8 @@ "Microsoft.NETCore.Platforms": "1.0.1-*" }, "frameworks": { - "dnx451": { - "frameworkAssemblies": { - "System.Collections": "", - "System.Runtime": "" - } - }, "dnxcore50": { - "dependencies": { - "System.Diagnostics.Process": "4.1.0-*", - "System.Linq": "4.0.2-*", - "System.Threading.Thread": "4.0.0-*" - } + "imports": "portable-net451+win8" } } } diff --git a/src/Microsoft.Dnx.Watcher/CommandOutputLogger.cs b/src/dotnet-watch/CommandOutputLogger.cs similarity index 98% rename from src/Microsoft.Dnx.Watcher/CommandOutputLogger.cs rename to src/dotnet-watch/CommandOutputLogger.cs index 59b329d0d1..673f7ee8d8 100644 --- a/src/Microsoft.Dnx.Watcher/CommandOutputLogger.cs +++ b/src/dotnet-watch/CommandOutputLogger.cs @@ -5,7 +5,7 @@ using System; using Microsoft.Extensions.CommandLineUtils; using Microsoft.Extensions.Logging; -namespace Microsoft.Dnx.Watcher +namespace Microsoft.DotNet.Watcher { /// /// Logger to print formatted command output. diff --git a/src/Microsoft.Dnx.Watcher/CommandOutputProvider.cs b/src/dotnet-watch/CommandOutputProvider.cs similarity index 95% rename from src/Microsoft.Dnx.Watcher/CommandOutputProvider.cs rename to src/dotnet-watch/CommandOutputProvider.cs index ea8fec48dd..fd4945a078 100644 --- a/src/Microsoft.Dnx.Watcher/CommandOutputProvider.cs +++ b/src/dotnet-watch/CommandOutputProvider.cs @@ -5,7 +5,7 @@ using System; using Microsoft.Extensions.PlatformAbstractions; using Microsoft.Extensions.Logging; -namespace Microsoft.Dnx.Watcher +namespace Microsoft.DotNet.Watcher { public class CommandOutputProvider : ILoggerProvider { diff --git a/src/dotnet-watch/Program.cs b/src/dotnet-watch/Program.cs new file mode 100644 index 0000000000..7f5c0ac257 --- /dev/null +++ b/src/dotnet-watch/Program.cs @@ -0,0 +1,139 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.PlatformAbstractions; +using Microsoft.DotNet.Watcher.Core; +using Microsoft.Extensions.Logging; + +namespace Microsoft.DotNet.Watcher +{ + public class Program + { + private const string AppArgumentSeparator = "--"; + + private readonly ILoggerFactory _loggerFactory; + + public Program() + { + _loggerFactory = new LoggerFactory(); + + var commandProvider = new CommandOutputProvider(PlatformServices.Default.Runtime); + _loggerFactory.AddProvider(commandProvider); + } + + public static int Main(string[] args) + { + using (CancellationTokenSource ctrlCTokenSource = new CancellationTokenSource()) + { + Console.CancelKeyPress += (sender, ev) => + { + ctrlCTokenSource.Cancel(); + ev.Cancel = false; + }; + + string[] watchArgs, appArgs; + SeparateWatchArguments(args, out watchArgs, out appArgs); + + return new Program().MainInternal(watchArgs, appArgs, ctrlCTokenSource.Token); + } + } + + // The argument separation rules are: if no "--" is encountered, all arguments are passed to the app being watched. + // Unless, the argument is "--help", in which case the help for the watcher is being invoked and everything else is discarded. + // To pass arguments to both the watcher and the app use "--" as separator. + // To pass "--help" to the app being watched, you must use "--": dotnet watch -- --help + internal static void SeparateWatchArguments(string[] args, out string[] watchArgs, out string[] appArgs) + { + // Special case "--help" + if (args.Length > 0 && ( + args[0].Equals("--help", StringComparison.OrdinalIgnoreCase) || + args[0].Equals("-h", StringComparison.OrdinalIgnoreCase) || + args[0].Equals("-?", StringComparison.OrdinalIgnoreCase))) + { + watchArgs = new string[] { args[0] }; + appArgs = new string[0]; + return; + } + + int argsIndex = -1; + watchArgs = args.TakeWhile((arg, idx) => + { + argsIndex = idx; + return !string.Equals(arg, AppArgumentSeparator, StringComparison.OrdinalIgnoreCase); + }).ToArray(); + + appArgs = args.Skip(argsIndex + 1).ToArray(); + + if (appArgs.Length == 0) + { + // If no explicit watcher arguments then all arguments get passed to the app being watched + appArgs = watchArgs; + watchArgs = new string[0]; + } + } + + private int MainInternal(string[] watchArgs, string[] appArgs, CancellationToken cancellationToken) + { + var app = new CommandLineApplication(); + app.Name = "dotnet-watch"; + app.FullName = "Microsoft dotnet File Watcher"; + + app.HelpOption("-?|-h|--help"); + + var commandArg = app.Option( + "--command ", + "Optional. The dotnet command to run. Default: 'run'.", + CommandOptionType.SingleValue); + + var workingDirArg = app.Option( + "--working-dir ", + "Optional. The working directory. Default: project's directory.", + CommandOptionType.SingleValue); + + var exitOnChangeArg = app.Option( + "--exit-on-change", + "Optional. The watcher will exit when a file change is detected instead of restarting the process. Default: not set.", + CommandOptionType.NoValue); + + + app.OnExecute(() => + { + var projectToWatch = Path.Combine(Directory.GetCurrentDirectory(), ProjectModel.Project.FileName); + + var workingDir = workingDirArg.HasValue() ? + workingDirArg.Value() : + Path.GetDirectoryName(projectToWatch); + + var command = commandArg.HasValue() ? + commandArg.Value() : + "run"; + + var watcher = DotNetWatcher.CreateDefault(_loggerFactory); + watcher.ExitOnChange = exitOnChangeArg.HasValue(); + + try + { + watcher.WatchAsync(projectToWatch, command, appArgs, workingDir, cancellationToken).Wait(); + } + catch (AggregateException ex) + { + if (ex.InnerExceptions.Count != 1 || !(ex.InnerException is TaskCanceledException)) + { + throw; + } + } + + + return 1; + }); + + return app.Execute(watchArgs); + } + } +} diff --git a/src/dotnet-watch/Properties/AssemblyInfo.cs b/src/dotnet-watch/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..a78f66dc06 --- /dev/null +++ b/src/dotnet-watch/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("dotnet-watch.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-US")] diff --git a/src/Microsoft.Dnx.Watcher/Microsoft.Dnx.Watcher.xproj b/src/dotnet-watch/dotnet-watch.xproj similarity index 100% rename from src/Microsoft.Dnx.Watcher/Microsoft.Dnx.Watcher.xproj rename to src/dotnet-watch/dotnet-watch.xproj diff --git a/src/Microsoft.Dnx.Watcher/project.json b/src/dotnet-watch/project.json similarity index 66% rename from src/Microsoft.Dnx.Watcher/project.json rename to src/dotnet-watch/project.json index c8fc4080ac..dbe7a7ec35 100644 --- a/src/Microsoft.Dnx.Watcher/project.json +++ b/src/dotnet-watch/project.json @@ -6,23 +6,15 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "Microsoft.Dnx.Watcher.Core": "1.0.0-*", + "Microsoft.DotNet.Watcher.Core": "1.0.0-*", "Microsoft.Extensions.CommandLineUtils": "1.0.0-*", "Microsoft.Extensions.Logging": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { } - }, - - "commands": { - "dnx-watch": "Microsoft.Dnx.Watcher" - }, - - "scripts": { - "postbuild": [ - ] + "dnxcore50": { + "imports": "portable-net451+win8" + } } } diff --git a/test/Microsoft.Dnx.Watcher.Tests/CommandLineParsingTests.cs b/test/Microsoft.Dnx.Watcher.Tests/CommandLineParsingTests.cs deleted file mode 100644 index c4ac14008b..0000000000 --- a/test/Microsoft.Dnx.Watcher.Tests/CommandLineParsingTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Xunit; - -namespace Microsoft.Dnx.Watcher.Tests -{ - // This project can output the Class library as a NuGet Package. - // To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build". - public class CommandLineParsingTests - { - [Fact] - public void NoWatcherArgs() - { - var args = "--arg1 v1 --arg2 v2".Split(' '); - - string[] watcherArgs, dnxArgs; - Program.SeparateWatchArguments(args, out watcherArgs, out dnxArgs); - - Assert.Empty(watcherArgs); - Assert.Equal(args, dnxArgs); - } - - [Fact] - public void ArgsForBothDnxAndWatcher() - { - var args = "--arg1 v1 --arg2 v2 --dnx-args --arg3 --arg4 v4".Split(' '); - - string[] watcherArgs, dnxArgs; - Program.SeparateWatchArguments(args, out watcherArgs, out dnxArgs); - - Assert.Equal(new string[] {"--arg1", "v1", "--arg2", "v2" }, watcherArgs); - Assert.Equal(new string[] { "--arg3", "--arg4", "v4" }, dnxArgs); - } - - [Fact] - public void MultipleSeparators() - { - var args = "--arg1 v1 --arg2 v2 --dnx-args --arg3 --dnxArgs --arg4 v4".Split(' '); - - string[] watcherArgs, dnxArgs; - Program.SeparateWatchArguments(args, out watcherArgs, out dnxArgs); - - Assert.Equal(new string[] { "--arg1", "v1", "--arg2", "v2" }, watcherArgs); - Assert.Equal(new string[] { "--arg3", "--dnxArgs", "--arg4", "v4" }, dnxArgs); - } - } -} diff --git a/test/Microsoft.Dnx.Watcher.Tests/Microsoft.Dnx.Watcher.Tests.xproj b/test/Microsoft.Dnx.Watcher.Tests/Microsoft.Dnx.Watcher.Tests.xproj deleted file mode 100644 index 7c8ac87ba2..0000000000 --- a/test/Microsoft.Dnx.Watcher.Tests/Microsoft.Dnx.Watcher.Tests.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 640d190b-26db-4dde-88ee-55814c86c43e - Microsoft.Dnx.Watcher.Tests - ..\artifacts\obj\$(MSBuildProjectName) - ..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.Dnx.Watcher.Tests/project.json b/test/Microsoft.Dnx.Watcher.Tests/project.json deleted file mode 100644 index f613c1cefc..0000000000 --- a/test/Microsoft.Dnx.Watcher.Tests/project.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilationOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-*", - "Microsoft.Dnx.Watcher": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "frameworks": { - "dnx451": { }, - "dnxcore50": { } - }, - "commands": { - "test": "xunit.runner.aspnet" - } -} -