Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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 DMApp.Common/AppPackageCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ protected AppPackageCreator(IFileSystem fileSystem, ILogCollector logCollector,
throw new ArgumentException("Value can not be empty or whitespace.", nameof(packageName));
}

if (!fileSystem.Directory.Exists(repositoryPath))
if (!fileSystem.Directory.Exists(repositoryPath) && !fileSystem.File.Exists(repositoryPath))
{
throw new System.IO.DirectoryNotFoundException("The specified directory '" + repositoryPath + "' does not exist.");
throw new System.IO.DirectoryNotFoundException("The specified file or directory '" + repositoryPath + "' does not exist.");
}

RepositoryPath = fileSystem.Path.GetFullPath(repositoryPath);
Expand Down
2 changes: 1 addition & 1 deletion DMApp.Common/DMApp.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<ItemGroup>
<PackageReference Include="Skyline.DataMiner.CICD.Common" Version="1.0.4" />
<PackageReference Include="Skyline.DataMiner.CICD.Loggers" Version="1.0.3" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageCreator" Version="1.0.0.33" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageCreator" Version="1.0.0.35-bravo" />
</ItemGroup>

<ItemGroup>
Expand Down
108 changes: 108 additions & 0 deletions DMApp.Common/Dotnet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
namespace Skyline.DataMiner.CICD.DMApp.Common
{
using System;
using System.Diagnostics;
using System.Text;

internal class Dotnet : IDotnet
{
private readonly DataReceivedEventHandler onOutput;
private readonly DataReceivedEventHandler onError;

public Dotnet(DataReceivedEventHandler onOutput, DataReceivedEventHandler onError)
{
this.onOutput = onOutput;
this.onError = onError;
}

public bool Run(string command, bool ignoreOutput)
{
bool success = ignoreOutput
? Run(command, null, null)
: Run(command).succes;

return success;
}

public (bool succes, string output, string errors) Run(string command)
{
StringBuilder totalOutput = new StringBuilder();
StringBuilder totalErrors = new StringBuilder();

bool success = Run(command, OnOutputWrapped, OnErrorWrapped);

return (success, totalOutput.ToString(), totalErrors.ToString());

void OnOutputWrapped(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
totalOutput.AppendLine(e.Data);
onOutput(sender, e);
}
}

void OnErrorWrapped(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
totalErrors.AppendLine(e.Data);
onError(sender, e);
}
}
}

private static bool Run(string command, DataReceivedEventHandler overrideOnOutput, DataReceivedEventHandler overrideOnError)
{
bool useOutput = overrideOnOutput != null;
bool useError = overrideOnError != null;

const string pathTo = "dotnet";
ProcessStartInfo details = new ProcessStartInfo(pathTo, command)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = useError,
RedirectStandardOutput = useOutput
};

bool success;
using (var process = new Process())
{
process.StartInfo = details;

if (useError)
{
process.ErrorDataReceived += overrideOnError;
}

if (useOutput)
{
process.OutputDataReceived += overrideOnOutput;
}

if (process.Start())
{
if (useOutput)
{
process.BeginOutputReadLine();
}

if (useError)
{
process.BeginErrorReadLine();
}

process.WaitForExit();
success = process.ExitCode == 0;
}
else
{
success = false;
}
}

return success;
}
}
}
19 changes: 19 additions & 0 deletions DMApp.Common/DotnetFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Skyline.DataMiner.CICD.DMApp.Common
{
using System.Diagnostics;

/// <summary>
/// Creates instances of <see cref="IDotnet"/>.
/// </summary>
public static class DotnetFactory
{
/// <summary>
/// Creates a single instance of <see cref="IDotnet"/>.
/// </summary>
/// <returns>An instance of <see cref="IDotnet"/>.</returns>
public static IDotnet Create(DataReceivedEventHandler onOutput, DataReceivedEventHandler onError)
{
return new Dotnet(onOutput, onError);
}
}
}
12 changes: 6 additions & 6 deletions DMApp.Common/IAppPackageCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ public interface IAppPackageCreator
/// <value>The log collector.</value>
ILogCollector LogCollector { get; }

/// <summary>
/// Gets the path of the folder containing the items to be added to the package.
/// </summary>
/// <value>The path of the folder containing the items to be added to the package.</value>
string RepositoryPath { get; }

/// <summary>
/// Gets the package name.
/// </summary>
Expand All @@ -35,6 +29,12 @@ public interface IAppPackageCreator
/// <value>The package version.</value>
DMAppVersion PackageVersion { get; }

/// <summary>
/// Gets the path of the folder containing the items to be added to the package.
/// </summary>
/// <value>The path of the folder containing the items to be added to the package.</value>
string RepositoryPath { get; }

/// <summary>
/// Adds the items to the package.
/// </summary>
Expand Down
23 changes: 23 additions & 0 deletions DMApp.Common/IDotnet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Skyline.DataMiner.CICD.DMApp.Common
{
/// <summary>
/// Allows running dotnet commands.
/// </summary>
public interface IDotnet
{
/// <summary>
/// Run a dotnet command.
/// </summary>
/// <param name="command">Command to run.</param>
/// <param name="ignoreOutput"><c>True</c> to ignore the output.</param>
/// <returns><c>True</c> when the command was successful.</returns>
bool Run(string command, bool ignoreOutput);

/// <summary>
/// Run a dotnet command.
/// </summary>
/// <param name="command">Command to run.</param>
/// <returns><c>True</c> when the command was successful and the corresponding output and errors.</returns>
(bool succes, string output, string errors) Run(string command);
}
}
100 changes: 100 additions & 0 deletions DMApp.Keystone/AppPackageCreatorForKeystone.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
namespace Skyline.DataMiner.CICD.DMApp.Keystone
{
using System;
using System.Diagnostics;
using System.Threading.Tasks;

using Skyline.DataMiner.CICD.DMApp.Common;
using Skyline.DataMiner.CICD.FileSystem;
using Skyline.DataMiner.CICD.Loggers;

using static Skyline.AppInstaller.AppPackage;

/// <summary>
/// Represents a creator for application packages specifically for Keystone within the DataMiner System.
/// </summary>
public class AppPackageCreatorForKeystone : AppPackageCreator
{
private readonly ToolMetaData toolMetaData;

/// <summary>
/// Initializes a new instance of the <see cref="AppPackageCreatorForKeystone"/> class.
/// </summary>
/// <param name="toolMetaData">Metadata associated with the tool.</param>
/// <param name="fileSystem">File system interface to manage file operations.</param>
/// <param name="logCollector">Log collector to capture logs during operations.</param>
/// <param name="directoryPath">The directory path where packages are to be created.</param>
/// <param name="packageName">The name of the package.</param>
/// <param name="packageVersion">The version of the package.</param>
public AppPackageCreatorForKeystone(ToolMetaData toolMetaData, IFileSystem fileSystem, ILogCollector logCollector, string directoryPath, string packageName, DMAppVersion packageVersion) : base(fileSystem, logCollector, directoryPath, packageName, packageVersion)
{
this.toolMetaData = toolMetaData;
}

/// <summary>
/// Asynchronously adds items to the application package.
/// </summary>
/// <param name="appPackageBuilder">The application package builder to which the items are added.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public override async Task AddItemsAsync(AppPackageBuilder appPackageBuilder)
{
if (appPackageBuilder == null) throw new ArgumentNullException(nameof(appPackageBuilder));
string pathToCreatedTool;

if (RepositoryPath.EndsWith(".nupkg"))
Comment thread
MichielOda marked this conversation as resolved.
{
// Already provided a nuget dotnet tool?
pathToCreatedTool = RepositoryPath;
}
else
{
// Dotnet tools cannot directly run .exe files. They make their own .exe that runs the Main method from a .dll. So we make our "in-between" tool that then executes the user application.
IUserExecutable userExecutable = new UserExecutable();

static void OnOutput(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
Console.WriteLine(e.Data);
}
}

static void OnError(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
Console.Error.WriteLine(e.Data); // Write the error data to the console
}
}

var dotnet = DotnetFactory.Create(OnOutput, OnError);

pathToCreatedTool = userExecutable.WrapIntoDotnetTool(FileSystem, dotnet, RepositoryPath, toolMetaData);
}

Console.WriteLine($"Creating dmapp from keystone file {pathToCreatedTool}");
appPackageBuilder.WithKeystone(pathToCreatedTool);
}

