<style> SonarqubleAnalyzer

This commit is contained in:
nsnail 2022-12-14 16:30:36 +08:00
parent d913e0b7cc
commit 51943833ed
16 changed files with 156 additions and 124 deletions

View File

@ -6,5 +6,6 @@
<OutputPath>$(BaseOutputPath)/$(MSBuildProjectName)/bin</OutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)/$(MSBuildProjectName)/obj</IntermediateOutputPath>
<MSBuildProjectExtensionsPath>$(BaseIntermediateOutputPath)/$(MSBuildProjectName)/obj</MSBuildProjectExtensionsPath>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
</PropertyGroup>
</Project>

8
SonarqubleAnalyzer.props Normal file
View File

@ -0,0 +1,8 @@
<Project>
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.50.0.58025">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -27,6 +27,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{AD79881E-7
README.md = README.md
README.zh-CN.md = README.zh-CN.md
SafetyDelUnusedResx.ahk = SafetyDelUnusedResx.ahk
SonarqubleAnalyzer.props = SonarqubleAnalyzer.props
switch-nuget.cmd = switch-nuget.cmd
switch-project.cmd = switch-project.cmd
switcher.json = switcher.json

View File

@ -6,15 +6,11 @@ using System.Runtime.InteropServices;
namespace Dot.Color;
internal class MouseHook : IDisposable
internal sealed class MouseHook : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
private struct Msllhookstruct
{
// [FieldOffset(20)] private readonly nint dwExtraInfo;
// [FieldOffset(12)] private readonly uint flags;
// [FieldOffset(8)] private readonly uint mouseData;
// [FieldOffset(16)] private readonly uint time;
[FieldOffset(0)] public readonly int X;
[FieldOffset(4)] public readonly int Y;
}
@ -42,7 +38,9 @@ internal class MouseHook : IDisposable
private void Dispose(bool disposing)
{
if (_disposed) return;
#pragma warning disable S108
if (disposing) { }
#pragma warning restore S108
if (_hookId != default) Win32.UnhookWindowsHookEx(_hookId);
_disposed = true;

View File

@ -1,8 +1,4 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Dot;

View File

@ -1,5 +1,6 @@
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
// ReSharper disable once RedundantUsingDirective
using Panel = Spectre.Console.Panel;
namespace Dot;
@ -11,43 +12,15 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
private int _excludeCnt; //排除文件数
// ReSharper disable once StaticMemberInGenericType
#pragma warning disable S2743
private static readonly object _lock = new(); //线程锁
private int _readCnt; //读取文件数
private int _totalCnt; //总文件数
private int _writeCnt; //写入文件数
private readonly ConcurrentDictionary<string, int> _writeStats = new(); //写入统计:后缀,数量
// ReSharper disable once ReturnTypeCanBeEnumerable.Local
private string[] EnumerateFiles(string path, string searchPattern, out int excludeCnt)
private async Task CoreInternal()
{
var exCnt = 0;
if (Opt.ExcludeRegexes?.FirstOrDefault() is null) //默认排除.git 、 node_modules 目录
Opt.ExcludeRegexes = new[] { @"\.git", "node_modules" };
var excludeRegexes = Opt.ExcludeRegexes.Select(x => new Regex(x));
var fileList = Directory.EnumerateFiles(path, searchPattern
, new EnumerationOptions {
RecurseSubdirectories = true
, AttributesToSkip
= FileAttributes.ReparsePoint
, IgnoreInaccessible = true
, MaxRecursionDepth = Opt.MaxRecursionDepth
})
.Where(x => {
if (!excludeRegexes.Any(y => y.IsMatch(x))) return true;
++exCnt;
return false;
})
.ToArray();
excludeCnt = exCnt;
return fileList;
}
protected override async Task Core()
{
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path), string.Format(Str.PathNotFound, Opt.Path));
if (!Opt.WriteMode) AnsiConsole.MarkupLine("[gray]{0}[/]", Str.ExerciseMode);
IEnumerable<string> fileList;
await AnsiConsole.Progress()
@ -79,6 +52,39 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
}
// ReSharper disable once ReturnTypeCanBeEnumerable.Local
private string[] EnumerateFiles(string path, string searchPattern, out int excludeCnt)
{
var exCnt = 0;
if (Opt.ExcludeRegexes?.FirstOrDefault() is null) //默认排除.git 、 node_modules 目录
Opt.ExcludeRegexes = new[] { @"\.git", "node_modules" };
var excludeRegexes = Opt.ExcludeRegexes.Select(x => new Regex(x));
var fileList = Directory.EnumerateFiles(path, searchPattern
, new EnumerationOptions {
RecurseSubdirectories = true
, AttributesToSkip
= FileAttributes.ReparsePoint
, IgnoreInaccessible = true
, MaxRecursionDepth = Opt.MaxRecursionDepth
})
.Where(x => {
if (!excludeRegexes.Any(y => y.IsMatch(x))) return true;
++exCnt;
return false;
})
.ToArray();
excludeCnt = exCnt;
return fileList;
}
protected override Task Core()
{
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path), string.Format(Str.PathNotFound, Opt.Path));
return CoreInternal();
}
protected static FileStream CreateTempFile(out string file)
{
file = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid()}.tmp");
@ -105,7 +111,9 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
// ignored
}
}
catch (IOException) { }
catch (IOException) {
// ignored
}
return fsr;
}

