Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,37 @@ public static void EnsureDirectoryExists(this string path)
Directory.CreateDirectory(path);
}
}

public static void CopyTo(
this DirectoryInfo sourceDir,
string destinationDir,
bool recursive = true
)
{
if (!sourceDir.Exists)
{
throw new DirectoryNotFoundException(
$"Source directory not found: {sourceDir.FullName}"
);
}

Directory.CreateDirectory(destinationDir);

foreach (var file in sourceDir.GetFiles())
{
var targetFilePath = Path.Combine(destinationDir, file.Name);
file.CopyTo(targetFilePath, true);
}

if (!recursive)
{
return;
}

foreach (var subDir in sourceDir.GetDirectories())
{
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
subDir.CopyTo(newDestinationDir, true);
}
}
}
22 changes: 10 additions & 12 deletions ScriptBeeWebApp/src/Common/Model/Config/ConfigFolders.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
namespace ScriptBee.Domain.Model.Config;
namespace ScriptBee.Domain.Model.Config;

public static class ConfigFolders
{
private const string Root = ".scriptbee";

private const string PluginsFolder = "plugins";

private const string ProjectsFolder = "projects";

public const string SrcFolder = "src";

private static readonly string PathToUserFolder = Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile
);

public static readonly string PathToRoot = Path.Combine(PathToUserFolder, Root);
private static readonly string PathToRoot = Path.Combine(PathToUserFolder, ".scriptbee");

public static readonly string PathToPlugins = Path.Combine(PathToRoot, "plugins");

public static readonly string PathToPlugins = Path.Combine(PathToRoot, PluginsFolder);
public static readonly string PathToGatewayPlugins = Path.Combine(
PathToRoot,
"gateway",
"plugins"
);

public static readonly string PathToProjects = Path.Combine(PathToRoot, ProjectsFolder);
public static readonly string PathToProjects = Path.Combine(PathToRoot, "projects");
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ namespace ScriptBee.Web.Config;

public class PluginsSettings
{
public string? InstallationFolder { get; set; }
public string? InstallationFolder { get; init; }

public string? GatewayInstallationFolder { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ string pluginConfigurationSection
services.AddOptions<PluginsSettings>().BindConfiguration(pluginConfigurationSection);
return services
.AddSingleton<IManagePluginsUseCase, PluginManager>()
.AddSingleton<IPluginPathProvider, PluginPathProvider>()
.AddSingleton<PluginPathProvider>()
.AddSingleton<IPluginPathProvider>(sp => sp.GetRequiredService<PluginPathProvider>())
.AddSingleton<IGatewayPluginPathProvider>(sp =>
sp.GetRequiredService<PluginPathProvider>()
)
.AddPluginReader()
.AddPluginInstaller()
.AddPluginLoader();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
using Microsoft.Extensions.Options;
using ScriptBee.Domain.Model.Config;
using ScriptBee.Domain.Model.Project;
using ScriptBee.Plugins;
using ScriptBee.Service.Gateway.Plugins;
using ScriptBee.Web.Config;

namespace ScriptBee.Web.Services;

public sealed class PluginPathProvider(IOptions<PluginsSettings> pluginSettings)
: IPluginPathProvider
: IGatewayPluginPathProvider
{
public string GetPathToPlugins()
{
return pluginSettings.Value.InstallationFolder ?? ConfigFolders.PathToPlugins;
}

public string GetInstallationFolderPath()
{
return pluginSettings.Value.GatewayInstallationFolder ?? ConfigFolders.PathToGatewayPlugins;
}

public string GetPathToPlugins(ProjectId projectId)
{
return Path.Combine(ConfigFolders.PathToProjects, projectId.Value, "plugins");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ScriptBee.Plugins;

namespace ScriptBee.Service.Gateway.Plugins;

public interface IGatewayPluginPathProvider : IPluginPathProvider
{
string GetInstallationFolderPath();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@

namespace ScriptBee.Service.Gateway.Plugins;

public class PluginManager(
public sealed class PluginManager(
IPluginReader pluginReader,
IPluginLoader pluginLoader,
IPluginPathProvider pluginPathProvider,
IGatewayPluginPathProvider pluginPathProvider,
ILogger<PluginManager> logger
) : IManagePluginsUseCase
{
public void LoadPlugins()
{
var pluginFolderPath = pluginPathProvider.GetPathToPlugins();
var pluginFolderPath = pluginPathProvider.GetInstallationFolderPath();
logger.LogInformation("Loading plugins from {Folder}", pluginFolderPath);

var plugins = pluginReader.ReadPlugins(pluginFolderPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ public class ConfigFoldersService : IConfigFoldersService
{
public string GetPathToSrcFolder(ProjectId projectId, string path)
{
return Path.Combine(
ConfigFolders.PathToProjects,
projectId.ToString(),
ConfigFolders.SrcFolder,
path
);
return Path.Combine(ConfigFolders.PathToProjects, projectId.ToString(), "src", path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,74 @@ public void GivenExistingDirectory_WhenEnsureDirectoryExists_ThenNothingHappens(

Directory.Exists(path).ShouldBeTrue();
}

[Fact]
public void CopyTo_ThrowsDirectoryNotFoundException_WhenSourceDoesNotExist()
{
// Arrange
var nonExistentDir = new DirectoryInfo(
Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())
);

// Act & Assert
Assert.Throws<DirectoryNotFoundException>(() => nonExistentDir.CopyTo("any_destination"));
}

[Fact]
public void CopyTo_CopiesFiles_WhenNotRecursive()
{
// Arrange
var sourcePath = fixture.CreateSubFolder("Source1");
var destPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

File.WriteAllText(Path.Combine(sourcePath, "test.txt"), "hello");
var subDir = Directory.CreateDirectory(Path.Combine(sourcePath, "Sub"));
File.WriteAllText(Path.Combine(subDir.FullName, "hidden.txt"), "should not copy");

var sourceDir = new DirectoryInfo(sourcePath);

// Act
sourceDir.CopyTo(destPath, recursive: false);

// Assert
Assert.True(File.Exists(Path.Combine(destPath, "test.txt")));
Assert.False(Directory.Exists(Path.Combine(destPath, "Sub")));
}

[Fact]
public void CopyTo_CopiesEverything_WhenRecursive()
{
// Arrange
var sourcePath = fixture.CreateSubFolder("Source2");
var destPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

var subDirPath = Path.Combine(sourcePath, "Level1");
Directory.CreateDirectory(subDirPath);
File.WriteAllText(Path.Combine(sourcePath, "root.txt"), "root");
File.WriteAllText(Path.Combine(subDirPath, "child.txt"), "child");

var sourceDir = new DirectoryInfo(sourcePath);

// Act
sourceDir.CopyTo(destPath, recursive: true);

// Assert
Assert.True(File.Exists(Path.Combine(destPath, "root.txt")));
Assert.True(File.Exists(Path.Combine(destPath, "Level1", "child.txt")));
}

[Fact]
public void CopyTo_CreatesDestinationDirectory_IfItDoesNotExist()
{
// Arrange
var sourcePath = fixture.CreateSubFolder("Source3");
var destPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
var sourceDir = new DirectoryInfo(sourcePath);

// Act
sourceDir.CopyTo(destPath);

// Assert
Assert.True(Directory.Exists(destPath));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public class PluginManagerTests
private readonly IPluginReader _pluginReader = Substitute.For<IPluginReader>();
private readonly IPluginLoader _pluginLoader = Substitute.For<IPluginLoader>();

private readonly IPluginPathProvider _pluginPathProvider =
Substitute.For<IPluginPathProvider>();
private readonly IGatewayPluginPathProvider _pluginPathProvider =
Substitute.For<IGatewayPluginPathProvider>();

private readonly ILogger<PluginManager> _logger = Substitute.For<ILogger<PluginManager>>();

Expand All @@ -33,7 +33,7 @@ public PluginManagerTests()
[Fact]
public void GivenEmptyPlugins_WhenLoadPlugins_ThenNoPluginsLoaded()
{
_pluginPathProvider.GetPathToPlugins().Returns("plugin/path");
_pluginPathProvider.GetInstallationFolderPath().Returns("plugin/path");
_pluginReader.ReadPlugins("plugin/path").Returns(new List<Plugin>());

_pluginManager.LoadPlugins();
Expand All @@ -44,7 +44,7 @@ public void GivenEmptyPlugins_WhenLoadPlugins_ThenNoPluginsLoaded()
[Fact]
public void GivenAllValidPlugins_WhenLoadPlugins_ThenAllPluginsAreLoaded()
{
_pluginPathProvider.GetPathToPlugins().Returns("plugin/path");
_pluginPathProvider.GetInstallationFolderPath().Returns("plugin/path");
_pluginReader
.ReadPlugins("plugin/path")
.Returns(
Expand All @@ -70,7 +70,7 @@ public void GivenSomeInvalidPlugins_WhenLoadPlugins_ThenAllValidPluginsAreLoaded
Plugin testPlugin2 = new TestPlugin(new PluginId("id", new Version(0, 0, 1, 1)));
Plugin testPlugin3 = new TestPlugin(new PluginId("id", new Version(0, 0, 2, 1)));

_pluginPathProvider.GetPathToPlugins().Returns("plugin/path");
_pluginPathProvider.GetInstallationFolderPath().Returns("plugin/path");
_pluginReader
.ReadPlugins("plugin/path")
.Returns(new List<Plugin> { testPlugin1, testPlugin2, testPlugin3 });
Expand Down
Loading