Skip to content

Commit d5de5e2

Browse files
authored
Update RoboCommandPortable.cs
Claude Suggested Fixes
1 parent 78a7811 commit d5de5e2

1 file changed

Lines changed: 65 additions & 114 deletions

File tree

RoboSharp.Extensions/RoboCommandPortable.cs

Lines changed: 65 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#if NET6_0_OR_GREATER
1+
#if NET6_0_OR_GREATER
22

33
using RoboSharp.EventArgObjects;
44
using RoboSharp.Extensions.Helpers;
@@ -293,12 +293,8 @@ private async Task RunAsync(CancellationToken cancellationToken)
293293
bool touchFiles = CopyOptions.CreateDirectoryAndFileTree;
294294
bool purging = !SelectionOptions.ExcludeExtra && (CopyOptions.Purge || CopyOptions.Mirror);
295295
bool reportExtraFiles = (!SelectionOptions.ExcludeExtra || (purging && CopyOptions.Depth != 1) ) && (LoggingOptions.VerboseOutput || LoggingOptions.ReportExtraFiles);
296-
297-
// !!!! -- TODO : FIX REPORTeXTRAdIRS -- THIS IS NOT WORKING YET ---
298-
// Something to do with maxdepth == 1 & all other conditions...
299-
bool reportExtraDirs = maxDepth != 1 && !(!purging && !(CopyOptions.IsRecursive()) && !LoggingOptions.ReportExtraFiles && !CopyOptions.HasDefaultFileFilter());
300-
//reportExtraFiles || (CopyOptions.CopySubdirectories || CopyOptions.CopySubdirectoriesIncludingEmpty || CopyOptions.MoveFilesAndDirectories);
301-
296+
bool reportExtraDirs = !SelectionOptions.ExcludeExtra;
297+
302298
SemaphoreSlim multiThreadedController = new SemaphoreSlim(CopyOptions.MultiThreadedCopiesCount >= 128 ? 128 : CopyOptions.MultiThreadedCopiesCount <= 1 ? 1 : CopyOptions.MultiThreadedCopiesCount);
303299
Dictionary<string, ProcessedFileInfo> infoDict = new();
304300
ConcurrentDictionary<IFileCopier, Task> runningTasks = new();
@@ -353,81 +349,30 @@ private async Task RunAsync(CancellationToken cancellationToken)
353349

354350
// ── Process Purge candidates (destination-only files) ────────────────────
355351
// ── Perform this first to clear space and also reduce run-time (avoid evaluating files that are copied into destination)
356-
if (dirPair.Destination.Exists)
357-
{
358-
if (purging && dirPair.IsExtra())
359-
{
360-
dirPair.Destination.Delete(true);
361-
continue; // source does not exist -> move to next dirpair
362-
}
352+
// Detect Extra Directories (dest dirs not in source tree)
353+
if (dirPair.Destination.Exists)
354+
{
355+
foreach (var child in Directory.EnumerateDirectories(dirPair.Destination.FullName, "*", SearchOption.TopDirectoryOnly))
356+
{
357+
if (infoDict.ContainsKey(child))
358+
continue; // part of source tree, already handled
363359

364-
// Report or Purge extra files
365-
await foreach (IFileCopier purgeCopier in CreatePurgeCandidates(dirPair, cancellationToken))
366-
{
367-
cancellationToken.ThrowIfCancellationRequested();
360+
// This directory exists in dest but not source — it's Extra
361+
if (reportExtraDirs || purging)
362+
{
363+
var extraInfo = new ProcessedFileInfo(child, FileClassType.NewDir,
364+
fileClass: Configuration.LogParsing_ExtraDir, purging ? -1 : 0);
365+
resultsBuilder.AddDir(extraInfo);
366+
OnFileProcessed?.Invoke(this, new FileProcessedEventArgs(extraInfo));
367+
}
368368

369-
EvaluateFilePair(purgeCopier);
370-
ProcessedFileInfo purgeInfo = purgeCopier.ProcessedFileInfo;
369+
if (purging)
370+
{
371+
PurgeExtraDirectory(child, resultsBuilder, cancellationToken);
372+
}
373+
}
374+
}
371375

372-
if (purgeCopier.ShouldPurge)
373-
{
374-
OnFileProcessed?.Invoke(this, new FileProcessedEventArgs(purgeInfo));
375-
376-
try
377-
{
378-
purgeCopier.Destination.Delete();
379-
progressReporter.AddFileExtra(purgeInfo);
380-
resultsBuilder.AddFilePurged(purgeInfo);
381-
}
382-
catch (OperationCanceledException)
383-
{
384-
throw;
385-
}
386-
catch (Exception ex)
387-
{
388-
resultsBuilder.AddFileFailed(purgeInfo);
389-
OnCommandError?.Invoke(this, new CommandErrorEventArgs(ex.Message, ex));
390-
}
391-
}
392-
else
393-
{
394-
// Extra file is present but purge is disabled — treat as skipped/extra
395-
progressReporter.AddFileExtra(purgeInfo);
396-
resultsBuilder.AddFileExtra(purgeInfo);
397-
OnFileProcessed?.Invoke(this, new FileProcessedEventArgs(purgeInfo));
398-
}
399-
}
400-
401-
// Detect Extra Directories
402-
if (true || currentDepth <= maxDepth)
403-
{
404-
foreach (var child in Directory.EnumerateDirectories(dirPair.Destination.FullName, "*", SearchOption.TopDirectoryOnly))
405-
{
406-
// check if dictionary contains the key
407-
if (infoDict.ContainsKey(child))
408-
continue;
409-
410-
// not part of source tree:
411-
if (reportExtraDirs)
412-
{
413-
var info = new ProcessedFileInfo(child, FileClassType.NewDir, fileClass: Configuration.LogParsing_ExtraDir, purging ? -1 : 0);
414-
resultsBuilder.AddDir(info);
415-
}
416-
417-
if (purging)
418-
{
419-
try
420-
{
421-
Directory.Delete(child, true);
422-
}
423-
catch (Exception e)
424-
{
425-
OnCommandError?.Invoke(this, new CommandErrorEventArgs($"Unable to purge directory : {child}", e));
426-
}
427-
}
428-
}
429-
}
430-
}
431376