View File

@ -16,61 +16,9 @@ internal class Main : ToolBase<Option>
private ConcurrentDictionary<string, TaskStatusColumn.Statues> _repoStatus;
private async ValueTask DirHandle(KeyValuePair<string, ProgressTask> payload, CancellationToken _)
{
payload.Value.StartTask();
payload.Value.State.Status(TaskStatusColumn.Statues.Executing);
// 打印 git command rsp
void ExecRspReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data is null) return;
var msg = Encoding.UTF8.GetString(_gitOutputEnc.GetBytes(e.Data));
_repoRsp[payload.Key].Append(msg.EscapeMarkup());
}
// 启动git进程
{
var startInfo = new ProcessStartInfo {
CreateNoWindow = true
, WorkingDirectory = payload.Key
, FileName = "git"
, Arguments = Opt.Args
, UseShellExecute = false
, RedirectStandardOutput = true
, RedirectStandardError = true
};
using var p = Process.Start(startInfo);
p!.OutputDataReceived += ExecRspReceived;
p.ErrorDataReceived += ExecRspReceived;
p.BeginOutputReadLine();
p.BeginErrorReadLine();
await p.WaitForExitAsync(CancellationToken.None);
if (p.ExitCode == 0) {
payload.Value.State.Status(TaskStatusColumn.Statues.Succeed);
_repoStatus.AddOrUpdate(payload.Key, _ => TaskStatusColumn.Statues.Succeed
, (_, _) => TaskStatusColumn.Statues.Succeed);
payload.Value.StopTask();
}
else {
payload.Value.State.Status(TaskStatusColumn.Statues.Failed);
_repoStatus.AddOrUpdate(payload.Key, _ => TaskStatusColumn.Statues.Failed
, (_, _) => TaskStatusColumn.Statues.Failed);
}
payload.Value.StopTask();
}
}
protected override async Task Core()
private async Task CoreInternal()
{
_gitOutputEnc = Encoding.GetEncoding(Opt.GitOutputEncoding);
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path) //
, string.Format(Str.PathNotFound, Opt.Path));
var progressBar = new ProgressBarColumn { Width = 10 };
await AnsiConsole.Progress()
.Columns(progressBar //
@ -124,4 +72,59 @@ internal class Main : ToolBase<Option>
AnsiConsole.Write(table);
}
private async ValueTask DirHandle(KeyValuePair<string, ProgressTask> payload, CancellationToken _)
{
payload.Value.StartTask();
payload.Value.State.Status(TaskStatusColumn.Statues.Executing);
// 打印 git command rsp
void ExecRspReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data is null) return;
var msg = Encoding.UTF8.GetString(_gitOutputEnc.GetBytes(e.Data));
_repoRsp[payload.Key].Append(msg.EscapeMarkup());
}
// 启动git进程
var startInfo = new ProcessStartInfo {
CreateNoWindow = true
, WorkingDirectory = payload.Key
, FileName = "git"
, Arguments = Opt.Args
, UseShellExecute = false
, RedirectStandardOutput = true
, RedirectStandardError = true
};
using var p = Process.Start(startInfo);
p!.OutputDataReceived += ExecRspReceived;
p.ErrorDataReceived += ExecRspReceived;
p.BeginOutputReadLine();
p.BeginErrorReadLine();
await p.WaitForExitAsync(CancellationToken.None);
if (p.ExitCode == 0) {
payload.Value.State.Status(TaskStatusColumn.Statues.Succeed);
_repoStatus.AddOrUpdate(payload.Key, _ => TaskStatusColumn.Statues.Succeed
, (_, _) => TaskStatusColumn.Statues.Succeed);
payload.Value.StopTask();
}
else {
payload.Value.State.Status(TaskStatusColumn.Statues.Failed);
_repoStatus.AddOrUpdate(payload.Key, _ => TaskStatusColumn.Statues.Failed
, (_, _) => TaskStatusColumn.Statues.Failed);
}
payload.Value.StopTask();
}
protected override Task Core()
{
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path) //
, string.Format(Str.PathNotFound, Opt.Path));
return CoreInternal();
}
}

View File

