diff --git a/docs_new/mdsource/script_variables_repository.generated.source.md b/docs_new/mdsource/script_variables_repository.generated.source.md
index 166f3eb4..71c7bd68 100644
--- a/docs_new/mdsource/script_variables_repository.generated.source.md
+++ b/docs_new/mdsource/script_variables_repository.generated.source.md
@@ -6,6 +6,7 @@ This module contains the following methods, variables and/or constants:
- [`repository.branch`](#branch)
- [`repository.branches`](#branches)
+- [`repository.is_bare`](#is_bare)
- [`repository.linux_path`](#linux_path)
- [`repository.local_branches`](#local_branches)
- [`repository.location`](#location)
@@ -34,6 +35,26 @@ Gets the current branch of the repository
The name of the current branch.
+## is_bare
+
+`repository.is_bare`
+
+Gets the information if the repository is a bare repository.
+
+### Returns
+
+If the repository is cloned as bare repository.
+
+### Example
+
+#### Usage
+
+
+```
+repository.is_bare
+```
+
+
## linux_path
`repository.linux_path`
diff --git a/docs_new/script_variables_repository.generated.md b/docs_new/script_variables_repository.generated.md
index 166f3eb4..71c7bd68 100644
--- a/docs_new/script_variables_repository.generated.md
+++ b/docs_new/script_variables_repository.generated.md
@@ -6,6 +6,7 @@ This module contains the following methods, variables and/or constants:
- [`repository.branch`](#branch)
- [`repository.branches`](#branches)
+- [`repository.is_bare`](#is_bare)
- [`repository.linux_path`](#linux_path)
- [`repository.local_branches`](#local_branches)
- [`repository.location`](#location)
@@ -34,6 +35,26 @@ Gets the current branch of the repository
The name of the current branch.
+## is_bare
+
+`repository.is_bare`
+
+Gets the information if the repository is a bare repository.
+
+### Returns
+
+If the repository is cloned as bare repository.
+
+### Example
+
+#### Usage
+
+
+```
+repository.is_bare
+```
+
+
## linux_path
`repository.linux_path`
diff --git a/src/RepoM.ActionMenu.Core/ActionMenu/Context/RepositoryFunctions.cs b/src/RepoM.ActionMenu.Core/ActionMenu/Context/RepositoryFunctions.cs
index 44ee3078..14e0a44d 100644
--- a/src/RepoM.ActionMenu.Core/ActionMenu/Context/RepositoryFunctions.cs
+++ b/src/RepoM.ActionMenu.Core/ActionMenu/Context/RepositoryFunctions.cs
@@ -33,6 +33,20 @@ public RepositoryFunctions(IRepository repository)
[ActionMenuContextMember("name")]
public string Name => _repository.Name;
+ ///
+ /// Gets the information if the repository is a bare repository.
+ ///
+ /// If the repository is cloned as bare repository.
+ ///
+ ///
+ ///
+ /// repository.is_bare
+ ///
+ ///
+ [ActionMenuContextMember("is_bare")]
+ public bool IsBare => _repository.IsBare;
+
+
///
/// Gets the path of the repository. The path is windows or linux based (depending on the running OS) and does NOT end with a (back)slash.
///
diff --git a/src/RepoM.ActionMenu.Core/RepoMCodeGen.generated.cs b/src/RepoM.ActionMenu.Core/RepoMCodeGen.generated.cs
index 52326f5d..cbf5c66d 100644
--- a/src/RepoM.ActionMenu.Core/RepoMCodeGen.generated.cs
+++ b/src/RepoM.ActionMenu.Core/RepoMCodeGen.generated.cs
@@ -31,6 +31,7 @@ protected sealed override void RegisterFunctions()
{
RegisterConstant("branch", CurrentBranch);
RegisterConstant("branches", Branches);
+ RegisterConstant("is_bare", IsBare);
RegisterConstant("linux_path", LinuxPath);
RegisterConstant("local_branches", LocalBranches);
RegisterConstant("location", Location);
diff --git a/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs b/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs
index 79f6987b..16b045af 100644
--- a/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs
+++ b/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs
@@ -246,17 +246,22 @@ public bool IsPinned(IRepository repository)
private void CreateRepositoryObserver(IRepository repo, string path)
{
- if (!_repositoryObservers.ContainsKey(path))
+ if (_repositoryObservers.TryGetValue(path, out IRepositoryObserver? observer))
{
- IRepositoryObserver observer = _repositoryObserverFactory.Create();
- observer.Setup(repo, DelayGitStatusAfterFileOperationMilliseconds);
- _repositoryObservers.Add(path, observer);
+ return;
+ }
+
+ observer = _repositoryObserverFactory.Create();
- observer.OnChange += OnRepositoryObserverChange;
+ if (!_repositoryObservers.TryAdd(path, observer))
+ {
+ observer.Dispose();
+ return;
}
- _repositoryObservers[path].Start();
- _logger.LogDebug("{Method} - repo {Repo}, path: {Path} (total length: {RepositoryObserversLength})", nameof(CreateRepositoryObserver), repo.Name, path, _repositoryObservers.Count);
+ observer.Setup(repo, DelayGitStatusAfterFileOperationMilliseconds);
+ observer.OnChange += OnRepositoryObserverChange;
+ observer.Start();
}
private void OnRepositoryChangeDetected(IRepository repo)
@@ -303,8 +308,12 @@ private void DestroyRepositoryObserver(string path)
return;
}
+ if (!_repositoryObservers.Remove(path))
+ {
+ return;
+ }
+
observer.Stop();
- _repositoryObservers.Remove(path);
}
private void OnRepositoryDeletionDetected(string repoPath)
diff --git a/src/RepoM.Api/Git/DefaultRepositoryObserver.cs b/src/RepoM.Api/Git/DefaultRepositoryObserver.cs
index bb9bcca3..66f57982 100644
--- a/src/RepoM.Api/Git/DefaultRepositoryObserver.cs
+++ b/src/RepoM.Api/Git/DefaultRepositoryObserver.cs
@@ -67,14 +67,16 @@ public void Stop()
public void Dispose()
{
- if (_watcher != null)
+ IFileSystemWatcher? watcher = _watcher;
+ _watcher = null;
+
+ if (watcher != null)
{
- _watcher.Created -= FileSystemUpdated;
- _watcher.Changed -= FileSystemUpdated;
- _watcher.Deleted -= FileSystemUpdated;
- _watcher.Renamed -= FileSystemUpdated;
- _watcher.Dispose();
- _watcher = null;
+ watcher.Created -= FileSystemUpdated;
+ watcher.Changed -= FileSystemUpdated;
+ watcher.Deleted -= FileSystemUpdated;
+ watcher.Renamed -= FileSystemUpdated;
+ watcher.Dispose();
}
LibGit2Sharp.Repository? gr = _gitRepo;
diff --git a/src/RepoM.Api/Git/DefaultRepositoryReader.cs b/src/RepoM.Api/Git/DefaultRepositoryReader.cs
index 04a49b79..7672c2d7 100644
--- a/src/RepoM.Api/Git/DefaultRepositoryReader.cs
+++ b/src/RepoM.Api/Git/DefaultRepositoryReader.cs
@@ -85,10 +85,16 @@ public DefaultRepositoryReader(IRepositoryTagsFactory resolver, ILogger logger)
try
{
using var repo = new LibGit2Sharp.Repository(repoPath);
- RepositoryStatus status = repo.RetrieveStatus();
- var workingDirectory = new DirectoryInfo(repo.Info.WorkingDirectory);
+ RepositoryStatus? status = null;
+ var workingDirectory = new DirectoryInfo(repoPath);
+ if (!repo.Info.IsBare)
+ {
+ status = repo.RetrieveStatus();
+ workingDirectory = new DirectoryInfo(repo.Info.WorkingDirectory);
+ }
+
if (string.IsNullOrWhiteSpace(workingDirectory.Parent?.FullName))
{
_logger.LogError("WorkingDirectory.Parent.Fullname was null or empty for repository found in '{Path}'. Return null", repoPath);
@@ -99,6 +105,7 @@ public DefaultRepositoryReader(IRepositoryTagsFactory resolver, ILogger logger)
var repository = new Repository(workingDirectory.FullName)
{
+ IsBare = repo.Info.IsBare,
Name = workingDirectory.Name,
Location = workingDirectory.Parent.FullName,
Branches = repo.Branches.Select(b => b.FriendlyName).ToArray(),
diff --git a/src/RepoM.Api/Git/Repository.cs b/src/RepoM.Api/Git/Repository.cs
index d839901b..87658aa0 100644
--- a/src/RepoM.Api/Git/Repository.cs
+++ b/src/RepoM.Api/Git/Repository.cs
@@ -12,6 +12,7 @@ public class Repository : IRepository
public Repository(string path)
{
+ IsBare = false;
Name = string.Empty;
Branches = Array.Empty();
LocalBranches = Array.Empty();
@@ -44,6 +45,8 @@ public override int GetHashCode()
return Path.GetHashCode();
}
+ public bool IsBare { get; init; }
+
public string Name { get; set; }
public string Path { get; }
diff --git a/src/RepoM.Core.Plugin/Repository/IRepository.cs b/src/RepoM.Core.Plugin/Repository/IRepository.cs
index 36aa2492..2c2f161b 100644
--- a/src/RepoM.Core.Plugin/Repository/IRepository.cs
+++ b/src/RepoM.Core.Plugin/Repository/IRepository.cs
@@ -9,6 +9,8 @@ public interface IRepository
{
string Name { get; }
+ bool IsBare { get; }
+
string Path { get; }
string WindowsPath { get; }
diff --git a/src/RepoM.Plugin.EverythingFileSearch/Internal/EverythingGitRepositoryFinder.cs b/src/RepoM.Plugin.EverythingFileSearch/Internal/EverythingGitRepositoryFinder.cs
index 018fb4b4..e7d78802 100644
--- a/src/RepoM.Plugin.EverythingFileSearch/Internal/EverythingGitRepositoryFinder.cs
+++ b/src/RepoM.Plugin.EverythingFileSearch/Internal/EverythingGitRepositoryFinder.cs
@@ -16,7 +16,7 @@ public EverythingGitRepositoryFinder(IPathSkipper pathSkipper)
public List Find(string root, Action? onFoundAction)
{
- const string SEARCH = "file: .git\\HEAD";
+ const string SEARCH = "file:\"HEAD\" endwith:\"HEAD\" startwith:\"HEAD\"";
var result = Everything64Api.Search($"\"{root}\" {SEARCH}")
.Where(item => !string.IsNullOrWhiteSpace(item))
diff --git a/tests/RepoM.ActionMenu.Core.Tests/DummyRepository.cs b/tests/RepoM.ActionMenu.Core.Tests/DummyRepository.cs
index 532fa082..e94ae6b1 100644
--- a/tests/RepoM.ActionMenu.Core.Tests/DummyRepository.cs
+++ b/tests/RepoM.ActionMenu.Core.Tests/DummyRepository.cs
@@ -18,6 +18,8 @@ public class DummyRepository : IRepository
public string Name => "dummy name";
+ public bool IsBare => false;
+
public string Path => WindowsPath;
public string WindowsPath=> @"C:\Projects\Github\RepoM";
diff --git a/tests/RepoM.Api.Tests/Git/DefaultRepositoryReaderTests.cs b/tests/RepoM.Api.Tests/Git/DefaultRepositoryReaderTests.cs
new file mode 100644
index 00000000..8a918c3a
--- /dev/null
+++ b/tests/RepoM.Api.Tests/Git/DefaultRepositoryReaderTests.cs
@@ -0,0 +1,60 @@
+namespace RepoM.Api.Tests.Git;
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using FakeItEasy;
+using FluentAssertions;
+using Microsoft.Extensions.Logging;
+using RepoM.Api.Git;
+using RepoM.Api.IO.ModuleBasedRepositoryActionProvider;
+using Xunit;
+
+public class DefaultRepositoryReaderTests
+{
+ private readonly IRepositoryTagsFactory _resolver = A.Fake();
+ private readonly ILogger _logger = A.Dummy();
+
+ [Fact]
+ public void Ctor_ShouldThrow_WhenArgumentNull()
+ {
+ // arrange
+
+ // act
+ Func act1 = () => new DefaultRepositoryReader(_resolver, null!);
+ Func act2 = () => new DefaultRepositoryReader(null!, _logger);
+
+ // assert
+ act1.Should().Throw();
+ act2.Should().Throw();
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public async Task ReadRepositoryAsync_ShouldReturnNull_WhenPathIsNullOrEmpty(string? path)
+ {
+ // arrange
+ var sut = new DefaultRepositoryReader(_resolver, _logger);
+
+ // act
+ Repository? result = await sut.ReadRepositoryAsync(path!);
+
+ // assert
+ result.Should().BeNull();
+ }
+
+ [Fact]
+ public async Task ReadRepositoryAsync_ShouldReturnNull_WhenPathDoesNotExist()
+ {
+ // arrange
+ var path = Path.Combine("C:", Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
+ var sut = new DefaultRepositoryReader(_resolver, _logger);
+
+ // act
+ Repository? result = await sut.ReadRepositoryAsync(path);
+
+ // assert
+ result.Should().BeNull(because:$"Path '{path}' is generated and should not exists.");
+ }
+}
\ No newline at end of file