432377
// ── Process Source files for copy/move ──────────────────────────────────────────────────
433378
if (dirPair.Source.Exists)
@@ -551,42 +496,48 @@ private async Task PerformCopyOrMove(
551496
}
552497
}
553498

554-
/// <summary> Processes an EXTRA directory tree from the destination, potentially purging it.</summary>
555-
private void ProcessExtraDirectory(DirectoryPair pair, int currentDepth, ResultsBuilder resultsBuilder)
556-
{
557-
if (!pair.Destination.Exists) return;
558-
bool shouldPurge = CopyOptions.Purge && this.ShouldPurge(pair);
559-
560-
// This gets it to pass unit tests, but *feels* wrong
561-
if (!shouldPurge && !CopyOptions.IsRecursive() && !LoggingOptions.ReportExtraFiles && !CopyOptions.HasDefaultFileFilter()) return;
562-
563-
if (pair.ProcessedFileInfo is null)
564-
pair.ProcessedFileInfo = new ProcessedFileInfo(directory: pair.Destination, this, ProcessedDirectoryFlag.ExtraDir, size: -1);
565-
566-
resultsBuilder.AddDir(pair.ProcessedFileInfo);
567-
if (!shouldPurge) return;
568-
569-
////Process Files
570-
//IEnumerable<FilePair> files = pair.DestinationFiles;
571-
//foreach (var file in files)
572-
//{
573-
// if (cancelRequest.IsCancellationRequested) break;
574-
// ProcessExtraFile(file);
575-
//}
576-
577-
//// Dig into subdirectories
578-
//if (PairEvaluator.CanDigDeeper(currentDepth))
579-
//{
580-
// foreach (var dir in pair.ExtraDirectories)
581-
// {
582-
// if (cancelRequest.IsCancellationRequested) break;
583-
// ProcessExtraDirectory(dir, currentDepth + 1);
584-
// }
585-
//}
586-
587-
// Delete the current directory
499+
/// <summary>
500+
/// Recursively reports and deletes an extra destination directory and all its contents.
501+
/// Mirrors RoboCopy's behaviour: files are counted as Extra/Purged before the directory is deleted.
502+
/// </summary>
503+
private void PurgeExtraDirectory(string destDir, ResultsBuilder resultsBuilder, CancellationToken cancellationToken)
504+
{
505+
cancellationToken.ThrowIfCancellationRequested();
506+
507+
// Report and count each file inside the extra directory before deleting
508+
foreach (var file in Directory.EnumerateFiles(destDir, "*", SearchOption.TopDirectoryOnly))
509+
{
510+
var fileInfo = new FileInfo(file);
511+
var rPath = Path.GetRelativePath(CopyOptions.Destination, file);
512+
var pfi = new ProcessedFileInfo(rPath, FileClassType.NewDir,
513+
fileClass: Configuration.LogParsing_ExtraDir, size: -1);
514+
// Mark as extra/purged in results
515+
resultsBuilder.AddFilePurged(pfi);
516+
OnFileProcessed?.Invoke(this, new FileProcessedEventArgs(pfi));
517+
}
518+
519+
// Recurse into subdirectories of this extra dir
520+
foreach (var subDir in Directory.EnumerateDirectories(destDir, "*", SearchOption.TopDirectoryOnly))
521+
{
522+
cancellationToken.ThrowIfCancellationRequested();
523+
var extraInfo = new ProcessedFileInfo(subDir, FileClassType.NewDir,
524+
fileClass: Configuration.LogParsing_ExtraDir, size: -1);
525+
resultsBuilder.AddDir(extraInfo);
526+
OnFileProcessed?.Invoke(this, new FileProcessedEventArgs(extraInfo));
527+
PurgeExtraDirectory(subDir, resultsBuilder, cancellationToken);
528+
}
529+
530+
// Now delete the whole tree
531+
try
532+
{
533+
Directory.Delete(destDir, true);
534+
}
535+
catch (Exception e)
536+
{
537+
OnCommandError?.Invoke(this, new CommandErrorEventArgs($"Unable to purge directory: {destDir}", e));
538+
}
539+
}
588540

589-
}
590541

591542
/// <summary>
592543
/// Yields the root pair and (if recurse is true) all sub-directory pairs, mirroring Robocopy's directory tree walk.

0 commit comments

Comments
 (0)