@ -16,9 +16,12 @@ internal sealed class Main : ToolBase<Option>
if (item.NetworkInterfaceType != NetworkInterfaceType.Ethernet ||
item.OperationalStatus != OperationalStatus.Up)
continue;
foreach (var ip in item.GetIPProperties().UnicastAddresses)
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
Console.WriteLine(@$"{item.Name}: {ip.Address}");
var output = string.Join(Environment.NewLine
, item.GetIPProperties()
.UnicastAddresses
.Where(x => x.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(x => @$"{item.Name}: {x.Address}"));
Console.WriteLine(output);
}
using var http = new HttpClient();

View File

@ -23,6 +23,22 @@ internal class Main : ToolBase<Option>
return ret;
}
private async Task CoreInternal()
{
string result = null;
if (Opt.Compress)
result = await JsonCompress();
else if (Opt.ConvertToString)
result = await ConvertToString();
else if (Opt.Format) result = await JsonFormat();
if (!result.NullOrWhiteSpace()) {
#if NET7_0_WINDOWS
await ClipboardService.SetTextAsync(result!);
#endif
}
}
private Task<string> JsonCompress()
{
var ret = _inputObj.Json();
@ -40,12 +56,12 @@ internal class Main : ToolBase<Option>
return text.Replace("\\\"", "\"");
}
protected override async Task Core()
protected override Task Core()
{
var inputText = Opt.InputText;
#if NET7_0_WINDOWS
if (inputText.NullOrWhiteSpace()) inputText = await ClipboardService.GetTextAsync();
if (inputText.NullOrWhiteSpace()) inputText = ClipboardService.GetText();
#endif
if (inputText.NullOrWhiteSpace()) throw new ArgumentException(Str.InputTextIsEmpty);
@ -56,24 +72,16 @@ internal class Main : ToolBase<Option>
try {
inputText = UnescapeString(inputText);
_inputObj = inputText.Object<object>();
return;
return Task.CompletedTask;
}
catch (JsonException) {
// ignored
}
catch (JsonException) { }
throw new ArgumentException(Str.InvalidJsonString);
}
string result = null;
if (Opt.Compress)
result = await JsonCompress();
else if (Opt.ConvertToString)
result = await ConvertToString();
else if (Opt.Format) result = await JsonFormat();
if (result.NullOrWhiteSpace()) return;
#if NET7_0_WINDOWS
await ClipboardService.SetTextAsync(result!);
#endif
return CoreInternal();
}
}

View File

@ -1,4 +1,3 @@
using System.Globalization;
using System.Text;
using Dot;
using Dot.Git;
@ -29,6 +28,4 @@ app.Configure(config => {
});
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
// CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
return app.Run(args);

View File

@ -23,7 +23,7 @@ internal sealed class Main : FilesTool<Option>
}
protected override async ValueTask FileHandle(string file, CancellationToken _)
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
{
ShowMessage(1, 0, 0);

View File

@ -7,7 +7,7 @@ namespace Dot.ToLf;
[Localization(typeof(Str))]
internal sealed class Main : FilesTool<Option>
{
protected override async ValueTask FileHandle(string file, CancellationToken _)
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
{
ShowMessage(1, 0, 0);
@ -50,7 +50,9 @@ internal sealed class Main : FilesTool<Option>
}
#pragma warning disable S2583
if (hasWrote && !isBin) {
#pragma warning restore S2583
if (Opt.WriteMode) File.Copy(tmpFile, file, true);
ShowMessage(0, 1, 0);
UpdateStats(Path.GetExtension(file));

View File

@ -14,9 +14,9 @@ internal abstract class ToolBase<TOption> : Command<TOption> where TOption : Opt
}
}
public override int Execute(CommandContext context, TOption option)
public override int Execute(CommandContext context, TOption settings)
{
Opt = option;
Opt = settings;
Run().Wait();
return 0;
}

View File

@ -28,7 +28,7 @@ internal sealed class Main : FilesTool<Option>
}
protected override async ValueTask FileHandle(string file, CancellationToken _)
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
{
ShowMessage(1, 0, 0);
int spacesCnt;

View File

@ -5,7 +5,7 @@
<UseWindowsForms Condition="'$(TargetFramework)' == 'net7.0-windows'">true</UseWindowsForms>
<RootNamespace>Dot</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<NoWarn>CA1416;</NoWarn>
<NoWarn>CA1416;S1075</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
@ -28,5 +28,6 @@
<HintPath>..\..\..\..\..\ForkedGitReps\spectre.console\src\Spectre.Console\bin\Debug\net6.0\Spectre.Console.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="../SonarqubleAnalyzer.props"/>
<Import Project="../GenerateResx.targets"/>
</Project>

View File

@ -5,11 +5,17 @@
<RootNamespace>Dot.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.3.0"/>
<PackageReference Include="coverlet.collector" Version="3.1.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>