diff --git a/src/AssemblyCrawler.Tests/AssemblyCrawler.Tests.csproj b/src/AssemblyCrawler.Tests/AssemblyCrawler.Tests.csproj
new file mode 100644
index 0000000..b449488
--- /dev/null
+++ b/src/AssemblyCrawler.Tests/AssemblyCrawler.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AssemblyCrawler.Tests/AssemblyExtensionTests.cs b/src/AssemblyCrawler.Tests/AssemblyExtensionTests.cs
new file mode 100644
index 0000000..3b1ba80
--- /dev/null
+++ b/src/AssemblyCrawler.Tests/AssemblyExtensionTests.cs
@@ -0,0 +1,67 @@
+using AssemblyCrawler;
+using System.IO;
+
+namespace AssemblyCrawler.Tests;
+
+public class AssemblyExtensionTests : IDisposable
+{
+ private readonly string _tempDir;
+
+ public AssemblyExtensionTests()
+ {
+ _tempDir = Path.Combine(Path.GetTempPath(), "AssemblyExtensionTests_" + Guid.NewGuid().ToString("N"));
+ Directory.CreateDirectory(_tempDir);
+ }
+
+ public void Dispose()
+ {
+ if (Directory.Exists(_tempDir))
+ Directory.Delete(_tempDir, recursive: true);
+ }
+
+ // IsManagedAssembly uses FName (lowercased), so copy the DLL with a lowercase filename
+ private FileInfo GetManagedDllFileInfo()
+ {
+ string location = typeof(AssemblyExtensionTests).Assembly.Location;
+ string lowercaseName = Path.GetFileName(location).ToLowerInvariant();
+ string dest = Path.Combine(_tempDir, lowercaseName);
+ File.Copy(location, dest, overwrite: true);
+ return new FileInfo(dest);
+ }
+
+ [Fact]
+ public void IsManagedAssembly_ManagedDll_ReturnsTrue()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.True(assemblyInfo.IsManagedAssembly());
+ }
+
+ [Fact]
+ public void IsManagedAssembly_NonManagedFile_ReturnsFalse()
+ {
+ var tempFile = Path.Combine(_tempDir, "notmanaged.dll");
+ File.WriteAllBytes(tempFile, new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 });
+ var fileInfo = new FileInfo(tempFile);
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.False(assemblyInfo.IsManagedAssembly());
+ }
+
+ [Fact]
+ public void SortByHashCode_GroupsIdenticalAssembliesTogether()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var a1 = new AssemblyInfo(fileInfo);
+ var a2 = new AssemblyInfo(fileInfo);
+ var a3 = new AssemblyInfo(fileInfo);
+
+ var list = new List { a1, a2, a3 };
+ var sorted = list.SortByHashCode();
+
+ // All three should have the same hash code and be in the same group
+ Assert.Single(sorted);
+ Assert.Equal(3, sorted.Values.First().Count);
+ }
+}
diff --git a/src/AssemblyCrawler.Tests/AssemblyInfoTests.cs b/src/AssemblyCrawler.Tests/AssemblyInfoTests.cs
new file mode 100644
index 0000000..77270f8
--- /dev/null
+++ b/src/AssemblyCrawler.Tests/AssemblyInfoTests.cs
@@ -0,0 +1,89 @@
+using AssemblyCrawler;
+using System.IO;
+using System.Reflection;
+
+namespace AssemblyCrawler.Tests;
+
+public class AssemblyInfoTests : IDisposable
+{
+ private readonly string _tempDir;
+
+ public AssemblyInfoTests()
+ {
+ _tempDir = Path.Combine(Path.GetTempPath(), "AssemblyInfoTests_" + Guid.NewGuid().ToString("N"));
+ Directory.CreateDirectory(_tempDir);
+ }
+
+ public void Dispose()
+ {
+ if (Directory.Exists(_tempDir))
+ Directory.Delete(_tempDir, recursive: true);
+ }
+
+ // IsManagedAssembly uses FName (lowercased), so copy the DLL with a lowercase filename
+ private FileInfo GetManagedDllFileInfo()
+ {
+ string location = typeof(AssemblyInfoTests).Assembly.Location;
+ string lowercaseName = Path.GetFileName(location).ToLowerInvariant();
+ string dest = Path.Combine(_tempDir, lowercaseName);
+ File.Copy(location, dest, overwrite: true);
+ return new FileInfo(dest);
+ }
+
+ [Fact]
+ public void Constructor_ManagedDll_PopulatesFName()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.Equal(fileInfo.Name.ToLowerInvariant(), assemblyInfo.FName.Value);
+ }
+
+ [Fact]
+ public void Constructor_ManagedDll_IsManaged_ReturnsTrue()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.True(assemblyInfo.IsManaged.Value);
+ }
+
+ [Fact]
+ public void Constructor_ManagedDll_AName_IsNotEmpty()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.NotEmpty(assemblyInfo.AName.Value);
+ }
+
+ [Fact]
+ public void Constructor_ManagedDll_AssemblyVersion_IsNotNull()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.NotNull(assemblyInfo.AssemblyVersion.Value);
+ }
+
+ [Fact]
+ public void Constructor_NonManagedBinary_IsManaged_ReturnsFalse()
+ {
+ var tempFile = Path.Combine(_tempDir, "notadll.dll");
+ File.WriteAllBytes(tempFile, new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 });
+ var fileInfo = new FileInfo(tempFile);
+ var assemblyInfo = new AssemblyInfo(fileInfo);
+
+ Assert.False(assemblyInfo.IsManaged.Value);
+ }
+
+ [Fact]
+ public void GetHashCode_SameAssembly_ReturnsConsistentValue()
+ {
+ var fileInfo = GetManagedDllFileInfo();
+ var assemblyInfo1 = new AssemblyInfo(fileInfo);
+ var assemblyInfo2 = new AssemblyInfo(fileInfo);
+
+ Assert.Equal(assemblyInfo1.GetHashCode(), assemblyInfo2.GetHashCode());
+ }
+}
diff --git a/src/AssemblyCrawler.Tests/CrawlerTests.cs b/src/AssemblyCrawler.Tests/CrawlerTests.cs
new file mode 100644
index 0000000..6e3dcbe
--- /dev/null
+++ b/src/AssemblyCrawler.Tests/CrawlerTests.cs
@@ -0,0 +1,102 @@
+using AssemblyCrawler;
+using System.IO;
+
+namespace AssemblyCrawler.Tests;
+
+public class CrawlerTests : IDisposable
+{
+ private readonly string _tempDir;
+
+ public CrawlerTests()
+ {
+ _tempDir = Path.Combine(Path.GetTempPath(), "CrawlerTests_" + Guid.NewGuid().ToString("N"));
+ Directory.CreateDirectory(_tempDir);
+ }
+
+ public void Dispose()
+ {
+ if (Directory.Exists(_tempDir))
+ Directory.Delete(_tempDir, recursive: true);
+ }
+
+ private void CopyTestDllToDir(string dir, string fileName)
+ {
+ string sourceDll = typeof(CrawlerTests).Assembly.Location;
+ // Use lowercase filename to match FName.Value (which lowercases the name)
+ File.Copy(sourceDll, Path.Combine(dir, fileName.ToLowerInvariant()), overwrite: true);
+ }
+
+ [Fact]
+ public void Crawl_ValidDirectory_PopulatesAssemblyListAndCounts()
+ {
+ CopyTestDllToDir(_tempDir, "test1.dll");
+ CopyTestDllToDir(_tempDir, "test2.dll");
+
+ var crawler = new Crawler(_tempDir);
+ crawler.Crawl();
+
+ Assert.True(crawler.TotalFileCount >= 2);
+ Assert.True(crawler.TotalAssemblyCount >= 2);
+ Assert.True(crawler.AssemblyList.Count >= 2);
+ }
+
+ [Fact]
+ public void Crawl_CalledTwice_DoesNotReCrawl()
+ {
+ CopyTestDllToDir(_tempDir, "test1.dll");
+
+ var crawler = new Crawler(_tempDir);
+ crawler.Crawl();
+ int countAfterFirstCrawl = crawler.TotalAssemblyCount;
+
+ // Copy another DLL to the dir between crawls (shouldn't be picked up)
+ CopyTestDllToDir(_tempDir, "test2.dll");
+ crawler.Crawl();
+
+ Assert.Equal(countAfterFirstCrawl, crawler.TotalAssemblyCount);
+ }
+
+ [Fact]
+ public void Sort_BeforeCrawl_DoesNotCrash()
+ {
+ var crawler = new Crawler(_tempDir);
+
+ // Should print "Must parse directory first." but not throw
+ var exception = Record.Exception(() => crawler.Sort());
+ Assert.Null(exception);
+ }
+
+ [Fact]
+ public void Sort_AfterCrawl_SeparatesManagedAndUnmanaged()
+ {
+ CopyTestDllToDir(_tempDir, "managed1.dll");
+ CopyTestDllToDir(_tempDir, "managed2.dll");
+
+ // Create a non-managed binary file
+ var nonManagedPath = Path.Combine(_tempDir, "native.dll");
+ File.WriteAllBytes(nonManagedPath, new byte[128]);
+
+ var crawler = new Crawler(_tempDir);
+ crawler.Crawl();
+ crawler.Sort();
+
+ // AllAssemblies contains assemblies with duplicates (>1 copy)
+ // AllManagedAssemblies is the filtered managed subset
+ // Both should be valid without exception
+ Assert.NotNull(crawler.AllAssemblies);
+ Assert.NotNull(crawler.AllManagedAssemblies);
+ }
+
+ [Fact]
+ public void CrawlDirectory_IgnoresResourceDlls()
+ {
+ CopyTestDllToDir(_tempDir, "regular.dll");
+ CopyTestDllToDir(_tempDir, "resources.resources.dll");
+
+ var crawler = new Crawler(_tempDir);
+ crawler.Crawl();
+
+ // The .resources.dll should be ignored; only regular.dll counted
+ Assert.Equal(1, crawler.TotalAssemblyCount);
+ }
+}
diff --git a/src/AssemblyCrawler.Tests/StringExtensionTests.cs b/src/AssemblyCrawler.Tests/StringExtensionTests.cs
new file mode 100644
index 0000000..841c781
--- /dev/null
+++ b/src/AssemblyCrawler.Tests/StringExtensionTests.cs
@@ -0,0 +1,30 @@
+using AssemblyCrawler;
+
+namespace AssemblyCrawler.Tests;
+
+public class StringExtensionTests
+{
+ [Fact]
+ public void GetStableHashCode_SameInput_ReturnsSameValue()
+ {
+ var hash1 = "hello".GetStableHashCode();
+ var hash2 = "hello".GetStableHashCode();
+ Assert.Equal(hash1, hash2);
+ }
+
+ [Fact]
+ public void GetStableHashCode_DifferentInputs_ReturnsDifferentValues()
+ {
+ var hash1 = "hello".GetStableHashCode();
+ var hash2 = "world".GetStableHashCode();
+ Assert.NotEqual(hash1, hash2);
+ }
+
+ [Fact]
+ public void GetStableHashCode_EmptyString_ReturnsConsistentValue()
+ {
+ var hash1 = "".GetStableHashCode();
+ var hash2 = "".GetStableHashCode();
+ Assert.Equal(hash1, hash2);
+ }
+}
diff --git a/src/AssemblyCrawler.sln b/src/AssemblyCrawler.sln
index 1185269..13c30c3 100644
--- a/src/AssemblyCrawler.sln
+++ b/src/AssemblyCrawler.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyCrawler", "AssemblyCrawler\AssemblyCrawler.csproj", "{F4896D2F-EC6F-426D-9321-F874423D7DE5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyCrawler.Tests", "AssemblyCrawler.Tests\AssemblyCrawler.Tests.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
{F4896D2F-EC6F-426D-9321-F874423D7DE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4896D2F-EC6F-426D-9321-F874423D7DE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4896D2F-EC6F-426D-9321-F874423D7DE5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/AssemblyCrawler/Assembly.cs b/src/AssemblyCrawler/Assembly.cs
index b502fe9..8dd1384 100644
--- a/src/AssemblyCrawler/Assembly.cs
+++ b/src/AssemblyCrawler/Assembly.cs
@@ -6,35 +6,6 @@
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
-using System.Security.Cryptography;
-
-
-/* NOTES
-
-// Get
-
-
- // Any CPU = x86 + COMIMAGE_FLAGS_ILONLY will give the flag
-
- (dwManagedImageFlags &COMIMAGE_FLAGS_ILONLY) != 0;
-
-
- // How you get the core header
-
- if (image_optional_header.h32.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
- {
- *ManagedCode = image_optional_header.h32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size ? TRUE : FALSE;
- if (*ManagedCode)
- {
- fSucc = ReadCORHeader(hImage,
- image_optional_header.h32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress,
- image_optional_header.h32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size,
- image_section_headers,
- section_count,
- &ich);
- }
- }
-*/
namespace AssemblyCrawler
{
@@ -44,11 +15,11 @@ internal class AssemblyInfo
public readonly Lazy AName;
public readonly Lazy AssemblyVersion;
public readonly Lazy FileVersion;
- public Lazy FileSize;
- public Lazy PublicKeyToken;
- public Lazy FrameworkVersion;
+ public readonly Lazy FileSize;
+ public readonly Lazy PublicKeyToken;
+ public readonly Lazy FrameworkVersion;
- public Lazy IsManaged;
+ public readonly Lazy IsManaged;
public string Path => file.DirectoryName;
@@ -92,8 +63,10 @@ private AssemblyName GetAssemblyName()
{
return AssemblyName.GetAssemblyName(file.FullName);
}
- catch
- { }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"GetAssemblyName failed for '{file.FullName}': {ex.Message}");
+ }
}
return default;
}
@@ -163,31 +136,6 @@ private string InitializeFramework()
return "Unknown";
}
- public bool IsReadyToRun()
- {
- using var stream = File.OpenRead(file.FullName);
- using var reader = new PEReader(stream);
-
- // From Concord: https://devdiv.visualstudio.com/DevDiv/_git/Concord?path=/src/impl/Common/PEFile.cpp&version=GBmain&line=1761&lineEnd=1770&lineStartColumn=1&lineEndColumn=18&lineStyle=plain&_a=contents
- //DWORD dwSignature = 0;
- //HRESULT hr = ReadRVA(m_IMAGE_COR20_HEADER.ManagedNativeHeader.VirtualAddress, &dwSignature, sizeof(DWORD));
- //if (hr != S_OK)
- //{
- // VSFAIL("failed to read ManagedNativeHeader Signature???");
- //}
- //else
- //{
- // m_fManagedReadyToRun = dwSignature == 0x00525452; // 'RTR'
- //}
-
- return false;
- }
-
- private string GetPublicKey()
- {
- return HexByteArrayToString(assemblyName.Value?.GetPublicKey());
- }
-
private string GetPublicKeyToken()
{
return HexByteArrayToString(assemblyName.Value?.GetPublicKeyToken());
diff --git a/src/AssemblyCrawler/AssemblyCrawler.csproj b/src/AssemblyCrawler/AssemblyCrawler.csproj
index b4974ce..8f59415 100644
--- a/src/AssemblyCrawler/AssemblyCrawler.csproj
+++ b/src/AssemblyCrawler/AssemblyCrawler.csproj
@@ -2,12 +2,17 @@
Exe
- net6.0
+ net8.0
preview
enable
-
+
+
+
+
+ <_Parameter1>AssemblyCrawler.Tests
+
diff --git a/src/AssemblyCrawler/AssemblyExtension.cs b/src/AssemblyCrawler/AssemblyExtension.cs
index f928ec1..6de13bc 100644
--- a/src/AssemblyCrawler/AssemblyExtension.cs
+++ b/src/AssemblyCrawler/AssemblyExtension.cs
@@ -3,8 +3,6 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace AssemblyCrawler
{
diff --git a/src/AssemblyCrawler/Crawler.cs b/src/AssemblyCrawler/Crawler.cs
index ebd49cc..ca930d1 100644
--- a/src/AssemblyCrawler/Crawler.cs
+++ b/src/AssemblyCrawler/Crawler.cs
@@ -4,8 +4,6 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace AssemblyCrawler
{
@@ -56,10 +54,10 @@ public void CrawlDirectory(DirectoryInfo d)
var assemblyFiles = files.Where(file => string.Equals(file.Extension, ".dll", StringComparison.OrdinalIgnoreCase)
&& !file.Name.EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase) // Ignore Resource dlls
- && !file.Attributes.HasFlag(FileAttributes.ReparsePoint)); // Ignore symlinks
+ && !file.Attributes.HasFlag(FileAttributes.ReparsePoint)).ToList(); // Ignore symlinks
- TotalFileCount += files.Count();
- TotalAssemblyCount += assemblyFiles.Count();
+ TotalFileCount += files.Count;
+ TotalAssemblyCount += assemblyFiles.Count;
assemblies.AddRange(assemblyFiles.Select(a => new AssemblyInfo(a)));
@@ -122,7 +120,7 @@ public void Sort()
}
}
- sortedAssemblies_managed = new Dictionary>>(sortedAssemblies_all);
+ sortedAssemblies_managed = new Dictionary>>(sortedAssemblies_all, StringComparer.OrdinalIgnoreCase);
keyList = sortedAssemblies_managed.Keys.ToList();
foreach (var key in keyList)
@@ -132,141 +130,12 @@ public void Sort()
if (sortedAssemblies_managed[key][key2][0].IsManaged.Value == false)
{
sortedAssemblies_managed.Remove(key);
+ break;
}
}
}
Console.WriteLine($"Sort complete in {sw.ElapsedMilliseconds}ms");
}
-
- private const string AssemblyCacheFolderName = "AssemblyCache";
- private const string PreCacheFileName = "files.txt";
- //public void CreateSymlinks(string assemblyName)
- //{
- // //copy each specific assembly
- // if (string.IsNullOrWhiteSpace(assemblyName) || !sortedAssemblies_managed.ContainsKey(assemblyName))
- // {
- // Console.WriteLine("Empty or invalid assembly name");
- // }
-
- // var list = sortedAssemblies_managed[assemblyName];
- // if (!list.Any())
- // {
- // Console.WriteLine($"No duplicates found for ${assemblyName}.");
- // return;
- // }
-
- // var assemblyByHashCode = list.SortByHashCode();
-
- // // create new folder
- // var vsInstallationFolder = System.IO.Path.Combine(ParsePath, "Common7", "IDE");
- // while (!Directory.Exists(vsInstallationFolder))
- // {
- // Console.WriteLine($"Installation not found at '{vsInstallationFolder}'");
- // Console.WriteLine("Enter location of Visual Studio Installation:");
- // vsInstallationFolder = Console.ReadLine();
-
- // if (String.IsNullOrWhiteSpace(vsInstallationFolder))
- // {
- // return;
- // }
- // }
-
- // var assemblyCacheFolder = Path.Combine(vsInstallationFolder, AssemblyCacheFolderName);
- // CreateDirectoryIfNotExists(assemblyCacheFolder);
-
- // var assemblyNameFolder = Path.Combine(assemblyCacheFolder, assemblyName);
- // CreateDirectoryIfNotExists(assemblyNameFolder);
-
- // var keys = assemblyByHashCode.Keys.ToList();
- // //create symlinks
- // foreach (var key in keys)
- // {
- // try
- // {
- // var hashCodeFolder = Path.Combine(assemblyNameFolder, key.ToString("X8"));
- // CreateDirectoryIfNotExists(hashCodeFolder);
-
- // var instances = assemblyByHashCode[key].Where(item => !Path.GetFullPath(item.Path).StartsWith(Path.GetFullPath(hashCodeFolder), StringComparison.OrdinalIgnoreCase)).ToList();
-
- // if (!instances.Any())
- // {
- // continue;
- // }
-
- // var paths = instances.Select(item => item.Path).ToList();
-
- // var precacheFileName = Path.Combine(hashCodeFolder, PreCacheFileName);
-
- // {
- // using FileStream fs = new FileStream(precacheFileName, FileMode.Append);
- // using StreamWriter sw = new StreamWriter(fs);
-
- // //don't pick up the ones in the cache folder
- // paths.ForEach(item => sw.WriteLine(item));
- // sw.Flush();
- // sw.Close();
- // }
-
- // var fileName = instances[0].FName.Value;
- // var cacheAssemblyFileName = Path.Combine(hashCodeFolder, assemblyName);
-
- // // copy one into it if it doesn't exist
- // if (!File.Exists(cacheAssemblyFileName))
- // {
- // //these should all be the same so we don't care which one we're copying
- // File.Copy(Path.Combine(paths[0], fileName), cacheAssemblyFileName);
- // }
-
- // foreach (var path in paths)
- // {
- // var target = Path.Combine(path, fileName);
- // try
- // {
- // File.Delete(target);
- // MakeSymLink(target, cacheAssemblyFileName);
- // }
- // catch
- // {
- // //undo the delete if soemthing bad happens
- // if (!File.Exists(target))
- // {
- // File.Copy(cacheAssemblyFileName, target);
- // }
- // throw;
- // }
- // }
- // }
- // catch (UnauthorizedAccessException)
- // {
- // Console.WriteLine("Don't have access");
- // throw;
- // }
- // }
- //}
-
- private static void CreateDirectoryIfNotExists(string path)
- {
- if (!Directory.Exists(path))
- {
- Directory.CreateDirectory(path);
- }
- }
-
- private static void MakeSymLink(string symLinkPath, string destinationFile)
- {
- ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", $"/c mklink \"{symLinkPath}\" \"{destinationFile}\"");
- var process = Process.Start(psi);
- while (!process.HasExited)
- {
- process.WaitForExit();
- }
-
- if (process.ExitCode != 0)
- {
- Console.WriteLine($"Failed to create symlink {symLinkPath} pointing to {destinationFile}. ExitCode {process.ExitCode}.");
- throw new InvalidOperationException();
- }
- }
}
}
diff --git a/src/AssemblyCrawler/Program.cs b/src/AssemblyCrawler/Program.cs
index e009ee4..cd8afc0 100644
--- a/src/AssemblyCrawler/Program.cs
+++ b/src/AssemblyCrawler/Program.cs
@@ -15,7 +15,7 @@ public static void Main(string[] args)
{
if (args.Length > 0)
{
- Console.Error.WriteLine("Argument count not correct");
+ Console.Error.WriteLine("This program does not accept command-line arguments.");
return;
}
@@ -25,6 +25,14 @@ public static void Main(string[] args)
public static void InnerLoop(string? path = null)
{
+ if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path))
+ {
+ Crawler c = new Crawler(path);
+ c.Crawl();
+ crawler = c;
+ c.Sort();
+ }
+
bool exit = false;
while (!exit)
{
@@ -130,9 +138,6 @@ private static void List()
case "r":
GenerateRyansList(useManaged);
break;
- case "s":
- CreateSymLinkForAssembly();
- break;
case "q":
exit = true;
break;
@@ -145,22 +150,6 @@ private static void List()
}
}
- private static void CreateSymLinkForAssembly()
- {
- //// only symlink managed assemblies
- //var list = ListToUse(true);
- //Console.WriteLine("Enter assembly name for SymLinking:");
- //var assemblyName = Console.ReadLine();
- //if (string.IsNullOrWhiteSpace(assemblyName) || !list.Keys.Contains(assemblyName, StringComparer.OrdinalIgnoreCase))
- //{
- // Console.WriteLine("Invalid assemblyname or assemblyname not found. Only Managed Assembly names supported.");
- // return;
- //}
-
- //crawler.CreateSymlinks(assemblyName);
-
- }
-
private static void GenerateRyansList(bool useManaged)
{
var sortedList = ListToUse(useManaged);
@@ -178,7 +167,7 @@ private static void GenerateRyansList(bool useManaged)
}
else
{
- FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
+ FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
sw = new StreamWriter(fs);
}
@@ -250,7 +239,7 @@ private static void GetDetail(bool useManaged)
var keyItems = sortedList.Where(item => item.Value.Count() == count).ToList();
var keyItemCount = keyItems.Count();
- Console.WriteLine($"{keyItemCount} itemsfound for target count {count}.");
+ Console.WriteLine($"{keyItemCount} items found for target count {count}.");
for (int i = 0; i < keyItemCount; i++)
{
Console.WriteLine($" {keyItems[i].Key}");