/// <summary>
/// Contains methods to facilitate the creation of <see cref="AppPackageCreatorForKeystone"/> instances.
/// </summary>
public static class Factory
{
/// <summary>
/// Creates an instance of <see cref="AppPackageCreatorForKeystone"/> from a repository with specified parameters.
/// </summary>
/// <param name="metaData">Metadata associated with the tool.</param>
/// <param name="filesystem">File system interface to manage file operations.</param>
/// <param name="log">Log collector to capture logs during operations.</param>
/// <param name="directoryPath">The directory path where packages are to be created.</param>
/// <param name="packageName">The name of the package.</param>
/// <param name="packageVersion">The version of the package.</param>
/// <returns>Returns a new instance of <see cref="AppPackageCreatorForKeystone"/>.</returns>
public static IAppPackageCreator FromRepository(ToolMetaData metaData, IFileSystem filesystem, ILogCollector log, string directoryPath, string packageName, DMAppVersion packageVersion)
{
return new AppPackageCreatorForKeystone(metaData, filesystem, log, directoryPath, packageName, packageVersion);
}
}
}
}
40 changes: 40 additions & 0 deletions DMApp.Keystone/DMApp.Keystone.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Skyline.DataMiner.CICD.DMApp.Keystone</AssemblyName>
<RootNamespace>Skyline.DataMiner.CICD.DMApp.Keystone</RootNamespace>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>SkylineCommunications</Authors>
<Company>Skyline Communications</Company>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageIcon>icon.png</PackageIcon>
<PackageProjectUrl>https://skyline.be/</PackageProjectUrl>
<PackageTags>Skyline;DataMiner;CICD</PackageTags>
<Description>
Library to convert a directory with an executable into DataMiner Application Packages (.DMApp) file.
Code Entry Point: var builder = AppPackageCreatorForKeystone.Factory.FromDirectory(logCollector, repositoryPath, packageName, packageVersion);
</Description>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/SkylineCommunications/Skyline.DataMiner.CICD.Packages</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>

<ItemGroup>
<Compile Remove="ExeShimmy\**" />
<Content Include="ExeShimmy\**" CopyToOutputDirectory="Always" />
</ItemGroup>

<ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="" />
<None Include="..\_NuGetItems\icon.png" Pack="true" PackagePath="" />
<None Include="..\_NuGetItems\LICENSE.txt" Pack="true" PackagePath="" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DMApp.Common\DMApp.Common.csproj" />
</ItemGroup>

</Project>
46 changes: 46 additions & 0 deletions DMApp.Keystone/ExeShimmy/ExeShim.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>$ToolCommand$</ToolCommandName>
<AssemblyName>$ToolName$</AssemblyName>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<PackageVersion>$ToolVersion$</PackageVersion>
<Version>$ToolVersion$</Version>
<PackageTags>Skyline;DataMiner</PackageTags>
<PackageProjectUrl>https://skyline.be</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageIcon>Icon.png</PackageIcon>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<Authors>$Authors$</Authors>
<Company>$Company$</Company>
<Description></Description>
</PropertyGroup>

<ItemGroup>
<None Include="$ProgramNameShimmy$\**\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<Content Include="Icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</Content>
<Content Include="LICENSE.txt">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</Content>
<Content Include="README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</Content>
</ItemGroup>

</Project>
Binary file added DMApp.Keystone/ExeShimmy/Icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading