├── README.md ├── global.json ├── src ├── DotNetDo.Abstractions │ ├── ITaskManager.cs │ ├── ITaskProvider.cs │ ├── ITaskRunner.cs │ ├── TaskNode.cs │ ├── TaskResult.cs │ ├── LoggerActivityExtensions.cs │ ├── TaskInvocation.cs │ ├── TaskRunContext.cs │ ├── project.json │ ├── TaskDefinition.cs │ ├── TaskRunnerActivity.cs │ ├── ITaskRunnerBuilder.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── DotNetDo.Abstractions.xproj ├── DotNetDo.Helpers │ ├── ICommandExecutor.cs │ ├── CommandFailedException.cs │ ├── TaskRunnerBuilderExtensions.cs │ ├── CommandResult.cs │ ├── CommandSpec.cs │ ├── CommandHelper.cs │ ├── project.json │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── DotNetDo.Helpers.xproj │ ├── OS.cs │ ├── Command.cs │ ├── DefaultCommandExecutor.cs │ └── FileSystemHelper.cs ├── DotNetDo.BuildSystem │ ├── Project.cs │ ├── CleanDirectoriesTaskOptions.cs │ ├── BuildContext.cs │ ├── project.json │ ├── CleanDirectoriesTask.cs │ ├── BuildLifecycleTaskRunnerBuilderExtensions.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── DotNetDo.BuildSystem.xproj │ └── BuildLifecycleTaskProvider.cs ├── DotNetDo.Engine │ ├── Internal │ │ ├── IAnsiSystemConsole.cs │ │ ├── IConsole.cs │ │ ├── WindowsLogConsole.cs │ │ └── AnsiLogConsole.cs │ ├── TaskFailedException.cs │ ├── project.json │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── DotNetDo.Engine.xproj │ ├── TaskRunnerBuilder.cs │ ├── DefaultTaskRunner.cs │ ├── DefaultTaskManager.cs │ └── TaskRunnerLoggerProvider.cs ├── DotNetDo.BuildSystem.ManagedCode │ ├── NuGetRestoreTaskOptions.cs │ ├── DotNetBuildTaskOptions.cs │ ├── NuGetPackTaskOptions.cs │ ├── project.json │ ├── DotNet │ │ ├── DotNetCliCoreTasks.cs │ │ ├── DotNetRestoreTask.cs │ │ ├── DotNetPackTask.cs │ │ ├── DotNetBuildTask.cs │ │ └── DotNetCli.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── DotNetDo.BuildSystem.ManagedCode.xproj │ └── ManagedCodeTaskRunnerBuilderExtensions.cs ├── dotnet-do │ ├── project.json │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── dotnet-do.xproj │ └── Program.cs └── DotNetDo.Tasks │ ├── TaskAttribute.cs │ ├── project.json │ ├── Properties │ └── AssemblyInfo.cs │ ├── DotNetDo.Tasks.xproj │ └── TaskCollection.cs ├── CONTRIBUTING.md ├── .travis.yml ├── NuGet.Config ├── LICENSE.txt ├── tasks ├── Program.cs ├── InitializeTasks.cs ├── project.json ├── Properties │ └── AssemblyInfo.cs └── tasks.xproj ├── .gitattributes ├── Ideas.md ├── .gitignore └── dotnet-do.sln /README.md: -------------------------------------------------------------------------------- 1 | dotnet-do 2 | ========= 3 | 4 | ## This repository is obsolete and no longer used or maintained. 5 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src", "test" ], 3 | "sdk": { 4 | "version": "1.0.0-rc2-16357" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/ITaskManager.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetDo 2 | { 3 | public interface ITaskManager 4 | { 5 | TaskResult ExecuteTask(string task); 6 | } 7 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ====== 3 | 4 | Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. 5 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/ITaskProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo 4 | { 5 | public interface ITaskProvider 6 | { 7 | IEnumerable GetTasks(); 8 | } 9 | } -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/ITaskRunner.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo 4 | { 5 | public interface ITaskRunner 6 | { 7 | int Execute(IEnumerable commandLineArgs); 8 | } 9 | } -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/ICommandExecutor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace DotNetDo.Helpers 4 | { 5 | public interface ICommandExecutor 6 | { 7 | CommandResult Execute(CommandSpec spec, ProcessStartInfo startInfo, bool expectFailure); 8 | } 9 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/Project.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetDo.BuildSystem 2 | { 3 | public class Project 4 | { 5 | public string Name { get; } 6 | public string Path { get; } 7 | 8 | public Project(string name, string path) 9 | { 10 | Name = name; 11 | Path = path; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | sudo: required 3 | dist: trusty 4 | addons: 5 | apt: 6 | packages: 7 | - gettext 8 | - libcurl4-openssl-dev 9 | - libicu-dev 10 | - libssl-dev 11 | - libunwind8 12 | - zlib1g 13 | mono: 14 | - 4.0.5 15 | os: 16 | - linux 17 | - osx 18 | osx_image: xcode7.1 19 | script: 20 | - ./build.sh 21 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/CleanDirectoriesTaskOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo.BuildSystem 4 | { 5 | public class CleanDirectoriesTaskOptions 6 | { 7 | public IEnumerable Directories { get; } 8 | 9 | public CleanDirectoriesTaskOptions(IEnumerable directories) 10 | { 11 | Directories = directories; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/DotNetDo.Engine/Internal/IAnsiSystemConsole.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | namespace DotNetDo.Internal 5 | { 6 | public interface IAnsiSystemConsole 7 | { 8 | void Write(string message); 9 | 10 | void WriteLine(string message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/CommandFailedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetDo.Helpers 4 | { 5 | public class CommandFailedException : Exception 6 | { 7 | public CommandResult Result { get; } 8 | 9 | public CommandFailedException(CommandResult result) : base( 10 | $"Command failed: {result.Command} (exit code: {result.ExitCode})") 11 | { 12 | Result = result; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/NuGetRestoreTaskOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo.BuildSystem.ManagedCode 4 | { 5 | public class NuGetRestoreTaskOptions 6 | { 7 | public IEnumerable TargetDirectories { get; } 8 | 9 | public NuGetRestoreTaskOptions(IEnumerable targetDirectories) 10 | { 11 | TargetDirectories = targetDirectories; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/TaskNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DotNetDo 5 | { 6 | public class TaskNode 7 | { 8 | public TaskDefinition Definition { get; } 9 | 10 | public IList Dependencies { get; } 11 | 12 | public TaskNode(TaskDefinition definition) 13 | { 14 | Definition = definition; 15 | Dependencies = new List(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNetBuildTaskOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo.BuildSystem.ManagedCode 4 | { 5 | public class DotNetBuildTaskOptions 6 | { 7 | public IEnumerable ProjectGlobs { get; set; } 8 | public string VersionSuffix { get; set; } 9 | 10 | public DotNetBuildTaskOptions(IEnumerable projectGlobs) 11 | { 12 | ProjectGlobs = projectGlobs; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/Internal/IConsole.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | 6 | namespace DotNetDo.Internal 7 | { 8 | public interface IConsole 9 | { 10 | void Write(string message, ConsoleColor? background, ConsoleColor? foreground); 11 | void WriteLine(string message, ConsoleColor? background, ConsoleColor? foreground); 12 | void Flush(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/TaskResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetDo 4 | { 5 | public class TaskResult 6 | { 7 | public TaskNode Task { get; } 8 | public bool Success { get; } 9 | public object ReturnValue { get; } 10 | public Exception Exception { get; } 11 | 12 | public TaskResult(TaskNode task, bool success, object returnValue, Exception exception) 13 | { 14 | Task = task; 15 | Success = success; 16 | ReturnValue = returnValue; 17 | Exception = exception; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/BuildContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo.BuildSystem 4 | { 5 | // TODO: This is eventually going to want some extra stuff 6 | public class BuildContext 7 | { 8 | public TaskRunContext TaskRunContext { get; } 9 | 10 | public string ProjectRoot => TaskRunContext.DoRoot; 11 | public IDictionary Items => TaskRunContext.Items; 12 | 13 | public BuildContext(TaskRunContext taskRunContext) 14 | { 15 | TaskRunContext = taskRunContext; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/NuGetPackTaskOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetDo.BuildSystem.ManagedCode 4 | { 5 | public class NuGetPackTaskOptions 6 | { 7 | public string OutputRoot { get; set; } 8 | public string VersionSuffix { get; set; } 9 | public IEnumerable ProjectGlobs { get; set; } 10 | 11 | public NuGetPackTaskOptions(string outputRoot, IEnumerable projectGlobs) 12 | { 13 | OutputRoot = outputRoot; 14 | ProjectGlobs = projectGlobs; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/dotnet-do/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "dotnet-do Console Application", 4 | "authors": [ "anurse" ], 5 | 6 | "compilationOptions": { 7 | "emitEntryPoint": true 8 | }, 9 | 10 | "dependencies": { 11 | }, 12 | 13 | "commands": { 14 | "do": "run" 15 | }, 16 | 17 | "frameworks": { 18 | "dnxcore50": { 19 | "dependencies": { 20 | "NETStandard.Library": "1.0.0-rc2-23818", 21 | "System.Diagnostics.Process": "4.1.0-rc2-23818" 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/TaskRunnerBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace DotNetDo.Helpers 4 | { 5 | public static class TaskRunnerBuilderExtensions 6 | { 7 | public static ITaskRunnerBuilder UseDefaultHelpers(this ITaskRunnerBuilder self) 8 | { 9 | return self.UseServices( 10 | ServiceDescriptor.Singleton(), 11 | ServiceDescriptor.Singleton(), 12 | ServiceDescriptor.Singleton()); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DotNetDo.Tasks/TaskAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DotNetDo 6 | { 7 | public class TaskAttribute : Attribute 8 | { 9 | public string Name { get; set; } 10 | 11 | public string RunBefore { get; set; } 12 | 13 | public IEnumerable DependsOn { get; set; } 14 | 15 | public TaskAttribute() 16 | { 17 | DependsOn = Enumerable.Empty(); 18 | } 19 | 20 | public TaskAttribute(params string[] dependsOn) 21 | { 22 | DependsOn = dependsOn; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/LoggerActivityExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace DotNetDo 8 | { 9 | public static class LoggerActivityExtensions 10 | { 11 | public static TaskRunnerActivity BeginActivity(this ILogger self, string type, string name) 12 | { 13 | var activity = new TaskRunnerActivity(type, name); 14 | var scope = self.BeginScopeImpl(activity); 15 | activity.AttachToScope(scope); 16 | return activity; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/TaskInvocation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DotNetDo 5 | { 6 | public class TaskInvocation 7 | { 8 | public IServiceProvider Services { get; } 9 | 10 | public IReadOnlyDictionary DependencyResults { get; } 11 | public TaskNode Task { get; } 12 | 13 | public TaskInvocation(TaskNode task, IServiceProvider services, Dictionary dependencyResults) 14 | { 15 | Task = task; 16 | Services = services; 17 | DependencyResults = dependencyResults; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /tasks/Program.cs: -------------------------------------------------------------------------------- 1 | using DotNetDo; 2 | using DotNetDo.BuildSystem; 3 | using DotNetDo.BuildSystem.ManagedCode; 4 | 5 | namespace tasks 6 | { 7 | public class Program 8 | { 9 | public static int Main(string[] args) => TaskRunnerBuilder.CreateDefault() 10 | .UseStandardBuildSystem() 11 | .UseCleanDirectories("artifacts") 12 | .UseDotNetRestore("src", "test") 13 | .UseDotNetBuild("src/*/project.json") 14 | .UseDotNetPack("artifacts", "src/*/project.json", "!src/dotnet-do/project.json") 15 | .UseTasksFrom() 16 | .Execute(args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/TaskRunContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace DotNetDo 5 | { 6 | public class TaskRunContext 7 | { 8 | public string DoProjectPath { get; } 9 | 10 | public string DoRoot => Path.GetDirectoryName(Path.GetDirectoryName(DoProjectPath)); 11 | public string WorkingDirectory => Directory.GetCurrentDirectory(); 12 | 13 | public IDictionary Items { get; } = new Dictionary(); 14 | 15 | public TaskRunContext(string doProjectPath) 16 | { 17 | DoProjectPath = doProjectPath; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/TaskFailedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetDo 4 | { 5 | internal class TaskFailedException : Exception 6 | { 7 | public string FailedTask { get; } 8 | 9 | public TaskFailedException(string failedTask) 10 | { 11 | FailedTask = failedTask; 12 | } 13 | 14 | public TaskFailedException(string failedTask, string message) : base(message) 15 | { 16 | FailedTask = failedTask; 17 | } 18 | 19 | public TaskFailedException(string failedTask, string message, Exception innerException) : base(message, innerException) 20 | { 21 | FailedTask = failedTask; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "DotNetDo.BuildSystem Class Library", 4 | "authors": [ "anurse" ], 5 | 6 | "dependencies": { 7 | "DotNetDo.Tasks": "0.1.0-*", 8 | "DotNetDo.Helpers": "0.1.0-*" 9 | }, 10 | 11 | "frameworks": { 12 | "dotnet5.4": { 13 | "dependencies": { 14 | "Microsoft.CSharp": "4.0.1-rc2-23818", 15 | "System.Collections": "4.0.11-rc2-23818", 16 | "System.Linq": "4.1.0-rc2-23818", 17 | "System.Runtime": "4.1.0-rc2-23818", 18 | "System.Threading": "4.0.11-rc2-23818" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotNetDo.Tasks/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "DotNetDo.Tasks Class Library", 4 | "authors": [ "anurse" ], 5 | 6 | "dependencies": { 7 | "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-*", 8 | "DotNetDo.Abstractions": "0.1.0-*" 9 | }, 10 | 11 | "frameworks": { 12 | "dotnet5.4": { 13 | "dependencies": { 14 | "Microsoft.CSharp": "4.0.1-rc2-23818", 15 | "System.Collections": "4.0.11-rc2-23818", 16 | "System.Linq": "4.1.0-rc2-23818", 17 | "System.Runtime": "4.1.0-rc2-23818", 18 | "System.Threading": "4.0.11-rc2-23818" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tasks/InitializeTasks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DotNetDo; 3 | using DotNetDo.BuildSystem; 4 | using DotNetDo.BuildSystem.ManagedCode; 5 | 6 | namespace tasks 7 | { 8 | public class InitializeTasks : TaskCollection 9 | { 10 | [Task(RunBefore = BuildLifecycle.InitializeCore)] 11 | public void SetBuildVersion(DotNetBuildTaskOptions buildOptions) 12 | { 13 | var appveyorBuildNumber = Environment.GetEnvironmentVariable("APPVEYOR_BUILD_NUMBER"); 14 | if (!string.IsNullOrEmpty(appveyorBuildNumber)) 15 | { 16 | var buildNumber = int.Parse(appveyorBuildNumber); 17 | buildOptions.VersionSuffix = $"alpha-{buildNumber:0000}"; 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/CommandResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetDo.Helpers 4 | { 5 | public struct CommandResult 6 | { 7 | public CommandSpec Command { get; } 8 | public int ExitCode { get; } 9 | public string StdOut { get; } 10 | public string StdErr { get; } 11 | 12 | public CommandResult(CommandSpec command, int exitCode, string stdout, string stderr) : this() 13 | { 14 | ExitCode = exitCode; 15 | StdOut = stdout; 16 | StdErr = stderr; 17 | } 18 | 19 | public void EnsureSuccessful() 20 | { 21 | if(ExitCode != 0) 22 | { 23 | throw new CommandFailedException(this); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/CleanDirectoriesTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using DotNetDo.Helpers; 4 | 5 | namespace DotNetDo.BuildSystem 6 | { 7 | public class CleanDirectoriesTask : TaskCollection 8 | { 9 | // Take an IEnumerable because if this task is registered multiple times it will result in multiple options 10 | // being present in the container and we want to get them all 11 | [Task(RunBefore = BuildLifecycle.CleanCore)] 12 | public void CleanDirectories(IEnumerable optionses, FileSystemHelper fs) 13 | { 14 | foreach(var dir in optionses.SelectMany(o => o.Directories)) 15 | { 16 | fs.RmRf(dir); 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/CommandSpec.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace DotNetDo.Helpers 5 | { 6 | public struct CommandSpec 7 | { 8 | public string Command { get; } 9 | public IEnumerable Arguments { get; } 10 | 11 | // Naive argument escaping 12 | public string EscapedArguments => Arguments == null ? string.Empty : string.Join(" ", Arguments.Select(a => $"\"{a}\"")); 13 | 14 | public CommandSpec(string command, IEnumerable args) : this() 15 | { 16 | Command = command; 17 | Arguments = args ?? Enumerable.Empty(); 18 | } 19 | 20 | public override string ToString() 21 | { 22 | return $"{Command} {EscapedArguments}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "DotNetDo.Abstractions Class Library", 4 | "authors": [ "anurse" ], 5 | 6 | "dependencies": { 7 | "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-rc2-*", 8 | "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-*" 9 | }, 10 | 11 | "frameworks": { 12 | "dotnet5.4": { 13 | "dependencies": { 14 | "System.IO.FileSystem": "4.0.1-rc2-23818", 15 | "Microsoft.CSharp": "4.0.1-rc2-23818", 16 | "System.Collections": "4.0.11-rc2-23818", 17 | "System.Linq": "4.1.0-rc2-23818", 18 | "System.Runtime": "4.1.0-rc2-23818", 19 | "System.Threading": "4.0.11-rc2-23818" 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/TaskDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DotNetDo 5 | { 6 | public class TaskDefinition 7 | { 8 | public string Name { get; } 9 | 10 | public string Source { get; } 11 | 12 | public IEnumerable DependsOn { get; } 13 | 14 | public string RunBefore { get; } 15 | 16 | public Func Implementation { get; } 17 | 18 | public TaskDefinition(string name, string source, IEnumerable dependsOn, string runBefore, Func implementation) 19 | { 20 | Name = name; 21 | Source = source; 22 | DependsOn = dependsOn; 23 | RunBefore = runBefore; 24 | Implementation = implementation; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/BuildLifecycleTaskRunnerBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using DotNetDo.Helpers; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace DotNetDo.BuildSystem 5 | { 6 | public static class BuildLifecycleTaskRunnerBuilderExtensions 7 | { 8 | public static ITaskRunnerBuilder UseStandardBuildSystem(this ITaskRunnerBuilder self) 9 | { 10 | return self.UseServices(ServiceDescriptor.Singleton()) 11 | .UseDefaultHelpers(); 12 | } 13 | 14 | public static ITaskRunnerBuilder UseCleanDirectories(this ITaskRunnerBuilder self, params string[] directories) 15 | { 16 | return self.UseServices( 17 | ServiceDescriptor.Singleton(), 18 | ServiceDescriptor.Singleton(new CleanDirectoriesTaskOptions(directories))); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/TaskRunnerActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace DotNetDo 5 | { 6 | public class TaskRunnerActivity : IDisposable 7 | { 8 | private IDisposable _scopeToken; 9 | 10 | public string Type { get; } 11 | public string Name { get; } 12 | public string Conclusion { get; set; } 13 | public bool Success { get; set; } 14 | 15 | public TaskRunnerActivity(string type, string name) 16 | { 17 | Type = type; 18 | Name = name; 19 | } 20 | 21 | public void AttachToScope(IDisposable loggerScope) 22 | { 23 | Debug.Assert(_scopeToken == null, "Tried to attach to logger scope while already attached to one"); 24 | _scopeToken = loggerScope; 25 | } 26 | 27 | public void Dispose() 28 | { 29 | _scopeToken?.Dispose(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "DotNetDo.BuildSystem.ManagedCode Class Library", 4 | "authors": [ "anurse" ], 5 | 6 | "dependencies": { 7 | "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-*", 8 | "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-*", 9 | 10 | "DotNetDo.BuildSystem": "0.1.0-*" 11 | }, 12 | 13 | "frameworks": { 14 | "dotnet5.4": { 15 | "dependencies": { 16 | "System.IO": "4.1.0-rc2-23818", 17 | "System.IO.FileSystem": "4.0.1-rc2-23818", 18 | "Microsoft.CSharp": "4.0.1-rc2-23818", 19 | "System.Collections": "4.0.11-rc2-23818", 20 | "System.Linq": "4.1.0-rc2-23818", 21 | "System.Runtime": "4.1.0-rc2-23818", 22 | "System.Threading": "4.0.11-rc2-23818" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNet/DotNetCliCoreTasks.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace DotNetDo.BuildSystem.ManagedCode.DotNet 6 | { 7 | public class DotNetCliCoreTasks : TaskCollection 8 | { 9 | [Task(RunBefore = BuildLifecycle.PreInitialize)] 10 | public void CheckDotNetCli(ILogger log) 11 | { 12 | if (!DotNetCli.Default.Exists()) 13 | { 14 | throw new FileNotFoundException($"The .NET Core CLI could not be located in expected path: {DotNetCli.Default.BasePath}", DotNetCli.Default.DriverPath); 15 | } 16 | 17 | if (log.IsEnabled(LogLevel.Trace)) 18 | { 19 | log.LogTrace("Using .NET Core CLI Path: {0}", DotNetCli.Default.BasePath); 20 | log.LogTrace("Using .NET Core CLI Version: {0}", DotNetCli.Default.GetVersion()); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tasks/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | "description": "DevSandbox Console Application", 4 | 5 | "compilationOptions": { 6 | "emitEntryPoint": true 7 | }, 8 | 9 | "dependencies": { 10 | "DotNetDo.BuildSystem.ManagedCode": { "target": "package", "version": "0.1.0-*" }, 11 | "DotNetDo.BuildSystem": { "target": "package", "version": "0.1.0-*" }, 12 | "DotNetDo.Engine": { "target": "package", "version": "0.1.0-*" }, 13 | "DotNetDo.Tasks": { "target": "package", "version": "0.1.0-*" }, 14 | "DotNetDo.Helpers": { "target": "package", "version": "0.1.0-*" }, 15 | "DotNetDo.Abstractions": { "target": "package", "version": "0.1.0-*" } 16 | }, 17 | 18 | "commands": { 19 | "tasks": "tasks" 20 | }, 21 | 22 | "frameworks": { 23 | "dnxcore50": { 24 | "dependencies": { 25 | "NETStandard.Library" : "1.0.0-rc2-23811" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "DotNetDo.Engine Class Library", 4 | 5 | "dependencies": { 6 | "Microsoft.Extensions.DependencyInjection": "1.0.0-rc2-*", 7 | "Microsoft.Extensions.Logging": "1.0.0-rc2-*", 8 | "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-*", 9 | 10 | "DotNetDo.Abstractions": "0.1.0-*" 11 | }, 12 | 13 | "frameworks": { 14 | "dotnet5.4": { 15 | "dependencies": { 16 | "Microsoft.CSharp": "4.0.1-rc2-23818", 17 | "System.Diagnostics.Process": "4.1.0-rc2-23818", 18 | "System.IO": "4.1.0-rc2-23818", 19 | "System.IO.FileSystem": "4.0.1-rc2-23818", 20 | "System.Collections": "4.0.11-rc2-23818", 21 | "System.Linq": "4.1.0-rc2-23818", 22 | "System.Runtime": "4.1.0-rc2-23818", 23 | "System.Threading": "4.0.11-rc2-23818" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/CommandHelper.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetDo.Helpers 2 | { 3 | public class CommandHelper 4 | { 5 | private readonly ICommandExecutor _executor; 6 | 7 | public CommandHelper(ICommandExecutor executor) 8 | { 9 | _executor = executor; 10 | } 11 | 12 | public Command Create(CommandSpec spec) 13 | { 14 | return new Command(spec, _executor); 15 | } 16 | 17 | public Command Create(string command, params string[] args) 18 | { 19 | return Create(new CommandSpec(command, args)); 20 | } 21 | 22 | public CommandResult Exec(CommandSpec spec) 23 | { 24 | var result = new Command(spec, _executor).Execute(); 25 | result.EnsureSuccessful(); 26 | return result; 27 | } 28 | 29 | public CommandResult Exec(string command, params string[] args) 30 | { 31 | return Exec(new CommandSpec(command, args)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /tasks/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DevSandbox")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DevSandbox")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5dbb3dbc-6069-44d6-a427-3f6205cb6405")] 24 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.sh eol=lf 17 | 18 | *.cs text=auto diff=csharp 19 | *.vb text=auto 20 | *.resx text=auto 21 | *.c text=auto 22 | *.cpp text=auto 23 | *.cxx text=auto 24 | *.h text=auto 25 | *.hxx text=auto 26 | *.py text=auto 27 | *.rb text=auto 28 | *.java text=auto 29 | *.html text=auto 30 | *.htm text=auto 31 | *.css text=auto 32 | *.scss text=auto 33 | *.sass text=auto 34 | *.less text=auto 35 | *.js text=auto 36 | *.lisp text=auto 37 | *.clj text=auto 38 | *.sql text=auto 39 | *.php text=auto 40 | *.lua text=auto 41 | *.m text=auto 42 | *.asm text=auto 43 | *.erl text=auto 44 | *.fs text=auto 45 | *.fsx text=auto 46 | *.hs text=auto 47 | 48 | *.csproj text=auto 49 | *.vbproj text=auto 50 | *.fsproj text=auto 51 | *.dbproj text=auto 52 | *.sln text=auto eol=crlf -------------------------------------------------------------------------------- /src/dotnet-do/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("dotnet_do")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("dotnet_do")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0d7108e1-cda5-4227-840b-dd5feb76ab30")] 24 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0-*", 3 | "description": "DotNetDo.Helpers Class Library", 4 | "authors": [ "Andrew" ], 5 | 6 | "dependencies": { 7 | "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-*", 8 | "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-*", 9 | "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-*", 10 | "DotNetDo.Abstractions": "0.1.0-*" 11 | }, 12 | 13 | "frameworks": { 14 | "dotnet5.4": { 15 | "dependencies": { 16 | "System.Runtime.InteropServices.RuntimeInformation": "4.0.0-rc2-23818", 17 | "System.IO.FileSystem": "4.0.1-rc2-23818", 18 | "System.Diagnostics.Process": "4.1.0-rc2-23818", 19 | "Microsoft.CSharp": "4.0.1-rc2-23818", 20 | "System.Collections": "4.0.11-rc2-23818", 21 | "System.Linq": "4.1.0-rc2-23818", 22 | "System.Runtime": "4.1.0-rc2-23818", 23 | "System.Threading": "4.0.11-rc2-23818" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DotNetDo.Tasks/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetDo.Tasks")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DotNetDo.Tasks")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a9d823fd-4b57-414b-98ce-a5e74e9c63c5")] 24 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetDo.Engine")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DotNetDo.Engine")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b5d04bc3-8af8-4c80-81b2-9d01f0764e14")] 24 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetDo.Helpers")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DotNetDo.Helpers")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bf5ed686-d717-4722-b71e-76fe47331d15")] 24 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/ITaskRunnerBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace DotNetDo 6 | { 7 | public interface ITaskRunnerBuilder 8 | { 9 | ITaskRunnerBuilder UseServices(Action registrar); 10 | ITaskRunner Build(); 11 | bool HasService(Type serviceType); 12 | } 13 | 14 | public static class TaskRunnerBuilderExtensions 15 | { 16 | public static int Execute(this ITaskRunnerBuilder self, IEnumerable args) => self.Build().Execute(args); 17 | public static bool HasService(this ITaskRunnerBuilder self) => self.HasService(typeof(T)); 18 | public static ITaskRunnerBuilder UseServices(this ITaskRunnerBuilder self, params ServiceDescriptor[] descriptors) 19 | { 20 | return self.UseServices(services => 21 | { 22 | foreach (var descriptor in descriptors) 23 | { 24 | services.Add(descriptor); 25 | } 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetDo.Abstractions")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DotNetDo.Abstractions")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("88a55a16-1861-4adb-8799-96379155580d")] 24 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetDo.BuildSystem")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DotNetDo.BuildSystem")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3059adbe-5d0d-47dd-9529-75e2f23852d6")] 24 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetDo.BuildSystem.ManagedCode")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DotNetDo.BuildSystem.ManagedCode")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b249967d-1670-48eb-bebe-0b379d28aa27")] 24 | -------------------------------------------------------------------------------- /tasks/tasks.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0.24720 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | c06458ac-bc60-46e3-9ff5-745b942c99bd 10 | tasks 11 | ..\artifacts\obj\$(MSBuildProjectName) 12 | ..\artifacts\bin\$(MSBuildProjectName)\ 13 | 14 | 15 | 16 | 2.0 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/DotNetDo.Tasks/DotNetDo.Tasks.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | a9d823fd-4b57-414b-98ce-a5e74e9c63c5 10 | DotNetDo 11 | ..\..\artifacts\obj\$(MSBuildProjectName) 12 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 13 | 14 | 15 | 2.0 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/dotnet-do/dotnet-do.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 0d7108e1-cda5-4227-840b-dd5feb76ab30 10 | DotNetDo.Command 11 | ..\..\artifacts\obj\$(MSBuildProjectName) 12 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 13 | 14 | 15 | 2.0 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/DotNetDo.Engine.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | b5d04bc3-8af8-4c80-81b2-9d01f0764e14 10 | DotNetDo 11 | ..\..\artifacts\obj\$(MSBuildProjectName) 12 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 13 | 14 | 15 | 2.0 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/DotNetDo.Abstractions/DotNetDo.Abstractions.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 88a55a16-1861-4adb-8799-96379155580d 10 | DotNetDo 11 | ..\..\artifacts\obj\$(MSBuildProjectName) 12 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 13 | 14 | 15 | 2.0 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNet/DotNetRestoreTask.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using DotNetDo.Helpers; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace DotNetDo.BuildSystem.ManagedCode.DotNet 7 | { 8 | public class DotNetRestoreTask : TaskCollection 9 | { 10 | public static readonly string Name = nameof(RestoreNuGetPackages); 11 | 12 | [Task(RunBefore = BuildLifecycle.InitializeCore)] 13 | public void RestoreNuGetPackages(ILogger log, NuGetRestoreTaskOptions options, CommandHelper cmd) 14 | { 15 | foreach (var dir in options.TargetDirectories) 16 | { 17 | if (Directory.Exists(dir)) 18 | { 19 | log.LogTrace("Restoring packages in {0}", dir); 20 | cmd.Create(DotNetCli.Default.Restore()) 21 | .WorkingDirectory(dir) 22 | .Execute() 23 | .EnsureSuccessful(); 24 | } 25 | else 26 | { 27 | log.LogTrace("Skipping non-existant directory {0}", dir); 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/DotNetDo.Helpers.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | bf5ed686-d717-4722-b71e-76fe47331d15 11 | DotNetDo.Helpers 12 | ..\..\artifacts\obj\$(MSBuildProjectName) 13 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 14 | 15 | 16 | 17 | 2.0 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/DotNetDo.BuildSystem.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | 3059adbe-5d0d-47dd-9529-75e2f23852d6 11 | DotNetDo.BuildSystem 12 | ..\..\artifacts\obj\$(MSBuildProjectName) 13 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 14 | 15 | 16 | 17 | 2.0 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNetDo.BuildSystem.ManagedCode.xproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | b249967d-1670-48eb-bebe-0b379d28aa27 11 | DotNetDo.BuildSystem.ManagedCode 12 | ..\..\artifacts\obj\$(MSBuildProjectName) 13 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 14 | 15 | 16 | 17 | 2.0 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/Internal/WindowsLogConsole.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | 6 | namespace DotNetDo.Internal 7 | { 8 | public class WindowsLogConsole : IConsole 9 | { 10 | public void Write(string message, ConsoleColor? background, ConsoleColor? foreground) 11 | { 12 | if (background.HasValue) 13 | { 14 | System.Console.BackgroundColor = background.Value; 15 | } 16 | 17 | if (foreground.HasValue) 18 | { 19 | System.Console.ForegroundColor = foreground.Value; 20 | } 21 | 22 | System.Console.Write(message); 23 | 24 | System.Console.ResetColor(); 25 | } 26 | 27 | public void WriteLine(string message, ConsoleColor? background, ConsoleColor? foreground) 28 | { 29 | Write(message + Environment.NewLine, background, foreground); 30 | } 31 | 32 | public void Flush() 33 | { 34 | // No action required as for every write, data is sent directly to the console 35 | // output stream 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNet/DotNetPackTask.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using DotNetDo.Helpers; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace DotNetDo.BuildSystem.ManagedCode.DotNet 8 | { 9 | public class DotNetPackTask : TaskCollection 10 | { 11 | public static readonly string Name = nameof(PackNuGetPackages); 12 | 13 | [Task(RunBefore = BuildLifecycle.PackageCore)] 14 | public void PackNuGetPackages(ILogger log, NuGetPackTaskOptions options, CommandHelper cmd, FileSystemHelper fs) 15 | { 16 | foreach(var project in fs.Files(options.ProjectGlobs)) 17 | { 18 | log.LogTrace("Packing {0}", project.FullName); 19 | 20 | var args = new List(); 21 | args.Add(project.FullName); 22 | args.Add("--output"); 23 | args.Add(options.OutputRoot); 24 | args.Add("--no-build"); 25 | if (!string.IsNullOrEmpty(options.VersionSuffix)) 26 | { 27 | args.Add("--version-suffix"); 28 | args.Add(options.VersionSuffix); 29 | } 30 | 31 | cmd.Exec(DotNetCli.Default.Pack(args)); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/OS.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.PlatformAbstractions; 2 | 3 | namespace DotNetDo.Helpers 4 | { 5 | public static class OS 6 | { 7 | public static readonly bool IsWindows = PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows; 8 | public static readonly bool IsMacOSX = PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Darwin; 9 | public static readonly bool IsLinux = PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Linux; 10 | 11 | public static readonly string ExecutableSuffix = GetPlatformSpecificValue(win: ".exe", unix: string.Empty); 12 | public static readonly string DynamicLibrarySuffix = GetPlatformSpecificValue(win: ".dll", mac: ".dylib", linux: ".so"); 13 | public static readonly string DynamicLibraryPrefix = GetPlatformSpecificValue(win: string.Empty, unix: "lib"); 14 | 15 | public static string ExeName(string exe) => $"{exe}{ExecutableSuffix}"; 16 | public static string LibName(string lib) => $"{DynamicLibraryPrefix}{lib}"; 17 | public static string LibFileName(string lib) => $"{LibName(lib)}{DynamicLibrarySuffix}"; 18 | 19 | private static string GetPlatformSpecificValue(string win, string unix, string other = null) => GetPlatformSpecificValue(win, unix, unix, other); 20 | private static string GetPlatformSpecificValue(string win, string mac, string linux, string other = null) 21 | { 22 | return IsWindows ? win : (IsMacOSX ? mac : (IsLinux ? linux : other)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ideas.md: -------------------------------------------------------------------------------- 1 | # Random Idea dumping ground 2 | 3 | ## Project layout when using `dotnet-do` 4 | 5 | ``` 6 | [Repo Root]/ 7 | tasks/ 8 | project.json 9 | Program.cs 10 | SomeOfMyTasks.cs 11 | MoreOfMyTasks.cs 12 | ... 13 | src/ 14 | ... 15 | test/ 16 | ... 17 | ... 18 | ``` 19 | 20 | ## The dotnet-do command 21 | 22 | ``` 23 | dotnet do [--debug] [task] 24 | ``` 25 | 26 | Walks up the file system from the current dir, searching for `tasks/project.json` (maybe have a marker field in project.json to make sure we're getting a tasks project? `dotnet-do-project: true`?). When it finds it, it runs `dotnet run [args]` it in the current directory (passing along all the args given to `dotnet do`). 27 | 28 | If `--debug` is specified, it is passed along to the tasks app, which (by using the default Program.Main) will automatically print the PID to the console and wait for a debugger to attach. Maybe also have a `--debug-launch` switch that launches the debugger immediately on Windows? 29 | 30 | If `[task]` is not specified, the task named `Default` is run. 31 | 32 | If `[task]` is the special task name `init`, then a new `dotnet do` project structure is created in `[current directory]/tasks` 33 | 34 | ## "Helpers" 35 | 36 | We can provide a bunch of helpers in some static types and use `using static` to import them! 37 | 38 | ```csharp 39 | namespace DotNetDo 40 | { 41 | public static class Helpers 42 | { 43 | public void Exec(string command, params string[] args) {...} 44 | public void Call(string task) {...} 45 | public string Env(string variableName) {...} 46 | public void Env(string variableName, string newValue) {...} 47 | } 48 | } 49 | 50 | // in a user's tasks project ... 51 | 52 | using static DotNetDo.Helpers; 53 | namespace MyTasks 54 | { 55 | public class MyTasks: TaskCollection 56 | { 57 | [Task] 58 | public void Thingy() 59 | { 60 | Exec("chmod", "a+x", "frob"); 61 | Call("AnotherTask"); 62 | if(Env("PATH").Contains("...")) { 63 | } 64 | } 65 | } 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/Command.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | 5 | namespace DotNetDo.Helpers 6 | { 7 | public class Command 8 | { 9 | private readonly CommandSpec _spec; 10 | private readonly ICommandExecutor _executor; 11 | 12 | public ProcessStartInfo StartInfo { get; } 13 | public bool ExpectFailure { get; set; } 14 | 15 | public Command(CommandSpec spec, ICommandExecutor executor) 16 | { 17 | _spec = spec; 18 | _executor = executor; 19 | 20 | StartInfo = new ProcessStartInfo(); 21 | StartInfo.FileName = spec.Command; 22 | 23 | // Naive argument escaping 24 | StartInfo.Arguments = spec.EscapedArguments; 25 | } 26 | 27 | public Command CaptureStdErr() 28 | { 29 | StartInfo.RedirectStandardError = true; 30 | return this; 31 | } 32 | 33 | public Command CaptureStdOut() 34 | { 35 | StartInfo.RedirectStandardOutput = true; 36 | return this; 37 | } 38 | 39 | public Command WorkingDirectory(string dir) 40 | { 41 | StartInfo.WorkingDirectory = dir; 42 | return this; 43 | } 44 | 45 | public Command ShouldFail() 46 | { 47 | ExpectFailure = true; 48 | return this; 49 | } 50 | 51 | public Command Env(string name, string value) 52 | { 53 | #if NET451 54 | StartInfo.EnvironmentVariables[name] = value; 55 | #else 56 | StartInfo.Environment[name] = value; 57 | #endif 58 | return this; 59 | } 60 | 61 | public Command Env(IEnumerable> values) 62 | { 63 | foreach (var pair in values) 64 | { 65 | Env(pair.Key, pair.Value); 66 | } 67 | return this; 68 | } 69 | 70 | public CommandResult Execute() 71 | { 72 | return _executor.Execute(_spec, StartInfo, ExpectFailure); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNet/DotNetBuildTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetDo.Helpers; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace DotNetDo.BuildSystem.ManagedCode.DotNet 7 | { 8 | public class DotNetBuildTask : TaskCollection 9 | { 10 | public static readonly string Name = nameof(BuildDotNetProjects); 11 | 12 | [Task(RunBefore = BuildLifecycle.PostInitialize)] 13 | public void SetVersionSuffix(ILogger log, DotNetBuildTaskOptions buildOptions, NuGetPackTaskOptions packOptions) 14 | { 15 | if (string.IsNullOrEmpty(buildOptions.VersionSuffix)) 16 | { 17 | var versionSuffix = Environment.GetEnvironmentVariable("DOTNET_BUILD_VERSION"); 18 | if (!string.IsNullOrEmpty(versionSuffix)) 19 | { 20 | buildOptions.VersionSuffix = versionSuffix; 21 | } 22 | } 23 | 24 | if (string.IsNullOrEmpty(buildOptions.VersionSuffix)) 25 | { 26 | // Generate a timestamp based version 27 | var timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss"); 28 | buildOptions.VersionSuffix = $"t-{timestamp}"; 29 | } 30 | 31 | packOptions.VersionSuffix = buildOptions.VersionSuffix; 32 | log.LogInformation($"Version Suffix: {buildOptions.VersionSuffix}"); 33 | } 34 | 35 | [Task(RunBefore = BuildLifecycle.CompileCore)] 36 | public void BuildDotNetProjects(ILogger log, DotNetBuildTaskOptions options, CommandHelper cmd, FileSystemHelper fs) 37 | { 38 | foreach(var project in fs.Files(options.ProjectGlobs)) 39 | { 40 | log.LogTrace("Building {0}", project.FullName); 41 | 42 | var args = new List(); 43 | args.Add(project.FullName); 44 | if (!string.IsNullOrEmpty(options.VersionSuffix)) 45 | { 46 | args.Add("--version-suffix"); 47 | args.Add(options.VersionSuffix); 48 | } 49 | cmd.Exec(DotNetCli.Default.Build(args)); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/dotnet-do/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace DotNetDo.Command 7 | { 8 | public class Program 9 | { 10 | public static int Main(string[] args) 11 | { 12 | // Check if the `init` task is being run 13 | if (args.Any(a => a.Equals("init", StringComparison.OrdinalIgnoreCase))) 14 | { 15 | Console.Error.WriteLine("The 'init' task is reserved for the 'init' command, which is not yet implemented."); 16 | return 1; 17 | } 18 | 19 | // Walk up the file system tree to find the project 20 | var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); 21 | var candidate = Path.Combine(currentDirectory.FullName, "tasks", "project.json"); 22 | while(!File.Exists(candidate) && currentDirectory != null) 23 | { 24 | currentDirectory = currentDirectory.Parent; 25 | candidate = Path.Combine(currentDirectory.FullName, "tasks", "project.json"); 26 | } 27 | 28 | if(!File.Exists(candidate)) 29 | { 30 | Console.Error.WriteLine("Failed to locate tasks file."); 31 | return 2; 32 | } 33 | 34 | // Now run the thing! 35 | // TODO: Argument escaping. Spaces man... Spaces. 36 | // TODO: Also NuGet Restore? 37 | var psi = new ProcessStartInfo() 38 | { 39 | FileName = "dotnet", 40 | Arguments = $"run --project {candidate} {string.Join(" ", args.Select(a => $"\"{a}\""))}", 41 | WorkingDirectory = Directory.GetCurrentDirectory(), 42 | UseShellExecute = false 43 | }; 44 | 45 | // In theory this isn't needed while we're DNX hosted, but when we move to dotnet run, IApplicationEnvironment won't be available. 46 | #if NET451 47 | psi.EnvironmentVariables["DOTNET_DO_PROJECT"] = candidate; 48 | #else 49 | psi.Environment["DOTNET_DO_PROJECT"] = candidate; 50 | #endif 51 | 52 | var process = Process.Start(psi); 53 | process.WaitForExit(); 54 | return process.ExitCode; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/DefaultCommandExecutor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Text; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace DotNetDo.Helpers 7 | { 8 | public class DefaultCommandExecutor : ICommandExecutor 9 | { 10 | public readonly ILogger _log; 11 | 12 | public DefaultCommandExecutor(ILogger log) 13 | { 14 | _log = log; 15 | } 16 | 17 | public CommandResult Execute(CommandSpec spec, ProcessStartInfo startInfo, bool expectFailure) 18 | { 19 | var p = new Process(); 20 | p.StartInfo = startInfo; 21 | 22 | StringBuilder stdout = new StringBuilder(); 23 | if (p.StartInfo.RedirectStandardOutput) 24 | { 25 | p.OutputDataReceived += (sender, args) => stdout.AppendLine(args.Data); 26 | } 27 | 28 | StringBuilder stderr = new StringBuilder(); 29 | if (p.StartInfo.RedirectStandardError) 30 | { 31 | p.ErrorDataReceived += (sender, args) => stderr.AppendLine(args.Data); 32 | } 33 | 34 | using (var activity = _log.BeginActivity("EXEC", FormatStartInfo(p.StartInfo))) 35 | { 36 | p.Start(); 37 | 38 | if (p.StartInfo.RedirectStandardOutput) 39 | { 40 | p.BeginOutputReadLine(); 41 | } 42 | 43 | if (p.StartInfo.RedirectStandardError) 44 | { 45 | p.BeginErrorReadLine(); 46 | } 47 | 48 | p.WaitForExit(); 49 | 50 | activity.Success = (!expectFailure && p.ExitCode == 0) || (expectFailure && p.ExitCode == 0); 51 | activity.Conclusion = FormatConclusion(p.ExitCode, activity.Success); 52 | 53 | return new CommandResult(spec, p.ExitCode, stdout.ToString(), stderr.ToString()); 54 | } 55 | } 56 | 57 | private string FormatConclusion(int exitCode, bool success) 58 | { 59 | string expectation = ""; 60 | if(!success && exitCode != 0) 61 | { 62 | expectation = " but was expected to exit with 0"; 63 | } 64 | else if(!success && exitCode == 0) 65 | { 66 | expectation = " but was expected to return a non-zero exit code"; 67 | } 68 | return $"exited with exit code {exitCode}{expectation}"; 69 | } 70 | 71 | private string FormatStartInfo(ProcessStartInfo startInfo) 72 | { 73 | return $"{startInfo.FileName} {startInfo.Arguments}"; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/TaskRunnerBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace DotNetDo 8 | { 9 | public class TaskRunnerBuilder : ITaskRunnerBuilder 10 | { 11 | private ServiceCollection _services = new ServiceCollection(); 12 | public TaskRunnerBuilder() 13 | { 14 | } 15 | 16 | public static ITaskRunnerBuilder CreateDefault() 17 | { 18 | return new TaskRunnerBuilder().UseServices(ConfigureDefaultServices); 19 | } 20 | 21 | public ITaskRunnerBuilder UseServices(Action registrar) 22 | { 23 | registrar(_services); 24 | return this; 25 | } 26 | 27 | public bool HasService(Type serviceType) 28 | { 29 | return _services.Any(s => s.ServiceType.Equals(serviceType)); 30 | } 31 | 32 | public ITaskRunner Build() 33 | { 34 | var serviceProvider = _services.BuildServiceProvider(); 35 | var taskRunner = serviceProvider.GetRequiredService(); 36 | return taskRunner; 37 | } 38 | 39 | private static void ConfigureDefaultServices(IServiceCollection services) 40 | { 41 | services.AddSingleton(); 42 | services.AddSingleton(); 43 | services.AddSingleton(CreateContext()); 44 | 45 | services.AddSingleton(); 46 | services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); 47 | } 48 | 49 | private static TaskRunContext CreateContext() 50 | { 51 | var doProjectPath = Environment.GetEnvironmentVariable("DOTNET_DO_PROJECT"); 52 | if (string.IsNullOrEmpty(doProjectPath)) 53 | { 54 | doProjectPath = InferProjectPath(); 55 | } 56 | return new TaskRunContext(doProjectPath); 57 | } 58 | 59 | private static string InferProjectPath() 60 | { 61 | #if NET451 62 | var appBase = AppDomain.CurrentDomain.BaseDirectory; 63 | #else 64 | var appBase = AppContext.BaseDirectory; 65 | #endif 66 | 67 | // Search up for a project.json file 68 | var candidate = appBase; 69 | while (candidate != null && !File.Exists(Path.Combine(candidate, "project.json"))) 70 | { 71 | candidate = Path.GetDirectoryName(candidate); 72 | } 73 | if (candidate == null) 74 | { 75 | throw new FileNotFoundException($"Failed to locate 'project.json' file above app base: {appBase}. Try setting DOTNET_DO_PROJECT"); 76 | } 77 | return Path.Combine(candidate, "project.json"); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/ManagedCodeTaskRunnerBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using DotNetDo.BuildSystem.ManagedCode.DotNet; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace DotNetDo.BuildSystem.ManagedCode 6 | { 7 | public static class ManagedCodeTaskRunnerBuilderExtensions 8 | { 9 | public static ITaskRunnerBuilder UseDotNetPack(this ITaskRunnerBuilder self) => UseDotNetPack(self, new NuGetPackTaskOptions("artifacts", new[] { "src/*/project.json" })); 10 | 11 | public static ITaskRunnerBuilder UseDotNetPack(this ITaskRunnerBuilder self, string outputPath, params string[] projectGlobs) => UseDotNetPack(self, new NuGetPackTaskOptions(outputPath, projectGlobs)); 12 | 13 | public static ITaskRunnerBuilder UseDotNetPack(this ITaskRunnerBuilder self, NuGetPackTaskOptions options) 14 | { 15 | self.UseDotNetCliCore(); 16 | return self.UseServices( 17 | ServiceDescriptor.Singleton(options), 18 | ServiceDescriptor.Singleton(new DotNetPackTask())); 19 | } 20 | 21 | public static ITaskRunnerBuilder UseDotNetBuild(this ITaskRunnerBuilder self) => UseDotNetBuild(self, new DotNetBuildTaskOptions(new[] { "src/*/project.json" })); 22 | 23 | public static ITaskRunnerBuilder UseDotNetBuild(this ITaskRunnerBuilder self, params string[] projectGlobs) => UseDotNetBuild(self, new DotNetBuildTaskOptions(projectGlobs)); 24 | 25 | public static ITaskRunnerBuilder UseDotNetBuild(this ITaskRunnerBuilder self, DotNetBuildTaskOptions options) 26 | { 27 | self.UseDotNetCliCore(); 28 | return self.UseServices( 29 | ServiceDescriptor.Singleton(options), 30 | ServiceDescriptor.Singleton(new DotNetBuildTask())); 31 | } 32 | 33 | public static ITaskRunnerBuilder UseDotNetRestore(this ITaskRunnerBuilder self) => UseDotNetRestore(self, new NuGetRestoreTaskOptions(Enumerable.Empty())); 34 | 35 | public static ITaskRunnerBuilder UseDotNetRestore(this ITaskRunnerBuilder self, params string[] directoriesToRestore) => UseDotNetRestore(self, new NuGetRestoreTaskOptions(directoriesToRestore)); 36 | 37 | public static ITaskRunnerBuilder UseDotNetRestore(this ITaskRunnerBuilder self, NuGetRestoreTaskOptions options) 38 | { 39 | self.UseDotNetCliCore(); 40 | return self.UseServices( 41 | ServiceDescriptor.Singleton(options), 42 | ServiceDescriptor.Singleton(new DotNetRestoreTask())); 43 | } 44 | 45 | private static void UseDotNetCliCore(this ITaskRunnerBuilder self) 46 | { 47 | if (!self.HasService()) 48 | { 49 | self.UseServices(ServiceDescriptor.Singleton(new DotNetCliCoreTasks())); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/DotNetDo.Helpers/FileSystemHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using Microsoft.Extensions.FileSystemGlobbing; 6 | using Microsoft.Extensions.FileSystemGlobbing.Abstractions; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace DotNetDo.Helpers 10 | { 11 | public class FileSystemHelper 12 | { 13 | private readonly TaskRunContext _taskRunContext; 14 | private readonly ILogger _log; 15 | 16 | public DirectoryInfoBase Root => Dir(_taskRunContext.DoRoot); 17 | 18 | public FileSystemHelper(ILogger log, TaskRunContext taskRunContext) 19 | { 20 | _log = log; 21 | _taskRunContext = taskRunContext; 22 | } 23 | 24 | public string Resolve(params string[] relativePathSegments) 25 | { 26 | return Path.Combine(_taskRunContext.DoRoot, Path.Combine(relativePathSegments)); 27 | } 28 | 29 | /// 30 | /// Deletes the specified path recursively. If the path is a directory, all files and 31 | /// sub-directories will be deleted as well. 32 | /// 33 | /// 34 | public void RmRf(string path) 35 | { 36 | path = Resolve(path); 37 | 38 | if(Directory.Exists(path)) 39 | { 40 | _log.LogTrace("Deleting directory {0}", path); 41 | Directory.Delete(path, recursive: true); 42 | } 43 | else if(System.IO.File.Exists(path)) 44 | { 45 | _log.LogTrace("Deleting file {0}", path); 46 | System.IO.File.Delete(path); 47 | } 48 | else 49 | { 50 | _log.LogDebug("Not deleting non-existant path {0}", path); 51 | } 52 | } 53 | 54 | public FileInfoBase File(string relativePath) 55 | { 56 | return new FileInfoWrapper(new FileInfo(Resolve(relativePath))); 57 | } 58 | 59 | public DirectoryInfoBase Dir(string relativePath) 60 | { 61 | return new DirectoryInfoWrapper(new DirectoryInfo(_taskRunContext.DoRoot)); 62 | } 63 | 64 | /// 65 | /// Returns a list of files matching the specified globbing patterns. Patterns starting with 66 | /// `!` are interpreted as exclude patterns. 67 | /// 68 | public IEnumerable Files(params string[] globs) => Files((IEnumerable)globs); 69 | 70 | /// 71 | /// Returns a list of files matching the specified globbing patterns. Patterns starting with 72 | /// `!` are interpreted as exclude patterns. 73 | /// 74 | public IEnumerable Files(IEnumerable globs) 75 | { 76 | var matcher = new Matcher(); 77 | var includePatterns = globs.Where(s => s.Length > 0 && s[0] != '!'); 78 | var excludePatterns = globs.Where(s => s.Length > 0 && s[0] == '!').Select(s => s.Substring(1)); 79 | matcher.AddIncludePatterns(includePatterns); 80 | matcher.AddExcludePatterns(excludePatterns); 81 | var results = matcher.Execute(Root); 82 | return results.Files.Select(f => File(f.Path)); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem.ManagedCode/DotNet/DotNetCli.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using DotNetDo.Helpers; 6 | using Microsoft.Extensions.PlatformAbstractions; 7 | 8 | namespace DotNetDo.BuildSystem.ManagedCode.DotNet 9 | { 10 | public class DotNetCli 11 | { 12 | public static readonly DotNetCli Default = GetDefaultCli(); 13 | 14 | public string BasePath { get; } 15 | 16 | public string DriverPath => Path.Combine(BasePath, "bin", OS.ExeName("dotnet")); 17 | 18 | public DotNetCli(string path) 19 | { 20 | BasePath = path; 21 | } 22 | 23 | public CommandSpec Command(IEnumerable args) => new CommandSpec(DriverPath, args); 24 | 25 | public CommandSpec Command(params string[] args) => new CommandSpec(DriverPath, args); 26 | 27 | public CommandSpec Restore(IEnumerable args) => new CommandSpec(DriverPath, GetArgs("restore", args)); 28 | public CommandSpec Restore(params string[] args) => new CommandSpec(DriverPath, GetArgs("restore", args)); 29 | 30 | public CommandSpec Build(IEnumerable args) => new CommandSpec(DriverPath, GetArgs("build", args)); 31 | public CommandSpec Build(params string[] args) => new CommandSpec(DriverPath, GetArgs("build", args)); 32 | 33 | public CommandSpec Pack(IEnumerable args) => new CommandSpec(DriverPath, GetArgs("pack", args)); 34 | public CommandSpec Pack(params string[] args) => new CommandSpec(DriverPath, GetArgs("pack", args)); 35 | 36 | public CommandSpec Run(IEnumerable args) => new CommandSpec(DriverPath, GetArgs("run", args)); 37 | public CommandSpec Run(params string[] args) => new CommandSpec(DriverPath, GetArgs("run", args)); 38 | 39 | public CommandSpec Test(IEnumerable args) => new CommandSpec(DriverPath, GetArgs("test", args)); 40 | public CommandSpec Test(params string[] args) => new CommandSpec(DriverPath, GetArgs("test", args)); 41 | 42 | private static IEnumerable GetArgs(string command, IEnumerable args) => Enumerable.Concat(new[] { command }, args); 43 | 44 | public bool Exists() 45 | { 46 | return File.Exists(DriverPath); 47 | } 48 | 49 | public string GetVersion() 50 | { 51 | var versionFile = Path.Combine(BasePath, ".version"); 52 | var lines = File.ReadAllLines(versionFile); 53 | return $"{lines[1]} (commit {lines[0]})"; 54 | } 55 | 56 | private static DotNetCli GetDefaultCli() 57 | { 58 | // Hacky! 59 | var cliPath = Environment.GetEnvironmentVariable("DOTNET_CLI_PATH"); 60 | if (!string.IsNullOrEmpty(cliPath)) 61 | { 62 | return new DotNetCli(cliPath); 63 | } 64 | else if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows) 65 | { 66 | return new DotNetCli(Path.Combine( 67 | Environment.GetEnvironmentVariable("LOCALAPPDATA"), 68 | "Microsoft", 69 | "dotnet", 70 | "cli")); 71 | } 72 | else 73 | { 74 | return new DotNetCli("/usr/local/share/dotnet/cli"); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/DefaultTaskRunner.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace DotNetDo 9 | { 10 | public class DefaultTaskRunner : ITaskRunner 11 | { 12 | public static readonly string DefaultTask = "Default"; 13 | 14 | private readonly ILogger _log; 15 | private readonly ILoggerFactory _loggerFactory; 16 | private ITaskManager _tasks; 17 | 18 | public DefaultTaskRunner(ILogger log, ILoggerFactory loggerFactory, ITaskManager tasks) 19 | { 20 | _log = log; 21 | _tasks = tasks; 22 | _loggerFactory = loggerFactory; 23 | } 24 | 25 | public int Execute(IEnumerable commandLineArgs) 26 | { 27 | try 28 | { 29 | var args = ParseArguments(commandLineArgs); 30 | 31 | _loggerFactory.AddProvider(new TaskRunnerLoggerProvider((s, l) => args.Verbose ? true : l >= LogLevel.Information)); 32 | 33 | var tasks = args.Tasks; 34 | if (!tasks.Any()) 35 | { 36 | tasks = new[] { DefaultTask }; 37 | } 38 | 39 | foreach (var task in tasks) 40 | { 41 | var result = _tasks.ExecuteTask(task); 42 | if(!result.Success) 43 | { 44 | _log.LogError("Task '{0}' failed: '{1}'", result.Task.Definition.Name, result.Exception.Message); 45 | _log.LogTrace("Exception details: {0}", result.Exception); 46 | return 1; 47 | } 48 | } 49 | _log.LogInformation("All tasks completed!"); 50 | return 0; 51 | } 52 | catch (Exception ex) 53 | { 54 | _log.LogError($"Error: {ex.ToString()}", ex); 55 | return 1; 56 | } 57 | } 58 | 59 | private Args ParseArguments(IEnumerable commandLineArgs) 60 | { 61 | var args = new Args(); 62 | var enumerator = commandLineArgs.GetEnumerator(); 63 | while (enumerator.MoveNext()) // Using a while loop so we can advance the iterator when we hit args with values 64 | { 65 | var key = enumerator.Current; 66 | switch (key) 67 | { 68 | case "-d": 69 | case "--debug": 70 | WaitForDebugger(); 71 | break; 72 | case "-v": 73 | case "--verbose": 74 | args.Verbose = true; 75 | break; 76 | default: 77 | // Not a switch, add it to the list of targets to run 78 | args.Tasks.Add(key); 79 | break; 80 | } 81 | } 82 | 83 | return args; 84 | } 85 | 86 | private void WaitForDebugger() 87 | { 88 | // Why are we using Console directly? Because it only makes sense to write this to the console and we need to read a line 89 | Console.WriteLine("Waiting for the debugger. Press ENTER to continue."); 90 | Console.WriteLine($"Process ID: {Process.GetCurrentProcess().Id}"); 91 | Console.ReadLine(); 92 | } 93 | 94 | private class Args 95 | { 96 | public IList Tasks { get; } = new List(); 97 | public bool Verbose { get; internal set; } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/DotNetDo.Tasks/TaskCollection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading.Tasks; 8 | 9 | namespace DotNetDo 10 | { 11 | public static class TaskCollectionTaskRunnerBuilderExtensions 12 | { 13 | public static ITaskRunnerBuilder UseTasksFrom(this ITaskRunnerBuilder self) => UseTasksFrom(self, typeof(T)); 14 | 15 | public static ITaskRunnerBuilder UseAllTasksFromAssemblyContaining(this ITaskRunnerBuilder self) => UseAllTasksFromAssemblyContaining(self, typeof(T)); 16 | 17 | public static ITaskRunnerBuilder UseTasksFrom(this ITaskRunnerBuilder self, Type type) 18 | { 19 | return self.UseServices(s => s.AddSingleton(typeof(ITaskProvider), type)); 20 | } 21 | 22 | public static ITaskRunnerBuilder UseAllTasksFromAssemblyContaining(this ITaskRunnerBuilder self, Type type) 23 | { 24 | return self.UseServices(s => 25 | { 26 | foreach (var exportedType in type.GetTypeInfo().Assembly.GetExportedTypes()) 27 | { 28 | if (exportedType.GetTypeInfo().BaseType.Equals(typeof(TaskCollection))) 29 | { 30 | s.AddSingleton(typeof(ITaskProvider), exportedType); 31 | } 32 | } 33 | }); 34 | } 35 | } 36 | 37 | public abstract class TaskCollection : ITaskProvider 38 | { 39 | public IEnumerable GetTasks() => from m in GetType().GetMethods() 40 | let attr = m.GetCustomAttribute() 41 | where attr != null 42 | select CreateTask(m, attr); 43 | 44 | private TaskDefinition CreateTask(MethodInfo method, TaskAttribute attr) 45 | { 46 | return new TaskDefinition( 47 | name: string.IsNullOrEmpty(attr.Name) ? method.Name : attr.Name, 48 | source: $"{method.DeclaringType.FullName}.{method.Name}", 49 | dependsOn: attr.DependsOn, 50 | runBefore: attr.RunBefore, 51 | implementation: invocation => 52 | { 53 | var taskManager = invocation.Services.GetRequiredService(); 54 | 55 | var parameters = method.GetParameters(); 56 | var arguments = new object[parameters.Length]; 57 | for (var index = 0; index < parameters.Length; index++) 58 | { 59 | // Special case for logger, we give them a logger of the appropriate category 60 | if (parameters[index].ParameterType.Equals(typeof(ILogger))) 61 | { 62 | var factory = invocation.Services.GetRequiredService(); 63 | arguments[index] = factory.CreateLogger(invocation.Task.Definition.Name); 64 | } 65 | else 66 | { 67 | arguments[index] = invocation.Services.GetService(parameters[index].ParameterType); 68 | } 69 | } 70 | 71 | object result = null; 72 | Exception exception = null; 73 | bool success = true; 74 | try 75 | { 76 | result = method.Invoke(this, arguments); 77 | } 78 | catch(TargetInvocationException tie) 79 | { 80 | success = false; 81 | exception = tie.InnerException; 82 | } 83 | catch (Exception ex) 84 | { 85 | success = false; 86 | exception = ex; 87 | } 88 | 89 | return new TaskResult(invocation.Task, success, result, exception); 90 | }); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/Internal/AnsiLogConsole.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Text; 6 | 7 | namespace DotNetDo.Internal 8 | { 9 | /// 10 | /// For non-Windows platform consoles which understand the ANSI escape code sequences to represent color 11 | /// 12 | public class AnsiLogConsole : IConsole 13 | { 14 | private readonly StringBuilder _outputBuilder; 15 | private readonly IAnsiSystemConsole _systemConsole; 16 | 17 | public AnsiLogConsole(IAnsiSystemConsole systemConsole) 18 | { 19 | _outputBuilder = new StringBuilder(); 20 | _systemConsole = systemConsole; 21 | } 22 | 23 | public void Write(string message, ConsoleColor? background, ConsoleColor? foreground) 24 | { 25 | // Order: backgroundcolor, foregroundcolor, Message, reset foregroundcolor, reset backgroundcolor 26 | if (background.HasValue) 27 | { 28 | _outputBuilder.Append(GetBackgroundColorEscapeCode(background.Value)); 29 | } 30 | 31 | if (foreground.HasValue) 32 | { 33 | _outputBuilder.Append(GetForegroundColorEscapeCode(foreground.Value)); 34 | } 35 | 36 | _outputBuilder.Append(message); 37 | 38 | if (foreground.HasValue) 39 | { 40 | _outputBuilder.Append("\x1B[39m"); // reset to default foreground color 41 | } 42 | 43 | if (background.HasValue) 44 | { 45 | _outputBuilder.Append("\x1B[49m"); // reset to the background color 46 | } 47 | } 48 | 49 | public void WriteLine(string message, ConsoleColor? background, ConsoleColor? foreground) 50 | { 51 | Write(message, background, foreground); 52 | _outputBuilder.AppendLine(); 53 | } 54 | 55 | public void Flush() 56 | { 57 | _systemConsole.Write(_outputBuilder.ToString()); 58 | _outputBuilder.Clear(); 59 | } 60 | 61 | private static string GetForegroundColorEscapeCode(ConsoleColor color) 62 | { 63 | // Foreground colors are at 30-37 and 90-97, so add 30 to whatever we get back 64 | var code = 30 + GetColorEscapeCode(color); 65 | return $"\x1B[{code}m"; 66 | } 67 | 68 | private static string GetBackgroundColorEscapeCode(ConsoleColor color) 69 | { 70 | // Foreground colors are at 40-47 and 100-107, so add 40 to whatever we get back 71 | var code = 40 + GetColorEscapeCode(color); 72 | return $"\x1B[{code}m"; 73 | } 74 | 75 | private static int GetColorEscapeCode(ConsoleColor color) 76 | { 77 | switch (color) 78 | { 79 | case ConsoleColor.Black: 80 | return 0; 81 | case ConsoleColor.Blue: 82 | return 64; 83 | case ConsoleColor.Cyan: 84 | return 66; 85 | case ConsoleColor.DarkBlue: 86 | return 4; 87 | case ConsoleColor.DarkCyan: 88 | return 6; 89 | case ConsoleColor.DarkGray: 90 | return 60; 91 | case ConsoleColor.DarkGreen: 92 | return 2; 93 | case ConsoleColor.DarkMagenta: 94 | return 5; 95 | case ConsoleColor.DarkRed: 96 | return 1; 97 | case ConsoleColor.DarkYellow: 98 | return 3; 99 | case ConsoleColor.Gray: 100 | return 7; 101 | case ConsoleColor.Green: 102 | return 62; 103 | case ConsoleColor.Magenta: 104 | return 65; 105 | case ConsoleColor.Red: 106 | return 61; 107 | case ConsoleColor.White: 108 | return 67; 109 | case ConsoleColor.Yellow: 110 | return 63; 111 | default: 112 | return 9; 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # DotNet CLI install 2 | .dotnet/ 3 | dotnet_install.ps1 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | 8 | # User-specific files 9 | *.suo 10 | *.user 11 | *.userosscache 12 | *.sln.docstates 13 | 14 | # User-specific files (MonoDevelop/Xamarin Studio) 15 | *.userprefs 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Dd]ebugPublic/ 20 | [Rr]elease/ 21 | [Rr]eleases/ 22 | x64/ 23 | x86/ 24 | bld/ 25 | [Bb]in/ 26 | [Oo]bj/ 27 | [Ll]og/ 28 | 29 | # Visual Studio 2015 cache/options directory 30 | .vs/ 31 | # Uncomment if you have tasks that create the project's static files in wwwroot 32 | #wwwroot/ 33 | 34 | # MSTest test Results 35 | [Tt]est[Rr]esult*/ 36 | [Bb]uild[Ll]og.* 37 | 38 | # NUNIT 39 | *.VisualState.xml 40 | TestResult.xml 41 | 42 | # Build Results of an ATL Project 43 | [Dd]ebugPS/ 44 | [Rr]eleasePS/ 45 | dlldata.c 46 | 47 | # DNX 48 | project.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # NCrunch 115 | _NCrunch_* 116 | .*crunch*.local.xml 117 | nCrunchTemp_* 118 | 119 | # MightyMoose 120 | *.mm.* 121 | AutoTest.Net/ 122 | 123 | # Web workbench (sass) 124 | .sass-cache/ 125 | 126 | # Installshield output folder 127 | [Ee]xpress/ 128 | 129 | # DocProject is a documentation generator add-in 130 | DocProject/buildhelp/ 131 | DocProject/Help/*.HxT 132 | DocProject/Help/*.HxC 133 | DocProject/Help/*.hhc 134 | DocProject/Help/*.hhk 135 | DocProject/Help/*.hhp 136 | DocProject/Help/Html2 137 | DocProject/Help/html 138 | 139 | # Click-Once directory 140 | publish/ 141 | 142 | # Publish Web Output 143 | *.[Pp]ublish.xml 144 | *.azurePubxml 145 | # TODO: Comment the next line if you want to checkin your web deploy settings 146 | # but database connection strings (with potential passwords) will be unencrypted 147 | *.pubxml 148 | *.publishproj 149 | 150 | # NuGet Packages 151 | *.nupkg 152 | # The packages folder can be ignored because of Package Restore 153 | **/packages/* 154 | # except build/, which is used as an MSBuild target. 155 | !**/packages/build/ 156 | # Uncomment if necessary however generally it will be regenerated when needed 157 | #!**/packages/repositories.config 158 | # NuGet v3's project.json files produces more ignoreable files 159 | *.nuget.props 160 | *.nuget.targets 161 | 162 | # Microsoft Azure Build Output 163 | csx/ 164 | *.build.csdef 165 | 166 | # Microsoft Azure Emulator 167 | ecf/ 168 | rcf/ 169 | 170 | # Microsoft Azure ApplicationInsights config file 171 | ApplicationInsights.config 172 | 173 | # Windows Store app package directory 174 | AppPackages/ 175 | BundleArtifacts/ 176 | 177 | # Visual Studio cache files 178 | # files ending in .cache can be ignored 179 | *.[Cc]ache 180 | # but keep track of directories ending in .cache 181 | !*.[Cc]ache/ 182 | 183 | # Others 184 | ClientBin/ 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # Paket dependency manager 238 | .paket/paket.exe 239 | 240 | # FAKE - F# Make 241 | .fake/ 242 | -------------------------------------------------------------------------------- /src/DotNetDo.BuildSystem/BuildLifecycleTaskProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DotNetDo.BuildSystem 6 | { 7 | // Standard build workflow 8 | // 9 | // Clean -> PreClean CleanCore PostClean 10 | // Default -> Initialize Compile Test Package Publish 11 | // N -> PreN NCore PostN 12 | 13 | public static class BuildLifecycle 14 | { 15 | public const string Build = nameof(Build); 16 | public const string Rebuild = nameof(Rebuild); 17 | 18 | public const string Clean = nameof(Clean); 19 | public const string CleanCore = nameof(CleanCore); 20 | public const string PreClean = nameof(PreClean); 21 | public const string PostClean = nameof(PostClean); 22 | 23 | public const string Publish = nameof(Publish); 24 | public const string PublishCore = nameof(PublishCore); 25 | public const string PrePublish = nameof(PrePublish); 26 | public const string PostPublish = nameof(PostPublish); 27 | 28 | public const string Package = nameof(Package); 29 | public const string PackageCore = nameof(PackageCore); 30 | public const string PrePackage = nameof(PrePackage); 31 | public const string PostPackage = nameof(PostPackage); 32 | 33 | public const string Test = nameof(Test); 34 | public const string TestCore = nameof(TestCore); 35 | public const string PreTest = nameof(PreTest); 36 | public const string PostTest = nameof(PostTest); 37 | 38 | public const string Compile = nameof(Compile); 39 | public const string CompileCore = nameof(CompileCore); 40 | public const string PreCompile = nameof(PreCompile); 41 | public const string PostCompile = nameof(PostCompile); 42 | 43 | public const string Initialize = nameof(Initialize); 44 | public const string InitializeCore = nameof(InitializeCore); 45 | public const string PreInitialize = nameof(PreInitialize); 46 | public const string PostInitialize = nameof(PostInitialize); 47 | } 48 | 49 | public class BuildLifecycleTaskProvider : ITaskProvider 50 | { 51 | public IEnumerable GetTasks() 52 | { 53 | yield return CreateStandardLifecycleTask("Default", BuildLifecycle.Build); 54 | yield return CreateStandardLifecycleTask(BuildLifecycle.Rebuild, BuildLifecycle.Clean, BuildLifecycle.Build); 55 | yield return CreateStandardLifecycleTask(BuildLifecycle.Build, BuildLifecycle.Initialize, BuildLifecycle.Compile, BuildLifecycle.Test, BuildLifecycle.Package, BuildLifecycle.Publish); 56 | 57 | yield return CreateStandardLifecycleTask(BuildLifecycle.Clean, BuildLifecycle.PreClean, BuildLifecycle.CleanCore, BuildLifecycle.PostClean); 58 | yield return CreateStandardLifecycleTask(BuildLifecycle.PreClean); 59 | yield return CreateStandardLifecycleTask(BuildLifecycle.CleanCore); 60 | yield return CreateStandardLifecycleTask(BuildLifecycle.PostClean); 61 | 62 | yield return CreateStandardLifecycleTask(BuildLifecycle.Publish, BuildLifecycle.PrePublish, BuildLifecycle.PublishCore, BuildLifecycle.PostPublish); 63 | yield return CreateStandardLifecycleTask(BuildLifecycle.PrePublish); 64 | yield return CreateStandardLifecycleTask(BuildLifecycle.PublishCore); 65 | yield return CreateStandardLifecycleTask(BuildLifecycle.PostPublish); 66 | 67 | yield return CreateStandardLifecycleTask(BuildLifecycle.Package, BuildLifecycle.PrePackage, BuildLifecycle.PackageCore, BuildLifecycle.PostPackage); 68 | yield return CreateStandardLifecycleTask(BuildLifecycle.PrePackage); 69 | yield return CreateStandardLifecycleTask(BuildLifecycle.PackageCore); 70 | yield return CreateStandardLifecycleTask(BuildLifecycle.PostPackage); 71 | 72 | yield return CreateStandardLifecycleTask(BuildLifecycle.Test, BuildLifecycle.PreTest, BuildLifecycle.TestCore, BuildLifecycle.PostTest); 73 | yield return CreateStandardLifecycleTask(BuildLifecycle.PreTest); 74 | yield return CreateStandardLifecycleTask(BuildLifecycle.TestCore); 75 | yield return CreateStandardLifecycleTask(BuildLifecycle.PostTest); 76 | 77 | yield return CreateStandardLifecycleTask(BuildLifecycle.Compile, BuildLifecycle.PreCompile, BuildLifecycle.CompileCore, BuildLifecycle.PostCompile); 78 | yield return CreateStandardLifecycleTask(BuildLifecycle.PreCompile); 79 | yield return CreateStandardLifecycleTask(BuildLifecycle.CompileCore); 80 | yield return CreateStandardLifecycleTask(BuildLifecycle.PostCompile); 81 | 82 | yield return CreateStandardLifecycleTask(BuildLifecycle.Initialize, BuildLifecycle.PreInitialize, BuildLifecycle.InitializeCore, BuildLifecycle.PostInitialize); 83 | yield return CreateStandardLifecycleTask(BuildLifecycle.PreInitialize); 84 | yield return CreateStandardLifecycleTask(BuildLifecycle.InitializeCore); 85 | yield return CreateStandardLifecycleTask(BuildLifecycle.PostInitialize); 86 | } 87 | 88 | private TaskDefinition CreateStandardLifecycleTask(string name, params string[] dependencies) 89 | { 90 | return new TaskDefinition(name, typeof(BuildLifecycleTaskProvider).FullName, dependencies, runBefore: null, implementation: null); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /dotnet-do.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F069C1AF-5803-4CB8-ADE3-4D63AC486D03}" 9 | ProjectSection(SolutionItems) = preProject 10 | global.json = global.json 11 | NuGet.Config = NuGet.Config 12 | EndProjectSection 13 | EndProject 14 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-do", "src\dotnet-do\dotnet-do.xproj", "{0D7108E1-CDA5-4227-840B-DD5FEB76AB30}" 15 | EndProject 16 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetDo.Engine", "src\DotNetDo.Engine\DotNetDo.Engine.xproj", "{B5D04BC3-8AF8-4C80-81B2-9D01F0764E14}" 17 | EndProject 18 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "tasks", "tasks\tasks.xproj", "{C06458AC-BC60-46E3-9FF5-745B942C99BD}" 19 | EndProject 20 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetDo.BuildSystem", "src\DotNetDo.BuildSystem\DotNetDo.BuildSystem.xproj", "{3059ADBE-5D0D-47DD-9529-75E2F23852D6}" 21 | EndProject 22 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetDo.Abstractions", "src\DotNetDo.Abstractions\DotNetDo.Abstractions.xproj", "{88A55A16-1861-4ADB-8799-96379155580D}" 23 | EndProject 24 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetDo.BuildSystem.ManagedCode", "src\DotNetDo.BuildSystem.ManagedCode\DotNetDo.BuildSystem.ManagedCode.xproj", "{B249967D-1670-48EB-BEBE-0B379D28AA27}" 25 | EndProject 26 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetDo.Tasks", "src\DotNetDo.Tasks\DotNetDo.Tasks.xproj", "{A9D823FD-4B57-414B-98CE-A5E74E9C63C5}" 27 | EndProject 28 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetDo.Helpers", "src\DotNetDo.Helpers\DotNetDo.Helpers.xproj", "{BF5ED686-D717-4722-B71E-76FE47331D15}" 29 | EndProject 30 | Global 31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 32 | Debug|Any CPU = Debug|Any CPU 33 | Release|Any CPU = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {0D7108E1-CDA5-4227-840B-DD5FEB76AB30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {0D7108E1-CDA5-4227-840B-DD5FEB76AB30}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {0D7108E1-CDA5-4227-840B-DD5FEB76AB30}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {0D7108E1-CDA5-4227-840B-DD5FEB76AB30}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {B5D04BC3-8AF8-4C80-81B2-9D01F0764E14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {B5D04BC3-8AF8-4C80-81B2-9D01F0764E14}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {B5D04BC3-8AF8-4C80-81B2-9D01F0764E14}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {B5D04BC3-8AF8-4C80-81B2-9D01F0764E14}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {C06458AC-BC60-46E3-9FF5-745B942C99BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {C06458AC-BC60-46E3-9FF5-745B942C99BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {C06458AC-BC60-46E3-9FF5-745B942C99BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {C06458AC-BC60-46E3-9FF5-745B942C99BD}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {3059ADBE-5D0D-47DD-9529-75E2F23852D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {3059ADBE-5D0D-47DD-9529-75E2F23852D6}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {3059ADBE-5D0D-47DD-9529-75E2F23852D6}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {3059ADBE-5D0D-47DD-9529-75E2F23852D6}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {88A55A16-1861-4ADB-8799-96379155580D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {88A55A16-1861-4ADB-8799-96379155580D}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {88A55A16-1861-4ADB-8799-96379155580D}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {88A55A16-1861-4ADB-8799-96379155580D}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {B249967D-1670-48EB-BEBE-0B379D28AA27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {B249967D-1670-48EB-BEBE-0B379D28AA27}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {B249967D-1670-48EB-BEBE-0B379D28AA27}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {B249967D-1670-48EB-BEBE-0B379D28AA27}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {A9D823FD-4B57-414B-98CE-A5E74E9C63C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {A9D823FD-4B57-414B-98CE-A5E74E9C63C5}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {A9D823FD-4B57-414B-98CE-A5E74E9C63C5}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {A9D823FD-4B57-414B-98CE-A5E74E9C63C5}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {BF5ED686-D717-4722-B71E-76FE47331D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {BF5ED686-D717-4722-B71E-76FE47331D15}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {BF5ED686-D717-4722-B71E-76FE47331D15}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {BF5ED686-D717-4722-B71E-76FE47331D15}.Release|Any CPU.Build.0 = Release|Any CPU 68 | EndGlobalSection 69 | GlobalSection(SolutionProperties) = preSolution 70 | HideSolutionNode = FALSE 71 | EndGlobalSection 72 | GlobalSection(NestedProjects) = preSolution 73 | {0D7108E1-CDA5-4227-840B-DD5FEB76AB30} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 74 | {B5D04BC3-8AF8-4C80-81B2-9D01F0764E14} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 75 | {3059ADBE-5D0D-47DD-9529-75E2F23852D6} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 76 | {88A55A16-1861-4ADB-8799-96379155580D} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 77 | {B249967D-1670-48EB-BEBE-0B379D28AA27} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 78 | {A9D823FD-4B57-414B-98CE-A5E74E9C63C5} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 79 | {BF5ED686-D717-4722-B71E-76FE47331D15} = {2AA411A5-5F2D-4BF2-B64C-A0C78BCC6875} 80 | EndGlobalSection 81 | EndGlobal 82 | -------------------------------------------------------------------------------- /src/DotNetDo.Engine/DefaultTaskManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | 7 | namespace DotNetDo 8 | { 9 | public class DefaultTaskManager : ITaskManager 10 | { 11 | private readonly ILogger _log; 12 | private readonly IServiceProvider _services; 13 | 14 | private readonly IDictionary _results = new Dictionary(); 15 | 16 | public IReadOnlyDictionary Tasks { get; } 17 | public IReadOnlyDictionary Results { get; } 18 | 19 | public DefaultTaskManager(ILogger log, IServiceProvider services, IEnumerable taskProviders) 20 | { 21 | _log = log; 22 | _services = services; 23 | 24 | var tasks = RegisterTasks(taskProviders.SelectMany(p => p.GetTasks())); 25 | Tasks = new ReadOnlyDictionary(tasks); 26 | Results = new ReadOnlyDictionary(_results); 27 | } 28 | 29 | private IDictionary RegisterTasks(IEnumerable tasks) 30 | { 31 | var graph = new Dictionary(StringComparer.OrdinalIgnoreCase); 32 | foreach (var task in tasks) 33 | { 34 | TaskNode oldTask; 35 | if (graph.TryGetValue(task.Name, out oldTask)) 36 | { 37 | _log.LogTrace("Overriding task {0} defined in {1} by the definition in {2}", task.Name, oldTask.Definition.Source, task.Source); 38 | } 39 | 40 | graph[task.Name] = new TaskNode(task); 41 | } 42 | 43 | // Need a second pass to wire up the "RunBefore"s and stich up the graph 44 | foreach(var task in graph.Values) 45 | { 46 | foreach(var dep in task.Definition.DependsOn) 47 | { 48 | TaskNode dependencyNode; 49 | if(!graph.TryGetValue(dep, out dependencyNode)) 50 | { 51 | throw new KeyNotFoundException($"Task '{task.Definition.Name}' depends on '{dep}', which does not exist."); 52 | } 53 | task.Dependencies.Add(dependencyNode); 54 | } 55 | 56 | if(!string.IsNullOrEmpty(task.Definition.RunBefore)) 57 | { 58 | TaskNode target; 59 | if(!graph.TryGetValue(task.Definition.RunBefore, out target)) 60 | { 61 | throw new InvalidOperationException($"Task '{task.Definition.Name}' is requesting to run before '{task.Definition.RunBefore}', which does not exist"); 62 | } 63 | 64 | // Add in to the graph as a dependency of the specified target 65 | target.Dependencies.Add(task); 66 | } 67 | } 68 | return graph; 69 | } 70 | 71 | public TaskResult ExecuteTask(string taskName) 72 | { 73 | TaskNode task; 74 | if (!Tasks.TryGetValue(taskName, out task)) 75 | { 76 | throw new KeyNotFoundException($"Unknown task: {taskName}"); 77 | } 78 | 79 | return ExecuteTask(task, ChainPredicate(_ => false, task.Definition.Name)); 80 | } 81 | 82 | private TaskResult ExecuteTask(TaskNode task, Func circularDependencyGuard) 83 | { 84 | if(!task.Dependencies.Any() && task.Definition.Implementation == null) 85 | { 86 | _log.LogTrace($"Skipping empty task: {task.Definition.Name}"); 87 | return new TaskResult(task, success: true, returnValue: null, exception: null); 88 | } 89 | 90 | using (var activity = _log.BeginActivity("TASK", task.Definition.Name)) 91 | { 92 | // Run dependencies 93 | TaskResult result; 94 | var dependencyResults = new Dictionary(); 95 | foreach (var dependency in task.Dependencies) 96 | { 97 | if (circularDependencyGuard(dependency.Definition.Name)) 98 | { 99 | throw new InvalidOperationException($"Circular dependency detected at '{dependency.Definition.Name}'"); 100 | } 101 | 102 | result = ExecuteTask(dependency, ChainPredicate(circularDependencyGuard, dependency.Definition.Name)); 103 | if (!result.Success) 104 | { 105 | return result; 106 | } 107 | dependencyResults[dependency.Definition.Name] = result; 108 | } 109 | 110 | // Run the task itself 111 | result = ExecuteTask(new TaskInvocation(task, _services, dependencyResults)); 112 | 113 | activity.Success = result.Success; 114 | 115 | if (result.Exception != null) 116 | { 117 | activity.Conclusion = $"failed with {result.Exception.GetType().Name}: {result.Exception.Message}"; 118 | } 119 | 120 | return result; 121 | } 122 | } 123 | 124 | private TaskResult ExecuteTask(TaskInvocation taskInvocation) 125 | { 126 | TaskResult result; 127 | if (_results.TryGetValue(taskInvocation.Task.Definition.Name, out result)) 128 | { 129 | _log.LogTrace("Returning cached result for task: {0}", taskInvocation.Task.Definition.Name); 130 | return result; 131 | } 132 | 133 | var implementation = taskInvocation.Task.Definition.Implementation; 134 | if (implementation == null) 135 | { 136 | _log.LogTrace("Skipping empty task: {0}", taskInvocation.Task.Definition.Name); 137 | result = new TaskResult(taskInvocation.Task, success: true, returnValue: null, exception: null); 138 | } 139 | else 140 | { 141 | _log.LogTrace("Executing task: {0}", taskInvocation.Task.Definition.Name); 142 | result = implementation(taskInvocation); 143 | } 144 | _results[taskInvocation.Task.Definition.Name] = result; 145 | return result; 146 | } 147 | 148 | private Func ChainPredicate(Func circularDependencyGuard, string name) 149 | { 150 | return other => 151 | string.Equals(name, other, StringComparison.OrdinalIgnoreCase) || 152 | circularDependencyGuard(other); 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /src/DotNetDo.Engine/TaskRunnerLoggerProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.Extensions.PlatformAbstractions; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using DotNetDo.Internal; 6 | 7 | namespace DotNetDo 8 | { 9 | public class TaskRunnerLoggerProvider : ILoggerProvider 10 | { 11 | public static readonly int CategoryMaxLength = 9; 12 | public static readonly int StatusMaxLength = 4; 13 | private readonly Func _filter; 14 | private readonly ConcurrentDictionary _loggers = new ConcurrentDictionary(); 15 | private DateTime? _startTime = null; 16 | 17 | public TaskRunnerLoggerProvider(Func filter) 18 | { 19 | _filter = filter; 20 | } 21 | 22 | public ILogger CreateLogger(string categoryName) 23 | { 24 | return _loggers.GetOrAdd(categoryName, s => new TaskRunnerLogger(this, s, _filter)); 25 | } 26 | 27 | public void Dispose() 28 | { 29 | } 30 | 31 | private TimeSpan GetTimeOffset() 32 | { 33 | var time = DateTime.UtcNow; 34 | if (_startTime == null) 35 | { 36 | _startTime = time; 37 | return TimeSpan.Zero; 38 | } 39 | else 40 | { 41 | return time - _startTime.Value; 42 | } 43 | } 44 | 45 | private class TaskRunnerLogger : ILogger 46 | { 47 | private string _categoryName; 48 | private Func _filter; 49 | private IConsole _console; 50 | private readonly TaskRunnerLoggerProvider _provider; 51 | 52 | public TaskRunnerLogger(TaskRunnerLoggerProvider provider, string categoryName, Func filter) 53 | { 54 | _categoryName = categoryName; 55 | _filter = filter; 56 | _provider = provider; 57 | 58 | if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows) 59 | { 60 | _console = new WindowsLogConsole(); 61 | } 62 | else 63 | { 64 | _console = new AnsiLogConsole(new AnsiSystemConsole()); 65 | } 66 | } 67 | 68 | public IDisposable BeginScopeImpl(object state) 69 | { 70 | var action = state as TaskRunnerActivity; 71 | if(action != null) 72 | { 73 | LogStartAction(action); 74 | return new DisposableAction(() => LogEndAction(action)); 75 | } 76 | else 77 | { 78 | LogCore("START", "", state.ToString(), ConsoleColor.White, ConsoleColor.White, start: true); 79 | return new DisposableAction(() => LogCore("STOP", "", state.ToString(), ConsoleColor.White, ConsoleColor.White, start: false)); 80 | } 81 | } 82 | 83 | public bool IsEnabled(LogLevel logLevel) 84 | { 85 | return _filter(_categoryName, logLevel); 86 | } 87 | 88 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 89 | { 90 | if (!_filter(_categoryName, logLevel)) 91 | { 92 | return; 93 | } 94 | 95 | var categoryColor = ConsoleColor.White; 96 | var messageColor = ConsoleColor.White; 97 | var category = "LOG"; 98 | switch (logLevel) 99 | { 100 | case LogLevel.Debug: 101 | categoryColor = ConsoleColor.DarkMagenta; 102 | messageColor = ConsoleColor.DarkMagenta; 103 | category = "DEBUG"; 104 | break; 105 | case LogLevel.Trace: 106 | categoryColor = ConsoleColor.DarkGray; 107 | messageColor = ConsoleColor.DarkGray; 108 | category = "TRACE"; 109 | break; 110 | case LogLevel.Information: 111 | categoryColor = ConsoleColor.Green; 112 | category = "INFO"; 113 | break; 114 | case LogLevel.Warning: 115 | categoryColor = ConsoleColor.Yellow; 116 | category = "WARNING"; 117 | break; 118 | case LogLevel.Error: 119 | categoryColor = ConsoleColor.Red; 120 | category = "ERROR"; 121 | break; 122 | case LogLevel.Critical: 123 | categoryColor = ConsoleColor.Red; 124 | category = "FATAL"; 125 | break; 126 | default: 127 | break; 128 | } 129 | LogCore(category, string.Empty, formatter(state, exception), categoryColor, messageColor, start: null); 130 | } 131 | 132 | private void LogStartAction(TaskRunnerActivity action) 133 | { 134 | LogCore(action.Type, string.Empty, action.Name, categoryColor: ConsoleColor.Green, messageColor: ConsoleColor.White, start: true); 135 | } 136 | 137 | private void LogEndAction(TaskRunnerActivity action) 138 | { 139 | var message = action.Name; 140 | if(!string.IsNullOrEmpty(action.Conclusion)) 141 | { 142 | message = $"{message} {action.Conclusion}"; 143 | } 144 | var categoryColor = action.Success ? ConsoleColor.Green : ConsoleColor.Red; 145 | var messageColor = action.Success ? ConsoleColor.White : ConsoleColor.Red; 146 | LogCore(action.Type, action.Success ? "OK" : "FAIL", message, categoryColor, messageColor, start: false); 147 | } 148 | 149 | private void LogCore(string category, string status, string message, ConsoleColor categoryColor, ConsoleColor messageColor, bool? start) 150 | { 151 | // Split the message by lines 152 | var startString = start == null ? " " : (start == true ? ">" : "<"); 153 | foreach (var line in message.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) 154 | { 155 | _console.Write($"[{category.PadRight(CategoryMaxLength)}{startString}] ", background: null, foreground: categoryColor); 156 | _console.Write($"[{_provider.GetTimeOffset().ToString(@"hh\:mm\:ss\.ff")}] ", background: null, foreground: messageColor != ConsoleColor.White ? messageColor : ConsoleColor.Blue); 157 | _console.Write($"[{PadCenter(status, StatusMaxLength)}] ", background: null, foreground: messageColor != ConsoleColor.White ? messageColor : ConsoleColor.Yellow); 158 | _console.WriteLine(line, background: null, foreground: messageColor); 159 | _console.Flush(); 160 | } 161 | } 162 | 163 | private string PadCenter(string input, int length) 164 | { 165 | var padding = length - input.Length; 166 | 167 | if(padding < 2) 168 | { 169 | return input; 170 | } 171 | 172 | var leftPadding = (int)Math.Floor((double)padding / 2.0); 173 | var rightPadding = (int)Math.Ceiling((double)padding / 2.0); 174 | return new string(' ', leftPadding) + input + new string(' ', rightPadding); 175 | } 176 | 177 | private class AnsiSystemConsole : IAnsiSystemConsole 178 | { 179 | public void Write(string message) 180 | { 181 | System.Console.Write(message); 182 | } 183 | 184 | public void WriteLine(string message) 185 | { 186 | System.Console.WriteLine(message); 187 | } 188 | } 189 | 190 | private class DisposableAction : IDisposable 191 | { 192 | private Action _act; 193 | 194 | public DisposableAction(Action act) 195 | { 196 | _act = act; 197 | } 198 | 199 | public void Dispose() 200 | { 201 | _act(); 202 | } 203 | } 204 | } 205 | } 206 | } 207 | --------------------------------------------------------------------------------