feat(git-provider): First pass of creating directories from New-GitRepo command
- move GitManager to ModuleCore - refactor SetGitRepoCommand to own file
This commit is contained in:
parent
1363f6ce02
commit
b9f856e716
3 changed files with 173 additions and 36 deletions
131
src/ModuleCore/Git/GitManager.cs
Normal file
131
src/ModuleCore/Git/GitManager.cs
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
namespace ModuleCore.Git;
|
||||||
|
|
||||||
|
// TODO: better name for this
|
||||||
|
public class GitManager
|
||||||
|
{
|
||||||
|
private static readonly Lazy<GitManager> GitManagerInstance = new(() => new GitManager());
|
||||||
|
public static GitManager Instance => GitManagerInstance.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simply <see cref="Path.DirectorySeparatorChar"/>.ToString()
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string DirectorySeparator = Path.DirectorySeparatorChar.ToString();
|
||||||
|
|
||||||
|
private readonly InternalDirectory _repositories;
|
||||||
|
|
||||||
|
private GitManager()
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{nameof(GitManager)} init");
|
||||||
|
// Initialise the root container
|
||||||
|
_repositories = new InternalDirectory()
|
||||||
|
{
|
||||||
|
Name = DirectorySeparator,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a git repository based on an absolute location. If <paramref name="registrationName"/> is null or empty,
|
||||||
|
/// the registration will use the folder name for the git repo at the top level.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="absoluteRepositoryLocation"></param>
|
||||||
|
/// <param name="registrationName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void RegisterRepo(string absoluteRepositoryLocation, string registrationName)
|
||||||
|
{
|
||||||
|
// Regardless of if we get a name or not, the fully qualified version for us
|
||||||
|
// starts with a
|
||||||
|
var directorySegmentsFromName = NameToSegments(
|
||||||
|
string.IsNullOrWhiteSpace(registrationName)
|
||||||
|
? new DirectoryInfo(absoluteRepositoryLocation).Name
|
||||||
|
: registrationName
|
||||||
|
);
|
||||||
|
|
||||||
|
_repositories.Add(absoluteRepositoryLocation, directorySegmentsFromName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Takes a name and returns it as a queue of its parts, starting with a root of <see cref="DirectorySeparator"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private Queue<string> NameToSegments(string name)
|
||||||
|
{
|
||||||
|
var segments = NormaliseNamePath(name).Split(DirectorySeparator);
|
||||||
|
|
||||||
|
return segments.Length == 1
|
||||||
|
? new Queue<string>([DirectorySeparator, name])
|
||||||
|
: new Queue<string>([DirectorySeparator, ..segments]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalises the path separators in the given string to use Path.DirectorySeparatorChar
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private string NormaliseNamePath(string name)
|
||||||
|
{
|
||||||
|
// Feels a bit hacky, but this will actually normalise a path to a valid form. So if the input is
|
||||||
|
// some/directory/paths, Path.GetRelativePath will normalise it to some\directory\paths, relative to ./
|
||||||
|
// which is kind of handy but I also just wish there was a Path method that would do this for me. I know that
|
||||||
|
// the whole point of Path is that it's based on a file system, but file systems can also be arbitrary and not
|
||||||
|
// always be drive rooted.
|
||||||
|
// Either way, this works and saves me having to reimplement a worse method when it's more important that users
|
||||||
|
// are able to use file paths in whatever form they prefer, which means we leverage the internal implementation
|
||||||
|
// in a weird way.
|
||||||
|
return Path.GetRelativePath("./", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InternalDirectory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the folder this
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
public Dictionary<string, InternalDirectory> Children { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If not null, this is the absolute location of a registered git repository
|
||||||
|
/// </summary>
|
||||||
|
public string? FullRepositoryPath { get; set; }
|
||||||
|
|
||||||
|
internal void Add(string absoluteRepositoryLocation, Queue<string> directorySegmentsFromName)
|
||||||
|
{
|
||||||
|
var topStack = directorySegmentsFromName.Dequeue();
|
||||||
|
|
||||||
|
if (topStack == Name)
|
||||||
|
{
|
||||||
|
// We're at the end of the directory segments so we can safely say we're at the end of the tree so
|
||||||
|
// we add it to the relevant dictionary
|
||||||
|
if (directorySegmentsFromName.Count == 0)
|
||||||
|
{
|
||||||
|
FullRepositoryPath = absoluteRepositoryLocation;
|
||||||
|
//Children.Add(topStack, directory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var nextSegment = directorySegmentsFromName.Peek();
|
||||||
|
// Attempt to get the next level of the directory. If we don't have a key entry, create one
|
||||||
|
if (!Children.TryGetValue(nextSegment, out var nextChild))
|
||||||
|
{
|
||||||
|
nextChild = new InternalDirectory()
|
||||||
|
{
|
||||||
|
Name = nextSegment,
|
||||||
|
};
|
||||||
|
Children.Add(nextSegment, nextChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the next
|
||||||
|
nextChild.Add(absoluteRepositoryLocation, directorySegmentsFromName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// logically it shouldn't be possible to have a value on top of the stack that _doesn't_ exist, but
|
||||||
|
// just incase we throw as this should only happen if an Add is attempted on the root and the queue was
|
||||||
|
// not correctly rooted to /
|
||||||
|
throw new Exception($"Directory segment does not seem to exist: {topStack}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Management.Automation;
|
using System.Management.Automation;
|
||||||
using SQLite;
|
using ModuleCore.Git;
|
||||||
|
|
||||||
namespace PowershellModule.Git;
|
namespace PowershellModule.Git;
|
||||||
|
|
||||||
|
|
@ -12,27 +12,40 @@ public class NewGitRepoCommand : PSCmdlet
|
||||||
private const string Noun = "GitRepo";
|
private const string Noun = "GitRepo";
|
||||||
|
|
||||||
[Parameter(
|
[Parameter(
|
||||||
Mandatory = true,
|
|
||||||
Position = 0,
|
Position = 0,
|
||||||
ValueFromPipeline = true,
|
ValueFromPipeline = true,
|
||||||
HelpMessage = "Reference name for the repo")]
|
HelpMessage = "Reference name for the repo")]
|
||||||
public string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
public NewGitRepoCommand()
|
public NewGitRepoCommand()
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{nameof(NewGitRepoCommand)} init");
|
Console.WriteLine($"{nameof(NewGitRepoCommand)} init");
|
||||||
var gm = GitManager.Instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void BeginProcessing()
|
protected override void BeginProcessing()
|
||||||
{
|
{
|
||||||
//using var conn = new SQLiteConnection("./test.db");
|
|
||||||
|
|
||||||
var pwd = this.SessionState.Path.CurrentLocation.Path;
|
var pwd = this.SessionState.Path.CurrentLocation.Path;
|
||||||
WriteObject("Checking if current directory is a git repository...");
|
WriteObject("Checking if current directory is a git repository...");
|
||||||
|
|
||||||
var repoFolfder = IsGitRepo(pwd);
|
var repoFolfder = IsGitRepo(pwd);
|
||||||
|
|
||||||
|
if (repoFolfder is not null)
|
||||||
|
{
|
||||||
|
GitManager.Instance.RegisterRepo(repoFolfder.Directory, Name ?? repoFolfder.Folder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not sure how we'd hit this path, but in case we do, show some sort of error.
|
||||||
|
// TODO: I should probably have IsGitRepo throw instead so I can get the location it tried in the stack track
|
||||||
|
WriteError(new ErrorRecord(
|
||||||
|
new Exception("Unable to register repo - failed to parse git repo location"),
|
||||||
|
"git-parse-failed",
|
||||||
|
ErrorCategory.InvalidData,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
base.BeginProcessing();
|
base.BeginProcessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,33 +112,3 @@ public class NewGitRepoCommand : PSCmdlet
|
||||||
public string Folder { get; set; } = null!;
|
public string Folder { get; set; } = null!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmdlet(VerbsCommon.Set, Noun)]
|
|
||||||
public class SetGitRepoCommand : PSCmdlet
|
|
||||||
{
|
|
||||||
private const string Noun = "GitRepo";
|
|
||||||
|
|
||||||
public SetGitRepoCommand()
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{nameof(NewGitRepoCommand)} init");
|
|
||||||
var a = GitManager.Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void BeginProcessing()
|
|
||||||
{
|
|
||||||
SessionState.Path.SetLocation("F:/Repos/PowershellModule/src/PowershellModule/Git");
|
|
||||||
base.BeginProcessing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: better name for this
|
|
||||||
public class GitManager
|
|
||||||
{
|
|
||||||
private static readonly Lazy<GitManager> GitManagerInstance = new(() => new GitManager());
|
|
||||||
public static GitManager Instance => GitManagerInstance.Value;
|
|
||||||
|
|
||||||
private GitManager()
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{nameof(GitManager)} init");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
23
src/PowershellModule/Git/SetGitRepoCommand.cs
Normal file
23
src/PowershellModule/Git/SetGitRepoCommand.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using ModuleCore.Git;
|
||||||
|
|
||||||
|
namespace PowershellModule.Git;
|
||||||
|
|
||||||
|
[Cmdlet(VerbsCommon.Set, Noun)]
|
||||||
|
public class SetGitRepoCommand : PSCmdlet
|
||||||
|
{
|
||||||
|
private const string Noun = "GitRepo";
|
||||||
|
|
||||||
|
public SetGitRepoCommand()
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{nameof(NewGitRepoCommand)} init");
|
||||||
|
var a = GitManager.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void BeginProcessing()
|
||||||
|
{
|
||||||
|
SessionState.Path.SetLocation("F:/Repos/PowershellModule/src/PowershellModule/Git");
|
||||||
|
base.BeginProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue