Browse Source

Fix #1923: Add progress reporting to PowerShell GetDecompiledProjectCmdlet

pull/1930/head
Siegfried Pammer 5 years ago
parent
commit
d051e3aca4
  1. 58
      ICSharpCode.Decompiler.PowerShell/GetDecompiledProjectCmdlet.cs
  2. 9
      ICSharpCode.Decompiler.PowerShell/ICSharpCode.Decompiler.PowerShell.csproj
  3. 18
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

58
ICSharpCode.Decompiler.PowerShell/GetDecompiledProjectCmdlet.cs

@ -1,8 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Management.Automation; using System.Management.Automation;
using System.Text; using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
@ -10,7 +11,7 @@ namespace ICSharpCode.Decompiler.PowerShell
{ {
[Cmdlet(VerbsCommon.Get, "DecompiledProject")] [Cmdlet(VerbsCommon.Get, "DecompiledProject")]
[OutputType(typeof(string))] [OutputType(typeof(string))]
public class GetDecompiledProjectCmdlet : PSCmdlet public class GetDecompiledProjectCmdlet : PSCmdlet, IProgress<DecompilationProgress>
{ {
[Parameter(Position = 0, Mandatory = true)] [Parameter(Position = 0, Mandatory = true)]
public CSharpDecompiler Decompiler { get; set; } public CSharpDecompiler Decompiler { get; set; }
@ -20,6 +21,20 @@ namespace ICSharpCode.Decompiler.PowerShell
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string LiteralPath { get; set; } public string LiteralPath { get; set; }
int completed;
string fileName;
ConcurrentQueue<ProgressRecord> progress = new ConcurrentQueue<ProgressRecord>();
public void Report(DecompilationProgress value)
{
int current = completed;
int next = current + 1;
next = Interlocked.CompareExchange(ref completed, next, current);
progress.Enqueue(new ProgressRecord(1, "Decompiling " + fileName, $"Completed {next} of {value.TotalNumberOfFiles}: {value.Status}") {
PercentComplete = (int)(next * 100.0 / value.TotalNumberOfFiles)
});
}
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath); string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
@ -29,16 +44,43 @@ namespace ICSharpCode.Decompiler.PowerShell
} }
try { try {
WholeProjectDecompiler decompiler = new WholeProjectDecompiler(); var task = Task.Run(() => DoDecompile(path));
PEFile module = Decompiler.TypeSystem.MainModule.PEFile; int timeout = 100;
decompiler.AssemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Reader.DetectTargetFrameworkId());
decompiler.DecompileProject(module, path); // Give the decompiler some time to spin up all threads
Thread.Sleep(timeout);
WriteObject("Decompilation finished"); while (!task.IsCompleted) {
if (progress.TryDequeue(out var record)) {
while (progress.TryDequeue(out var next)) {
record = next;
}
timeout = 100;
WriteProgress(record);
} else {
Thread.Sleep(timeout);
timeout = Math.Min(1000, timeout * 2);
}
}
task.Wait();
WriteProgress(new ProgressRecord(1, "Decompiling " + fileName, "Decompilation finished") { RecordType = ProgressRecordType.Completed });
} catch (Exception e) { } catch (Exception e) {
WriteVerbose(e.ToString()); WriteVerbose(e.ToString());
WriteError(new ErrorRecord(e, ErrorIds.DecompilationFailed, ErrorCategory.OperationStopped, null)); WriteError(new ErrorRecord(e, ErrorIds.DecompilationFailed, ErrorCategory.OperationStopped, null));
} }
} }
private void DoDecompile(string path)
{
WholeProjectDecompiler decompiler = new WholeProjectDecompiler();
PEFile module = Decompiler.TypeSystem.MainModule.PEFile;
decompiler.AssemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Reader.DetectTargetFrameworkId());
decompiler.ProgressIndicator = this;
fileName = module.FileName;
completed = 0;
decompiler.DecompileProject(module, path);
}
} }
} }

9
ICSharpCode.Decompiler.PowerShell/ICSharpCode.Decompiler.PowerShell.csproj

@ -9,10 +9,17 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" /> <PackageReference Include="PowerShellStandard.Library" Version="5.1.0" />
<PackageReference Include="ICSharpCode.Decompiler" Version="6.0.0.5559-preview2" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" /> <PackageReference Include="Mono.Cecil" Version="0.10.3" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<PackageReference Include="ICSharpCode.Decompiler" Version="6.0.0.5559-preview2" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="MonoCecilDebugInfoProvider.cs" /> <Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="MonoCecilDebugInfoProvider.cs" />
<Compile Include="..\ILSpy\DebugInfo\PortableDebugInfoProvider.cs" Link="PortableDebugInfoProvider.cs" /> <Compile Include="..\ILSpy\DebugInfo\PortableDebugInfoProvider.cs" Link="PortableDebugInfoProvider.cs" />

18
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -17,7 +17,6 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -89,6 +88,8 @@ namespace ICSharpCode.Decompiler.CSharp
public string StrongNameKeyFile { get; set; } public string StrongNameKeyFile { get; set; }
public int MaxDegreeOfParallelism { get; set; } = Environment.ProcessorCount; public int MaxDegreeOfParallelism { get; set; } = Environment.ProcessorCount;
public IProgress<DecompilationProgress> ProgressIndicator { get; set; }
#endregion #endregion
// per-run members // per-run members
@ -364,6 +365,8 @@ namespace ICSharpCode.Decompiler.CSharp
return Path.Combine(dir, file); return Path.Combine(dir, file);
} }
}, StringComparer.OrdinalIgnoreCase).ToList(); }, StringComparer.OrdinalIgnoreCase).ToList();
int total = files.Count;
var progress = this.ProgressIndicator;
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, settings); DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, settings);
Parallel.ForEach( Parallel.ForEach(
files, files,
@ -382,6 +385,7 @@ namespace ICSharpCode.Decompiler.CSharp
throw new DecompilerException(module, $"Error decompiling for '{file.Key}'", innerException); throw new DecompilerException(module, $"Error decompiling for '{file.Key}'", innerException);
} }
} }
progress?.Report(new DecompilationProgress(total, file.Key));
}); });
return files.Select(f => Tuple.Create("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken)); return files.Select(f => Tuple.Create("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken));
} }
@ -537,4 +541,16 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
} }
public readonly struct DecompilationProgress
{
public readonly int TotalNumberOfFiles;
public readonly string Status;
public DecompilationProgress(int total, string status = null)
{
this.TotalNumberOfFiles = total;
this.Status = status ?? "";
}
}
} }

Loading…
Cancel
Save