Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
# CONFIGURATION
###########################################################################

$TempDirectory = Join-Path $PSScriptRoot '.fallout/temp'
$TempDirectory = "$PSScriptRoot/.fallout/temp"

$DotNetGlobalFile = Join-Path $PSScriptRoot 'global.json'
$DotNetGlobalFile = "$PSScriptRoot/global.json"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "STS"

Expand Down
46 changes: 43 additions & 3 deletions src/Fallout.Cli/Commands/AddPackageCommand.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Fallout.Common;
Expand All @@ -6,13 +7,14 @@
using Fallout.Common.Tooling;
using Fallout.Common.Tools.DotNet;
using Fallout.Solutions;
using Microsoft.Build.Evaluation;

namespace Fallout.Cli.Commands;

/// <summary>
/// <c>fallout :add-package</c>: adds (or upgrades) a NuGet package reference in the build project.
/// </summary>
internal sealed class AddPackageCommand(IConfigurationReader configuration, IPackageManager packages) : IFalloutCommand
internal sealed class AddPackageCommand(IPackageManager packages) : IFalloutCommand
{
public string Name => "add-package";

Expand All @@ -31,8 +33,7 @@ await NuGetVersionResolver.GetLatestVersion(packageId, includePrereleases: false
.ToString())
.NotNull("packageVersion != null");

var configuration1 = configuration.Read(buildScript, evaluate: true);
var buildProjectFile = configuration1[ConfigurationReader.BuildProjectFileKey];
var buildProjectFile = FindBuildProject(rootDirectory);
Host.Information($"Installing {packageId}/{packageVersion} to {buildProjectFile} ...");
packages.AddOrReplacePackage(packageId, packageVersion, PackageManager.DownloadType, buildProjectFile);
DotNetTasks.DotNet($"restore {buildProjectFile}");
Expand All @@ -49,4 +50,43 @@ await NuGetVersionResolver.GetLatestVersion(packageId, includePrereleases: false
Host.Information($"Done installing {packageId}/{packageVersion} to {buildProjectFile}");
return 0;
}

internal static AbsolutePath FindBuildProject(AbsolutePath rootDirectory)
{
var buildProject = rootDirectory.GlobFiles("**/*.csproj")
.Where(x => HasMatchingRootDirectory(x, rootDirectory))
.OrderBy(x => x.ToString().Length)
.FirstOrDefault();

Assert.True(buildProject != null,
$"Could not find a build project with a FalloutRootDirectory property pointing to '{rootDirectory}'.");

return buildProject;
}

private static bool HasMatchingRootDirectory(AbsolutePath projectFile, AbsolutePath rootDirectory)
{
ProjectProperty rootDirectoryProperty;
try
{
rootDirectoryProperty = ProjectModelTasks.ParseProject(projectFile).NotNull()
.GetProperty("FalloutRootDirectory");
}
catch
{
return false;
}

if (string.IsNullOrWhiteSpace(rootDirectoryProperty?.EvaluatedValue))
{
return false;
}

var configuredRootDirectory = rootDirectoryProperty.EvaluatedValue;
var resolvedRootDirectory = Path.IsPathRooted(configuredRootDirectory)
? (AbsolutePath)configuredRootDirectory
: projectFile.Parent / configuredRootDirectory;

return resolvedRootDirectory == rootDirectory;
}
}
2 changes: 2 additions & 0 deletions src/Fallout.Cli/Commands/SetupCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ public async Task<int> ExecuteAsync(string[] args, AbsolutePath rootDirectory, A
new
{
RootDirectory = buildDirectory.GetWinRelativePathTo(rootDirectory),
BuildDirectory = buildProjectRelativeDirectory,
BuildProjectName = buildProjectName,
ScriptDirectory = buildDirectory.GetWinRelativePathTo(WorkingDirectory),
TargetFramework = TARGET_FRAMEWORK,
FalloutVersion = falloutVersion,
Expand Down
4 changes: 2 additions & 2 deletions src/Fallout.Cli/templates/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
# CONFIGURATION
###########################################################################

$TempDirectory = Join-Path $PSScriptRoot '_ROOT_DIRECTORY_/.fallout/temp'
$TempDirectory = "$PSScriptRoot/.fallout/temp"

$DotNetGlobalFile = Join-Path $PSScriptRoot '_ROOT_DIRECTORY_/global.json'
$DotNetGlobalFile = "$PSScriptRoot/global.json"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "STS"

Expand Down
91 changes: 91 additions & 0 deletions tests/Fallout.Cli.Specs/Commands/AddPackageCommandSpecs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.IO;
using Fallout.Cli.Commands;
using Fallout.Common.IO;
using FluentAssertions;
using Xunit;

namespace Fallout.Cli.Specs.Commands;

public class AddPackageCommandSpecs
{
[Fact]
public void Project_with_root_directory_property_is_selected()
{
// Arrange
using var root = TempRoot.Create();
root.WriteProject("src/app.csproj", "<Project />");
var expected = root.WriteProject("build/custom.csproj",
"<Project><PropertyGroup><FalloutRootDirectory>..</FalloutRootDirectory></PropertyGroup></Project>");

// Act
var actual = AddPackageCommand.FindBuildProject(root.Path);

// Assert
actual.Should().Be(expected);
}

[Fact]
public void Missing_root_directory_property_gives_clear_error()
{
// Arrange
using var root = TempRoot.Create();
root.WriteProject("build/build.csproj",
"<Project><!-- <FalloutRootDirectory>..</FalloutRootDirectory> --></Project>");

// Act
var action = () => AddPackageCommand.FindBuildProject(root.Path);

// Assert
action.Should().Throw<Exception>()
.WithMessage("*Could not find a build project*FalloutRootDirectory*");
}

[Fact]
public void Project_with_shortest_path_is_selected()
{
// Arrange
using var root = TempRoot.Create();
root.WriteProject("build/nested/first.csproj",
"<Project><PropertyGroup><FalloutRootDirectory>../..</FalloutRootDirectory></PropertyGroup></Project>");
var expected = root.WriteProject("build/second.csproj",
"<Project><PropertyGroup><FalloutRootDirectory>..</FalloutRootDirectory></PropertyGroup></Project>");

// Act
var actual = AddPackageCommand.FindBuildProject(root.Path);

// Assert
actual.Should().Be(expected);
}

private sealed class TempRoot : IDisposable
{
public AbsolutePath Path { get; }

private TempRoot(AbsolutePath path) => Path = path;

public static TempRoot Create()
{
var path = (AbsolutePath)System.IO.Path.Combine(
System.IO.Path.GetTempPath(), "fallout-add-package-" + Guid.NewGuid().ToString("N"));
path.CreateDirectory();
return new TempRoot(path);
}

public AbsolutePath WriteProject(string relativePath, string content)
{
var project = Path / relativePath;
project.Parent.CreateDirectory();
File.WriteAllText(project, content);
return project;
}

public void Dispose()
{
if (Directory.Exists(Path))
{
Directory.Delete(Path, recursive: true);
}
}
}
}
Loading