diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29e73d4..d9fc2fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build +name: Build on: push: @@ -17,8 +17,12 @@ on: workflow_dispatch: jobs: - build-on-windows: - runs-on: windows-latest + build: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -26,58 +30,36 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v2 with: - dotnet-version: "6.0.x" + dotnet-version: | + 6.0.x + 7.0.x include-prerelease: false - name: Build run: | cd Common.BasicHelper - dotnet build -c Release - - build-on-ubuntu: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Setup .NET - uses: actions/setup-dotnet@v2 - with: - dotnet-version: "6.0.x" - include-prerelease: false + dotnet build -c Release - - name: Build + - name: Test run: | - cd Common.BasicHelper - dotnet build -c Release + cd Common.BasicHelper.Test + + dotnet test -c Release - name: Add to GitHub Repo + if: ${{ matrix.os == 'ubuntu-latest' }} run: | nuget sources add -name github -Source https://nuget.pkg.github.com/Crequency/index.json -Username Crequency -Password ${{ secrets.GitHubToken }} - name: Install NuGet + if: ${{ matrix.os == 'ubuntu-latest' }} uses: nuget/setup-nuget@v1 with: nuget-version: "6.x" - name: Publish Package to GitHub and NuGet + if: ${{ matrix.os == 'ubuntu-latest' }} run: | nuget push ./Common.BasicHelper/bin/Release/*.nupkg -Source https://api.nuget.org/v3/index.json -SkipDuplicate -ApiKey ${{ secrets.NugetKey }} -NoSymbol nuget push ./Common.BasicHelper/bin/Release/*.nupkg -Source github -SkipDuplicate - - build-on-macos: - runs-on: macos-latest - - steps: - - uses: actions/checkout@v3 - - - name: Setup .NET - uses: actions/setup-dotnet@v2 - with: - dotnet-version: "6.0.x" - include-prerelease: false - - - name: Build - run: | - cd Common.BasicHelper - dotnet build -c Release diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml deleted file mode 100644 index 688b5ec..0000000 --- a/.github/workflows/codecov.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: CodeCov - -on: - push: - branches: - - "main" - paths-ignore: - - ".*/**" - - "**/*.md" - pull_request: - branches: - - "main" - paths-ignore: - - ".*/**" - - "**/*.md" - - workflow_dispatch: - -jobs: - codecov: - runs-on: ubuntu-latest - - steps: - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 diff --git a/.github/workflows/pr-merged.yml b/.github/workflows/pr-merged.yml new file mode 100644 index 0000000..5b1b914 --- /dev/null +++ b/.github/workflows/pr-merged.yml @@ -0,0 +1,22 @@ +name: "Pull Request Labeler" +on: + pull_request: + types: + - closed + +jobs: + pr-merged: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: actions/github-script@v6 + with: + script: | + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["merged"] + }) diff --git a/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs b/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs index 9f8017f..1bb360e 100644 --- a/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs +++ b/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs @@ -6,12 +6,26 @@ public class CommandsExecutor_Tests [TestMethod] public void Test_ExecuteAsCommand() { - Console.WriteLine("help".ExecuteAsCommand()); + if (OperatingSystem.IsWindows()) + Console.WriteLine("help".ExecuteAsCommand()); + + if (OperatingSystem.IsLinux()) + Console.WriteLine("apt".ExecuteAsCommand("-v")); + + if (OperatingSystem.IsMacOS()) + Console.WriteLine("sw_vers".ExecuteAsCommand()); } [TestMethod] public async Task Test_ExecuteAsCommandAsync() { - Console.WriteLine(await "help".ExecuteAsCommandAsync()); + if (OperatingSystem.IsWindows()) + Console.WriteLine(await "help".ExecuteAsCommandAsync()); + + if (OperatingSystem.IsLinux()) + Console.WriteLine(await "apt".ExecuteAsCommandAsync("-v")); + + if (OperatingSystem.IsMacOS()) + Console.WriteLine(await "sw_vers".ExecuteAsCommandAsync()); } } diff --git a/Common.BasicHelper.Test/Network/NetUtils_Tests.cs b/Common.BasicHelper.Test/Network/NetUtils_Tests.cs index a23206f..0158841 100644 --- a/Common.BasicHelper.Test/Network/NetUtils_Tests.cs +++ b/Common.BasicHelper.Test/Network/NetUtils_Tests.cs @@ -8,27 +8,36 @@ public class NetUtils_Tests [TestMethod] public void Test_IsWebConected() { - Assert.IsTrue(NetUtils.IsWebConected("localhost", 3)); - Assert.IsFalse(NetUtils.IsWebConected("192.168.255.255", 3)); + if (OperatingSystem.IsWindows()) + { + Assert.IsTrue(NetUtils.IsWebConected("localhost", 3)); + Assert.IsFalse(NetUtils.IsWebConected("192.168.255.255", 3)); + } } [TestMethod] public void Test_DownloadFile() { - var path = Path.GetFullPath($"{Path.GetTempPath()}/test_downloadFile.txt"); + if (OperatingSystem.IsWindows()) + { + var path = Path.GetFullPath($"{Path.GetTempPath()}/test_downloadFile.txt"); - NetUtils.DownloadFile(testDownloadFilePath, path); + NetUtils.DownloadFile(testDownloadFilePath, path); - File.Delete(path); + File.Delete(path); + } } [TestMethod] public void Test_WebDownloadFile() { - var path = Path.GetFullPath($"{Path.GetTempPath()}/test_webDownloadFile.txt"); + if (OperatingSystem.IsWindows()) + { + var path = Path.GetFullPath($"{Path.GetTempPath()}/test_webDownloadFile.txt"); - NetUtils.WebDownloadFile(testDownloadFilePath, path); + NetUtils.WebDownloadFile(testDownloadFilePath, path); - File.Delete(path); + File.Delete(path); + } } } \ No newline at end of file diff --git a/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs b/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs index 0a1713e..e554da5 100644 --- a/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs +++ b/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs @@ -14,9 +14,12 @@ public void Test_Dump() .Dump() ; - var interfaces = NetworkInterface.GetAllNetworkInterfaces(); - foreach (var iface in interfaces) - iface.Dump(); + if (OperatingSystem.IsWindows()) + { + var interfaces = NetworkInterface.GetAllNetworkInterfaces(); + foreach (var iface in interfaces) + iface.Dump(); + } } [TestMethod()] @@ -28,9 +31,12 @@ public void Test_Dump2Lines() .Dump2Lines() ; - var interfaces = NetworkInterface.GetAllNetworkInterfaces(); - foreach (var iface in interfaces) - iface.Dump2Lines(); + if (OperatingSystem.IsWindows()) + { + var interfaces = NetworkInterface.GetAllNetworkInterfaces(); + foreach (var iface in interfaces) + iface.Dump2Lines(); + } } [TestMethod()] diff --git a/Common.BasicHelper.Test/Utils/Password_Tests.cs b/Common.BasicHelper.Test/Utils/Password_Tests.cs index 6127619..35d9a03 100644 --- a/Common.BasicHelper.Test/Utils/Password_Tests.cs +++ b/Common.BasicHelper.Test/Utils/Password_Tests.cs @@ -6,7 +6,7 @@ public class Password_Tests [TestMethod] public void Test_GeneratePassword() { - foreach (var item in Enumerable.Range(0, 10)) + foreach (var _ in Enumerable.Range(0, 10)) Console.WriteLine(Password.GeneratePassword(length: 12)); } } diff --git a/Common.BasicHelper/Core/Shell/CommandsExecutor.cs b/Common.BasicHelper/Core/Shell/CommandsExecutor.cs index c31d266..10fa493 100644 --- a/Common.BasicHelper/Core/Shell/CommandsExecutor.cs +++ b/Common.BasicHelper/Core/Shell/CommandsExecutor.cs @@ -67,7 +67,7 @@ public static async Task GetExecutionResultAsync string args, bool findInPath = false, Action? action = null, - CancellationToken? token = default + CancellationToken? token = null ) { if (findInPath) @@ -90,19 +90,24 @@ public static async Task GetExecutionResultAsync StartInfo = psi, }; - //var sb = new StringBuilder(); - - //void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) - // => sb.AppendLine(outLine.Data); - - //process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); - //process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); - process.Start(); var output = process.StandardOutput.ReadToEnd(); - await Task.Run(process.WaitForExit); + await Task.Run(() => + { + if (token is null) process.WaitForExit(); + + while (!process.HasExited) + { + if (token is not null && token.Value.IsCancellationRequested) + { + process.Kill(); + + break; + } + } + }); return output; } diff --git a/Common.BasicHelper/Core/TaskSystem/SignalTask.cs b/Common.BasicHelper/Core/TaskSystem/SignalTask.cs new file mode 100644 index 0000000..c520400 --- /dev/null +++ b/Common.BasicHelper/Core/TaskSystem/SignalTask.cs @@ -0,0 +1,63 @@ +using Common.BasicHelper.Utils.Extensions; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Common.BasicHelper.Core.TaskSystem; + +public class SignalTask +{ + public Queue Actions { get; } = new(); + + public bool SignalReusable { get; set; } = false; + + public bool ActionsReusable { get; set; } = false; + + public SignalTask AddAction(Action action) + { + Actions.Enqueue(action); + + return this; + } + + public SignalTask ReuseSignal(bool reusable = true) + { + SignalReusable = reusable; + + return this; + } + + public SignalTask ReuseActions(bool reusable = true) + { + ActionsReusable = reusable; + + return this; + } + + public SignalTask ExecuteAll(bool? reuseall = null) + { + Actions.ForEach(action => action(), reuseall ?? ActionsReusable); + + return this; + } + + public async Task ExecuteAllAsync(bool? reuseall = null, CancellationToken? token = null) + { + await Actions.ForEachAsync( + action => action(), + reuseall ?? ActionsReusable, + token ?? default + ); + + return this; + } +} + +public static class SignalTaskExtensions +{ + public static SignalTask AddTo(this Action action, SignalTask task) => task.AddAction(action); + + public static SignalTask ExecuteAll(this SignalTask task, bool reuseAll = false) + => task.ExecuteAll(reuseAll); +} diff --git a/Common.BasicHelper/Core/TaskSystem/SignalTasksManager.cs b/Common.BasicHelper/Core/TaskSystem/SignalTasksManager.cs new file mode 100644 index 0000000..6e90151 --- /dev/null +++ b/Common.BasicHelper/Core/TaskSystem/SignalTasksManager.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Common.BasicHelper.Core.TaskSystem; + +public class SignalTasksManager +{ + private readonly Dictionary SignalTasks = new(); + + /// + /// 触发信号 + /// + /// 信号名称 + /// 任务管理器本身 + public SignalTasksManager RaiseSignal(string signal) + { + if (SignalTasks.TryGetValue(signal, out var signalTask)) + { + signalTask.ExecuteAll(); + + if (!signalTask.SignalReusable) + SignalTasks.Remove(signal); + } + + return this; + } + + /// + /// 信号发生时运行任务 + /// + /// 信号 + /// 任务 + /// 任务管理器本身 + public SignalTasksManager SignalRun(string signal, Action action, bool reusable = false) + { + if (SignalTasks.TryGetValue(signal, out var signalTask)) + signalTask.AddAction(action); + else + SignalTasks.Add( + signal, + new SignalTask() + .ReuseSignal(reusable) + .AddAction(action) + ); + + return this; + } + + /// + /// 清除所有信号响应任务 + /// + /// 任务管理器本身 + public SignalTasksManager Clear() + { + SignalTasks.Clear(); + + return this; + } +} diff --git a/Common.BasicHelper/Utils/Extensions/QueueHelper.cs b/Common.BasicHelper/Utils/Extensions/QueueHelper.cs index c14ad28..e20747c 100644 --- a/Common.BasicHelper/Utils/Extensions/QueueHelper.cs +++ b/Common.BasicHelper/Utils/Extensions/QueueHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace Common.BasicHelper.Utils.Extensions; @@ -57,8 +58,12 @@ public static Queue Pop(this Queue queue) /// 是否将出队元素重新入队 /// 操作锁 /// 队列本身 - public static Queue ForEach(this Queue queue, Action action, - bool reappend = false, object? locker = null) + public static Queue ForEach( + this Queue queue, + Action action, + bool reappend = false, + object? locker = null + ) { Queue func() { @@ -92,8 +97,12 @@ Queue func() /// 是否将出队元素重新入队 /// 操作锁 /// 返回队列本身的任务 - public static async Task> ForEachAsync(this Queue queue, Action action, - bool reappend = false) + public static async Task> ForEachAsync( + this Queue queue, + Action action, + bool reappend = false, + CancellationToken token = default + ) { Queue func() { @@ -108,6 +117,6 @@ Queue func() return queue; } - return await Task.Run(func); + return await Task.Run(func, token); } }