From b04e365f6e42ff6fe72590f61f951c96dc004072 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 07:30:01 +0000 Subject: [PATCH 1/3] Skip Finder and Explorer metadata files instead of counting them as failed [patch] ProcessDirectory handed every file in the input folder to the decoder, so .DS_Store, ._ AppleDouble files, Thumbs.db, ehthumbs.db and desktop.ini each counted as a failed icon and printed a decoder dump. Any folder a Mac or Windows file manager had opened then exited 2 even though every icon was written. Skip dot-files and those names (case-insensitively) before decoding, counting them as neither written nor failed. Ordinary non-image files such as notes.txt still count as failed. Fixes #135 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019FkGdWB8Ko3mTn9JiBH973 --- IconHelper.Test/ProcessDirectoryTests.cs | 21 +++++++++++++++++++++ IconHelper/IconHelper.cs | 15 ++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/IconHelper.Test/ProcessDirectoryTests.cs b/IconHelper.Test/ProcessDirectoryTests.cs index 757c8b2..a996283 100644 --- a/IconHelper.Test/ProcessDirectoryTests.cs +++ b/IconHelper.Test/ProcessDirectoryTests.cs @@ -166,6 +166,27 @@ public void ContinuesAfterAFileThatCannotBeDecoded() Assert.IsTrue(File.Exists(Path.Combine(output, "good.png"))); } + [TestMethod] + public void SkipsFileManagerMetadataWithoutCountingItAsFailed() + { + using TempDirectory temp = new(); + string input = temp.Combine("in"); + string output = temp.Combine("out"); + Directory.CreateDirectory(input); + File.WriteAllBytes(Path.Combine(input, ".DS_Store"), [0, 0, 0, 1, (byte)'B', (byte)'u', (byte)'d', (byte)'1']); + File.WriteAllText(Path.Combine(input, "._good.png"), "AppleDouble resource fork"); + File.WriteAllText(Path.Combine(input, "desktop.ini"), "[.ShellClassInfo]\r\n"); + File.WriteAllText(Path.Combine(input, "THUMBS.DB"), "not an image"); + File.WriteAllText(Path.Combine(input, "ehthumbs.db"), "not an image"); + WritePng(Path.Combine(input, "good.png"), 64); + + BatchResult result = IconHelper.ProcessDirectory(ArgumentsFor(input, output), NamedColors.White); + + Assert.AreEqual(new BatchResult(1, 0), result, "File-manager metadata should be neither written nor failed."); + Assert.AreEqual(IconHelper.ExitSuccess, IconHelper.ExitCodeFor(result)); + Assert.AreEqual(1, Directory.GetFiles(output).Length); + } + [TestMethod] public void ReportsAndSkipsAFileThatCannotBeOpened() { diff --git a/IconHelper/IconHelper.cs b/IconHelper/IconHelper.cs index de15552..2b1bd2c 100644 --- a/IconHelper/IconHelper.cs +++ b/IconHelper/IconHelper.cs @@ -125,7 +125,8 @@ internal static BatchResult ProcessDirectory(Arguments args, Color color) // whole string let a directory anywhere above the input -- a user name, a date stamp, // a project folder -- decide that every file below it was already generated. That // failure is silent and total: nothing is written and the run still exits 0. - if (Path.GetFileName(file).Contains(".new.png", StringComparison.Ordinal)) + string fileName = Path.GetFileName(file); + if (fileName.Contains(".new.png", StringComparison.Ordinal) || IsFileManagerMetadata(fileName)) { continue; } @@ -169,6 +170,18 @@ internal static BatchResult ProcessDirectory(Arguments args, Color color) return new BatchResult(processed, failed); } + /// + /// Names that Finder and Explorer drop into any folder they open: dot-files such as .DS_Store and + /// ._ AppleDouble files, plus Thumbs.db, ehthumbs.db and desktop.ini. They are not icons, so they + /// count as neither written nor failed; counting them as failures made every batch on such a + /// folder exit 2 and taught scripts to ignore the code that reports real decode failures. + /// + internal static bool IsFileManagerMetadata(string fileName) + => fileName.StartsWith('.') + || fileName.Equals("Thumbs.db", StringComparison.OrdinalIgnoreCase) + || fileName.Equals("ehthumbs.db", StringComparison.OrdinalIgnoreCase) + || fileName.Equals("desktop.ini", StringComparison.OrdinalIgnoreCase); + /// /// Reduces an icon to a coverage mask: every pixel carries the flat target colour and the shape /// lives entirely in the alpha channel. The result is trimmed of its transparent margins, centred From 564f40095981ba7ae563971b10579fafbd0c8c6d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 07:36:11 +0000 Subject: [PATCH 2/3] Use Path.Join for the metadata test's fixture paths [patch] Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019FkGdWB8Ko3mTn9JiBH973 --- IconHelper.Test/ProcessDirectoryTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/IconHelper.Test/ProcessDirectoryTests.cs b/IconHelper.Test/ProcessDirectoryTests.cs index a996283..f409a21 100644 --- a/IconHelper.Test/ProcessDirectoryTests.cs +++ b/IconHelper.Test/ProcessDirectoryTests.cs @@ -173,12 +173,12 @@ public void SkipsFileManagerMetadataWithoutCountingItAsFailed() string input = temp.Combine("in"); string output = temp.Combine("out"); Directory.CreateDirectory(input); - File.WriteAllBytes(Path.Combine(input, ".DS_Store"), [0, 0, 0, 1, (byte)'B', (byte)'u', (byte)'d', (byte)'1']); - File.WriteAllText(Path.Combine(input, "._good.png"), "AppleDouble resource fork"); - File.WriteAllText(Path.Combine(input, "desktop.ini"), "[.ShellClassInfo]\r\n"); - File.WriteAllText(Path.Combine(input, "THUMBS.DB"), "not an image"); - File.WriteAllText(Path.Combine(input, "ehthumbs.db"), "not an image"); - WritePng(Path.Combine(input, "good.png"), 64); + File.WriteAllBytes(Path.Join(input, ".DS_Store"), [0, 0, 0, 1, (byte)'B', (byte)'u', (byte)'d', (byte)'1']); + File.WriteAllText(Path.Join(input, "._good.png"), "AppleDouble resource fork"); + File.WriteAllText(Path.Join(input, "desktop.ini"), "[.ShellClassInfo]\r\n"); + File.WriteAllText(Path.Join(input, "THUMBS.DB"), "not an image"); + File.WriteAllText(Path.Join(input, "ehthumbs.db"), "not an image"); + WritePng(Path.Join(input, "good.png"), 64); BatchResult result = IconHelper.ProcessDirectory(ArgumentsFor(input, output), NamedColors.White); From 64fce869273c355f0a48b143821c92b838a5609e Mon Sep 17 00:00:00 2001 From: Matthew Edmondson Date: Fri, 9 Oct 2026 21:36:03 +1100 Subject: [PATCH 3/3] Suppress the unpatched ImageSharp 3.1.12 advisories so restore passes NuGet audit reports five advisories against SixLabors.ImageSharp 3.1.12, and with warnings as errors NU1902/NU1903 fail restore on every build. No 3.1.x release patches them; the fix is 4.x, which moved to a split licence, so the 3.1.x pin stays and each advisory is suppressed by name. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_013j5p1tUWLykEtnhAziUkZa --- Directory.Build.props | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 8c119d5..821e140 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,2 +1,16 @@ + + + + + + + +