Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add progress to Copy-Item #18735

Merged
merged 15 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ internal static bool IsMinimalProgressRenderingEnabled()

sb.Append(secRemain);

if (PercentComplete > 0 && PercentComplete < 100 && barWidth > 0)
if (PercentComplete >= 0 && PercentComplete < 100 && barWidth > 0)
{
int barLength = PercentComplete * barWidth / 100;
if (barLength >= barWidth)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
Expand All @@ -18,6 +19,7 @@
using System.Security;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.XPath;

Expand Down Expand Up @@ -58,6 +60,8 @@ public sealed partial class FileSystemProvider : NavigationCmdletProvider,
// copy script will accommodate the new value.
private const int FILETRANSFERSIZE = 4 * 1024 * 1024;

private const int COPY_FILE_ACTIVITY_ID = 0;

// The name of the key in an exception's Data dictionary when attempting
// to copy an item onto itself.
private const string SelfCopyDataKey = "SelfCopy";
Expand Down Expand Up @@ -3548,14 +3552,73 @@ private static bool DirectoryInfoHasChildItems(DirectoryInfo directory)
}
else // Copy-Item local
{
if (Context != null && Context.ExecutionContext.SessionState.PSVariable.Get(SpecialVariables.ProgressPreferenceVarPath.UserPath).Value is ActionPreference progressPreference && progressPreference == ActionPreference.Continue)
{
{
Task.Run(() =>
{
GetTotalFiles(path, recurse);
});
_copyStopwatch.Start();
}
}

CopyItemLocalOrToSession(path, destinationPath, recurse, Force, null);
if (_totalFiles > 0)
{
_copyStopwatch.Stop();
var progress = new ProgressRecord(COPY_FILE_ACTIVITY_ID, " ", " ");
progress.RecordType = ProgressRecordType.Completed;
WriteProgress(progress);
}
}
}

_excludeMatcher.Clear();
_excludeMatcher = null;
}

private void GetTotalFiles(string path, bool recurse)
{
bool isContainer = IsItemContainer(path);

try
{
if (isContainer)
{
var enumOptions = new EnumerationOptions()
{
IgnoreInaccessible = true,
AttributesToSkip = 0,
RecurseSubdirectories = recurse
};

var directory = new DirectoryInfo(path);
foreach (var file in directory.EnumerateFiles("*", enumOptions))
{
if (!SessionStateUtilities.MatchesAnyWildcardPattern(file.Name, _excludeMatcher, defaultValue: false))
{
_totalFiles++;
_totalBytes += file.Length;
}
}
}
else
{
var file = new FileInfo(path);
if (!SessionStateUtilities.MatchesAnyWildcardPattern(file.Name, _excludeMatcher, defaultValue: false))
{
_totalFiles++;
_totalBytes += file.Length;
}
}
}
catch
{
// ignore exception
}
}

private void CopyItemFromRemoteSession(string path, string destinationPath, bool recurse, bool force, PSSession fromSession)
{
using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create())
Expand Down Expand Up @@ -3864,6 +3927,22 @@ private void CopyFileInfoItem(FileInfo file, string destinationPath, bool force,

FileInfo result = new FileInfo(destinationPath);
WriteItemObject(result, destinationPath, false);

if (_totalFiles > 0)
{
_copiedFiles++;
_copiedBytes += file.Length;
double speed = (double)(_copiedBytes / 1024 / 1024) / _copyStopwatch.Elapsed.TotalSeconds;
var progress = new ProgressRecord(
COPY_FILE_ACTIVITY_ID,
StringUtil.Format(FileSystemProviderStrings.CopyingLocalFileActivity, _copiedFiles, _totalFiles),
StringUtil.Format(FileSystemProviderStrings.CopyingLocalBytesStatus, Utils.DisplayHumanReadableFileSize(_copiedBytes), Utils.DisplayHumanReadableFileSize(_totalBytes), speed)
);
var percentComplete = (int)Math.Min(_copiedBytes * 100 / _totalBytes, 100);
progress.PercentComplete = percentComplete;
progress.RecordType = ProgressRecordType.Processing;
WriteProgress(progress);
}
}
else
{
Expand Down Expand Up @@ -4788,6 +4867,12 @@ private bool PathIsReservedDeviceName(string destinationPath, string errorId)
return pathIsReservedDeviceName;
}

private long _totalFiles;
private long _totalBytes;
private long _copiedFiles;
private long _copiedBytes;
private readonly Stopwatch _copyStopwatch = new Stopwatch();
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved

#endregion CopyItem

#endregion ContainerCmdletProvider members
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,4 +339,10 @@
<data name="NewItemTargetIsSameAsLink" xml:space="preserve">
<value>The target and path cannot be the same.</value>
</data>
<data name="CopyingLocalFileActivity" xml:space="preserve">
<value>Copied {0} of {1} files</value>
</data>
<data name="CopyingLocalBytesStatus" xml:space="preserve">
<value>{0} of {1} ({2:0.0} MB/s)</value>
</data>
</root>
2 changes: 1 addition & 1 deletion test/xUnit/csharp/test_Prediction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContex
{
// The delay is exaggerated to make the test reliable.
// xUnit must spin up a lot tasks, which makes the test unreliable when the time difference between 'delay' and 'timeout' is small.
Thread.Sleep(2000);
Thread.Sleep(3000);
}

// You can get the user input from the AST.
Expand Down