├── docs
├── .vitepress
│ ├── .gitignore
│ └── config.ts
├── imgs
│ ├── build.gif
│ ├── e2txt.gif
│ ├── info.gif
│ ├── txt2e.gif
│ ├── fp
│ │ ├── build.png
│ │ ├── clean.png
│ │ └── e2txt.gif
│ ├── ebuild_init.png
│ ├── envir_var.png
│ ├── unzip_e2txt.png
│ ├── unzip_ecl.png
│ ├── unzip_ebuild.png
│ ├── ebuild_toolchain.png
│ └── config
│ │ ├── run_cmd-args.png
│ │ ├── run_e-script.png
│ │ └── run_show-envs.png
├── project
│ ├── examples.md
│ ├── e2txt.md
│ ├── environ.md
│ ├── build.md
│ ├── basic.md
│ └── run.md
├── cli
│ └── index.md
├── thanks.md
├── index.md
├── README.md
├── first-project.md
└── installation.md
├── src
├── EBuild.Test
│ ├── test-project
│ │ ├── a.e
│ │ ├── b.e
│ │ ├── scripts
│ │ │ └── not-build.e
│ │ ├── ebuild.pwd.yaml
│ │ └── ebuild.yaml
│ ├── Usings.cs
│ ├── YamlConverterTests.cs
│ ├── ConfigTests.cs
│ ├── ToolchainTests.cs
│ └── EBuild.Test.csproj
└── EBuild
│ ├── Hooks
│ └── Hook.cs
│ ├── Project
│ ├── Cleaners
│ │ ├── OptionalProjectCleaner.cs
│ │ ├── ICleaner.cs
│ │ ├── ProjectCleaner.cs
│ │ ├── ProjectECodeCleaner.cs
│ │ ├── ProjectRecoverECleaner.cs
│ │ └── ProjectOutputCleaner.cs
│ ├── ProjectPath.cs
│ ├── SourcePath.cs
│ └── EnvironmentVariables.cs
│ ├── Plugins
│ ├── Plugin.cs
│ ├── IPlugin.cs
│ ├── PluginContext.cs
│ └── BuildHookScriptPlugin.cs
│ ├── Config
│ ├── Project.cs
│ ├── E2Txt.cs
│ ├── Build.cs
│ ├── RootConfig.cs
│ ├── Target.cs
│ └── Resolved
│ │ └── ResolvedConfig.cs
│ ├── Toolchain
│ ├── IToolchain.cs
│ ├── ELangToolchain.cs
│ ├── E2TxtToolchain.cs
│ ├── GeneralToolchain.cs
│ └── EclToolchain.cs
│ ├── Extensions
│ ├── Attributes.cs
│ └── ServiceCollection.cs
│ ├── Yaml
│ └── Converters
│ │ ├── EnumAliasAttribute.cs
│ │ └── EnumConverter.cs
│ ├── DependencyInjection
│ ├── TypeResolver.cs
│ └── TypeRegistrar.cs
│ ├── Consoles
│ ├── LinesDisplayer.cs
│ ├── MultiTaskDisplayer.cs
│ └── TableDisplayer.cs
│ ├── EBuild.csproj
│ ├── Commands
│ ├── SubCommands
│ │ ├── Txt2ECommand.cs
│ │ ├── ToolchainCommand.cs
│ │ ├── CleanCommand.cs
│ │ ├── InfoCommand.cs
│ │ ├── E2TxtCommand.cs
│ │ ├── RunCommand.cs
│ │ ├── InitCommand.cs
│ │ └── BuildCommand.cs
│ └── Base
│ │ ├── CommandBase.cs
│ │ ├── ProjectCommand.cs
│ │ └── TargetCommand.cs
│ ├── Global
│ └── Defaults.cs
│ ├── Sources
│ ├── PasswordResolver.cs
│ └── ESourceMeta.cs
│ └── Program.cs
├── examples
├── .gitignore
├── simple
│ ├── ebuild.pwd.yaml
│ ├── README.md
│ ├── Windows控制台程序.e
│ ├── Windows窗口程序.e
│ ├── Windows窗口程序--带密码.e
│ ├── scripts
│ │ └── 易语言做脚本示例.e
│ ├── .gitignore
│ └── ebuild.yaml
└── first-project
│ ├── README.md
│ ├── Windows控制台程序.e
│ ├── .gitignore
│ └── ebuild.yaml
├── .editorconfig
├── .idea
├── codeStyles
│ └── codeStyleConfig.xml
├── vcs.xml
├── .gitignore
├── .idea.ebuild
│ └── .idea
│ │ ├── vcs.xml
│ │ ├── indexLayout.xml
│ │ ├── misc.xml
│ │ ├── encodings.xml
│ │ ├── .gitignore
│ │ └── git_toolbox_prj.xml
├── modules.xml
├── ebuild.iml
└── git_toolbox_prj.xml
├── package.json
├── .github
└── workflows
│ ├── deploy-docs.yaml
│ ├── changelog.yml
│ └── build.yml
├── .run
├── ebuild.run.xml
├── ebuild info.run.xml
├── ebuild build.run.xml
├── ebuild e2txt.run.xml
├── ebuild init.run.xml
├── ebuild txt2e.run.xml
└── ebuild toolchain.run.xml
├── LICENSE
├── ebuild.sln
├── .gitignore
└── yarn.lock
/docs/.vitepress/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
--------------------------------------------------------------------------------
/src/EBuild.Test/test-project/a.e:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/EBuild.Test/test-project/b.e:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | bigfiles/
2 | test-init/
--------------------------------------------------------------------------------
/src/EBuild.Test/test-project/scripts/not-build.e:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [{*.ts,*.yaml,*.yml}]
2 | indent_size = 2
--------------------------------------------------------------------------------
/examples/simple/ebuild.pwd.yaml:
--------------------------------------------------------------------------------
1 | Windows窗口程序--带密码.e: 123
--------------------------------------------------------------------------------
/src/EBuild.Test/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/src/EBuild.Test/test-project/ebuild.pwd.yaml:
--------------------------------------------------------------------------------
1 | ./b.e: 12345
--------------------------------------------------------------------------------
/docs/imgs/build.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/build.gif
--------------------------------------------------------------------------------
/docs/imgs/e2txt.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/e2txt.gif
--------------------------------------------------------------------------------
/docs/imgs/info.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/info.gif
--------------------------------------------------------------------------------
/docs/imgs/txt2e.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/txt2e.gif
--------------------------------------------------------------------------------
/docs/imgs/fp/build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/fp/build.png
--------------------------------------------------------------------------------
/docs/imgs/fp/clean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/fp/clean.png
--------------------------------------------------------------------------------
/docs/imgs/fp/e2txt.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/fp/e2txt.gif
--------------------------------------------------------------------------------
/docs/imgs/ebuild_init.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/ebuild_init.png
--------------------------------------------------------------------------------
/docs/imgs/envir_var.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/envir_var.png
--------------------------------------------------------------------------------
/docs/imgs/unzip_e2txt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/unzip_e2txt.png
--------------------------------------------------------------------------------
/docs/imgs/unzip_ecl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/unzip_ecl.png
--------------------------------------------------------------------------------
/docs/imgs/unzip_ebuild.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/unzip_ebuild.png
--------------------------------------------------------------------------------
/docs/imgs/ebuild_toolchain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/ebuild_toolchain.png
--------------------------------------------------------------------------------
/examples/simple/README.md:
--------------------------------------------------------------------------------
1 | # ebuild-example
2 |
3 | 这是由[ebuild](https://github.com/SalHe/ebuild)创建的示例工程。
4 |
--------------------------------------------------------------------------------
/examples/simple/Windows控制台程序.e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/examples/simple/Windows控制台程序.e
--------------------------------------------------------------------------------
/examples/simple/Windows窗口程序.e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/examples/simple/Windows窗口程序.e
--------------------------------------------------------------------------------
/docs/imgs/config/run_cmd-args.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/config/run_cmd-args.png
--------------------------------------------------------------------------------
/docs/imgs/config/run_e-script.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/config/run_e-script.png
--------------------------------------------------------------------------------
/docs/imgs/config/run_show-envs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/docs/imgs/config/run_show-envs.png
--------------------------------------------------------------------------------
/examples/first-project/README.md:
--------------------------------------------------------------------------------
1 | # ebuild-example
2 |
3 | 这是由[ebuild](https://github.com/SalHe/ebuild)创建的示例工程。
4 |
--------------------------------------------------------------------------------
/examples/simple/Windows窗口程序--带密码.e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/examples/simple/Windows窗口程序--带密码.e
--------------------------------------------------------------------------------
/examples/simple/scripts/易语言做脚本示例.e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/examples/simple/scripts/易语言做脚本示例.e
--------------------------------------------------------------------------------
/examples/first-project/Windows控制台程序.e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SalHe/ebuild/HEAD/examples/first-project/Windows控制台程序.e
--------------------------------------------------------------------------------
/src/EBuild/Hooks/Hook.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Hooks;
2 |
3 | public enum Hook
4 | {
5 | PreBuild,
6 | PostBuild
7 | }
--------------------------------------------------------------------------------
/examples/simple/.gitignore:
--------------------------------------------------------------------------------
1 | # 恢复出来的易语言源文件和密码文件不纳入版本控制
2 | *.recover.e
3 | #ebuild.pwd.yaml
4 | **/*.ecode/log
5 |
6 | # 易语言产生的备份源码文件
7 | *.bak
8 |
9 | # 编译输出
10 | ebuild-out/
--------------------------------------------------------------------------------
/docs/project/examples.md:
--------------------------------------------------------------------------------
1 | # 案例
2 |
3 | 关于更加完整的配置,您可以参考:
4 |
5 | - [ebuild 官方案例](https://github.com/SalHe/ebuild/tree/master/examples)
6 |
7 | 或者如果您想在这里展示您的工程配置,欢迎在GitHub上编辑本文件以在此展示您的工程。
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/examples/first-project/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # 恢复出来的易语言源文件和密码文件不纳入版本控制
3 | *.recover.e
4 | ebuild.pwd.yaml
5 | **/*.ecode/log
6 |
7 | # 易语言产生的备份源码文件
8 | *.bak
9 |
10 |
11 | # 编译输出
12 | ebuild-out/
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/EBuild/Project/Cleaners/OptionalProjectCleaner.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Project.Cleaners;
2 |
3 | public abstract class OptionalProjectCleaner : ProjectCleaner
4 | {
5 | public override bool Optional => true;
6 | }
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/.idea.ebuild/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.ebuild/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/docs/project/e2txt.md:
--------------------------------------------------------------------------------
1 | # e2txt相关配置
2 |
3 | ```yaml
4 | e2txt:
5 | name-style: 中文 # 命名风格:中文、英文
6 | generate-e: true # 生成易语言代码文件
7 | ```
8 |
9 | 关于此处配置的具体含义请参考`e2txt`官方说明。
10 |
11 | ::: tip
12 |
13 | 这些配置将影响生成的代码文件结构等,建议在工程建立之初确定,后期不做改动。
14 |
15 | :::
--------------------------------------------------------------------------------
/.idea/.idea.ebuild/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/EBuild/Project/Cleaners/ICleaner.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Project.Cleaners;
2 |
3 | public interface ICleaner
4 | {
5 | bool Optional { get; }
6 | bool Once { get; }
7 | string CleanContent { get; }
8 | void Clean(TTarget target, TProject projectConfig);
9 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/EBuild/Plugins/Plugin.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Hooks;
2 |
3 | namespace EBuild.Plugins;
4 |
5 | public class Plugin : IPlugin
6 | {
7 | public virtual Task OnHook(PluginContext context, CancellationToken cancellationToken, Hook hook)
8 | {
9 | return Task.FromResult(true);
10 | }
11 | }
--------------------------------------------------------------------------------
/.idea/.idea.ebuild/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/ebuild.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/EBuild/Config/Project.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Config;
2 |
3 | public class Project
4 | {
5 | public string Name { get; set; }
6 | public string Version { get; set; }
7 | public string Description { get; set; }
8 | public string Author { get; set; }
9 | public string Repository { get; set; }
10 | public string Homepage { get; set; }
11 | }
--------------------------------------------------------------------------------
/.idea/.idea.ebuild/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /contentModel.xml
6 | /projectSettingsUpdater.xml
7 | /modules.xml
8 | /.idea.ebuild.iml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/src/EBuild/Config/E2Txt.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Yaml.Converters;
2 |
3 | namespace EBuild.Config;
4 |
5 | public class E2Txt
6 | {
7 | public enum NameStyleEnum
8 | {
9 | [EnumAlias("英文")] English,
10 | [EnumAlias("中文")] Chinese
11 | }
12 |
13 | public NameStyleEnum NameStyle { get; set; }
14 | public bool GenerateE { get; set; }
15 | }
--------------------------------------------------------------------------------
/docs/cli/index.md:
--------------------------------------------------------------------------------
1 | # 命令行帮助文档
2 |
3 | 由于目前`ebuild`使用[C#](https://docs.microsoft.com/zh-cn/dotnet/csharp/)基于[.NET6](https://dotnet.microsoft.com/zh-cn/)重写,所使用的命令行解析库暂时不支持自动生成文档,所以命令行帮助文档目前暂时无法及时跟进。
4 |
5 | 此外,非常欢迎您为`ebuild`编写文档。
6 |
7 | ::: tip 为何要重写?
8 | 关于为何重写,您可以参见[使用C#+.NET6重写ebuild,为后续开发打基础](https://github.com/SalHe/ebuild/pull/1)。
9 | :::
10 |
11 | 如果您需要查看`ebuild`的命令行帮助文档,建议在命令行中为`ebuild`键入`--help`参数查看详细的帮助信息。
--------------------------------------------------------------------------------
/docs/thanks.md:
--------------------------------------------------------------------------------
1 | # 特别鸣谢
2 |
3 | `ebuild`的存在离不开以下作者和项目为易语言生态带来的贡献:
4 |
5 | - [e2txt](http://e2ee.jimstone.com.cn/) by [JimStone](http://e2ee.jimstone.com.cn/)
6 | - [易语言命令行编译工具 ecl](https://bbs.125.la/forum.php?mod=viewthread&tid=14553929&highlight=ecl)
7 | by [被封七号](https://bbs.125.la/home.php?mod=space&uid=504218&do=thread&type=thread&view=me&from=space)
8 |
9 | > 如有任何形式的对于作者或项目的侵犯行为,请见谅,并联系我对项目做出调整或者下架。
10 |
--------------------------------------------------------------------------------
/src/EBuild/Project/Cleaners/ProjectCleaner.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config.Resolved;
2 |
3 | namespace EBuild.Project.Cleaners;
4 |
5 | public abstract class ProjectCleaner : ICleaner
6 | {
7 | public virtual bool Optional => false;
8 | public virtual bool Once => false;
9 | public abstract string CleanContent { get; }
10 | public abstract void Clean(ResolvedTarget target, ResolvedConfig projectConfig);
11 | }
--------------------------------------------------------------------------------
/src/EBuild/Toolchain/IToolchain.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Toolchain;
2 |
3 | public record EnvironmentVariable(string VariableName, string Description, Func Value);
4 |
5 | public interface IToolchain
6 | {
7 | public string Description { get; }
8 | public string Link { get; }
9 | public string ExecutablePath { get; }
10 | public IList EnvironmentVariables { get; }
11 | public void Search(string projectRootDir);
12 | public bool Exists();
13 | }
--------------------------------------------------------------------------------
/src/EBuild/Config/Build.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Yaml.Converters;
2 |
3 | namespace EBuild.Config;
4 |
5 | public enum Compiler
6 | {
7 | [EnumAlias("静态编译")] Static,
8 | [EnumAlias("普通编译")] Normal,
9 | [EnumAlias("独立编译")] Independent,
10 | [EnumAlias("黑月编译")] BlackMoon,
11 | [EnumAlias("黑月汇编")] BlackMoonAsm,
12 | [EnumAlias("黑月C++")] BlackMoonCpp,
13 | [EnumAlias("黑月MFC")] BlackMoonMFC
14 | }
15 |
16 | public class Build
17 | {
18 | public Compiler Compiler { get; set; }
19 | }
--------------------------------------------------------------------------------
/src/EBuild/Project/Cleaners/ProjectECodeCleaner.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config.Resolved;
2 |
3 | namespace EBuild.Project.Cleaners;
4 |
5 | public class ProjectECodeCleaner : OptionalProjectCleaner
6 | {
7 | public override string CleanContent => "*.ecode(文本格式代码文件夹)";
8 |
9 | public override void Clean(ResolvedTarget target, ResolvedConfig projectConfig)
10 | {
11 | Console.WriteLine($"正在删除 {target.Target.GetECodeDir()}");
12 | Directory.Delete(target.Target.GetECodeDir(), true);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/EBuild/Project/Cleaners/ProjectRecoverECleaner.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config.Resolved;
2 |
3 | namespace EBuild.Project.Cleaners;
4 |
5 | public class ProjectRecoverECleaner : ProjectCleaner
6 | {
7 | public override string CleanContent => "*.recover.e(由文本格式代码恢复的源文件)";
8 |
9 | public override void Clean(ResolvedTarget target, ResolvedConfig projectConfig)
10 | {
11 | Console.WriteLine($"正在删除 {target.Target.GetRecoverEPath()}");
12 | File.Delete(target.Target.GetRecoverEPath());
13 | }
14 | }
--------------------------------------------------------------------------------
/src/EBuild/Plugins/IPlugin.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config.Resolved;
2 | using EBuild.Hooks;
3 |
4 | namespace EBuild.Plugins;
5 |
6 | public interface IPlugin
7 | {
8 | ///
9 | /// 当触发指定构建时期 时,会调用该函数。
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | Task OnHook(PluginContext context, CancellationToken cancellationToken, Hook hook);
16 | }
--------------------------------------------------------------------------------
/examples/first-project/ebuild.yaml:
--------------------------------------------------------------------------------
1 | project:
2 | name: ebuild-example
3 | version: "1.0"
4 | description: 这是由ebuild创建的示例工程。
5 | author: SalHe
6 | repository: https://github.com/SalHe/ebuild
7 | homepage: https://github.com/SalHe
8 | excludes:
9 | - '**/*.recover.e'
10 | - '**/*.ecode/**.e'
11 | - '**/*.代码/**.e'
12 | exclude-builds:
13 | - './scripts/**/*.e' # 脚本文件不纳入'ebuild build'命令中进行自动构建
14 | includes:
15 | - '**/*.e'
16 | e2txt:
17 | name-style: 中文
18 | generate-e: true
19 | build:
20 | compiler: 独立编译
21 |
--------------------------------------------------------------------------------
/.idea/git_toolbox_prj.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/EBuild/Project/Cleaners/ProjectOutputCleaner.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config.Resolved;
2 |
3 | namespace EBuild.Project.Cleaners;
4 |
5 | public class ProjectOutputCleaner : ProjectCleaner
6 | {
7 | public override string CleanContent => "编译结果";
8 | public override bool Once => true; // 与最原始的 golang 实现版的行为保持一致
9 |
10 | public override void Clean(ResolvedTarget target, ResolvedConfig projectConfig)
11 | {
12 | Console.WriteLine($"正在删除 {projectConfig.OutputDir}", true);
13 | Directory.Delete(projectConfig.OutputDir, true);
14 | }
15 | }
--------------------------------------------------------------------------------
/src/EBuild/Extensions/Attributes.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace EBuild.Extensions;
4 |
5 | public static class Attributes
6 | {
7 | public static bool GetEnumValueAttribute(TEnum enumValue, out TAttribute? attribute)
8 | where TEnum : Enum
9 | where TAttribute : Attribute
10 | {
11 | var type = enumValue.GetType();
12 | var enumName = type.GetEnumName(enumValue)!;
13 | attribute = type.GetField(enumName)?.GetCustomAttribute();
14 | return attribute != null;
15 | }
16 | }
--------------------------------------------------------------------------------
/.idea/.idea.ebuild/.idea/git_toolbox_prj.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ebuild",
3 | "version": "1.1.0.0",
4 | "main": "index.js",
5 | "repository": "https://github.com/SalHe/ebuild.git",
6 | "author": "SalHe Li ",
7 | "license": "MIT",
8 | "private": true,
9 | "scripts": {
10 | "docs:dev": "vitepress dev docs",
11 | "docs:build": "vitepress build docs",
12 | "docs:serve": "vitepress serve docs"
13 | },
14 | "devDependencies": {
15 | "@types/markdown-it": "^12.2.3",
16 | "markdown-it-task-checkbox": "^1.0.6",
17 | "vitepress": "^1.0.0-alpha.4",
18 | "vue": "^3.2.37"
19 | }
20 | }
--------------------------------------------------------------------------------
/src/EBuild/Project/ProjectPath.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Project;
2 |
3 | public static class ProjectPath
4 | {
5 | public static string GetConfigFilePath(string projectRootDir)
6 | {
7 | return Path.GetFullPath("ebuild.yaml", projectRootDir);
8 | }
9 |
10 | public static string GetSourcePasswordFilePath(string projectRootDir)
11 | {
12 | return Path.GetFullPath("ebuild.pwd.yaml", projectRootDir);
13 | }
14 |
15 | public static string GetDefaultOutputPath(string projectRootDir)
16 | {
17 | return Path.GetFullPath("ebuild-out", projectRootDir);
18 | }
19 | }
--------------------------------------------------------------------------------
/.github/workflows/deploy-docs.yaml:
--------------------------------------------------------------------------------
1 | name: Deploy Docs
2 |
3 | on:
4 | push:
5 | paths: 'docs/**'
6 | branches:
7 | - master
8 |
9 | jobs:
10 | deploy:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v3
15 | with:
16 | node-version: 16
17 | cache: yarn
18 | - run: yarn install --frozen-lockfile
19 |
20 | - name: Build
21 | run: yarn docs:build
22 |
23 | - name: Deploy
24 | uses: peaceiris/actions-gh-pages@v3
25 | with:
26 | github_token: ${{ secrets.GITHUB_TOKEN }}
27 | publish_dir: docs/.vitepress/dist
28 |
--------------------------------------------------------------------------------
/src/EBuild/Extensions/ServiceCollection.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Microsoft.Extensions.DependencyInjection;
3 |
4 | namespace EBuild.Extensions;
5 |
6 | internal static class ServiceCollection
7 | {
8 | public static void AddImplementation(
10 | this IServiceCollection services)
11 | where TService : class
12 | where TImplementation : class, TService
13 | {
14 | services.AddSingleton();
15 | services.AddSingleton(s => s.GetService());
16 | }
17 | }
--------------------------------------------------------------------------------
/src/EBuild/Project/SourcePath.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config;
2 |
3 | namespace EBuild.Project;
4 |
5 | public static class SourcePath
6 | {
7 | public static string GetECodeDir(string source)
8 | {
9 | return Path.ChangeExtension(source, "ecode");
10 | }
11 |
12 | public static string GetRecoverEPath(string source)
13 | {
14 | return Path.ChangeExtension(source, "recover.e");
15 | }
16 |
17 | public static string GetECodeDir(this Target target)
18 | {
19 | return GetECodeDir(target.Source);
20 | }
21 |
22 | public static string GetRecoverEPath(this Target target)
23 | {
24 | return GetRecoverEPath(target.Source);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/EBuild/Config/RootConfig.cs:
--------------------------------------------------------------------------------
1 | using YamlDotNet.Serialization;
2 |
3 | namespace EBuild.Config;
4 |
5 | public class RootConfig
6 | {
7 | public Project Project { get; set; }
8 | public IDictionary? Scripts { get; set; }
9 | public IList Excludes { get; set; } = new List();
10 | public IList Includes { get; set; } = new List();
11 | public IList ExcludeBuilds { get; set; } = new List();
12 |
13 | [YamlMember(Alias = "e2txt")] public E2Txt E2Txt { get; set; }
14 |
15 | public Build Build { get; set; } = new Build()
16 | {
17 | Compiler = Compiler.Normal
18 | };
19 |
20 | public IList? Targets { get; set; }
21 | }
--------------------------------------------------------------------------------
/src/EBuild/Yaml/Converters/EnumAliasAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace EBuild.Yaml.Converters;
4 |
5 | [AttributeUsage(AttributeTargets.Field)]
6 | public class EnumAliasAttribute : Attribute
7 | {
8 | public EnumAliasAttribute(string name)
9 | {
10 | Name = name;
11 | }
12 |
13 | public string Name { get; set; }
14 |
15 | public static EnumAliasAttribute? GetEnumAliasAttribute(object? enumValue)
16 | {
17 | if (enumValue == null) return null;
18 | var type = enumValue.GetType();
19 | if (type is not { IsEnum: true }) return null;
20 | var enumName = type.GetEnumName(enumValue)!;
21 | return type.GetField(enumName)?.GetCustomAttribute();
22 | }
23 | }
--------------------------------------------------------------------------------
/src/EBuild.Test/YamlConverterTests.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config;
2 | using EBuild.Yaml.Converters;
3 | using YamlDotNet.Core;
4 | using YamlDotNet.Serialization;
5 |
6 | namespace EBuild.Test;
7 |
8 | public class YamlConverterTests
9 | {
10 | [SetUp]
11 | public void Setup()
12 | {
13 | }
14 |
15 | [Test]
16 | public void TestEnumConverter()
17 | {
18 | var doc = @"
19 | - BlackMoon
20 | - black-moon
21 | - 黑月编译
22 | ";
23 | var compilers = new DeserializerBuilder()
24 | .WithTypeConverter(EnumConverter.Instance)
25 | .Build()
26 | .Deserialize(new Parser(new StringReader(doc)));
27 | foreach (var compiler in compilers) Assert.That(compiler, Is.EqualTo(Compiler.BlackMoon));
28 | }
29 | }
--------------------------------------------------------------------------------
/src/EBuild/DependencyInjection/TypeResolver.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console.Cli;
2 |
3 | namespace EBuild.DependencyInjection;
4 |
5 | public sealed class TypeResolver : ITypeResolver, IDisposable
6 | {
7 | private readonly IServiceProvider _provider;
8 |
9 | public TypeResolver(IServiceProvider provider)
10 | {
11 | _provider = provider ?? throw new ArgumentNullException(nameof(provider));
12 | }
13 |
14 | public object Resolve(Type type)
15 | {
16 | if (type == null)
17 | {
18 | return null;
19 | }
20 |
21 | return _provider.GetService(type);
22 | }
23 |
24 | public void Dispose()
25 | {
26 | if (_provider is IDisposable disposable)
27 | {
28 | disposable.Dispose();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | title: E-Build
5 | titleTemplate: E-Build 是一个专注于易语言构建的工具。
6 |
7 | hero:
8 | name: E-Build
9 | text: E-Build 是一个专注于易语言自动化构建的工具。
10 | tagline: 基于 e2txt 和 ecl 的专注于易语言自动化构建的工具。
11 | actions:
12 | - theme: brand
13 | text: 开始了解
14 | link: ./README
15 | - theme: alt
16 | text: 查看源码
17 | link: https://github.com/SalHe/ebuild
18 |
19 | features:
20 | - title: 版本控制
21 | details: 可快速将工程中的易语言源代码借助 e2txt 转换成文本格式的代码(或者反向转换),利于版本控制和多人协同开发.
22 | - title: 自动构建
23 | details: 使用配置化的方式将易语言源代码纳入工程,且可以自定义构建目标,使用不同的构建细节借助 ecl 去完成源码编译,不需要反复开启易语言编译.
24 | - title: 脚本执行
25 | details: 可以将工程相关的命令、脚本纳入到工程配置中方便执行,同时还可以使用易语言源文件编写脚本,由 ebuild 自动帮助您编译并执行.
26 | - title: 生命周期
27 | details: 为工程的构建定义了一些生命周期,您可以在这些生命周期执行一些您想要的工作,比如将文件安装到某处等,方便了您的构建过程.
28 | ---
--------------------------------------------------------------------------------
/src/EBuild/Plugins/PluginContext.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Commands.Base;
2 | using EBuild.Config.Resolved;
3 | using EBuild.Project;
4 |
5 | namespace EBuild.Plugins;
6 |
7 | public class PluginContext
8 | {
9 | public delegate void UpdateStatusDelegate(TargetStatus status, string log);
10 |
11 | public ResolvedTarget? BuildTarget { get; internal init; } = null;
12 | public ResolvedConfig ProjectConfig { get; }
13 | public EnvironmentVariables EnvironmentVariables { get; }
14 | public CancellationToken CancellationToken { get; internal init; }
15 | public UpdateStatusDelegate? UpdateStatus { get; internal init; }
16 |
17 | public PluginContext(ResolvedConfig projectConfig, EnvironmentVariables environmentVariables)
18 | {
19 | ProjectConfig = projectConfig;
20 | EnvironmentVariables = environmentVariables;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/EBuild/Consoles/LinesDisplayer.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 |
3 | namespace EBuild.Consoles;
4 |
5 | public class LinesDisplayer : MultiTaskDisplayer
6 | {
7 | public override void SetHeader(string header)
8 | {
9 | AnsiConsole.MarkupLine(header);
10 | }
11 |
12 | public override void Update(TTarget target, TStatus status, string log)
13 | {
14 | var content = $"{Markup.Escape("[") + Markup.Escape(TargetName(target)) + Markup.Escape("]")} > {log}";
15 | AnsiConsole.MarkupLine(string.Format(StatusString(status), content));
16 | }
17 |
18 | public override Task StartAsync (Func, Task> action)
19 | {
20 | AnsiConsole.Profile.Width = int.MaxValue; // 防止长日志自动折行(soft-warp)
21 | return action(this);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/EBuild.Test/test-project/ebuild.yaml:
--------------------------------------------------------------------------------
1 | project:
2 | name: ebuild-example
3 | version: "1.0"
4 | description: 这是由ebuild创建的示例工程。
5 | author: SalHe
6 | repository: https://github.com/SalHe/ebuild
7 | homepage: https://github.com/SalHe
8 | excludes:
9 | - '**/*.recover.e'
10 | - '**/*.ecode/**.e'
11 | - '**/*.代码/**.e'
12 | exclude-builds:
13 | - './scripts/**/*.e' # 脚本文件不纳入'ebuild build'命令中进行自动构建
14 | includes:
15 | - '**/*.e'
16 | e2txt:
17 | name-style: 中文
18 | generate-e: true
19 | build:
20 | compiler: 独立编译
21 | targets:
22 | - name: a.e——静态编译版
23 | description: 这是一个简单的控制台程序,会在标准输出输出一句问候。
24 | source: ./a.e
25 | output: a——静态编译版.exe
26 | build:
27 | compiler: 静态编译
28 |
29 | - name: a——黑月版
30 | description: 这是一个简单的控制台程序,会在标准输出输出一句问候。
31 | source: ./a.e
32 | output: a——黑月版.exe
33 | build:
34 | compiler: 黑月编译
35 |
--------------------------------------------------------------------------------
/src/EBuild/Config/Target.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Hooks;
2 |
3 | namespace EBuild.Config;
4 |
5 | public class Target
6 | {
7 | public string Name { get; set; }
8 | public string Description { get; set; }
9 | public string Source { get; set; }
10 | public string Output { get; set; }
11 | public bool Package { get; set; }
12 | public IDictionary Hooks { get; set; }
13 | public Build? Build { get; set; }
14 | public string CompileConfig { get; set; }
15 | public string CompileDescription { get; set; }
16 |
17 | public string DisplayName(string projectRootDir)
18 | {
19 | return string.IsNullOrEmpty(Name)
20 | ? Path.GetRelativePath(projectRootDir, Source)
21 | : Name;
22 | }
23 |
24 | public string OutputPath(string outputDir)
25 | {
26 | return Path.GetFullPath(Output, outputDir);
27 | }
28 | }
--------------------------------------------------------------------------------
/src/EBuild/EBuild.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 | enable
7 | enable
8 | 1.1.0
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/EBuild/Toolchain/ELangToolchain.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 |
3 | namespace EBuild.Toolchain;
4 |
5 | public class ELangToolchain : GeneralToolchain
6 | {
7 | public override IList EnvironmentVariables => new List()
8 | {
9 | new("ELANG_DIR", "易语言安装路径", () => Path.GetDirectoryName(ExecutablePath) ?? ""),
10 | };
11 |
12 | public ELangToolchain() : base("易语言", "http://www.eyuyan.com/pdown.htm", "e")
13 | {
14 | }
15 |
16 | public override void Search(string projectRootDir)
17 | {
18 | base.Search(projectRootDir);
19 | if (!Exists())
20 | {
21 | using var registryKey = Registry.CurrentUser.OpenSubKey("Software\\FlySky\\E\\Install");
22 | var eLibDir = registryKey.GetValue("Path")?.ToString() ?? "";
23 | ExecutablePath = Path.Combine(Path.GetFullPath("..", eLibDir), "e.exe");
24 | if (!File.Exists(ExecutablePath)) ExecutablePath = "";
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/.run/ebuild.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.run/ebuild info.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.run/ebuild build.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.run/ebuild e2txt.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.run/ebuild init.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.run/ebuild txt2e.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 SalHe Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/EBuild/DependencyInjection/TypeRegistrar.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Spectre.Console.Cli;
3 |
4 | namespace EBuild.DependencyInjection;
5 |
6 | public sealed class TypeRegistrar : ITypeRegistrar
7 | {
8 | private readonly IServiceCollection _builder;
9 |
10 | public TypeRegistrar(IServiceCollection builder)
11 | {
12 | _builder = builder;
13 | }
14 |
15 | public ITypeResolver Build()
16 | {
17 | return new TypeResolver(_builder.BuildServiceProvider());
18 | }
19 |
20 | public void Register(Type service, Type implementation)
21 | {
22 | _builder.AddSingleton(service, implementation);
23 | }
24 |
25 | public void RegisterInstance(Type service, object implementation)
26 | {
27 | _builder.AddSingleton(service, implementation);
28 | }
29 |
30 | public void RegisterLazy(Type service, Func func)
31 | {
32 | if (func is null)
33 | {
34 | throw new ArgumentNullException(nameof(func));
35 | }
36 |
37 | _builder.AddSingleton(service, (provider) => func());
38 | }
39 | }
--------------------------------------------------------------------------------
/.run/ebuild toolchain.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/EBuild/Consoles/MultiTaskDisplayer.cs:
--------------------------------------------------------------------------------
1 | namespace EBuild.Consoles;
2 |
3 | public interface IMultiTaskDisplayer
4 | {
5 | public Func TargetName { get; set; }
6 | public void SetHeader(string header);
7 | public void Update(TTarget target, TTargetStatus status, string log);
8 | public Task StartAsync (Func, Task> action);
9 |
10 | public virtual Action GetUpdater(TTarget target)
11 | {
12 | return (status, log) => Update(target, status, log);
13 | }
14 | }
15 |
16 | public abstract class MultiTaskDisplayer : IMultiTaskDisplayer
17 | {
18 | private IMultiTaskDisplayer _multiTaskDisplayerImplementation;
19 | public Func TargetName { get; set; }
20 | public Func StatusString { get; set; }
21 | public abstract void SetHeader(string header);
22 | public abstract void Update(TTarget target, TStatus status, string log);
23 | public abstract Task StartAsync (Func, Task> action);
24 | }
--------------------------------------------------------------------------------
/docs/project/environ.md:
--------------------------------------------------------------------------------
1 | # 环境变量
2 |
3 | 在[执行脚本](./run.md#工程相关脚本)、[执行易语言源文件](./run.md#使用易语言程序作为脚本)以及[执行构建目标生命周期脚本](./build.md#构建生命周期相关脚本)的时候,`ebuild`会设置一些环境变量用于辅助脚本的编写,以下对所设置的环境变量做出说明。
4 |
5 | | 环境变量名 | 说明 | 执行脚本/易语言源文件 | 构建生命周期 |
6 | | ------------------------- | ---------------------- | --------------------- | ------------ |
7 | | EBUILD_EXECUTABLE_PATH | `ebuild`可执行文件路径 | ✔ | ✔ |
8 | | ELANG_DIR | `易语言`安装目录 | ✔ | ✔ |
9 | | ECL_DIR | `ecl`安装目录 | ✔ | ✔ |
10 | | E2TXT_DIR | `e2txt`安装目录 | ✔ | ✔ |
11 | | EBUILD_PROJECT_ROOT_DIR | 工程根目录 | ✔ | ✔ |
12 | | EBUILD_PROJECT_OUTPUT_DIR | 构建输出目录 | ✔ | ✔ |
13 | | EBUILD_PERIOD | 构建生命周期 | ❌ | ✔ |
14 | | EBUILD_SOURCE_FILE | 被构建的源文件 | ❌ | ✔ |
15 | | EBUILD_TARGET_FILE | 构建目标输出路径 | ❌ | ✔ |
16 | | EBUILD_TARGET_TYPE | 构建目标类型 | ❌ | ✔ |
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/Txt2ECommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Config.Resolved;
3 | using EBuild.Plugins;
4 | using EBuild.Project;
5 | using EBuild.Toolchain;
6 | using YamlDotNet.Serialization;
7 |
8 | namespace EBuild.Commands.SubCommands;
9 |
10 | [Description("将文本格式的代码转换为易语言源文件。")]
11 | public class Txt2ECommand : E2TxtCommand
12 | {
13 | public Txt2ECommand(IDeserializer deserializer, E2TxtToolchain e2txt, IEnumerable plugins) : base(
14 | deserializer, e2txt, plugins)
15 | {
16 | }
17 |
18 | protected override string GenerateHeading(WholeStatus status)
19 | {
20 | switch (status)
21 | {
22 | case WholeStatus.Doing:
23 | return "txt2e";
24 | case WholeStatus.Completed:
25 | return "[green]:check_mark:txt2e[/]";
26 | case WholeStatus.ErrorOccured:
27 | return "[red]:cross_mark:txt2e[/]";
28 | }
29 |
30 | return "";
31 | }
32 |
33 | protected override IList GetArgs(ResolvedTarget target)
34 | {
35 | return E2TxtToolchain.Txt2EArgs(
36 | target.Target.GetECodeDir(), target.Target.GetRecoverEPath(), _resolvedConfig.RootConfig.E2Txt);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/EBuild/Project/EnvironmentVariables.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Specialized;
2 | using EBuild.Toolchain;
3 |
4 | namespace EBuild.Project;
5 |
6 | public class EnvironmentVariables : List, ICloneable
7 | {
8 | private readonly IEnumerable _toolchains;
9 |
10 | public EnvironmentVariables(IEnumerable toolchains)
11 | {
12 | _toolchains = toolchains;
13 | }
14 |
15 | public void ForProject(string projectRoot, string outputDir)
16 | {
17 | foreach (var toolchain in _toolchains)
18 | {
19 | toolchain.Search(projectRoot);
20 | AddRange(toolchain.EnvironmentVariables);
21 | }
22 |
23 | Add(new("EBUILD_PROJECT_ROOT_DIR", "工程根目录", () => projectRoot));
24 | Add(new("EBUILD_PROJECT_OUTPUT_DIR", "构建输出目录", () => outputDir));
25 | }
26 |
27 | public void LoadToStringDictionary(StringDictionary d)
28 | {
29 | foreach (var variable in this)
30 | {
31 | d[variable.VariableName] = variable.Value();
32 | }
33 | }
34 |
35 | public object Clone()
36 | {
37 | var evs = new EnvironmentVariables(_toolchains);
38 | this.ForEach(evs.Add);
39 | return evs;
40 | }
41 | }
--------------------------------------------------------------------------------
/docs/project/build.md:
--------------------------------------------------------------------------------
1 | # 构建(编译)
2 |
3 | 您可以全局性的指定编译源文件时采用的编译方式,如:独立编译、静态编译等。也可以单独为目标(`target`)指定构建配置。
4 |
5 | 对于未指定构建配置的目标将采用全局的构建配置。
6 |
7 |
8 | ## 全局配置
9 |
10 | ```yaml
11 | project:
12 | # ......
13 | build:
14 | compiler: 独立编译
15 | ```
16 |
17 | 在上述配置中,指定了全局默认的构建配置采用的编译方式为“独立编译”,您可以指定其他的[编译方式](#编译方式)。
18 |
19 | ## 编译方式
20 |
21 | 支持的编译方式如下:
22 |
23 | - 黑月编译
24 | - 黑月汇编
25 | - 黑月C++
26 | - 黑月MFC
27 | - 静态编译
28 | - 独立编译
29 |
30 | ::: info
31 | 编译方式定义于: https://github.com/SalHe/ebuild/blob/master/config/source.go
32 | :::
33 |
34 | ## 特定目标配置
35 |
36 | 您可以在`targets`下配置若干构建目标,对目标的输出文件名、编译方式等做出说明。
37 |
38 | 配置格式如下:
39 |
40 | ```yaml
41 | projects:
42 | # ......
43 | targets:
44 | - name: <目标的名称>
45 | description: <目标的描述>
46 | source: <目标的源文件路径>
47 | build:
48 | compiler: <编译方式>
49 | output: <输出文件名> # 当使用相对路径时,将相对于构建输出目录
50 | package: false # 是否为易包
51 | hooks: # 构建生命周期相关脚本
52 | pre-build: <编译该目标前执行的脚本>
53 | post-build: <编译该目标前之后的脚本>
54 | - name: ...
55 | ...
56 |
57 | ```
58 |
59 | ### 构建生命周期相关脚本
60 |
61 | `ebuild`将对目标的构建拆分成了若干生命周期,您可以在生命周期中指定执行一些代码。比如编译完成后,您可以使用脚本将输出文件复制到某处,或者对文件创建副本等。
62 |
63 | `ebuild`在执行这些脚本时也会传入一些额外的环境变量,用于在脚本中获得当前构建目标的一些信息。
64 |
65 | 目前的生命周期主要有:
66 |
67 | - pre-build: 在编译目标之前执行
68 | - post-build: 在编译目标之后执行
--------------------------------------------------------------------------------
/src/EBuild/Commands/Base/CommandBase.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Plugins;
2 | using Spectre.Console.Cli;
3 |
4 | namespace EBuild.Commands.Base;
5 |
6 | public class GeneralSettings : CommandSettings
7 | {
8 | }
9 |
10 | public class CommandBase : AsyncCommand
11 | where TSettings : GeneralSettings
12 | {
13 | public CommandBase(IEnumerable plugins)
14 | {
15 | _plugins = plugins;
16 | }
17 |
18 | public TSettings CommandSettings { get; private set; }
19 | public CommandContext CommandContext { get; set; }
20 | protected IEnumerable _plugins;
21 |
22 | public sealed override async Task ExecuteAsync(CommandContext context, TSettings settings)
23 | {
24 | CancellationTokenSource cts = new CancellationTokenSource();
25 | cts.Token.Register(() => Console.CancelKeyPress -= Handler);
26 |
27 | void Handler(object? sender, ConsoleCancelEventArgs e)
28 | {
29 | e.Cancel = true;
30 | cts.Cancel();
31 | }
32 |
33 | Console.CancelKeyPress += Handler;
34 |
35 | CommandSettings = settings;
36 | CommandContext = context;
37 |
38 | return await OnExecuteAsync(cts.Token);
39 | }
40 |
41 | public virtual Task OnExecuteAsync(CancellationToken cancellationToken)
42 | {
43 | return Task.FromResult(0);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/ToolchainCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Commands.Base;
3 | using EBuild.Plugins;
4 | using EBuild.Toolchain;
5 | using Spectre.Console;
6 | using YamlDotNet.Serialization;
7 |
8 | namespace EBuild.Commands.SubCommands;
9 |
10 | [Description("检查工具链。")]
11 | public class ToolchainCommand : ProjectCommand
12 | {
13 | private readonly IEnumerable _toolchains;
14 |
15 | public ToolchainCommand(IEnumerable toolchains, IDeserializer deserializer,
16 | IEnumerable plugins) : base(deserializer,plugins)
17 | {
18 | _toolchains = toolchains;
19 | }
20 |
21 | protected override bool ShowLoadConfig() => false;
22 |
23 | protected override int OnExecuteInternal()
24 | {
25 | var table = new Table();
26 | table.AddColumn("工具");
27 | table.AddColumn("安装路径");
28 | table.AddColumn("下载链接");
29 |
30 | var exitCode = 0;
31 | foreach (var toolchain in _toolchains)
32 | {
33 | toolchain.Search(ProjectRoot);
34 | table.AddRow(
35 | toolchain.Description,
36 | toolchain.Exists() ? toolchain.ExecutablePath : ":cross_mark:",
37 | toolchain.Link
38 | );
39 | }
40 |
41 | AnsiConsole.Write(table);
42 | return exitCode;
43 | }
44 | }
--------------------------------------------------------------------------------
/src/EBuild/Global/Defaults.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Yaml.Converters;
2 | using YamlDotNet.Core;
3 | using YamlDotNet.Serialization;
4 | using YamlDotNet.Serialization.EventEmitters;
5 | using YamlDotNet.Serialization.NamingConventions;
6 |
7 | namespace EBuild.Global;
8 |
9 | internal class LiteralMultilineEventEmitter : ChainedEventEmitter
10 | {
11 | public LiteralMultilineEventEmitter(IEventEmitter nextEmitter) : base(nextEmitter)
12 | {
13 | }
14 |
15 | public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
16 | {
17 | if (eventInfo.Source.Type == typeof(string) && eventInfo.Source.Value is string value && value.Contains("\n"))
18 | eventInfo.Style = ScalarStyle.Literal;
19 |
20 | base.Emit(eventInfo, emitter);
21 | }
22 | }
23 |
24 | public static class Defaults
25 | {
26 | public static IDeserializer Deserializer = new DeserializerBuilder()
27 | .WithDefaults()
28 | .Build();
29 |
30 | public static ISerializer Serializer = new SerializerBuilder()
31 | .WithDefaults()
32 | .WithEventEmitter(e => new LiteralMultilineEventEmitter(e))
33 | .Build();
34 |
35 | private static T WithDefaults(this T builder) where T : BuilderSkeleton
36 | {
37 | return builder
38 | .WithNamingConvention(HyphenatedNamingConvention.Instance)
39 | .WithTypeConverter(EnumConverter.Instance);
40 | }
41 | }
--------------------------------------------------------------------------------
/src/EBuild.Test/ConfigTests.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config.Resolved;
2 | using EBuild.Global;
3 | using EBuild.Project;
4 | using EBuild.Sources;
5 |
6 | namespace EBuild.Test;
7 |
8 | public class ConfigTests
9 | {
10 | private static readonly string _projectDir = Path.GetFullPath("./test-project", Directory.GetCurrentDirectory());
11 | private static string _pwdFilePath = ProjectPath.GetSourcePasswordFilePath(_projectDir);
12 | private ResolvedConfig _resolvedConfig;
13 |
14 | [SetUp]
15 | public void ResolveConfig()
16 | {
17 | _resolvedConfig = ResolvedConfig.Load(_projectDir, Defaults.Deserializer,
18 | PasswordFileResolver.FromProjectRootDir(_projectDir));
19 | }
20 |
21 | [Test]
22 | public void ResolveTargetsTest()
23 | {
24 | Assert.That(_resolvedConfig.ResolveTargets.Count, Is.EqualTo(4));
25 | }
26 |
27 | [Test]
28 | public void ExcludeBuildsTest()
29 | {
30 | Assert.That(
31 | _resolvedConfig.ResolveTargets
32 | .Where(x => "not-build".Equals(x.Target.Name))
33 | .All(x => !x.ShouldBuild)
34 | );
35 | }
36 |
37 | [Test]
38 | public void PasswordResolveTest()
39 | {
40 | Assert.That(
41 | _resolvedConfig.ResolveTargets
42 | .Where(x => !string.IsNullOrEmpty(x.Password))
43 | .All(x => "12345".Equals(x.Password))
44 | );
45 | }
46 | }
--------------------------------------------------------------------------------
/src/EBuild/Consoles/TableDisplayer.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 |
3 | namespace EBuild.Consoles;
4 |
5 | public class TableDisplayer : MultiTaskDisplayer
6 | {
7 | private readonly IList _targets;
8 | private LiveDisplayContext _ctx;
9 | private Table _table;
10 |
11 | public TableDisplayer(IList targets)
12 | {
13 | _targets = targets;
14 | }
15 |
16 | public override async Task StartAsync (Func, Task> action)
17 | {
18 | _table = new Table();
19 | _table.AddColumns("状态", "目标", "日志");
20 | foreach (var target in _targets)
21 | _table.AddRow("", Markup.Escape(TargetName(target)), "");
22 |
23 | TR? res = default;
24 | await AnsiConsole.Live(_table)
25 | .StartAsync(async ctx =>
26 | {
27 | _ctx = ctx;
28 | res = await action(this);
29 | });
30 | return res;
31 | }
32 |
33 | public override void SetHeader(string header)
34 | {
35 | _table.Title(header);
36 | _ctx.Refresh();
37 | }
38 |
39 | public override void Update(TTarget target, TTargetStatus status, string log)
40 | {
41 | int id = _targets.IndexOf(target);
42 | _table.UpdateCell(id, 0, StatusString(status));
43 | _table.UpdateCell(id, 2, log);
44 | _ctx.Refresh();
45 | }
46 | }
--------------------------------------------------------------------------------
/src/EBuild/Sources/PasswordResolver.cs:
--------------------------------------------------------------------------------
1 | using YamlDotNet.Serialization;
2 |
3 | namespace EBuild.Sources;
4 |
5 | public interface IPasswordResolver
6 | {
7 | string Resolve(string source);
8 | }
9 |
10 | public class PasswordFileResolver : IPasswordResolver
11 | {
12 | private readonly string _projectRoot;
13 | private readonly string _pwdFilePath;
14 | private Dictionary? _pwdDict;
15 |
16 | public PasswordFileResolver(string passwordFilePath, string projectRoot)
17 | {
18 | _pwdFilePath = passwordFilePath;
19 | _projectRoot = projectRoot;
20 | }
21 |
22 | public string Resolve(string source)
23 | {
24 | if (_pwdDict == null)
25 | {
26 | _pwdDict = new Dictionary();
27 | try
28 | {
29 | var original = new Deserializer().Deserialize>(File.OpenText(_pwdFilePath));
30 | foreach (var (file, pwd) in original) _pwdDict[Path.GetFullPath(file, _projectRoot)] = pwd;
31 | }
32 | catch (Exception e)
33 | {
34 | // ignored
35 | }
36 | }
37 |
38 | if (_pwdDict.ContainsKey(source))
39 | return _pwdDict[source];
40 | return string.Empty;
41 | }
42 |
43 | public static PasswordFileResolver FromProjectRootDir(string project)
44 | {
45 | return new PasswordFileResolver(Path.GetFullPath("./ebuild.pwd.yaml", project), project);
46 | }
47 | }
--------------------------------------------------------------------------------
/ebuild.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EBuild", "src\EBuild\EBuild.csproj", "{3AD6A129-0773-4DAE-8B4E-95FAF615D4AB}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EBuild.Test", "src\EBuild.Test\EBuild.Test.csproj", "{0016EE03-A7BA-4E74-A1E9-4045FB4BD7BC}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(SolutionProperties) = preSolution
16 | HideSolutionNode = FALSE
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {3AD6A129-0773-4DAE-8B4E-95FAF615D4AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {3AD6A129-0773-4DAE-8B4E-95FAF615D4AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {3AD6A129-0773-4DAE-8B4E-95FAF615D4AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {3AD6A129-0773-4DAE-8B4E-95FAF615D4AB}.Release|Any CPU.Build.0 = Release|Any CPU
23 | {0016EE03-A7BA-4E74-A1E9-4045FB4BD7BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {0016EE03-A7BA-4E74-A1E9-4045FB4BD7BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {0016EE03-A7BA-4E74-A1E9-4045FB4BD7BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {0016EE03-A7BA-4E74-A1E9-4045FB4BD7BC}.Release|Any CPU.Build.0 = Release|Any CPU
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/.github/workflows/changelog.yml:
--------------------------------------------------------------------------------
1 | name: Changelog
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 |
7 | jobs:
8 | build:
9 | name: "✏️ Changelog generation"
10 | runs-on: ubuntu-18.04
11 | steps:
12 | - name: "📥 Check-out"
13 | uses: actions/checkout@v2
14 | - name: "✏️ Generate full changelog"
15 | id: generate-full-changelog
16 | uses: heinrichreimer/github-changelog-generator-action@v2.3
17 | with:
18 | token: ${{ secrets.GITHUB_TOKEN }}
19 | headerLabel: "# 📑 更新日志"
20 | breakingLabel: '### 💥 破坏性变更'
21 | enhancementLabel: '### 🚀 增强'
22 | bugsLabel: '### 🐛 BUG修复'
23 | deprecatedLabel: '### ⚠️ 弃用'
24 | removedLabel: '### 🔥 移除'
25 | securityLabel: '### 🛡️ 安全'
26 | issuesLabel: '### 📁 Issues'
27 | prLabel: '### 📁 Pull requests'
28 | addSections: '{"documentation":{"prefix":"### 📖 文档","labels":["documentation"]},"tests":{"prefix":"### ✅ 测试","labels":["tests"]}}'
29 | issues: true
30 | issuesWoLabels: true
31 | pullRequests: true
32 | prWoLabels: true
33 | author: true
34 | unreleased: true
35 | compareLink: true
36 | stripGeneratorNotice: true
37 | verbose: true
38 | - name: "🖨️ Print changelog to console"
39 | run: cat CHANGELOG.md
40 | - name: "📤 Upload changelog"
41 | uses: actions/upload-artifact@v1.0.0
42 | with:
43 | name: "Changelog"
44 | path: CHANGELOG.md
45 |
--------------------------------------------------------------------------------
/src/EBuild/Yaml/Converters/EnumConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using YamlDotNet.Core;
3 | using YamlDotNet.Core.Events;
4 | using YamlDotNet.Serialization;
5 | using YamlDotNet.Serialization.NamingConventions;
6 |
7 | namespace EBuild.Yaml.Converters;
8 |
9 | public class EnumConverter : IYamlTypeConverter
10 | {
11 | public static readonly EnumConverter Instance = new EnumConverter();
12 |
13 | public bool Accepts(Type type)
14 | {
15 | return type.IsEnum;
16 | }
17 |
18 | public object? ReadYaml(IParser parser, Type type)
19 | {
20 | var possibleNames = new HashSet();
21 | var scalar = parser.Consume();
22 | possibleNames.Add(scalar.Value);
23 | possibleNames.Add(PascalCaseNamingConvention.Instance.Apply(scalar.Value));
24 |
25 | foreach (var value in Enum.GetValues(type))
26 | {
27 | var alias = type.GetField(Enum.GetName(type, value)!)!.GetCustomAttribute();
28 | if (alias != null && possibleNames.Contains(alias.Name)) return value;
29 | }
30 |
31 | foreach (var possibleName in possibleNames)
32 | if (Enum.TryParse(type, possibleName, out var result))
33 | return result;
34 |
35 | return null;
36 | }
37 |
38 | public void WriteYaml(IEmitter emitter, object? value, Type type)
39 | {
40 | var alias = type.GetCustomAttribute();
41 | emitter.Emit(alias != null ? new Scalar(alias.Name) : new Scalar(value?.ToString() ?? ""));
42 | }
43 | }
--------------------------------------------------------------------------------
/src/EBuild.Test/ToolchainTests.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config;
2 | using EBuild.Toolchain;
3 |
4 | namespace EBuild.Test;
5 |
6 | internal class ToolchainTests
7 | {
8 | private readonly E2TxtToolchain _e2txt;
9 |
10 | [Test]
11 | public void E2TxtArgsTest()
12 | {
13 | var source = "esrc!!!!!!!!!!!!!";
14 | var ecode = "ecode!!!!!!!!!!!!!";
15 | E2Txt config = new E2Txt { GenerateE = true, NameStyle = E2Txt.NameStyleEnum.Chinese };
16 | CollectionAssert.AreEquivalent(
17 | new List { "-ns", "2", "-e", "-log", "-enc", "UTF-8" },
18 | E2TxtToolchain.GeneralArgs(config));
19 |
20 | var e2TxtArgs = E2TxtToolchain.E2TxtArgs(source, ecode, config);
21 | CollectionAssert.AreEquivalent(
22 | new List
23 | { "-ns", "2", "-e", "-log", "-enc", "UTF-8", "-src", source, "-dst", ecode, "-mode", "e2t" },
24 | e2TxtArgs);
25 | Assert.That(e2TxtArgs[e2TxtArgs.IndexOf("-src") + 1], Is.EqualTo(source));
26 | Assert.That(e2TxtArgs[e2TxtArgs.IndexOf("-dst") + 1], Is.EqualTo(ecode));
27 |
28 | var txt2EArgs = E2TxtToolchain.Txt2EArgs(ecode, source, config);
29 | CollectionAssert.AreEquivalent(
30 | new List
31 | { "-ns", "2", "-e", "-log", "-enc", "UTF-8", "-src", ecode, "-dst", source, "-mode", "t2e" },
32 | txt2EArgs);
33 | Assert.That(txt2EArgs[txt2EArgs.IndexOf("-src") + 1], Is.EqualTo(ecode));
34 | Assert.That(txt2EArgs[txt2EArgs.IndexOf("-dst") + 1], Is.EqualTo(source));
35 | }
36 | }
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build Latest
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches: ["master"]
7 | paths: ["./src/**"]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | matrix:
14 | sc: ["--self-contained"]
15 | single-file: ["true", "false"]
16 | runtime: ["win-x86"]
17 | steps:
18 |
19 | - uses: actions/checkout@v3
20 |
21 | - name: Setup .NET
22 | uses: actions/setup-dotnet@v2
23 | with:
24 | dotnet-version: 6.0.x
25 |
26 | - name: Restore dependencies
27 | run: dotnet restore --runtime ${{ matrix.runtime }}
28 |
29 | - name: Build
30 | run: dotnet build --no-restore
31 |
32 | - name: Test
33 | run: dotnet test --no-build --verbosity normal
34 |
35 | - name: Publish
36 | run: dotnet publish ./src/EBuild/ --runtime ${{ matrix.runtime }} --configuration Release ${{ matrix.sc }} --no-restore -p:PublishSingleFile=${{ matrix.single-file }} -p:PublishTrimmed=true
37 |
38 | - name: Upload Artifact
39 | if: matrix.single-file == 'true'
40 | uses: actions/upload-artifact@v1.0.0
41 | with:
42 | name: ebuild-${{ matrix.runtime }}-single-file
43 | path: ./src/EBuild/bin/Release/net6.0/${{ matrix.runtime }}/publish
44 |
45 | - name: Upload Artifact
46 | if: matrix.single-file == 'false'
47 | uses: actions/upload-artifact@v1.0.0
48 | with:
49 | name: ebuild-${{ matrix.runtime }}
50 | path: ./src/EBuild/bin/Release/net6.0/${{ matrix.runtime }}/publish
51 |
--------------------------------------------------------------------------------
/src/EBuild.Test/EBuild.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Always
26 |
27 |
28 | Always
29 |
30 |
31 | Always
32 |
33 |
34 | Always
35 |
36 |
37 | Always
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/project/basic.md:
--------------------------------------------------------------------------------
1 | # 基本配置
2 |
3 | ## 工程描述信息
4 |
5 | ```yaml
6 | project:
7 | name: ebuild-example # 工程名
8 | version: "1.0" # 工程版本
9 | description: 这是由ebuild创建的示例工程。 # 工程的描述信息
10 | author: SalHe # 工程作者
11 | repository: https://github.com/SalHe/ebuild # 工程的源码仓库地址
12 | homepage: https://github.com/SalHe # 工程主页
13 | ```
14 |
15 | 您可以在`ebuild.yaml`中看到上述的内容,在`project`之下有若干用于描述工程的信息,他们对工程没有任何影响,仅仅是用于描述工程,方便了解工程的信息。
16 |
17 |
18 | ## 管理源码
19 |
20 | 在`ebuild`中,并不是所有源码都会参与`e2txt`、`txt2e`、编译等的过程,只有那些按照约定包含(includes)进来但又没有被排除掉的文件(excludes)的文件才能参与这些过程。
21 |
22 | ### 被管理的源文件
23 |
24 | ```yaml
25 | project:
26 | # ......
27 | includes:
28 | - '**/*.e'
29 | ```
30 |
31 | 在`includes`节点中,您可以配置多种文件名匹配模式来选择你需要被纳入控制的源码。在上述配置中,要求工程管理所有目录(`**/`)下的易语言源文件(`*.e`)。
32 |
33 | ### 排除的源文件
34 |
35 | 有时候,您希望在工程中排除一些源文件,使他们不纳入`ebuild`的控制——既不参与`e2txt`也不参与编译。那么您可以配置`excludes`。
36 |
37 | ```yaml
38 | project:
39 | # ......
40 | excludes:
41 | - '**/*.recover.e'
42 | - '**/*.ecode/*.e'
43 | - '**/*.代码/*.e'
44 | ```
45 |
46 | 上述代码中,排除了三种模式的文件,比如`XXX.recover.e`被排除掉了。
47 |
48 | `excludes`的优先级是高于`includes`的,即:纵使`includes`中包含了`XXX.recover.e`,他也不会被纳入`ebuild`的控制。
49 |
50 | ### 仅在构建中排除源文件
51 |
52 | ```yaml
53 | project:
54 | # ......
55 | exclude-builds:
56 | - './scripts/**/*.e' # 脚本文件不纳入'ebuild build'命令中进行自动构建
57 | ```
58 |
59 | 与`excludes`不同,有些源文件您希望参与`e2txt`,但不希望他作为编译目标——作为脚本的易语言源文件便是一个例子,上述配置使得`scripts`目录下的所有易语言源文件`*.e`都不参与编译,但是他们仍然参与`e2txt`。
60 |
61 | `exclude-builds`的优先级高于`includes`,低于`excludes`,即:倘若`excludes`排除了指定源文件,即便该配置中未排除那个文件,该文件最终仍然被排除(既不参与`e2txt`也不参与编译)。
--------------------------------------------------------------------------------
/src/EBuild/Sources/ESourceMeta.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Yaml.Converters;
2 |
3 | namespace EBuild.Sources;
4 |
5 | public enum SourceType
6 | {
7 | [EnumAlias("源码")] Src = 1,
8 | [EnumAlias("模块")] ECom = 3,
9 | }
10 |
11 | public enum TargetType
12 | {
13 | [ESourceTargetType(Extension = "exe")] WinForm = 0,
14 | [ESourceTargetType(Extension = "exe")] WinConsole = 1,
15 | [ESourceTargetType(Extension = "dll")] WinDll = 2,
16 | [ESourceTargetType(Extension = "ec")] WinEc = 1000,
17 | [ESourceTargetType(Extension = null)] LinuxConsole = 10000,
18 | [ESourceTargetType(Extension = null)] LinuxEc = 11000
19 | }
20 |
21 | public class ESourceMeta
22 | {
23 | public SourceType SourceType { get; set; }
24 | public TargetType TargetType { get; set; }
25 |
26 | private ESourceMeta()
27 | {
28 | }
29 |
30 | public static ESourceMeta? FromSource(string sourcePath)
31 | {
32 | try
33 | {
34 | using var fs = File.OpenRead(sourcePath);
35 | using var br = new BinaryReader(fs);
36 | fs.Seek(124L, SeekOrigin.Begin);
37 | var st = (SourceType)br.ReadInt32();
38 | fs.Seek(132L, SeekOrigin.Begin);
39 | var tt = (TargetType)br.ReadInt32();
40 | return new ESourceMeta()
41 | {
42 | SourceType = st,
43 | TargetType = tt,
44 | };
45 | }
46 | catch (Exception e)
47 | {
48 | return null;
49 | }
50 | }
51 | }
52 |
53 | [AttributeUsage(AttributeTargets.Field)]
54 | public class ESourceTargetTypeAttribute : Attribute
55 | {
56 | public string? Extension { get; set; }
57 | }
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # EBuild
2 |
3 | `ebuild`是一个针对易语言的构建工具,该工具主要使用配置化的方式完成自动化的将易语言源文件转换成文本格式描述的文件(使用了[e2txt](http://e2ee.jimstone.com.cn/downloads/))
4 | ,以及借助[ecl](https://bbs.125.la/forum.php?mod=viewthread&tid=14553929&highlight=ecl)完成源文件编译。
5 |
6 | 目前,`ebuild`已不再使用`Go`语言开发,转而使用`C#`基于`.NET6`开发,关于这样做的原因请参见:[使用C#+.NET6重写ebuild,为后续开发打基础](https://github.com/SalHe/ebuild/pull/1)。
7 |
8 | ## 特性
9 |
10 | - [x] 可根据需要选择需要完成自动化管理的易语言源文件
11 | - [x] 可排除特定源文件
12 | - [x] 批量完成e2txt/txt2e
13 | - 全转换
14 | - 指定转换目标
15 | - [x] 文件清理
16 | - *.recover.e 使用`txt2e`从文本格式代码恢复出来的易语言二进制源文件
17 | - *.ecode 使用`e2txt`从易语言二进制源文件转换出来的文本格式代码
18 | - ebuild-out 中构建生成的文件
19 | - [ ] 检测源文件变化,并自动转换成文本格式的代码
20 | - [x] 批量构建目标
21 | - 全构建
22 | - 指定构建目标
23 | - [x] 构建前后动作
24 | - [x] 立即编译并执行易语言源文件
25 | - [ ] 使用易语言程序作为当前项目`ebuild`插件,以参与程序编译过程
26 |
27 | ## 命令行帮助
28 |
29 | 请见[命令行帮助](./cli/)
30 |
31 | ## 效果图
32 |
33 | ### 预览项目信息
34 |
35 | ```shell
36 | ./ebuild.exe info --project ./example/
37 | ```
38 |
39 | 
40 |
41 | ### e2txt/txt2e
42 |
43 | ```shell
44 | ./ebuild.exe e2txt --project ./example/
45 | ./ebuild.exe txt2e --project ./example/
46 | ```
47 |
48 | 
49 | 
50 |
51 | ### 构建
52 |
53 | ```shell
54 | ./ebuild.exe build --project ./example/
55 | ```
56 |
57 | 
58 |
59 | ## 引用项目
60 |
61 | 该项目的存在离不开以下作者和项目为易语言生态带来的贡献:
62 |
63 | - [e2txt](http://e2ee.jimstone.com.cn/) by [JimStone](http://e2ee.jimstone.com.cn/)
64 | - [易语言命令行编译工具 ecl](https://bbs.125.la/forum.php?mod=viewthread&tid=14553929&highlight=ecl)
65 | by [被封七号](https://bbs.125.la/home.php?mod=space&uid=504218&do=thread&type=thread&view=me&from=space)
66 |
67 | > 如有任何形式的对于作者或项目的侵犯行为,请见谅,并联系我对项目做出调整或者下架。
68 |
--------------------------------------------------------------------------------
/docs/first-project.md:
--------------------------------------------------------------------------------
1 | # 第一个工程
2 |
3 | 在安装好`ebuild`及相关工具之后,您便可以享受由`ebuild`为您带来的好处了。
4 |
5 | ## 初始化工程
6 |
7 | 新建一个文件夹如`ebuild工程`,打开命令行并进入到该文件夹中,执行:
8 |
9 | ```shell
10 | ebuild init
11 | ```
12 |
13 | 执行完成后,您可以看到以下提示,同时`ebuild`将为您创建与工程相关的一些文件。
14 |
15 | 
16 |
17 | ## 工程文件
18 |
19 | ```
20 | ebuild-project
21 | ├── .gitignore # git将忽略的文件列表
22 | ├── ebuild.pwd.yaml # ebuild中源码的密码(如果有密码的话)
23 | ├── ebuild.yaml # ebuild工程配置文件,描述了工程自身的信息、包含的源码、源码的编译方式等。
24 | └── README.md
25 | ```
26 |
27 | ## 添加源码
28 |
29 | 现在您可以在该目录下创建易语言源码。
30 |
31 | 比如在工程目录下创建一个`Windows控制台程序.e`:
32 |
33 | ```
34 | .版本 2
35 |
36 | .程序集 程序集1
37 |
38 | .子程序 _启动子程序, 整数型, , 本子程序在程序启动后最先执行
39 |
40 |
41 | 标准输出 (, “你好,ebuild!”)
42 |
43 | 返回 (0) ' 可以根据您的需要返回任意数值
44 | ```
45 |
46 | ## `e2txt`
47 |
48 | 接下来,您便可以使用`ebuild e2txt`将工程中包含的源码借助`e2txt`将易语言源码转换成文本格式的代码,这样可以方便您使用`git`来管理您的代码。
49 |
50 | 
51 |
52 | 完成上述转换后,您可以在`<工程根目录>\Windows控制台程序.ecode`看到您的文本格式的代码。
53 |
54 | ## `txt2e`
55 |
56 | 同时也可以使用`ebuild txt2e`将工程中的文本格式的代码恢复为易语言源文件(该恢复过程只针对被包含在工程中的源文件对应的文本格式代码),此外恢复的源文件的文件名中将加入`.recover`。比如,`<工程根目录>\Windows控制台程序.ecode`恢复后,您将得到恢复后的源文件``<工程根目录>\Windows控制台程序.recover.e`。
57 |
58 | ::: info
59 | 由于`e2txt`和`txt2e`并不是一个完全逆向的过程,`ebuild`不会主动将您原本的源文件替换为恢复的源文件`*.recover.e`,这是出于对您数据的安全性考虑。
60 | :::
61 |
62 | ## 构建工程
63 |
64 | 使用`ebuild build`您便可以将工程中的所有源文件根据配置完成编译了。编译后的文件目前会输出到`<工程根目录>\ebuild-out\`中,后续版本可能考虑允许您自定义输出目录。
65 |
66 | 
67 |
68 | 在上述的输出结果中,我们可以看到编译后的文件输出到`C:\Users\SalHe\Desktop\ebuild-project\ebuild-out\Windows控制台程序.exe`去了。
69 |
70 | ## 清理工程
71 |
72 | 使用`ebuild clean`您可以清理`ebuild`生成的中间文件。
73 |
74 | 
75 |
76 | ## 最后
77 |
78 | 这里只是简单说明`ebuild`的使用,关于配置文件的详细细节和命令行的相关参数等将在其他文档中进行讨论。
79 |
80 | 本文中的工程可以参见 https://github.com/SalHe/ebuild/blob/master/examples/first-project 。
--------------------------------------------------------------------------------
/src/EBuild/Toolchain/E2TxtToolchain.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Config;
2 |
3 | namespace EBuild.Toolchain;
4 |
5 | public class E2TxtToolchain : GeneralToolchain
6 | {
7 | public override IList EnvironmentVariables => new List()
8 | {
9 | new("E2TXT_DIR", "e2txt安装路径", () => Path.GetDirectoryName(ExecutablePath) ?? ""),
10 | };
11 |
12 | public E2TxtToolchain() : base("e2txt", "http://e2ee.jimstone.com.cn/downloads/", "e2txt")
13 | {
14 | }
15 |
16 | public static IList GeneralArgs(E2Txt e2txtConfig)
17 | {
18 | var args = new List() { "-log", "-enc", "UTF-8" };
19 |
20 | switch (e2txtConfig.NameStyle)
21 | {
22 | case E2Txt.NameStyleEnum.English:
23 | args.Add("-ns");
24 | args.Add("1");
25 | break;
26 | case E2Txt.NameStyleEnum.Chinese:
27 | args.Add("-ns");
28 | args.Add("2");
29 | break;
30 | }
31 |
32 | if (e2txtConfig.GenerateE)
33 | args.Add("-e");
34 |
35 | return args;
36 | }
37 |
38 | private static IList Args(string from, string to, string mode, E2Txt e2txtCofig)
39 | {
40 | var args = GeneralArgs(e2txtCofig);
41 | args.Add("-src");
42 | args.Add(from);
43 | args.Add("-dst");
44 | args.Add(to);
45 | args.Add("-mode");
46 | args.Add(mode);
47 | return args;
48 | }
49 |
50 | public static IList E2TxtArgs(string source, string ecodeDir, E2Txt e2txtCofig)
51 | {
52 | return Args(source, ecodeDir, "e2t", e2txtCofig);
53 | }
54 |
55 | public static IList Txt2EArgs(string ecodeDir, string source, E2Txt e2txtCofig)
56 | {
57 | return Args(ecodeDir, source, "t2e", e2txtCofig);
58 | }
59 | }
--------------------------------------------------------------------------------
/src/EBuild/Toolchain/GeneralToolchain.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace EBuild.Toolchain;
4 |
5 | public abstract class GeneralToolchain : IToolchain
6 | {
7 | private readonly string _executableName;
8 |
9 | public GeneralToolchain(string description, string link, string executableName)
10 | {
11 | _executableName = executableName;
12 | Description = description;
13 | Link = link;
14 | }
15 |
16 | public string Description { get; }
17 | public string Link { get; }
18 | public string ExecutablePath { get; protected set; } = string.Empty;
19 | public abstract IList EnvironmentVariables { get; }
20 |
21 | public virtual void Search(string projectRootDir)
22 | {
23 | var possible = new List()
24 | {
25 | GetExecutablePath(projectRootDir, _executableName),
26 | GetExecutablePath(Directory.GetCurrentDirectory(), _executableName),
27 | GetExecutablePath(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName ?? "") ?? "",
28 | _executableName)
29 | };
30 | foreach (var path in possible)
31 | if (File.Exists(path))
32 | {
33 | ExecutablePath = path;
34 | return;
35 | }
36 |
37 | ExecutablePath = Environment.GetEnvironmentVariable("PATH")!
38 | .Split(";")
39 | .Where(s => File.Exists(Path.Combine(s, _executableName + ".exe")))
40 | .FirstOrDefault(string.Empty);
41 | }
42 |
43 | public bool Exists()
44 | {
45 | return !string.IsNullOrEmpty(ExecutablePath) && File.Exists(ExecutablePath);
46 | }
47 |
48 | private string GetExecutablePath(string root, string name)
49 | {
50 | return Path.GetFullPath(Path.Join(root, ".toolchain", name, name + ".exe"));
51 | }
52 | }
--------------------------------------------------------------------------------
/examples/simple/ebuild.yaml:
--------------------------------------------------------------------------------
1 | project:
2 | name: ebuild-example
3 | version: "1.0"
4 | description: 这是由ebuild创建的示例工程。
5 | author: SalHe
6 | repository: https://github.com/SalHe/ebuild
7 | homepage: https://github.com/SalHe
8 | scripts:
9 | show-envs: |
10 | @echo off
11 | echo EBuild="%EBUILD_EXECUTABLE_PATH%"
12 | echo 易语言="%ELANG_DIR%"
13 | echo Ecl="%ECL_DIR%"
14 | echo E2Txt="%E2Txt_DIR%"
15 | get-input: |
16 | @echo off
17 | @REM 演示如何获取用户输入
18 |
19 | set /p Username=用户名:
20 | set /p Password=密码:
21 |
22 | echo/
23 | echo 您的用户名:%Username%
24 | echo 您的密码:%Password%
25 | cmd-args: |
26 | @echo off
27 | echo arg0=%0
28 | echo arg1=%1
29 | echo arg2=%2
30 | echo arg3=%3
31 | excludes:
32 | - '**/*.recover.e'
33 | - '**/*.ecode/**.e'
34 | - '**/*.代码/**.e'
35 | exclude-builds:
36 | - './scripts/**/*.e' # 脚本文件不纳入'ebuild build'命令中进行自动构建
37 | includes:
38 | - '**/*.e'
39 | e2txt:
40 | name-style: 中文
41 | generate-e: true
42 | build:
43 | compiler: 独立编译
44 | targets:
45 | - name: Windows窗口程序示例
46 | description: 这是一个特别简单的窗口程序,里面有个按钮,你点击后会弹出提示。
47 | source: ./Windows窗口程序.e # 相对于项目根路径
48 | # 因为没有为该目标指定编译方式,所以会默认采用工程配置'build.compiler'中的编译方式
49 | output: Windows窗口程序示例.exe
50 | package: false # 不是易包
51 | hooks:
52 | pre-build: |
53 | @echo off
54 | echo 当前时期:%EBUILD_PERIOD%
55 | echo 源文件:%EBUILD_SOURCE_FILE%
56 | echo 目标文件:%EBUILD_TARGET_FILE%
57 | echo 目标类型:%EBUILD_TARGET_TYPE%
58 | post-build: |
59 | @echo off
60 | copy "%EBUILD_TARGET_FILE%" "%EBUILD_TARGET_FILE%.copy"
61 |
62 | - name: Windows控制台程序——静态编译版
63 | description: 这是一个简单的控制台程序,会在标准输出输出一句问候。
64 | source: ./Windows控制台程序.e
65 | output: Windows控制台程序示例——静态编译版.exe
66 | build:
67 | compiler: 静态编译
68 |
69 | - name: Windows控制台程序——黑月版
70 | description: 这是一个简单的控制台程序,会在标准输出输出一句问候。
71 | source: ./Windows控制台程序.e
72 | output: Windows控制台程序示例——黑月版.exe
73 | build:
74 | compiler: 黑月编译
75 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vitepress";
2 | import miCheckbox from "markdown-it-task-checkbox";
3 | import { version } from '../../package.json';
4 |
5 | export default defineConfig({
6 | lang: 'zh-CN',
7 | base: '/ebuild/',
8 | title: 'EBuild',
9 | description: 'EBuild 是一个专注于易语言的构建工具。',
10 | lastUpdated: true,
11 | themeConfig: {
12 | outlineTitle: '目录',
13 | footer: {
14 | message: '本开源软件受 MIT 协议保护',
15 | copyright: 'Copyright (c) 2022 SalHe Li'
16 | },
17 |
18 | nav: [
19 | { text: '使用向导', link: '/README' },
20 | { text: '命令行帮助', link: '/cli/' },
21 | { text: `v${version}`, link: `https://github.com/SalHe/ebuild/releases/tag/v${version}` },
22 | {
23 | text: '友情链接',
24 | items: [
25 | { text: "SalHe's Home", link: "https://salhe.github.io" },
26 | { text: "SalHe's Blog", link: "https://salhe.github.io/blog" }
27 | ]
28 | }
29 | ],
30 | sidebar: [
31 | {
32 | text: '介绍',
33 | items: [
34 | { text: '什么是 ebuild?', link: '/README' },
35 | { text: '安装', link: '/installation' },
36 | { text: '第一个工程', link: '/first-project' },
37 | { text: '鸣谢', link: '/thanks' },
38 | ]
39 | },
40 | {
41 | text: '工程配置',
42 | items: [
43 | { text: '基本配置', link: '/project/basic' },
44 | { text: '工程脚本 - 重复工作', link: '/project/run' },
45 | { text: 'e2txt配置', link: '/project/e2txt' },
46 | { text: '构建配置', link: '/project/build' },
47 | { text: '环境变量', link: '/project/environ' },
48 | { text: '案例', link: '/project/examples' },
49 | ]
50 | },
51 | {
52 | text: '命令行帮助',
53 | items: [
54 | { text: '概览', link: '/cli/' },
55 | ]
56 | }
57 | ],
58 | editLink: {
59 | pattern: 'https://github.com/SalHe/ebuild/edit/master/docs/:path',
60 | text: '在 GitHub 上编辑'
61 | },
62 | socialLinks: [
63 | { icon: 'github', link: 'https://github.com/SalHe/ebuild' },
64 | ],
65 | algolia: {
66 | appId: 'I0YZBJE735',
67 | apiKey: 'be48f498e8c14176450fe574c8347f12',
68 | indexName: 'ebuild'
69 | },
70 | },
71 | markdown: {
72 | config: (md) => {
73 | md.use(miCheckbox, { readonly: true })
74 | }
75 | }
76 | })
77 |
--------------------------------------------------------------------------------
/src/EBuild/Plugins/BuildHookScriptPlugin.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Text;
3 | using EBuild.Commands.Base;
4 | using EBuild.Hooks;
5 | using Spectre.Console;
6 |
7 | namespace EBuild.Plugins;
8 |
9 | public class BuildHookScriptPlugin : Plugin
10 | {
11 | public override async Task OnHook(PluginContext context, CancellationToken cancellationToken, Hook hook)
12 | {
13 | if (context.BuildTarget!.Target?.Hooks?.ContainsKey(hook) != true) return true;
14 | string batContent = context.BuildTarget!.Target?.Hooks?[hook].ReplaceLineEndings("\r\n") ?? "";
15 | if (string.IsNullOrEmpty(batContent))
16 | return true;
17 |
18 | var tempFile = Path.GetTempFileName();
19 | var tempBatFile = Path.ChangeExtension(tempFile, "ebuild-hooks.bat");
20 | File.Move(tempFile, tempBatFile);
21 | await File.WriteAllTextAsync(tempBatFile, batContent, cancellationToken);
22 |
23 | context.UpdateStatus?.Invoke(TargetStatus.Doing, $"正在准备执行编译周期脚本: {tempBatFile.EscapeMarkup()}");
24 |
25 | var process = new Process();
26 | context.EnvironmentVariables.LoadToStringDictionary(process.StartInfo.EnvironmentVariables);
27 | process.StartInfo.FileName = tempBatFile;
28 |
29 | process.StartInfo.StandardOutputEncoding =
30 | process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
31 | process.StartInfo.RedirectStandardOutput = process.StartInfo.RedirectStandardError = true;
32 | process.StartInfo.RedirectStandardInput = true;
33 |
34 | void Handler(object sender, DataReceivedEventArgs e)
35 | {
36 | if (!string.IsNullOrEmpty(e.Data))
37 | context.UpdateStatus?.Invoke(TargetStatus.Doing, e.Data);
38 | }
39 |
40 | process.OutputDataReceived += Handler;
41 | process.ErrorDataReceived += Handler;
42 |
43 | cancellationToken.Register(() =>
44 | {
45 | process.CancelErrorRead();
46 | process.CancelOutputRead();
47 | process.Kill();
48 | });
49 | process.Start();
50 | process.BeginOutputReadLine();
51 | process.BeginErrorReadLine();
52 | await process.WaitForExitAsync(cancellationToken);
53 |
54 | // 思考了一下还是决定不允许在构建脚本中接收输入(标准输入),尽管之前golang版本中已实现
55 |
56 | context.UpdateStatus?.Invoke(TargetStatus.Doing, $"脚本退出代码:{process.ExitCode}");
57 |
58 | File.Delete(tempBatFile);
59 |
60 | return process.ExitCode == 0;
61 | }
62 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/CleanCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Commands.Base;
3 | using EBuild.Plugins;
4 | using EBuild.Project.Cleaners;
5 | using Spectre.Console;
6 | using Spectre.Console.Cli;
7 | using YamlDotNet.Serialization;
8 |
9 | namespace EBuild.Commands.SubCommands;
10 |
11 | [Description(@"清理恢复的源码等工程中间文件。
12 | 该命令可以清理恢复的源码等工程中间文件。包括:
13 |
14 | 1. txt2e 中从文本格式代码恢复出来的易语言源文件(*.recover.e,只清理包含在工程源文件和目标中的恢复代码);
15 | 2. e2txt 中从易语言源文件转换成的文本格式代码的文件夹(*.ecode,只清理包含在工程源文件和目标中的恢复代码)。(可选,默认不清理)
16 | 3. build 中构建出来的目标文件(实际会清理构建输出文件夹中的所有文件)。
17 | ")]
18 | public class CleanCommand : ProjectCommand
19 | {
20 | public class Settings : ProjectSettings
21 | {
22 | [CommandOption("--ecode")]
23 | [Description("清理 .ecode 文件夹")]
24 | public bool CleanECode { get; init; } = false;
25 |
26 | [CommandOption("-f|--force")]
27 | [Description("强制同意。针对危险的操作,ebuild会尝试询问您是否确定,但是如果您开启了此标志,则ebuild认为您坚持对所有危险操作继续执行。")]
28 | public bool ForceClean { get; init; } = false;
29 | }
30 |
31 | private readonly IEnumerable _projectCleaners;
32 |
33 | public CleanCommand(IDeserializer deserializer, IEnumerable projectCleaners,
34 | IEnumerable plugins) : base(deserializer,plugins)
35 | {
36 | _projectCleaners = projectCleaners;
37 | }
38 |
39 | protected override Task OnExecuteInternalAsync(CancellationToken token)
40 | {
41 | var activatedCleaners = _projectCleaners.Where(x => x is not ProjectECodeCleaner || CommandSettings.CleanECode);
42 | foreach (var cleaner in activatedCleaners)
43 | {
44 | AnsiConsole.MarkupLine($"[green]正在清理 {Markup.Escape(cleaner.CleanContent)}[/]");
45 | if (!CommandSettings.ForceClean && cleaner.Optional &&
46 | !AnsiConsole.Confirm($"即将清理 [red]{Markup.Escape(cleaner.CleanContent)}[/],这可能会使您的数据丢失,是否确认清理?", false))
47 | {
48 | AnsiConsole.MarkupLine("[yellow]您已放弃清理[/]");
49 | AnsiConsole.WriteLine();
50 | continue;
51 | }
52 |
53 | foreach (var target in _resolvedConfig.ResolveTargets)
54 | {
55 | try
56 | {
57 | cleaner.Clean(target, _resolvedConfig);
58 | }
59 | catch (Exception)
60 | {
61 | // ignored
62 | }
63 |
64 | if (cleaner.Once) break;
65 | }
66 |
67 | Console.WriteLine();
68 | }
69 |
70 | return Task.FromResult(0);
71 | }
72 | }
--------------------------------------------------------------------------------
/src/EBuild/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Text;
3 | using EBuild.Commands.SubCommands;
4 | using EBuild.DependencyInjection;
5 | using EBuild.Extensions;
6 | using EBuild.Global;
7 | using EBuild.Plugins;
8 | using EBuild.Project;
9 | using EBuild.Project.Cleaners;
10 | using EBuild.Toolchain;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Logging;
13 | using Spectre.Console.Cli;
14 |
15 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
16 |
17 | var services = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
18 | services.AddLogging(builder => builder.ClearProviders());
19 |
20 | services.AddSingleton(_ => Defaults.Deserializer);
21 | services.AddSingleton(_ => Defaults.Serializer);
22 |
23 | services.AddSingleton(
24 | x => new EnvironmentVariables(x.GetService>()!)
25 | {
26 | new("EBUILD_EXECUTABLE_PATH", "ebuild可执行文件路径", () => Assembly.GetExecutingAssembly().Location ?? "")
27 | });
28 |
29 | services.AddImplementation();
30 | services.AddImplementation();
31 | services.AddImplementation();
32 |
33 | services.AddImplementation();
34 | services.AddImplementation();
35 | services.AddImplementation();
36 |
37 | services.AddImplementation();
38 |
39 | var app = new CommandApp(new TypeRegistrar(services));
40 | app.Configure(c =>
41 | {
42 | #if DEBUG
43 | c.PropagateExceptions();
44 | c.ValidateExamples();
45 | #endif
46 |
47 | c.UseStrictParsing();
48 | c.SetApplicationVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString());
49 |
50 | c.AddCommand("init")
51 | .WithExample(new[] { "init", "--default" })
52 | .WithExample(new[] { "init", "--project", "./examples/proj-1" });
53 | c.AddCommand("info")
54 | .WithExample(new[] { "info", "--project", "./examples/proj-1" });
55 | c.AddCommand("toolchain");
56 | c.AddCommand("e2txt")
57 | .WithExample(new[] { "e2txt", "./源码1.e", "我的DLL" });
58 | c.AddCommand("txt2e")
59 | .WithExample(new[] { "txt2e", "./源码1.e", "我的DLL" });
60 | c.AddCommand("build")
61 | .WithExample(new[] { "build", "./源码1.e", "我的DLL" });
62 | c.AddCommand("clean")
63 | .WithExample(new[] { "clean", "--ecode" })
64 | .WithExample(new[] { "clean", "--ecode", "--force" });
65 | c.AddCommand("run");
66 | });
67 | return app.Run(args);
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | # 安装
2 |
3 | 在使用`ebuild`之前,您还需要安装以下工具:
4 |
5 | - [易语言](http://www.eyuyan.com/)
6 | - [e2txt](http://e2ee.jimstone.com.cn/)
7 | - [易语言命令行编译工具 ecl](https://bbs.125.la/forum.php?mod=viewthread&tid=14553929&highlight=ecl)
8 |
9 | ## 安装易语言
10 |
11 | 安装易语言使用易语言官方安装包安装完成即可。
12 |
13 | ## 安装`ebuild`
14 |
15 | ### 下载并解压`ebuild`
16 |
17 | 从[GitHub下载ebuild最新版本](https://github.com/SalHe/ebuild/releases),并将其解压到一个文件夹中即可。
18 |
19 | 
20 |
21 | ::: tip
22 |
23 | 为了您的安全,建议您不要从其他地方下载`ebuild`。同时也非常推荐从源文件编译`ebuild`。
24 |
25 | :::
26 |
27 | ### 配置环境变量
28 |
29 | 可以将`ebuild`安装目录添加到系统环境变量`Path`中去,这样即可在命令行窗口中直接使用`ebuild`。
30 |
31 | 
32 |
33 | 您可以将ebuild的安装目录按下图方式追加到`Path`环境变量的末尾去。比如`ebuild`的安装目录为`E:\Users\SalHe\Downloads\ebuild-v1.0.0-windows-386`,则您应在`Path`末尾追加`;E:\Users\SalHe\Downloads\ebuild-v1.0.0-windows-386`(请注意前有分号。)
34 |
35 | ### 创建 `.toolchain` 文件夹
36 |
37 | 在`ebuild`的安装目录下创建名为`.toolchain`的文件夹,用于存放`e2txt`和`ecl`。
38 |
39 | ## 安装`e2txt`
40 |
41 | 从[E2EE](http://e2ee.jimstone.com.cn/downloads/)找到`e2txt 1.2 - 易语言代码文本互转神器`并下载。
42 |
43 | 下载后,将`e2txt`解压到`\.toolchain\e2txt`目录下。
44 |
45 | 
46 |
47 |
48 | ## 安装`ecl`
49 |
50 | 从[易语言命令行编译工具 ecl v1.2.4.3(beta)(出处: 精易论坛)](https://bbs.125.la/forum.php?mod=viewthread&tid=14553929)下载`ecl`,并安装与[安装`e2txt`](#安装e2txt)类似的方式将`ecl`解压到`\.toolchain\ecl`目录下。
51 |
52 | 
53 |
54 | ## 完成安装后的效果
55 |
56 | 完成安装后,您的目录结构应大致如下:
57 |
58 | ```
59 | ebuild-v1.0
60 | ├── .toolchain
61 | │ ├── e2txt
62 | │ │ ├── BaseELangIDE.dll
63 | │ │ ├── e2txt-gui.exe
64 | │ │ ├── e2txt.exe
65 | │ │ ├── Lang
66 | │ │ │ └── ELang
67 | │ │ └── readme.txt
68 | │ └── ecl
69 | │ ├── ecl.exe
70 | │ └── 调用例子
71 | │ ├── 普通编译.bat
72 | │ ├── 源码
73 | │ ├── 编译带密码的源码.bat
74 | │ ├── 静态编译.bat
75 | │ └── 黑月编译.bat
76 | └── ebuild.exe
77 | ```
78 |
79 | ## 检查安装情况
80 |
81 | 打开命令行,执行以下命令,您便可以看到工具链是否安装成功:
82 |
83 | ```shell
84 | ebuild toolchain
85 | ```
86 |
87 | 
88 |
89 | ## 其他安装方法
90 |
91 | 上述安装步骤可以帮助您在全局都可以使用`ebuild`。但是事实上,您还可以选择其他安装方式。
92 | 以搜索易语言(e.exe)为例,`ebuild`实际上会按照以下顺序搜索工具链(或者您可以[查看代码](https://github.com/SalHe/ebuild/blob/d9afe0e016390e56d4edd639b579a1330193e0a9/toolchain/init.go#L32)以了解):
93 |
94 | - `<工程根目录>\.toolchain\e\e.exe`
95 | - `<当前工作目录>\.toolchain\e\e.exe`
96 | - `\.toolchain\e\e.exe`
97 | - 根据系统查找方式搜索(搜索`Path`变量)
98 | - *查找注册表(仅限于易语言)*
99 |
100 | 所以您也可以将您的工具链安装在以上目录中去。当您需要针对您的工程使用特定版本的其他工具的时候,您就可以将对应的工具放到`<工程根目录>\.toolchain\XXX`中去,这样根据`ebuild`的搜寻顺序,总是能够使用您在工程中指定版本的工具。
--------------------------------------------------------------------------------
/docs/project/run.md:
--------------------------------------------------------------------------------
1 | # 工程脚本
2 |
3 | 也许您在工程需要做除了编译之外的一些重复工作,重复做的话特别烦。一般可以将这些重复工作写成脚本,在需要的时候执行一下脚本即可,就不用手动操作了。`ebuild`刚好集成了一些相关的功能。
4 |
5 | ## 工程相关脚本
6 |
7 | 在`ebuild.yaml`中有一个名为`scripts`的节点,其下可以存放若干脚本,可以使用`ebuild run`执行。您大可将工程相关的一些固定操作写成脚本放到`scripts`中。`ebuild`在执行这些脚本的时候,会传递一些环境变量
8 |
9 | ```yaml
10 | project:
11 | # ......
12 | scripts:
13 | show-envs: |
14 | @echo off
15 | echo EBuild="%EBUILD_EXECUTABLE_PATH%"
16 | echo 易语言="%ELANG_DIR%"
17 | echo Ecl="%ECL_DIR%"
18 | echo E2Txt="%E2Txt_DIR%"
19 | get-input: |
20 | @echo off
21 | @REM 演示如何获取用户输入
22 |
23 | set /p Username=用户名:
24 | set /p Password=密码:
25 |
26 | echo/
27 | echo 您的用户名:%Username%
28 | echo 您的密码:%Password%
29 | cmd-args: |
30 | @echo off
31 | echo arg0=%0
32 | echo arg1=%1
33 | echo arg2=%2
34 | echo arg3=%3
35 | ```
36 |
37 | 在上述配置中我们定义了三个脚本:`show-envs`、`get-input`、`cmd-args`。分别演示了输出`ebuild`传递的环境变量、从标准输入获取用户输入、获取传递给脚本的命令行参数。
38 |
39 | 要执行上述脚本,我们只需要在命令行中执行`ebuild run XXX`。
40 |
41 | 
42 |
43 | ## 向脚本传递参数
44 |
45 | 如果您要想所执行的脚本传递参数,只需要执行:
46 |
47 | ```shell
48 | ebuild run XXX -- 命令行参数...
49 | ```
50 |
51 | 如:
52 |
53 | 
54 |
55 |
56 | ## 使用易语言程序作为脚本
57 |
58 | 也许您不熟悉`bat`脚本的编写,那么您可以选择使用易语言来编写您的脚本。然后使用`ebuild`来运行(run)您的源文件即可。
59 |
60 | 比如当前工程有源文件[`<工程根目录>\scripts\易语言做脚本示例.e`](https://github.com/SalHe/ebuild/blob/4f53059ce09148ee58821b8460b8cef8e6bbd18e/examples/simple/scripts/%E6%98%93%E8%AF%AD%E8%A8%80%E5%81%9A%E8%84%9A%E6%9C%AC%E7%A4%BA%E4%BE%8B.e)。其代码如下:
61 |
62 | ```
63 | .版本 2
64 |
65 | .程序集 程序集1
66 |
67 | .子程序 _启动子程序, 整数型, , 本子程序在程序启动后最先执行
68 | .局部变量 命令行参数, 文本型, , "0"
69 | .局部变量 i, 整数型
70 |
71 |
72 | 标准输出 (, “你好,这是脚本!” + #换行符)
73 | 标准输出 (, “它会被自动编译并执行!” + #换行符)
74 | 标准输出 (, #换行符)
75 |
76 | 标准输出 (, “Ebuild: ” + 读环境变量 (“EBUILD_EXECUTABLE_PATH”) + #换行符)
77 | 标准输出 (, “易语言: ” + 读环境变量 (“ELANG_DIR”) + #换行符)
78 | 标准输出 (, “Ecl: ” + 读环境变量 (“ECL_DIR”) + #换行符)
79 | 标准输出 (, “E2Txt: ” + 读环境变量 (“E2TXT_DIR”) + #换行符)
80 | 标准输出 (, #换行符)
81 |
82 | 标准输出 (, “命令行参数:” + #换行符)
83 | 取命令行 (命令行参数)
84 | .计次循环首 (取数组成员数 (命令行参数), i)
85 | 标准输出 (, 命令行参数 [i] + #换行符)
86 | .计次循环尾 ()
87 | 标准输出 (, #换行符)
88 |
89 | 标准输出 (, “工程根路径:” + 读环境变量 (“EBUILD_PROJECT_ROOT_DIR”) + #换行符)
90 | 标准输出 (, “工程输出路径:” + 读环境变量 (“EBUILD_PROJECT_OUTPUT_DIR”) + #换行符)
91 | 标准输出 (, #换行符)
92 |
93 | 返回 (0) ' 可以根据您的需要返回任意数值
94 | ```
95 |
96 |
97 | 您可以执行以下命令来"执行"易语言源文件:
98 |
99 | ```shell
100 | ebuild run ./scripts/易语言做脚本示例.e -- 传递给易语言程序的命令行参数...
101 | ```
102 |
103 | 比如:
104 |
105 | 
106 |
107 | ::: tip ebuild是如何执行源文件的?
108 |
109 | 其实`ebuild`只是自动使用`ecl`完成了将您所指定的源码编译成可执行文件的过程,在上面的图中我们也可以看到`ebuild`编译源文件的提示。
110 |
111 | 因为"执行"过程中需要编译源文件,所以建议您的源文件不应该太大。
112 |
113 | :::
--------------------------------------------------------------------------------
/src/EBuild/Commands/Base/ProjectCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Config.Resolved;
3 | using EBuild.Plugins;
4 | using EBuild.Project;
5 | using EBuild.Sources;
6 | using EBuild.Toolchain;
7 | using Spectre.Console;
8 | using Spectre.Console.Cli;
9 | using YamlDotNet.Serialization;
10 |
11 | namespace EBuild.Commands.Base;
12 |
13 | public class ProjectSettings : GeneralSettings
14 | {
15 | [CommandOption("-p|--project")]
16 | [Description("工程根目录,默认为当前工作路径。")]
17 | [DefaultValue(".")]
18 | public string ProjectRoot { get; set; } = Directory.GetCurrentDirectory();
19 | }
20 |
21 | public class ProjectCommand : CommandBase
22 | where TSettings : ProjectSettings
23 | {
24 | private readonly IDeserializer _deserializer;
25 | protected ResolvedConfig _resolvedConfig;
26 | protected string ProjectRoot { get; private set; } = "";
27 |
28 | public ProjectCommand(IDeserializer deserializer, IEnumerable plugins) : base(plugins)
29 | {
30 | _deserializer = deserializer;
31 | }
32 |
33 | protected virtual bool ShowLoadConfig()
34 | {
35 | return true;
36 | }
37 |
38 | protected virtual IEnumerable NeededToolchains { get; } = new IToolchain[0];
39 |
40 | public sealed override async Task OnExecuteAsync(CancellationToken cancellationToken)
41 | {
42 | ProjectRoot = CommandSettings.ProjectRoot;
43 | try
44 | {
45 | ResolveProjectRoot();
46 | if (!CheckToolchians())
47 | return 1;
48 | if (ShowLoadConfig())
49 | {
50 | LoadProject();
51 | AnsiConsole.MarkupLine("[green]已启用配置:{0}[/]", _resolvedConfig.ConfigFile);
52 | }
53 | }
54 | catch (FileNotFoundException e)
55 | {
56 | Console.Error.WriteLine("找不到对应的配置文件,请检查!");
57 | return 1;
58 | }
59 | catch (UnauthorizedAccessException e)
60 | {
61 | Console.Error.WriteLine("没有权限访问配置文件。");
62 | return 1;
63 | }
64 | catch (DirectoryNotFoundException e)
65 | {
66 | Console.Error.WriteLine("找不到对应目录。");
67 | return 1;
68 | }
69 |
70 | return await OnExecuteInternalAsync(cancellationToken);
71 | }
72 |
73 | private bool CheckToolchians()
74 | {
75 | foreach (var toolchain in NeededToolchains)
76 | {
77 | toolchain.Search(ProjectRoot);
78 | if (!toolchain.Exists())
79 | {
80 | AnsiConsole.MarkupLine("[red]找不到 {0}[/]", Markup.Escape(toolchain.Description));
81 | return false;
82 | }
83 | }
84 |
85 | return true;
86 | }
87 |
88 | private void ResolveProjectRoot()
89 | {
90 | ProjectRoot = Path.GetFullPath(ProjectRoot);
91 | }
92 |
93 | protected virtual Task OnExecuteInternalAsync(CancellationToken cancellationToken)
94 | {
95 | return Task.Run(OnExecuteInternal, cancellationToken);
96 | }
97 |
98 | protected virtual int OnExecuteInternal()
99 | {
100 | return 0;
101 | }
102 |
103 | private void LoadProject()
104 | {
105 | var pwdResolver = PasswordFileResolver.FromProjectRootDir(ProjectRoot);
106 | _resolvedConfig = ResolvedConfig.Load(ProjectRoot, _deserializer, pwdResolver);
107 | _resolvedConfig.OutputDir = ProjectPath.GetDefaultOutputPath(ProjectRoot);
108 | }
109 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/InfoCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Commands.Base;
3 | using EBuild.Config.Resolved;
4 | using EBuild.Plugins;
5 | using EBuild.Yaml.Converters;
6 | using Spectre.Console;
7 | using Spectre.Console.Cli;
8 | using YamlDotNet.Serialization;
9 |
10 | namespace EBuild.Commands.SubCommands;
11 |
12 | [Description("查看当前工程信息。")]
13 | public class InfoCommand : ProjectCommand
14 | {
15 | public class Settings : ProjectSettings
16 | {
17 | [CommandOption("--abs")]
18 | [Description("显示源码的绝对路径")]
19 | public bool AbsolutePath { get; set; } = false;
20 |
21 | [CommandOption("--password")]
22 | [Description("显示源码的密码")]
23 | public bool ShowPassword { get; set; }
24 | }
25 |
26 |
27 | public InfoCommand(IDeserializer deserializer, IEnumerable plugins) : base(deserializer,plugins)
28 | {
29 | }
30 |
31 | protected override int OnExecuteInternal()
32 | {
33 | ShowProjectIntro();
34 | ShowScripts();
35 | ShowE2txt();
36 | ShowResolvedTargets();
37 | return 0;
38 | }
39 |
40 | private void ShowProjectIntro()
41 | {
42 | AnsiConsole.MarkupLine("[green bold]当前项目信息[/]");
43 | Console.WriteLine("项目:{0}", _resolvedConfig.RootConfig.Project.Name);
44 | Console.WriteLine("描述:{0}", _resolvedConfig.RootConfig.Project.Description);
45 | Console.WriteLine("版本:{0}", _resolvedConfig.RootConfig.Project.Version);
46 | Console.WriteLine("作者:{0}", _resolvedConfig.RootConfig.Project.Author);
47 | Console.WriteLine("仓库:{0}", _resolvedConfig.RootConfig.Project.Repository);
48 | Console.WriteLine("主页:{0}", _resolvedConfig.RootConfig.Project.Homepage);
49 | Console.WriteLine();
50 | }
51 |
52 | private void ShowScripts()
53 | {
54 | AnsiConsole.MarkupLine("[green bold]脚本[/]");
55 | foreach (var (key, value) in _resolvedConfig.RootConfig.Scripts)
56 | Console.WriteLine(key);
57 | Console.WriteLine();
58 | }
59 |
60 | private void ShowE2txt()
61 | {
62 | AnsiConsole.MarkupLine("[green bold]e2txt配置[/]");
63 | Console.WriteLine("风格:{0}",
64 | EnumAliasAttribute.GetEnumAliasAttribute(_resolvedConfig.RootConfig.E2Txt.NameStyle)!.Name);
65 | Console.WriteLine("生成易代码:{0}", _resolvedConfig.RootConfig.E2Txt.GenerateE);
66 | Console.WriteLine();
67 | }
68 |
69 | private void ShowResolvedTargets()
70 | {
71 | AnsiConsole.MarkupLine("[green bold]构建目标 [grey]{0}[/][/]", _resolvedConfig.OutputDir);
72 | var table = new Table();
73 | table.AddColumn("源码");
74 | table.AddColumn("来源");
75 | if (CommandSettings.ShowPassword)
76 | table.AddColumn("密码");
77 | table.AddColumn("构建");
78 | table.AddColumn("编译器");
79 | table.AddColumn("输出");
80 | foreach (var target in _resolvedConfig.ResolveTargets)
81 | {
82 | var cols = new List();
83 | cols.Add(Markup.Escape(CommandSettings.AbsolutePath
84 | ? target.Target.Source
85 | : Path.GetRelativePath(ProjectRoot, target.Target.Source)));
86 | switch (target.Origin)
87 | {
88 | case TargetOrigin.Custom:
89 | cols.Add("自定义");
90 | break;
91 | case TargetOrigin.Search:
92 | cols.Add("搜索");
93 | break;
94 | }
95 |
96 | if (CommandSettings.ShowPassword)
97 | cols.Add(Markup.Escape(target.Password));
98 |
99 | cols.Add(target.ShouldBuild ? "[green]:check_mark:[/]" : "[red]:cross_mark:[/]");
100 | cols.Add(Markup.Escape(EnumAliasAttribute.GetEnumAliasAttribute(target.Target.Build.Compiler)?.Name ??
101 | target.Target.Build.Compiler.ToString()));
102 | cols.Add(Markup.Escape(target.Target.Output));
103 |
104 | table.AddRow(cols.ToArray());
105 | }
106 |
107 | AnsiConsole.Write(table);
108 | }
109 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/Base/TargetCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Config.Resolved;
3 | using EBuild.Consoles;
4 | using EBuild.Plugins;
5 | using EBuild.Yaml.Converters;
6 | using Spectre.Console;
7 | using Spectre.Console.Cli;
8 | using YamlDotNet.Serialization;
9 |
10 | namespace EBuild.Commands.Base;
11 |
12 | public class TargetSettings : ProjectSettings
13 | {
14 | [CommandOption("-c|--concurrency")]
15 | [Description("并行任务个数。")]
16 | public int ConcurrencyCount { get; init; } = 1;
17 |
18 | [CommandArgument(0, "[目标或源文件...]")]
19 | [Description("参与本次操作的目标或源文件。")]
20 | public string[] Targets { get; init; } = Array.Empty();
21 | }
22 |
23 | public abstract class TargetCommand : ProjectCommand
24 | where TSettings : TargetSettings
25 | {
26 | protected enum WholeStatus
27 | {
28 | Doing,
29 | Completed,
30 | ErrorOccured
31 | }
32 |
33 | protected virtual int MaxConcurrencyCount => int.MaxValue;
34 |
35 | public TargetCommand(IDeserializer deserializer, IEnumerable plugins) : base(deserializer, plugins)
36 | {
37 | }
38 |
39 | protected abstract string GenerateHeading(WholeStatus status);
40 |
41 | protected virtual IMultiTaskDisplayer GetDisplayer(IList targets)
42 | {
43 | return new TableDisplayer(targets)
44 | {
45 | TargetName = target => target.Target.DisplayName(ProjectRoot),
46 | StatusString = e => EnumAliasAttribute.GetEnumAliasAttribute(e).Name
47 | };
48 | }
49 |
50 | protected sealed override async Task OnExecuteInternalAsync(CancellationToken cancellationToken)
51 | {
52 | var possibleFile = CommandSettings.Targets.Select(x => Path.GetFullPath(x, ProjectRoot));
53 |
54 | var activatedTargets = _resolvedConfig.ResolveTargets
55 | .Where(x => CommandSettings.Targets.Length <= 0 || CommandSettings.Targets.Contains(x.Target.Name) ||
56 | possibleFile.Contains(x.Target.Source))
57 | .ToList();
58 |
59 | if (activatedTargets.Count <= 0)
60 | {
61 | AnsiConsole.MarkupLine("[bold]没有找到符合要求的目标哦。[/]");
62 | return 0;
63 | }
64 |
65 | var displayer = GetDisplayer(activatedTargets);
66 |
67 | return await displayer.StartAsync(_ =>
68 | Task.FromResult(StartTargetTasks(activatedTargets, displayer, cancellationToken)));
69 | }
70 |
71 | private int StartTargetTasks(IList activatedTargets,
72 | IMultiTaskDisplayer displayer,
73 | CancellationToken cancellationToken)
74 | {
75 | var c = Math.Min(CommandSettings.ConcurrencyCount, MaxConcurrencyCount);
76 | var semaphore = new Semaphore(c, c);
77 | var allOk = true;
78 |
79 | displayer.SetHeader(GenerateHeading(WholeStatus.Doing));
80 |
81 | var tasks = new List();
82 | for (int i = 0; i < activatedTargets.Count(); i++)
83 | {
84 | var activatedTarget = activatedTargets[i];
85 |
86 | var task = Task.Run(async () =>
87 | {
88 | var updateTargetStatus = displayer.GetUpdater(activatedTarget);
89 | updateTargetStatus(TargetStatus.Waiting, "正在等待...");
90 |
91 | if (await OnPreDoTargetAsync(activatedTarget, updateTargetStatus, cancellationToken))
92 | {
93 | semaphore.WaitOne();
94 | if (!await OnDoTargetAsync(activatedTarget, updateTargetStatus, cancellationToken))
95 | allOk = false;
96 | semaphore.Release();
97 | }
98 | }, cancellationToken);
99 | tasks.Add(task);
100 | }
101 |
102 | Task.WaitAll(tasks.ToArray(), cancellationToken);
103 |
104 | displayer.SetHeader(GenerateHeading(allOk ? WholeStatus.Completed : WholeStatus.ErrorOccured));
105 | return allOk ? 0 : 1;
106 | }
107 |
108 | protected abstract Task OnPreDoTargetAsync(ResolvedTarget target,
109 | Action updateTargetStatus,
110 | CancellationToken cancellationToken);
111 |
112 | protected abstract Task OnDoTargetAsync(ResolvedTarget target,
113 | Action updateTargetStatus,
114 | CancellationToken cancellationToken);
115 | }
116 |
117 | public enum TargetStatus
118 | {
119 | [EnumAlias("等待中")] Waiting,
120 |
121 | [EnumAlias("[yellow]:red_exclamation_mark:[/]")]
122 | Skipped,
123 | [EnumAlias("进行中")] Doing,
124 | [EnumAlias("[green]:check_mark:[/]")] Done,
125 | [EnumAlias("[red]:cross_mark:[/]")] Error
126 | }
--------------------------------------------------------------------------------
/src/EBuild/Config/Resolved/ResolvedConfig.cs:
--------------------------------------------------------------------------------
1 | using EBuild.Extensions;
2 | using EBuild.Project;
3 | using EBuild.Sources;
4 | using Microsoft.Extensions.FileSystemGlobbing;
5 | using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
6 | using Spectre.Console;
7 | using YamlDotNet.Serialization;
8 |
9 | namespace EBuild.Config.Resolved;
10 |
11 | public class ResolvedConfig
12 | {
13 | public string ProjectRootDir { get; private init; }
14 | public string OutputDir { get; set; }
15 | public string ConfigFile => ProjectPath.GetConfigFilePath(ProjectRootDir);
16 | public RootConfig RootConfig { get; private set; }
17 | public IReadOnlyList ResolveTargets { get; private set; }
18 |
19 | private ResolvedConfig()
20 | {
21 | }
22 |
23 | public static ResolvedConfig Load(string projectRoot, IDeserializer deserializer,
24 | PasswordFileResolver passwordFileResolver)
25 | {
26 | var resolvedConfig = new ResolvedConfig
27 | {
28 | ProjectRootDir = projectRoot
29 | };
30 | resolvedConfig.RootConfig = deserializer.Deserialize(File.OpenText(resolvedConfig.ConfigFile));
31 | var resolvedTargets = new List();
32 | resolvedConfig.ResolveTargets = resolvedTargets;
33 |
34 | // 自定义的源码
35 | var sourcesAdded = new HashSet();
36 | if (resolvedConfig.RootConfig.Targets != null)
37 | {
38 | foreach (var targetInConfig in resolvedConfig.RootConfig.Targets)
39 | {
40 | targetInConfig.Source = Path.GetFullPath(targetInConfig.Source, projectRoot);
41 | if (targetInConfig.Build == null)
42 | targetInConfig.Build = resolvedConfig.RootConfig.Build;
43 |
44 | sourcesAdded.Add(targetInConfig.Source);
45 | var pwd = passwordFileResolver.Resolve(targetInConfig.Source);
46 | resolvedTargets.Add(new ResolvedTarget(targetInConfig, TargetOrigin.Custom, Password: pwd));
47 | }
48 | }
49 |
50 | // 搜索的源码
51 | var matcher = new Matcher();
52 | matcher.AddIncludePatterns(resolvedConfig.RootConfig.Includes);
53 | matcher.AddExcludePatterns(resolvedConfig.RootConfig.Excludes);
54 | var result = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(projectRoot)));
55 | var excludeBuildsMatcher = new Matcher();
56 | excludeBuildsMatcher.AddIncludePatterns(resolvedConfig.RootConfig.ExcludeBuilds);
57 | foreach (var file in result.Files)
58 | {
59 | var sourcePath = Path.GetFullPath(file.Path, projectRoot);
60 | if (sourcesAdded.Contains(sourcePath))
61 | continue;
62 | var pwd = passwordFileResolver.Resolve(sourcePath);
63 |
64 | var target = new Target()
65 | {
66 | Name = string.Empty,
67 | Source = sourcePath,
68 | Output = Path.ChangeExtension(Path.GetRelativePath(projectRoot, sourcePath),
69 | null),
70 | Package = false,
71 | Build = resolvedConfig.RootConfig.Build
72 | };
73 |
74 | resolvedTargets.Add(new ResolvedTarget(target, TargetOrigin.Search,
75 | !excludeBuildsMatcher.Match(file.Path).HasMatches, pwd));
76 | }
77 |
78 | foreach (var target in resolvedConfig.ResolveTargets)
79 | {
80 | if (string.IsNullOrEmpty(target.Password) && !Path.HasExtension(target.Target.Output) &&
81 | target.SourceMeta != null)
82 | {
83 | if (target.Origin == TargetOrigin.Custom)
84 | {
85 | AnsiConsole.MarkupLine(
86 | $"[yellow]您可能未给{Markup.Escape("[")}{{0}}{Markup.Escape("]")}指定输出后缀,易语言会自动加上后缀,请注意。[/]",
87 | Markup.Escape(target.Target.Name));
88 | }
89 | else
90 | {
91 | Attributes.GetEnumValueAttribute(target.SourceMeta.TargetType,
92 | out ESourceTargetTypeAttribute? attribute);
93 | target.Target.Output = Path.ChangeExtension(target.Target.Output, attribute!.Extension);
94 | }
95 | }
96 |
97 | if (target.SourceMeta == null)
98 | AnsiConsole.MarkupLine("[yellow]{0} 可能不是一个合法的源文件。[/]", Markup.Escape(target.Target.Source));
99 | }
100 |
101 | return resolvedConfig;
102 | }
103 | }
104 |
105 | public enum TargetOrigin
106 | {
107 | Search,
108 | Custom
109 | }
110 |
111 | public class ResolvedTarget
112 | {
113 | public ResolvedTarget(Target Target,
114 | TargetOrigin Origin = TargetOrigin.Search,
115 | bool ShouldBuild = true,
116 | string Password = "")
117 | {
118 | this.Target = Target;
119 | this.Origin = Origin;
120 | this.ShouldBuild = ShouldBuild;
121 | this.Password = Password;
122 | this.SourceMeta = ESourceMeta.FromSource(Target.Source);
123 | }
124 |
125 | public Target Target { get; init; }
126 | public TargetOrigin Origin { get; init; }
127 | public bool ShouldBuild { get; init; }
128 | public string Password { get; init; }
129 | public ESourceMeta? SourceMeta { get; }
130 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/E2TxtCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Diagnostics;
3 | using System.Text;
4 | using System.Text.RegularExpressions;
5 | using EBuild.Commands.Base;
6 | using EBuild.Config.Resolved;
7 | using EBuild.Plugins;
8 | using EBuild.Project;
9 | using EBuild.Toolchain;
10 | using Spectre.Console;
11 | using YamlDotNet.Serialization;
12 |
13 | namespace EBuild.Commands.SubCommands;
14 |
15 | [Description("将易语言代码转换到txt。")]
16 | public class E2TxtCommand : TargetCommand
17 | {
18 | private readonly E2TxtToolchain _e2txt;
19 |
20 | public E2TxtCommand(IDeserializer deserializer, E2TxtToolchain e2txt, IEnumerable plugins) : base(
21 | deserializer, plugins)
22 | {
23 | _e2txt = e2txt;
24 | }
25 |
26 | protected override IEnumerable NeededToolchains => new IToolchain[] { _e2txt };
27 |
28 | protected override string GenerateHeading(WholeStatus status)
29 | {
30 | switch (status)
31 | {
32 | case WholeStatus.Doing:
33 | return "e2txt";
34 | case WholeStatus.Completed:
35 | return "[green]:check_mark:e2txt[/]";
36 | case WholeStatus.ErrorOccured:
37 | return "[red]:cross_mark:e2txt[/]";
38 | }
39 |
40 | return "";
41 | }
42 |
43 | private static readonly Regex _multispaces = new Regex(@"\s+");
44 |
45 | protected override async Task OnDoTargetAsync(ResolvedTarget target,
46 | Action updateTargetStatus,
47 | CancellationToken cancellationToken)
48 | {
49 | updateTargetStatus(TargetStatus.Doing, "开始转换");
50 |
51 | var noError = true;
52 | var convertOk = false;
53 |
54 | var args = GetArgs(target);
55 | updateTargetStatus(TargetStatus.Doing,
56 | string.Format("[grey]{0}[/]", Markup.Escape(_e2txt.ExecutablePath + " " + string.Join(" ", args))));
57 |
58 | var process = new Process();
59 | foreach (var s in args) process.StartInfo.ArgumentList.Add(s);
60 | process.StartInfo.FileName = _e2txt.ExecutablePath;
61 | process.StartInfo.RedirectStandardOutput = true;
62 | process.StartInfo.RedirectStandardError = true;
63 | process.StartInfo.StandardOutputEncoding = Encoding.GetEncoding("gbk");
64 | process.StartInfo.StandardErrorEncoding = Encoding.GetEncoding("gbk");
65 |
66 | var error = "";
67 |
68 | var d = (DataReceivedEventHandler)((sender, eventArgs) =>
69 | {
70 | if (!string.IsNullOrEmpty(eventArgs.Data))
71 | {
72 | if (eventArgs.Data.StartsWith("SUCC:"))
73 | {
74 | // 成功
75 | convertOk = true;
76 | var outputDir = eventArgs.Data.Substring(5);
77 | updateTargetStatus(TargetStatus.Done,
78 | string.Format("[green]转换成功:{0}[/]",
79 | Markup.Escape(outputDir)
80 | )
81 | );
82 | }
83 | else if (eventArgs.Data.StartsWith("ERROR:"))
84 | {
85 | // 错误提示
86 | noError = false;
87 | error += eventArgs.Data.Substring(6) + "\n";
88 | updateTargetStatus(TargetStatus.Error,
89 | string.Format("[red]转换出错:{0}[/]",
90 | Markup.Escape(_multispaces.Replace(error, " "))
91 | )
92 | );
93 | }
94 | else
95 | {
96 | // 日志
97 | if (!convertOk)
98 | updateTargetStatus(noError ? TargetStatus.Doing : TargetStatus.Error,
99 | Markup.Escape(_multispaces.Replace(eventArgs.Data, " ")));
100 | }
101 | }
102 | });
103 | process.OutputDataReceived += d;
104 | process.ErrorDataReceived += d;
105 |
106 | process.Start();
107 | process.BeginOutputReadLine();
108 | process.BeginErrorReadLine();
109 | cancellationToken.Register(() =>
110 | {
111 | process.Kill();
112 | process.CancelOutputRead();
113 | process.CancelErrorRead();
114 | });
115 | await process.WaitForExitAsync(cancellationToken);
116 |
117 | if (!noError)
118 | {
119 | updateTargetStatus(TargetStatus.Error,
120 | string.Format("[red]转换过程中出现错误:\n{0}[/]",
121 | Markup.Escape(error)
122 | )
123 | );
124 | }
125 |
126 | return convertOk;
127 | }
128 |
129 | protected virtual IList GetArgs(ResolvedTarget target)
130 | {
131 | return E2TxtToolchain.E2TxtArgs(target.Target.Source, target.Target.GetECodeDir(),
132 | _resolvedConfig.RootConfig.E2Txt);
133 | }
134 |
135 | protected override Task OnPreDoTargetAsync(ResolvedTarget target,
136 | Action updateTargetStatus,
137 | CancellationToken cancellationToken)
138 | {
139 | if (string.IsNullOrEmpty(target.Password))
140 | {
141 | updateTargetStatus(TargetStatus.Waiting, "等待转换中...");
142 | return Task.FromResult(true);
143 | }
144 |
145 | updateTargetStatus(TargetStatus.Skipped, "[yellow]源文件存在密码,已跳过转换![/]");
146 | return Task.FromResult(false);
147 | }
148 | }
--------------------------------------------------------------------------------
/src/EBuild/Toolchain/EclToolchain.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using EBuild.Config;
3 | using EBuild.Config.Resolved;
4 | using EBuild.Sources;
5 | using EBuild.Yaml.Converters;
6 |
7 | namespace EBuild.Toolchain;
8 |
9 | public class EclToolchain : GeneralToolchain
10 | {
11 | private enum Error
12 | {
13 | [EnumAlias("编译成功")] Ok = 0,
14 | [EnumAlias("处理成功")] Success = 1,
15 |
16 | [EnumAlias("未定义类型的错误")] Unknown = -1,
17 | [EnumAlias("命令行有错误")] Param = -2,
18 | [EnumAlias("找不到文件")] FileNotFound = -3,
19 | [EnumAlias("文件无效")] FileInvalid = -4,
20 | [EnumAlias("编译失败")] Compile = -5,
21 | [EnumAlias("不支持的编译类型")] InvalidCompileType = -6,
22 | [EnumAlias("无法识别或无法运行的易语言程序")] ECannotStart = -7,
23 | [EnumAlias("无法获取易语言菜单")] CanNotGetMenu = -8,
24 | [EnumAlias("易语言意外结束")] Shutdown = -9,
25 | [EnumAlias("静态编译失败")] Static = -10,
26 | [EnumAlias("生成link.ini文件过程中出错")] MakeLinkIni = -11,
27 | [EnumAlias("老版黑月的相关数据无法定位")] BmInfo = -12,
28 | [EnumAlias("黑月编译失败")] BmCompile = -13,
29 | [EnumAlias("源码密码不正确")] Password = -14,
30 | [EnumAlias("缺乏易模块")] EC = -15,
31 | [EnumAlias("缺少支持库")] ELib = -16,
32 | [EnumAlias("启动易语言超时")] StartTimeout = -17,
33 | [EnumAlias("编译超时")] CompileTimeout = -18,
34 | [EnumAlias("不支持易包编译")] NotSupportEPkg = -19,
35 | }
36 |
37 | public override IList EnvironmentVariables => new List()
38 | {
39 | new("ECL_DIR", "ecl安装路径", () => Path.GetDirectoryName(ExecutablePath) ?? ""),
40 | };
41 |
42 | public EclToolchain() : base("易语言命令行编译工具", "https://bbs.125.la/forum.php?mod=viewthread&tid=14553929&highlight=ecl",
43 | "ecl")
44 | {
45 | }
46 |
47 | public static IList Args(ResolvedTarget target, string outputDir, bool hideSecret = false)
48 | {
49 | return Args(
50 | target.Target.Source,
51 | target.Target.OutputPath(outputDir),
52 | target.SourceMeta,
53 | target.Target.Build?.Compiler,
54 | target.Target.CompileConfig,
55 | target.Target.CompileDescription,
56 | target.Password,
57 | target.Target.Package,
58 | hideSecret
59 | );
60 | }
61 |
62 | public static IList Args(string source, string outputPath, ESourceMeta? sourceMeta, Compiler? compiler,
63 | string compileConfig, string compileDescription, string password, bool isPackage,
64 | bool hideSecret = false)
65 | {
66 | var args = new List() { "make", source, outputPath };
67 | if (isPackage) args.Add("-p");
68 | else
69 | {
70 | if (sourceMeta?.TargetType != TargetType.LinuxEc &&
71 | sourceMeta?.TargetType != TargetType.WinEc) // 编译模块不用选择编译器
72 | args.AddRange(CompilerArgs(compiler, compileConfig,
73 | compileDescription));
74 | if (!string.IsNullOrEmpty(password))
75 | args.AddRange(new[] { "-pwd", hideSecret ? "******" : password });
76 | }
77 |
78 | return args;
79 | }
80 |
81 | public static IList CompilerArgs(Compiler? compiler, string bmConfig, string bmDescription)
82 | {
83 | var args = new List();
84 | if (compiler != null)
85 | {
86 | switch (compiler)
87 | {
88 | case Compiler.Static:
89 | args.Add("-s");
90 | break;
91 | case Compiler.Normal:
92 | break;
93 | case Compiler.Independent:
94 | args.Add("-d");
95 | break;
96 | case Compiler.BlackMoon:
97 | args.Add("-bm");
98 | break;
99 | case Compiler.BlackMoonAsm:
100 | args.Add("-bm0");
101 | break;
102 | case Compiler.BlackMoonCpp:
103 | args.Add("-bm1");
104 | break;
105 | case Compiler.BlackMoonMFC:
106 | args.Add("-bm2");
107 | break;
108 | default:
109 | throw new ArgumentOutOfRangeException(nameof(compiler), compiler, null);
110 | }
111 |
112 | if (compiler.ToString()!.StartsWith("BlackMoon"))
113 | {
114 | if (!string.IsNullOrEmpty(bmConfig)) args.AddRange(new string[] { "-bmcfg", bmConfig });
115 | if (!string.IsNullOrEmpty(bmDescription)) args.AddRange(new string[] { "-bmdesc", bmDescription });
116 | }
117 | }
118 |
119 | return args;
120 | }
121 |
122 | private static readonly Regex errorMatcher = new Regex(@"\(错误:(-\d+)\)(.+)");
123 |
124 | public static bool TryMatchError(string log, out bool compileOk, out int errorCode, out string tip)
125 | {
126 | var match = errorMatcher.Match(log);
127 | if (!match.Success)
128 | {
129 | errorCode = 0;
130 | tip = "";
131 | compileOk = false;
132 | return false;
133 | }
134 |
135 | errorCode = int.Parse(match.Groups[1].Value);
136 | var error = (Error)errorCode;
137 | // tip = EnumAliasAttribute.GetEnumAliasAttribute(error)?.Name ?? "ebuild暂未记录该错误代码";
138 | tip = match.Groups[2].Value;
139 | compileOk = error is Error.Ok or Error.Success;
140 | return true;
141 | }
142 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/RunCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.ComponentModel.DataAnnotations;
3 | using System.Diagnostics;
4 | using EBuild.Commands.Base;
5 | using EBuild.Config;
6 | using EBuild.Plugins;
7 | using EBuild.Project;
8 | using EBuild.Sources;
9 | using EBuild.Toolchain;
10 | using Spectre.Console;
11 | using Spectre.Console.Cli;
12 | using YamlDotNet.Serialization;
13 |
14 | namespace EBuild.Commands.SubCommands;
15 |
16 | [Description(@"运行脚本或易语言源文件。
17 |
18 | 当第一个参数对应了配置文件中某一脚本名字时,将执行脚本对应的内容;
19 | 当第一个参数对应了某一个源码的文件名时,将编译该易语言源文件并执行(要求源文件必须是Windows可执行程序或Windows控制台程序,由于需要编译,建议源文件尽可能小)。
20 |
21 | 由于执行的对象可能是脚本或者易语言源文件,所以建议您为脚本命名的时候不要与源文件重名。
22 | 此外,目前ebuild不会保证到底先执行哪种情况,所以更加建议您不要重名。
23 |
24 | 当您执行易语言源文件时,请您自行确保源文件的安全性。")]
25 | public class RunCommand : ProjectCommand
26 | {
27 | public class Settings : ProjectSettings
28 | {
29 | [CommandArgument(0, "<脚本名称|易语言源文件>")]
30 | [Required]
31 | public string TargetToRun { get; init; }
32 |
33 | [CommandOption("--verbose")]
34 | [Description("输出编译源文件的输出日志。")]
35 | [DefaultValue(false)]
36 | public bool Verbose { get; init; }
37 | }
38 |
39 | private readonly EclToolchain _eclToolchain;
40 | private readonly EnvironmentVariables _environmentVariables;
41 | protected override IEnumerable NeededToolchains { get; }
42 |
43 | public RunCommand(IDeserializer deserializer, IEnumerable toolchains, EclToolchain eclToolchain,
44 | EnvironmentVariables environmentVariables, IEnumerable plugins) :
45 | base(deserializer, plugins)
46 | {
47 | NeededToolchains = toolchains;
48 | _eclToolchain = eclToolchain;
49 | _environmentVariables = environmentVariables;
50 | }
51 |
52 | protected override async Task OnExecuteInternalAsync(CancellationToken cancellationToken)
53 | {
54 | var fullPath = Path.GetFullPath(CommandSettings.TargetToRun);
55 | var exeOrBatPath = "";
56 | if (File.Exists(fullPath))
57 | {
58 | AnsiConsole.MarkupLine("[yellow]源文件`{0}`存在,将尝试编译该文件并运行。[/]", fullPath);
59 | var meta = ESourceMeta.FromSource(fullPath);
60 | if (meta == null || meta.SourceType == SourceType.ECom ||
61 | (meta.TargetType != TargetType.WinConsole && meta.TargetType != TargetType.WinForm))
62 | {
63 | AnsiConsole.MarkupLine("[red]您必须提供一个有效的易语言源文件,并且该源码应编译成Windows控制台程序或Windows窗口程序。[/]");
64 | return 1;
65 | }
66 |
67 | exeOrBatPath = await QuickBuildESource(
68 | cancellationToken, _eclToolchain,
69 | CommandSettings.Verbose,
70 | fullPath, meta);
71 | if (!string.IsNullOrEmpty(exeOrBatPath))
72 | AnsiConsole.MarkupLine("[yellow]编译成功,准备运行:`{0}`[/]", Markup.Escape(exeOrBatPath));
73 | }
74 | else if (_resolvedConfig.RootConfig.Scripts?.ContainsKey(CommandSettings.TargetToRun) == true)
75 | {
76 | var tempFile = Path.GetTempFileName();
77 | var batContent = _resolvedConfig.RootConfig.Scripts[CommandSettings.TargetToRun];
78 | batContent = batContent.ReplaceLineEndings("\r\n");
79 | await File.WriteAllTextAsync(tempFile, batContent, cancellationToken);
80 | exeOrBatPath = Path.ChangeExtension(tempFile, "ebuild-run.bat");
81 | File.Move(tempFile, exeOrBatPath);
82 |
83 | AnsiConsole.MarkupLine("[yellow]准备运行:`{0}`[/]", Markup.Escape(exeOrBatPath));
84 | }
85 | else
86 | {
87 | AnsiConsole.MarkupLine("[red]找不到对于的脚本({0})或源码({1})[/]", Markup.Escape(fullPath),
88 | Markup.Escape(CommandSettings.TargetToRun));
89 | return 1;
90 | }
91 |
92 | var process = new Process();
93 | foreach (var arg in CommandContext.Remaining.Raw) process.StartInfo.ArgumentList.Add(arg);
94 | process.StartInfo.FileName = exeOrBatPath;
95 |
96 | _environmentVariables.ForProject(ProjectRoot, _resolvedConfig.OutputDir);
97 | _environmentVariables.LoadToStringDictionary(process.StartInfo.EnvironmentVariables);
98 |
99 | process.Start();
100 |
101 | cancellationToken.Register(() =>
102 | {
103 | process.Kill();
104 | File.Delete(exeOrBatPath);
105 | });
106 | await process.WaitForExitAsync(cancellationToken);
107 |
108 | process.Kill();
109 |
110 | File.Delete(exeOrBatPath);
111 | return process.ExitCode;
112 | }
113 |
114 | private static async Task QuickBuildESource(CancellationToken cancellationToken, EclToolchain eclToolchain,
115 | bool verbose, string fullPath, ESourceMeta meta)
116 | {
117 | var tempFile = Path.GetTempFileName();
118 | var tempExe = Path.ChangeExtension(tempFile, "ebuild-run.exe");
119 | File.Delete(tempFile);
120 |
121 | var process = new Process();
122 | foreach (var arg in EclToolchain.Args(fullPath, tempExe, meta, Compiler.Normal, "", "", "", false))
123 | process.StartInfo.ArgumentList.Add(arg);
124 | process.StartInfo.FileName = eclToolchain.ExecutablePath;
125 | if (!verbose)
126 | {
127 | process.StartInfo.RedirectStandardError = true;
128 | process.StartInfo.RedirectStandardOutput = true;
129 | }
130 |
131 | cancellationToken.Register(() =>
132 | {
133 | process.Kill();
134 | File.Delete(tempExe);
135 | tempExe = "";
136 | });
137 | process.Start();
138 | await process.WaitForExitAsync(cancellationToken);
139 | return tempExe;
140 | }
141 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/InitCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using EBuild.Commands.Base;
3 | using EBuild.Config;
4 | using EBuild.Plugins;
5 | using EBuild.Project;
6 | using EBuild.Yaml.Converters;
7 | using Spectre.Console;
8 | using Spectre.Console.Cli;
9 | using YamlDotNet.Serialization;
10 |
11 | namespace EBuild.Commands.SubCommands;
12 |
13 | [Description("初始化工程。")]
14 | public class InitCommand : ProjectCommand
15 | {
16 | public class Settings : ProjectSettings
17 | {
18 | [CommandOption("-d|--default")]
19 | [Description("采用默认配置初始化工程。")]
20 | public bool DefaultInit { get; init; }
21 | }
22 |
23 | private readonly ISerializer _serializer;
24 |
25 | public InitCommand(IDeserializer deserializer, ISerializer serializer, IEnumerable plugins) : base(deserializer,plugins)
26 | {
27 | _serializer = serializer;
28 | }
29 |
30 | protected override bool ShowLoadConfig()
31 | {
32 | return false;
33 | }
34 |
35 | protected override int OnExecuteInternal()
36 | {
37 | var configFilePath = ProjectPath.GetConfigFilePath(ProjectRoot);
38 | if (Directory.Exists(ProjectRoot) && Directory.GetFiles(ProjectRoot).Length > 0)
39 | {
40 | AnsiConsole.MarkupLine("[red]目录不为空,不能创建ebuild工程:{0}[/]", configFilePath);
41 | return 1;
42 | }
43 |
44 | var rootConfig = CreateRootConfig();
45 | Directory.CreateDirectory(ProjectRoot);
46 | try
47 | {
48 | File.WriteAllText(configFilePath, _serializer.Serialize(rootConfig));
49 | File.WriteAllText(Path.GetFullPath(".gitignore", ProjectRoot), @"
50 | # 恢复出来的易语言源文件和密码文件不纳入版本控制
51 | *.recover.e
52 | ebuild.pwd.yaml
53 | **/*.ecode/log
54 |
55 | # 易语言产生的备份源码文件
56 | *.bak
57 |
58 | # 编译输出
59 | ebuild-out/");
60 | File.WriteAllText(ProjectPath.GetSourcePasswordFilePath(ProjectRoot), "./带密码的源码.e: 123456");
61 | File.WriteAllText(Path.GetFullPath("README.md", ProjectRoot), @$"# {rootConfig.Project.Name}
62 |
63 | ## 编译
64 |
65 | ```shell
66 | ebuild build
67 | ```
68 |
69 | ## e2txt
70 |
71 | ```shell
72 | ebuild e2txt
73 | ```
74 | ");
75 | }
76 | catch (Exception e)
77 | {
78 | AnsiConsole.MarkupLine("[red]创建工程失败!{0}[/]", e);
79 | return 1;
80 | }
81 |
82 | AnsiConsole.WriteLine();
83 | AnsiConsole.MarkupLine("[green]创建工程完成。[/]");
84 | AnsiConsole.MarkupLine("[green]有关工程的配置可以参见ebuild示例代码:https://github.com/SalHe/ebuild/tree/master/examples[/]");
85 | AnsiConsole.MarkupLine("[green]此外,您也可以去ebuild官方网站查看更加详细的文档:https://salhe.github.io/ebuild/[/]");
86 | return 0;
87 | }
88 |
89 | private RootConfig CreateRootConfig()
90 | {
91 | var defaultProjectName = Path.GetFileName(ProjectRoot);
92 | var project = new Config.Project
93 | {
94 | Name = defaultProjectName,
95 | Version = "1.0",
96 | Description = $"{Environment.UserName}的工程:{defaultProjectName}",
97 | Author = Environment.UserName,
98 | Repository = $"https://github.com/{Environment.UserName}/{defaultProjectName}",
99 | Homepage = $"https://github.com/{Environment.UserName}"
100 | };
101 | var rootConfig = new RootConfig
102 | {
103 | Project = project,
104 | Scripts = new Dictionary
105 | {
106 | {
107 | "hello", "@echo off\necho Hello ebuild!"
108 | }
109 | },
110 | Includes = new List
111 | {
112 | "**/*.e"
113 | },
114 | Excludes = new List
115 | {
116 | "**/*.recover.e",
117 | "**/*.ecode/**.e",
118 | "**/*.代码/**.e"
119 | },
120 | ExcludeBuilds = new List
121 | {
122 | "./scripts/**/*.e"
123 | },
124 | Build = new Build
125 | {
126 | Compiler = Compiler.Static
127 | },
128 | E2Txt = new Config.E2Txt
129 | {
130 | GenerateE = true,
131 | NameStyle = Config.E2Txt.NameStyleEnum.Chinese
132 | }
133 | };
134 | if (!CommandSettings.DefaultInit)
135 | {
136 | project.Name = AnsiConsole.Ask("工程", project.Name);
137 | project.Version = AnsiConsole.Ask("版本", project.Version);
138 | project.Description = AnsiConsole.Ask("说明", project.Description);
139 | project.Author = AnsiConsole.Ask("作者", project.Author);
140 | project.Repository = AnsiConsole.Ask("仓库", project.Repository);
141 | project.Homepage = AnsiConsole.Ask("主页", project.Homepage);
142 |
143 | rootConfig.E2Txt.GenerateE = AnsiConsole.Confirm(Markup.Escape("[e2txt]生成易代码"), rootConfig.E2Txt.GenerateE);
144 | rootConfig.E2Txt.NameStyle = AnsiConsole.Prompt(
145 | new SelectionPrompt()
146 | .Title(Markup.Escape("[e2txt]命名风格"))
147 | .UseConverter(DisplaySelector)
148 | .AddChoices(Enum.GetValues())
149 | );
150 | AnsiConsole.MarkupLine(Markup.Escape("[e2txt]") + "命名风格:{0}", DisplaySelector(rootConfig.E2Txt.NameStyle));
151 |
152 | rootConfig.Build.Compiler = AnsiConsole.Prompt(
153 | new SelectionPrompt()
154 | .Title("全局默认编译器")
155 | .UseConverter(DisplaySelector)
156 | .AddChoices(Enum.GetValues())
157 | );
158 | AnsiConsole.MarkupLine("全局默认编译器:{0}", DisplaySelector(rootConfig.Build.Compiler));
159 | }
160 |
161 | return rootConfig;
162 | }
163 |
164 | private static string DisplaySelector(T enumValue)
165 | {
166 | return EnumAliasAttribute.GetEnumAliasAttribute(enumValue).Name;
167 | }
168 | }
--------------------------------------------------------------------------------
/src/EBuild/Commands/SubCommands/BuildCommand.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Diagnostics;
3 | using System.Text;
4 | using EBuild.Commands.Base;
5 | using EBuild.Config.Resolved;
6 | using EBuild.Consoles;
7 | using EBuild.Hooks;
8 | using EBuild.Plugins;
9 | using EBuild.Project;
10 | using EBuild.Toolchain;
11 | using Spectre.Console;
12 | using YamlDotNet.Serialization;
13 |
14 | namespace EBuild.Commands.SubCommands;
15 |
16 | [Description(@"构建目标。
17 |
18 | 本命令帮助您编译您配置文件的中的构建目标以及被搜索到的源文件。
19 | 您也可以手动指定要编译的目标或者源文件,如`ebuild build 程序1 程序2`。
20 | 当您不指定编译目标的时候,ebuild默认编译所有目标。")]
21 | public class BuildCommand : TargetCommand
22 | {
23 | private readonly EnvironmentVariables _environmentVariables;
24 | private readonly EclToolchain _eclToolchain;
25 |
26 | public BuildCommand(IDeserializer deserializer, IEnumerable plugins,
27 | EnvironmentVariables environmentVariables, EclToolchain eclToolchain) : base(deserializer, plugins)
28 | {
29 | _environmentVariables = environmentVariables;
30 | _eclToolchain = eclToolchain;
31 | }
32 |
33 | protected override IEnumerable NeededToolchains => new IToolchain[] { _eclToolchain };
34 | protected override int MaxConcurrencyCount => 1; // 如果多任务并行编译可能会影响 ecl 获取易语言窗口
35 |
36 | protected override IMultiTaskDisplayer GetDisplayer(IList targets)
37 | {
38 | var displayer = new LinesDisplayer()
39 | {
40 | TargetName = target => target.Target.DisplayName(ProjectRoot),
41 | StatusString = e =>
42 | {
43 | switch (e)
44 | {
45 | case TargetStatus.Waiting:
46 | return "[grey]{0}[/]";
47 | case TargetStatus.Skipped:
48 | return "[yellow]{0}[/]";
49 | case TargetStatus.Doing:
50 | return "{0}";
51 | case TargetStatus.Done:
52 | return "[green]{0}[/]";
53 | case TargetStatus.Error:
54 | return "[red]{0}[/]";
55 | }
56 |
57 | return "{0}";
58 | }
59 | };
60 | if (CommandSettings.ConcurrencyCount > MaxConcurrencyCount)
61 | displayer.SetHeader("[grey]目前不支持并行编译目标[/]");
62 | return displayer;
63 | }
64 |
65 | protected override string GenerateHeading(WholeStatus status)
66 | {
67 | switch (status)
68 | {
69 | case WholeStatus.Doing:
70 | return "[green]正在构建目标...[/]";
71 | case WholeStatus.Completed:
72 | return "[green]:check_mark: 完成构建[/]";
73 | case WholeStatus.ErrorOccured:
74 | return "[red]:cross_mark: 构建过程中出现错误[/]";
75 | }
76 |
77 | return "";
78 | }
79 |
80 | protected override async Task OnPreDoTargetAsync(ResolvedTarget target,
81 | Action updateTargetStatus,
82 | CancellationToken cancellationToken)
83 | {
84 | if (target.ShouldBuild)
85 | {
86 | Directory.CreateDirectory(Path.GetDirectoryName(target.Target.OutputPath(_resolvedConfig.OutputDir))!);
87 |
88 | var args = GetBuildArgs(target, true);
89 | updateTargetStatus(TargetStatus.Waiting,
90 | $"准备编译中... {Markup.Escape(_eclToolchain.ExecutablePath)} {Markup.Escape(string.Join(" ", args))}");
91 | }
92 | else
93 | {
94 | updateTargetStatus(TargetStatus.Skipped, "本目标已被排除编译,将被跳过");
95 | }
96 |
97 | if (target.ShouldBuild)
98 | {
99 | var evs = (EnvironmentVariables)_environmentVariables.Clone();
100 | SetupEnvironmentVariables(target, evs, Hook.PreBuild);
101 | foreach (var plugin in _plugins)
102 | {
103 | bool shouldContinue = await plugin.OnHook(new PluginContext(_resolvedConfig, evs)
104 | {
105 | BuildTarget = target,
106 | UpdateStatus = (status, log) => updateTargetStatus(status, $"[yellow][[{Hook.PreBuild}]]{log}[/]"),
107 | }, cancellationToken, Hook.PreBuild);
108 | if (!shouldContinue)
109 | {
110 | updateTargetStatus(TargetStatus.Skipped, $"[[{Hook.PreBuild}]]已由构建周期脚本取消该任务!");
111 | return false;
112 | }
113 | }
114 | }
115 |
116 | return target.ShouldBuild;
117 | }
118 |
119 | private void SetupEnvironmentVariables(ResolvedTarget target, EnvironmentVariables evs, Hook hook)
120 | {
121 | evs.ForProject(ProjectRoot, _resolvedConfig.OutputDir);
122 | evs.AddRange(new[]
123 | {
124 | new EnvironmentVariable("EBUILD_PERIOD", "构建生命周期", hook.ToString),
125 | new EnvironmentVariable("EBUILD_SOURCE_FILE", "被构建的源文件", () => target.Target.Source),
126 | new EnvironmentVariable("EBUILD_TARGET_FILE", "构建目标输出路径",
127 | () => target.Target.OutputPath(_resolvedConfig.OutputDir)),
128 | new EnvironmentVariable("EBUILD_TARGET_TYPE", "构建目标类型",
129 | () => target.SourceMeta?.TargetType.ToString() ?? "(Unkown)"),
130 | });
131 | }
132 |
133 | private IList GetBuildArgs(ResolvedTarget target, bool hideSecret = false)
134 | {
135 | return EclToolchain.Args(target, _resolvedConfig.OutputDir, hideSecret);
136 | }
137 |
138 | protected override async Task OnDoTargetAsync(ResolvedTarget target,
139 | Action updateTargetStatus,
140 | CancellationToken cancellationToken)
141 | {
142 | updateTargetStatus(TargetStatus.Doing, "开始编译");
143 |
144 | var compileOk = true;
145 | var handler = GetEclLogHandler(Update, () => compileOk = false);
146 |
147 | var process = new Process();
148 | foreach (var arg in GetBuildArgs(target)) process.StartInfo.ArgumentList.Add(arg);
149 | process.StartInfo.FileName = _eclToolchain.ExecutablePath;
150 | process.StartInfo.RedirectStandardOutput = true;
151 | process.StartInfo.RedirectStandardError = true;
152 | process.StartInfo.StandardOutputEncoding =
153 | process.StartInfo.StandardErrorEncoding = Encoding.GetEncoding("gbk");
154 | process.OutputDataReceived += handler;
155 | process.ErrorDataReceived += handler;
156 | process.Start();
157 | process.BeginOutputReadLine();
158 | process.BeginErrorReadLine();
159 | cancellationToken.Register(() => process.Kill());
160 | await process.WaitForExitAsync(cancellationToken);
161 |
162 | void Update(TargetStatus status, string log)
163 | {
164 | if (!string.IsNullOrEmpty(log))
165 | {
166 | updateTargetStatus(status, Markup.Escape(log));
167 | }
168 | }
169 |
170 | var evs = (EnvironmentVariables)_environmentVariables.Clone();
171 | SetupEnvironmentVariables(target, evs, Hook.PostBuild);
172 | foreach (var plugin in _plugins)
173 | {
174 | await plugin.OnHook(new PluginContext(_resolvedConfig, evs)
175 | {
176 | BuildTarget = target,
177 | UpdateStatus = (status, log) => updateTargetStatus(status, $"[yellow][[{Hook.PostBuild}]]{log}[/]"),
178 | }, cancellationToken, Hook.PostBuild);
179 | }
180 |
181 | if (compileOk)
182 | Update(TargetStatus.Done, $"编译成功,保存到:{target.Target.OutputPath(_resolvedConfig.OutputDir)}");
183 |
184 | return compileOk;
185 | }
186 |
187 | public static DataReceivedEventHandler GetEclLogHandler(Action update, Action compileFailed)
188 | {
189 | return (sender, e) =>
190 | {
191 | if (string.IsNullOrEmpty(e.Data))
192 | {
193 | return;
194 | }
195 |
196 | if (!EclToolchain.TryMatchError(e.Data, out bool isOk, out int errorCode, out string tip))
197 | {
198 | update(TargetStatus.Doing, e.Data);
199 | return;
200 | }
201 |
202 | if (!isOk)
203 | {
204 | update(TargetStatus.Error, $"编译目标出错,错误代码:{errorCode},错误提示:{tip}");
205 | compileFailed();
206 | }
207 | };
208 | }
209 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 | .toolchain
4 | *.ecode
5 |
6 | # If you prefer the allow list template instead of the deny list, see community template:
7 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
8 | #
9 | # Binaries for programs and plugins
10 | *.exe
11 | *.exe~
12 | *.dll
13 | *.so
14 | *.dylib
15 |
16 | # Output of the go coverage tool, specifically when used with LiteIDE
17 | *.out
18 |
19 | # Dependency directories (remove the comment below to include it)
20 | # vendor/
21 |
22 | # Go workspace file
23 | go.work### VisualStudio template
24 | ## Ignore Visual Studio temporary files, build results, and
25 | ## files generated by popular Visual Studio add-ons.
26 | ##
27 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
28 |
29 | # User-specific files
30 | *.rsuser
31 | *.suo
32 | *.user
33 | *.userosscache
34 | *.sln.docstates
35 |
36 | # User-specific files (MonoDevelop/Xamarin Studio)
37 | *.userprefs
38 |
39 | # Mono auto generated files
40 | mono_crash.*
41 |
42 | # Build results
43 | [Dd]ebug/
44 | [Dd]ebugPublic/
45 | [Rr]elease/
46 | [Rr]eleases/
47 | x64/
48 | x86/
49 | [Ww][Ii][Nn]32/
50 | [Aa][Rr][Mm]/
51 | [Aa][Rr][Mm]64/
52 | bld/
53 | [Bb]in/
54 | [Oo]bj/
55 | [Ll]og/
56 | [Ll]ogs/
57 |
58 | # Visual Studio 2015/2017 cache/options directory
59 | .vs/
60 | # Uncomment if you have tasks that create the project's static files in wwwroot
61 | #wwwroot/
62 |
63 | # Visual Studio 2017 auto generated files
64 | Generated\ Files/
65 |
66 | # MSTest test Results
67 | [Tt]est[Rr]esult*/
68 | [Bb]uild[Ll]og.*
69 |
70 | # NUnit
71 | *.VisualState.xml
72 | TestResult.xml
73 | nunit-*.xml
74 |
75 | # Build Results of an ATL Project
76 | [Dd]ebugPS/
77 | [Rr]eleasePS/
78 | dlldata.c
79 |
80 | # Benchmark Results
81 | BenchmarkDotNet.Artifacts/
82 |
83 | # .NET Core
84 | project.lock.json
85 | project.fragment.lock.json
86 | artifacts/
87 |
88 | # ASP.NET Scaffolding
89 | ScaffoldingReadMe.txt
90 |
91 | # StyleCop
92 | StyleCopReport.xml
93 |
94 | # Files built by Visual Studio
95 | *_i.c
96 | *_p.c
97 | *_h.h
98 | *.ilk
99 | *.meta
100 | *.obj
101 | *.iobj
102 | *.pch
103 | *.pdb
104 | *.ipdb
105 | *.pgc
106 | *.pgd
107 | *.rsp
108 | *.sbr
109 | *.tlb
110 | *.tli
111 | *.tlh
112 | *.tmp
113 | *.tmp_proj
114 | *_wpftmp.csproj
115 | *.log
116 | *.vspscc
117 | *.vssscc
118 | .builds
119 | *.pidb
120 | *.svclog
121 | *.scc
122 |
123 | # Chutzpah Test files
124 | _Chutzpah*
125 |
126 | # Visual C++ cache files
127 | ipch/
128 | *.aps
129 | *.ncb
130 | *.opendb
131 | *.opensdf
132 | *.sdf
133 | *.cachefile
134 | *.VC.db
135 | *.VC.VC.opendb
136 |
137 | # Visual Studio profiler
138 | *.psess
139 | *.vsp
140 | *.vspx
141 | *.sap
142 |
143 | # Visual Studio Trace Files
144 | *.e2e
145 |
146 | # TFS 2012 Local Workspace
147 | $tf/
148 |
149 | # Guidance Automation Toolkit
150 | *.gpState
151 |
152 | # ReSharper is a .NET coding add-in
153 | _ReSharper*/
154 | *.[Rr]e[Ss]harper
155 | *.DotSettings.user
156 |
157 | # TeamCity is a build add-in
158 | _TeamCity*
159 |
160 | # DotCover is a Code Coverage Tool
161 | *.dotCover
162 |
163 | # AxoCover is a Code Coverage Tool
164 | .axoCover/*
165 | !.axoCover/settings.json
166 |
167 | # Coverlet is a free, cross platform Code Coverage Tool
168 | coverage*.json
169 | coverage*.xml
170 | coverage*.info
171 |
172 | # Visual Studio code coverage results
173 | *.coverage
174 | *.coveragexml
175 |
176 | # NCrunch
177 | _NCrunch_*
178 | .*crunch*.local.xml
179 | nCrunchTemp_*
180 |
181 | # MightyMoose
182 | *.mm.*
183 | AutoTest.Net/
184 |
185 | # Web workbench (sass)
186 | .sass-cache/
187 |
188 | # Installshield output folder
189 | [Ee]xpress/
190 |
191 | # DocProject is a documentation generator add-in
192 | DocProject/buildhelp/
193 | DocProject/Help/*.HxT
194 | DocProject/Help/*.HxC
195 | DocProject/Help/*.hhc
196 | DocProject/Help/*.hhk
197 | DocProject/Help/*.hhp
198 | DocProject/Help/Html2
199 | DocProject/Help/html
200 |
201 | # Click-Once directory
202 | publish/
203 |
204 | # Publish Web Output
205 | *.[Pp]ublish.xml
206 | *.azurePubxml
207 | # Note: Comment the next line if you want to checkin your web deploy settings,
208 | # but database connection strings (with potential passwords) will be unencrypted
209 | *.pubxml
210 | *.publishproj
211 |
212 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
213 | # checkin your Azure Web App publish settings, but sensitive information contained
214 | # in these scripts will be unencrypted
215 | PublishScripts/
216 |
217 | # NuGet Packages
218 | *.nupkg
219 | # NuGet Symbol Packages
220 | *.snupkg
221 | # The packages folder can be ignored because of Package Restore
222 | **/[Pp]ackages/*
223 | # except build/, which is used as an MSBuild target.
224 | !**/[Pp]ackages/build/
225 | # Uncomment if necessary however generally it will be regenerated when needed
226 | #!**/[Pp]ackages/repositories.config
227 | # NuGet v3's project.json files produces more ignorable files
228 | *.nuget.props
229 | *.nuget.targets
230 |
231 | # Microsoft Azure Build Output
232 | csx/
233 | *.build.csdef
234 |
235 | # Microsoft Azure Emulator
236 | ecf/
237 | rcf/
238 |
239 | # Windows Store app package directories and files
240 | AppPackages/
241 | BundleArtifacts/
242 | Package.StoreAssociation.xml
243 | _pkginfo.txt
244 | *.appx
245 | *.appxbundle
246 | *.appxupload
247 |
248 | # Visual Studio cache files
249 | # files ending in .cache can be ignored
250 | *.[Cc]ache
251 | # but keep track of directories ending in .cache
252 | !?*.[Cc]ache/
253 |
254 | # Others
255 | ClientBin/
256 | ~$*
257 | *~
258 | *.dbmdl
259 | *.dbproj.schemaview
260 | *.jfm
261 | *.pfx
262 | *.publishsettings
263 | orleans.codegen.cs
264 |
265 | # Including strong name files can present a security risk
266 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
267 | #*.snk
268 |
269 | # Since there are multiple workflows, uncomment next line to ignore bower_components
270 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
271 | #bower_components/
272 |
273 | # RIA/Silverlight projects
274 | Generated_Code/
275 |
276 | # Backup & report files from converting an old project file
277 | # to a newer Visual Studio version. Backup files are not needed,
278 | # because we have git ;-)
279 | _UpgradeReport_Files/
280 | Backup*/
281 | UpgradeLog*.XML
282 | UpgradeLog*.htm
283 | ServiceFabricBackup/
284 | *.rptproj.bak
285 |
286 | # SQL Server files
287 | *.mdf
288 | *.ldf
289 | *.ndf
290 |
291 | # Business Intelligence projects
292 | *.rdl.data
293 | *.bim.layout
294 | *.bim_*.settings
295 | *.rptproj.rsuser
296 | *- [Bb]ackup.rdl
297 | *- [Bb]ackup ([0-9]).rdl
298 | *- [Bb]ackup ([0-9][0-9]).rdl
299 |
300 | # Microsoft Fakes
301 | FakesAssemblies/
302 |
303 | # GhostDoc plugin setting file
304 | *.GhostDoc.xml
305 |
306 | # Node.js Tools for Visual Studio
307 | .ntvs_analysis.dat
308 | node_modules/
309 |
310 | # Visual Studio 6 build log
311 | *.plg
312 |
313 | # Visual Studio 6 workspace options file
314 | *.opt
315 |
316 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
317 | *.vbw
318 |
319 | # Visual Studio LightSwitch build output
320 | **/*.HTMLClient/GeneratedArtifacts
321 | **/*.DesktopClient/GeneratedArtifacts
322 | **/*.DesktopClient/ModelManifest.xml
323 | **/*.Server/GeneratedArtifacts
324 | **/*.Server/ModelManifest.xml
325 | _Pvt_Extensions
326 |
327 | # Paket dependency manager
328 | .paket/paket.exe
329 | paket-files/
330 |
331 | # FAKE - F# Make
332 | .fake/
333 |
334 | # CodeRush personal settings
335 | .cr/personal
336 |
337 | # Python Tools for Visual Studio (PTVS)
338 | __pycache__/
339 | *.pyc
340 |
341 | # Cake - Uncomment if you are using it
342 | # tools/**
343 | # !tools/packages.config
344 |
345 | # Tabs Studio
346 | *.tss
347 |
348 | # Telerik's JustMock configuration file
349 | *.jmconfig
350 |
351 | # BizTalk build output
352 | *.btp.cs
353 | *.btm.cs
354 | *.odx.cs
355 | *.xsd.cs
356 |
357 | # OpenCover UI analysis results
358 | OpenCover/
359 |
360 | # Azure Stream Analytics local run output
361 | ASALocalRun/
362 |
363 | # MSBuild Binary and Structured Log
364 | *.binlog
365 |
366 | # NVidia Nsight GPU debugger configuration file
367 | *.nvuser
368 |
369 | # MFractors (Xamarin productivity tool) working folder
370 | .mfractor/
371 |
372 | # Local History for Visual Studio
373 | .localhistory/
374 |
375 | # BeatPulse healthcheck temp database
376 | healthchecksdb
377 |
378 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
379 | MigrationBackup/
380 |
381 | # Ionide (cross platform F# VS Code tools) working folder
382 | .ionide/
383 |
384 | # Fody - auto-generated XML schema
385 | FodyWeavers.xsd
386 |
387 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@algolia/autocomplete-core@1.7.1":
6 | version "1.7.1"
7 | resolved "https://registry.npmmirror.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.1.tgz#025538b8a9564a9f3dd5bcf8a236d6951c76c7d1"
8 | integrity sha512-eiZw+fxMzNQn01S8dA/hcCpoWCOCwcIIEUtHHdzN5TGB3IpzLbuhqFeTfh2OUhhgkE8Uo17+wH+QJ/wYyQmmzg==
9 | dependencies:
10 | "@algolia/autocomplete-shared" "1.7.1"
11 |
12 | "@algolia/autocomplete-preset-algolia@1.7.1":
13 | version "1.7.1"
14 | resolved "https://registry.npmmirror.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.1.tgz#7dadc5607097766478014ae2e9e1c9c4b3f957c8"
15 | integrity sha512-pJwmIxeJCymU1M6cGujnaIYcY3QPOVYZOXhFkWVM7IxKzy272BwCvMFMyc5NpG/QmiObBxjo7myd060OeTNJXg==
16 | dependencies:
17 | "@algolia/autocomplete-shared" "1.7.1"
18 |
19 | "@algolia/autocomplete-shared@1.7.1":
20 | version "1.7.1"
21 | resolved "https://registry.npmmirror.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.1.tgz#95c3a0b4b78858fed730cf9c755b7d1cd0c82c74"
22 | integrity sha512-eTmGVqY3GeyBTT8IWiB2K5EuURAqhnumfktAEoHxfDY2o7vg2rSnO16ZtIG0fMgt3py28Vwgq42/bVEuaQV7pg==
23 |
24 | "@algolia/cache-browser-local-storage@4.14.2":
25 | version "4.14.2"
26 | resolved "https://registry.npmmirror.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.2.tgz#d5b1b90130ca87c6321de876e167df9ec6524936"
27 | integrity sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA==
28 | dependencies:
29 | "@algolia/cache-common" "4.14.2"
30 |
31 | "@algolia/cache-common@4.14.2":
32 | version "4.14.2"
33 | resolved "https://registry.npmmirror.com/@algolia/cache-common/-/cache-common-4.14.2.tgz#b946b6103c922f0c06006fb6929163ed2c67d598"
34 | integrity sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==
35 |
36 | "@algolia/cache-in-memory@4.14.2":
37 | version "4.14.2"
38 | resolved "https://registry.npmmirror.com/@algolia/cache-in-memory/-/cache-in-memory-4.14.2.tgz#88e4a21474f9ac05331c2fa3ceb929684a395a24"
39 | integrity sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==
40 | dependencies:
41 | "@algolia/cache-common" "4.14.2"
42 |
43 | "@algolia/client-account@4.14.2":
44 | version "4.14.2"
45 | resolved "https://registry.npmmirror.com/@algolia/client-account/-/client-account-4.14.2.tgz#b76ac1ba9ea71e8c3f77a1805b48350dc0728a16"
46 | integrity sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==
47 | dependencies:
48 | "@algolia/client-common" "4.14.2"
49 | "@algolia/client-search" "4.14.2"
50 | "@algolia/transporter" "4.14.2"
51 |
52 | "@algolia/client-analytics@4.14.2":
53 | version "4.14.2"
54 | resolved "https://registry.npmmirror.com/@algolia/client-analytics/-/client-analytics-4.14.2.tgz#ca04dcaf9a78ee5c92c5cb5e9c74cf031eb2f1fb"
55 | integrity sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==
56 | dependencies:
57 | "@algolia/client-common" "4.14.2"
58 | "@algolia/client-search" "4.14.2"
59 | "@algolia/requester-common" "4.14.2"
60 | "@algolia/transporter" "4.14.2"
61 |
62 | "@algolia/client-common@4.14.2":
63 | version "4.14.2"
64 | resolved "https://registry.npmmirror.com/@algolia/client-common/-/client-common-4.14.2.tgz#e1324e167ffa8af60f3e8bcd122110fd0bfd1300"
65 | integrity sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==
66 | dependencies:
67 | "@algolia/requester-common" "4.14.2"
68 | "@algolia/transporter" "4.14.2"
69 |
70 | "@algolia/client-personalization@4.14.2":
71 | version "4.14.2"
72 | resolved "https://registry.npmmirror.com/@algolia/client-personalization/-/client-personalization-4.14.2.tgz#656bbb6157a3dd1a4be7de65e457fda136c404ec"
73 | integrity sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==
74 | dependencies:
75 | "@algolia/client-common" "4.14.2"
76 | "@algolia/requester-common" "4.14.2"
77 | "@algolia/transporter" "4.14.2"
78 |
79 | "@algolia/client-search@4.14.2":
80 | version "4.14.2"
81 | resolved "https://registry.npmmirror.com/@algolia/client-search/-/client-search-4.14.2.tgz#357bdb7e640163f0e33bad231dfcc21f67dc2e92"
82 | integrity sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==
83 | dependencies:
84 | "@algolia/client-common" "4.14.2"
85 | "@algolia/requester-common" "4.14.2"
86 | "@algolia/transporter" "4.14.2"
87 |
88 | "@algolia/logger-common@4.14.2":
89 | version "4.14.2"
90 | resolved "https://registry.npmmirror.com/@algolia/logger-common/-/logger-common-4.14.2.tgz#b74b3a92431f92665519d95942c246793ec390ee"
91 | integrity sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==
92 |
93 | "@algolia/logger-console@4.14.2":
94 | version "4.14.2"
95 | resolved "https://registry.npmmirror.com/@algolia/logger-console/-/logger-console-4.14.2.tgz#ec49cb47408f5811d4792598683923a800abce7b"
96 | integrity sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==
97 | dependencies:
98 | "@algolia/logger-common" "4.14.2"
99 |
100 | "@algolia/requester-browser-xhr@4.14.2":
101 | version "4.14.2"
102 | resolved "https://registry.npmmirror.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.2.tgz#a2cd4d9d8d90d53109cc7f3682dc6ebf20f798f2"
103 | integrity sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==
104 | dependencies:
105 | "@algolia/requester-common" "4.14.2"
106 |
107 | "@algolia/requester-common@4.14.2":
108 | version "4.14.2"
109 | resolved "https://registry.npmmirror.com/@algolia/requester-common/-/requester-common-4.14.2.tgz#bc4e9e5ee16c953c0ecacbfb334a33c30c28b1a1"
110 | integrity sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==
111 |
112 | "@algolia/requester-node-http@4.14.2":
113 | version "4.14.2"
114 | resolved "https://registry.npmmirror.com/@algolia/requester-node-http/-/requester-node-http-4.14.2.tgz#7c1223a1785decaab1def64c83dade6bea45e115"
115 | integrity sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==
116 | dependencies:
117 | "@algolia/requester-common" "4.14.2"
118 |
119 | "@algolia/transporter@4.14.2":
120 | version "4.14.2"
121 | resolved "https://registry.npmmirror.com/@algolia/transporter/-/transporter-4.14.2.tgz#77c069047fb1a4359ee6a51f51829508e44a1e3d"
122 | integrity sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==
123 | dependencies:
124 | "@algolia/cache-common" "4.14.2"
125 | "@algolia/logger-common" "4.14.2"
126 | "@algolia/requester-common" "4.14.2"
127 |
128 | "@babel/parser@^7.16.4":
129 | version "7.18.9"
130 | resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
131 | integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
132 |
133 | "@docsearch/css@3.1.1", "@docsearch/css@^3.0.0":
134 | version "3.1.1"
135 | resolved "https://registry.npmmirror.com/@docsearch/css/-/css-3.1.1.tgz#e0976bf995e383f8ee8657306311b9cb95016330"
136 | integrity sha512-utLgg7E1agqQeqCJn05DWC7XXMk4tMUUnL7MZupcknRu2OzGN13qwey2qA/0NAKkVBGugiWtON0+rlU0QIPojg==
137 |
138 | "@docsearch/js@^3.0.0":
139 | version "3.1.1"
140 | resolved "https://registry.npmmirror.com/@docsearch/js/-/js-3.1.1.tgz#fbcf85d034b11ae15397310ef117c7d6fb4e6871"
141 | integrity sha512-bt7l2aKRoSnLUuX+s4LVQ1a7AF2c9myiZNv5uvQCePG5tpvVGpwrnMwqVXOUJn9q6FwVVhOrQMO/t+QmnnAEUw==
142 | dependencies:
143 | "@docsearch/react" "3.1.1"
144 | preact "^10.0.0"
145 |
146 | "@docsearch/react@3.1.1":
147 | version "3.1.1"
148 | resolved "https://registry.npmmirror.com/@docsearch/react/-/react-3.1.1.tgz#3dffb5db8cf9eb95d6e732cf038264bfc10191ed"
149 | integrity sha512-cfoql4qvtsVRqBMYxhlGNpvyy/KlCoPqjIsJSZYqYf9AplZncKjLBTcwBu6RXFMVCe30cIFljniI4OjqAU67pQ==
150 | dependencies:
151 | "@algolia/autocomplete-core" "1.7.1"
152 | "@algolia/autocomplete-preset-algolia" "1.7.1"
153 | "@docsearch/css" "3.1.1"
154 | algoliasearch "^4.0.0"
155 |
156 | "@types/linkify-it@*":
157 | version "3.0.2"
158 | resolved "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9"
159 | integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==
160 |
161 | "@types/markdown-it@^12.2.3":
162 | version "12.2.3"
163 | resolved "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51"
164 | integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==
165 | dependencies:
166 | "@types/linkify-it" "*"
167 | "@types/mdurl" "*"
168 |
169 | "@types/mdurl@*":
170 | version "1.0.2"
171 | resolved "https://registry.npmmirror.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9"
172 | integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==
173 |
174 | "@types/web-bluetooth@^0.0.14":
175 | version "0.0.14"
176 | resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz#94e175b53623384bff1f354cdb3197a8d63cdbe5"
177 | integrity sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==
178 |
179 | "@vitejs/plugin-vue@^2.3.2":
180 | version "2.3.3"
181 | resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz#fbf80cc039b82ac21a1acb0f0478de8f61fbf600"
182 | integrity sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==
183 |
184 | "@vue/compiler-core@3.2.37":
185 | version "3.2.37"
186 | resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.37.tgz#b3c42e04c0e0f2c496ff1784e543fbefe91e215a"
187 | integrity sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==
188 | dependencies:
189 | "@babel/parser" "^7.16.4"
190 | "@vue/shared" "3.2.37"
191 | estree-walker "^2.0.2"
192 | source-map "^0.6.1"
193 |
194 | "@vue/compiler-dom@3.2.37":
195 | version "3.2.37"
196 | resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5"
197 | integrity sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==
198 | dependencies:
199 | "@vue/compiler-core" "3.2.37"
200 | "@vue/shared" "3.2.37"
201 |
202 | "@vue/compiler-sfc@3.2.37":
203 | version "3.2.37"
204 | resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4"
205 | integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==
206 | dependencies:
207 | "@babel/parser" "^7.16.4"
208 | "@vue/compiler-core" "3.2.37"
209 | "@vue/compiler-dom" "3.2.37"
210 | "@vue/compiler-ssr" "3.2.37"
211 | "@vue/reactivity-transform" "3.2.37"
212 | "@vue/shared" "3.2.37"
213 | estree-walker "^2.0.2"
214 | magic-string "^0.25.7"
215 | postcss "^8.1.10"
216 | source-map "^0.6.1"
217 |
218 | "@vue/compiler-ssr@3.2.37":
219 | version "3.2.37"
220 | resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz#4899d19f3a5fafd61524a9d1aee8eb0505313cff"
221 | integrity sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==
222 | dependencies:
223 | "@vue/compiler-dom" "3.2.37"
224 | "@vue/shared" "3.2.37"
225 |
226 | "@vue/devtools-api@^6.1.4":
227 | version "6.2.1"
228 | resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.2.1.tgz#6f2948ff002ec46df01420dfeff91de16c5b4092"
229 | integrity sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==
230 |
231 | "@vue/reactivity-transform@3.2.37":
232 | version "3.2.37"
233 | resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca"
234 | integrity sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==
235 | dependencies:
236 | "@babel/parser" "^7.16.4"
237 | "@vue/compiler-core" "3.2.37"
238 | "@vue/shared" "3.2.37"
239 | estree-walker "^2.0.2"
240 | magic-string "^0.25.7"
241 |
242 | "@vue/reactivity@3.2.37":
243 | version "3.2.37"
244 | resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.37.tgz#5bc3847ac58828e2b78526e08219e0a1089f8848"
245 | integrity sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==
246 | dependencies:
247 | "@vue/shared" "3.2.37"
248 |
249 | "@vue/runtime-core@3.2.37":
250 | version "3.2.37"
251 | resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.37.tgz#7ba7c54bb56e5d70edfc2f05766e1ca8519966e3"
252 | integrity sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==
253 | dependencies:
254 | "@vue/reactivity" "3.2.37"
255 | "@vue/shared" "3.2.37"
256 |
257 | "@vue/runtime-dom@3.2.37":
258 | version "3.2.37"
259 | resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz#002bdc8228fa63949317756fb1e92cdd3f9f4bbd"
260 | integrity sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==
261 | dependencies:
262 | "@vue/runtime-core" "3.2.37"
263 | "@vue/shared" "3.2.37"
264 | csstype "^2.6.8"
265 |
266 | "@vue/server-renderer@3.2.37":
267 | version "3.2.37"
268 | resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.37.tgz#840a29c8dcc29bddd9b5f5ffa22b95c0e72afdfc"
269 | integrity sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==
270 | dependencies:
271 | "@vue/compiler-ssr" "3.2.37"
272 | "@vue/shared" "3.2.37"
273 |
274 | "@vue/shared@3.2.37":
275 | version "3.2.37"
276 | resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702"
277 | integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==
278 |
279 | "@vueuse/core@^8.5.0":
280 | version "8.9.4"
281 | resolved "https://registry.npmmirror.com/@vueuse/core/-/core-8.9.4.tgz#c7db40f19390b3c9f4ff9294a30461497f62ec19"
282 | integrity sha512-B/Mdj9TK1peFyWaPof+Zf/mP9XuGAngaJZBwPaXBvU3aCTZlx3ltlrFFFyMV4iGBwsjSCeUCgZrtkEj9dS2Y3Q==
283 | dependencies:
284 | "@types/web-bluetooth" "^0.0.14"
285 | "@vueuse/metadata" "8.9.4"
286 | "@vueuse/shared" "8.9.4"
287 | vue-demi "*"
288 |
289 | "@vueuse/metadata@8.9.4":
290 | version "8.9.4"
291 | resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz#a4132db33e4c1b1023636acfa20aa7b37ab3d978"
292 | integrity sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw==
293 |
294 | "@vueuse/shared@8.9.4":
295 | version "8.9.4"
296 | resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz#c9741c30ffb666b50d62f0dd80b76119fd47573e"
297 | integrity sha512-wt+T30c4K6dGRMVqPddexEVLa28YwxW5OFIPmzUHICjphfAuBFTTdDoyqREZNDOFJZ44ARH1WWQNCUK8koJ+Ag==
298 | dependencies:
299 | vue-demi "*"
300 |
301 | algoliasearch@^4.0.0:
302 | version "4.14.2"
303 | resolved "https://registry.npmmirror.com/algoliasearch/-/algoliasearch-4.14.2.tgz#63f142583bfc3a9bd3cd4a1b098bf6fe58e56f6c"
304 | integrity sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==
305 | dependencies:
306 | "@algolia/cache-browser-local-storage" "4.14.2"
307 | "@algolia/cache-common" "4.14.2"
308 | "@algolia/cache-in-memory" "4.14.2"
309 | "@algolia/client-account" "4.14.2"
310 | "@algolia/client-analytics" "4.14.2"
311 | "@algolia/client-common" "4.14.2"
312 | "@algolia/client-personalization" "4.14.2"
313 | "@algolia/client-search" "4.14.2"
314 | "@algolia/logger-common" "4.14.2"
315 | "@algolia/logger-console" "4.14.2"
316 | "@algolia/requester-browser-xhr" "4.14.2"
317 | "@algolia/requester-common" "4.14.2"
318 | "@algolia/requester-node-http" "4.14.2"
319 | "@algolia/transporter" "4.14.2"
320 |
321 | body-scroll-lock@^4.0.0-beta.0:
322 | version "4.0.0-beta.0"
323 | resolved "https://registry.npmmirror.com/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz#4f78789d10e6388115c0460cd6d7d4dd2bbc4f7e"
324 | integrity sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==
325 |
326 | csstype@^2.6.8:
327 | version "2.6.20"
328 | resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda"
329 | integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==
330 |
331 | esbuild-android-64@0.14.51:
332 | version "0.14.51"
333 | resolved "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.51.tgz#414a087cb0de8db1e347ecca6c8320513de433db"
334 | integrity sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ==
335 |
336 | esbuild-android-arm64@0.14.51:
337 | version "0.14.51"
338 | resolved "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.51.tgz#55de3bce2aab72bcd2b606da4318ad00fb9c8151"
339 | integrity sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A==
340 |
341 | esbuild-darwin-64@0.14.51:
342 | version "0.14.51"
343 | resolved "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.51.tgz#4259f23ed6b4cea2ec8a28d87b7fb9801f093754"
344 | integrity sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA==
345 |
346 | esbuild-darwin-arm64@0.14.51:
347 | version "0.14.51"
348 | resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.51.tgz#d77b4366a71d84e530ba019d540b538b295d494a"
349 | integrity sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow==
350 |
351 | esbuild-freebsd-64@0.14.51:
352 | version "0.14.51"
353 | resolved "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.51.tgz#27b6587b3639f10519c65e07219d249b01f2ad38"
354 | integrity sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g==
355 |
356 | esbuild-freebsd-arm64@0.14.51:
357 | version "0.14.51"
358 | resolved "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.51.tgz#63c435917e566808c71fafddc600aca4d78be1ec"
359 | integrity sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg==
360 |
361 | esbuild-linux-32@0.14.51:
362 | version "0.14.51"
363 | resolved "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.14.51.tgz#c3da774143a37e7f11559b9369d98f11f997a5d9"
364 | integrity sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w==
365 |
366 | esbuild-linux-64@0.14.51:
367 | version "0.14.51"
368 | resolved "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.14.51.tgz#5d92b67f674e02ae0b4a9de9a757ba482115c4ae"
369 | integrity sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA==
370 |
371 | esbuild-linux-arm64@0.14.51:
372 | version "0.14.51"
373 | resolved "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.51.tgz#dac84740516e859d8b14e1ecc478dd5241b10c93"
374 | integrity sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw==
375 |
376 | esbuild-linux-arm@0.14.51:
377 | version "0.14.51"
378 | resolved "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.51.tgz#b3ae7000696cd53ed95b2b458554ff543a60e106"
379 | integrity sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg==
380 |
381 | esbuild-linux-mips64le@0.14.51:
382 | version "0.14.51"
383 | resolved "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.51.tgz#dad10770fac94efa092b5a0643821c955a9dd385"
384 | integrity sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A==
385 |
386 | esbuild-linux-ppc64le@0.14.51:
387 | version "0.14.51"
388 | resolved "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.51.tgz#b68c2f8294d012a16a88073d67e976edd4850ae0"
389 | integrity sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ==
390 |
391 | esbuild-linux-riscv64@0.14.51:
392 | version "0.14.51"
393 | resolved "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.51.tgz#608a318b8697123e44c1e185cdf6708e3df50b93"
394 | integrity sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA==
395 |
396 | esbuild-linux-s390x@0.14.51:
397 | version "0.14.51"
398 | resolved "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.51.tgz#c9e7791170a3295dba79b93aa452beb9838a8625"
399 | integrity sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw==
400 |
401 | esbuild-netbsd-64@0.14.51:
402 | version "0.14.51"
403 | resolved "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.51.tgz#0abd40b8c2e37fda6f5cc41a04cb2b690823d891"
404 | integrity sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A==
405 |
406 | esbuild-openbsd-64@0.14.51:
407 | version "0.14.51"
408 | resolved "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.51.tgz#4adba0b7ea7eb1428bb00d8e94c199a949b130e8"
409 | integrity sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA==
410 |
411 | esbuild-sunos-64@0.14.51:
412 | version "0.14.51"
413 | resolved "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.51.tgz#4b8a6d97dfedda30a6e39607393c5c90ebf63891"
414 | integrity sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA==
415 |
416 | esbuild-windows-32@0.14.51:
417 | version "0.14.51"
418 | resolved "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.14.51.tgz#d31d8ca0c1d314fb1edea163685a423b62e9ac17"
419 | integrity sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg==
420 |
421 | esbuild-windows-64@0.14.51:
422 | version "0.14.51"
423 | resolved "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz#7d3c09c8652d222925625637bdc7e6c223e0085d"
424 | integrity sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==
425 |
426 | esbuild-windows-arm64@0.14.51:
427 | version "0.14.51"
428 | resolved "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.51.tgz#0220d2304bfdc11bc27e19b2aaf56edf183e4ae9"
429 | integrity sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g==
430 |
431 | esbuild@^0.14.27:
432 | version "0.14.51"
433 | resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.51.tgz#1c8ecbc8db3710da03776211dc3ee3448f7aa51e"
434 | integrity sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==
435 | optionalDependencies:
436 | esbuild-android-64 "0.14.51"
437 | esbuild-android-arm64 "0.14.51"
438 | esbuild-darwin-64 "0.14.51"
439 | esbuild-darwin-arm64 "0.14.51"
440 | esbuild-freebsd-64 "0.14.51"
441 | esbuild-freebsd-arm64 "0.14.51"
442 | esbuild-linux-32 "0.14.51"
443 | esbuild-linux-64 "0.14.51"
444 | esbuild-linux-arm "0.14.51"
445 | esbuild-linux-arm64 "0.14.51"
446 | esbuild-linux-mips64le "0.14.51"
447 | esbuild-linux-ppc64le "0.14.51"
448 | esbuild-linux-riscv64 "0.14.51"
449 | esbuild-linux-s390x "0.14.51"
450 | esbuild-netbsd-64 "0.14.51"
451 | esbuild-openbsd-64 "0.14.51"
452 | esbuild-sunos-64 "0.14.51"
453 | esbuild-windows-32 "0.14.51"
454 | esbuild-windows-64 "0.14.51"
455 | esbuild-windows-arm64 "0.14.51"
456 |
457 | estree-walker@^2.0.2:
458 | version "2.0.2"
459 | resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
460 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
461 |
462 | fsevents@~2.3.2:
463 | version "2.3.2"
464 | resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
465 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
466 |
467 | function-bind@^1.1.1:
468 | version "1.1.1"
469 | resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
470 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
471 |
472 | has@^1.0.3:
473 | version "1.0.3"
474 | resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
475 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
476 | dependencies:
477 | function-bind "^1.1.1"
478 |
479 | is-core-module@^2.9.0:
480 | version "2.9.0"
481 | resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
482 | integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
483 | dependencies:
484 | has "^1.0.3"
485 |
486 | jsonc-parser@^3.0.0:
487 | version "3.1.0"
488 | resolved "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.1.0.tgz#73b8f0e5c940b83d03476bc2e51a20ef0932615d"
489 | integrity sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==
490 |
491 | magic-string@^0.25.7:
492 | version "0.25.9"
493 | resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
494 | integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
495 | dependencies:
496 | sourcemap-codec "^1.4.8"
497 |
498 | markdown-it-task-checkbox@^1.0.6:
499 | version "1.0.6"
500 | resolved "https://registry.npmmirror.com/markdown-it-task-checkbox/-/markdown-it-task-checkbox-1.0.6.tgz#9ebd7b6382e99162264605bc580f2ac118be4242"
501 | integrity sha512-7pxkHuvqTOu3iwVGmDPeYjQg+AIS9VQxzyLP9JCg9lBjgPAJXGEkChK6A2iFuj3tS0GV3HG2u5AMNhcQqwxpJw==
502 |
503 | nanoid@^3.3.4:
504 | version "3.3.4"
505 | resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
506 | integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
507 |
508 | path-parse@^1.0.7:
509 | version "1.0.7"
510 | resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
511 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
512 |
513 | picocolors@^1.0.0:
514 | version "1.0.0"
515 | resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
516 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
517 |
518 | postcss@^8.1.10, postcss@^8.4.13:
519 | version "8.4.14"
520 | resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
521 | integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
522 | dependencies:
523 | nanoid "^3.3.4"
524 | picocolors "^1.0.0"
525 | source-map-js "^1.0.2"
526 |
527 | preact@^10.0.0:
528 | version "10.10.0"
529 | resolved "https://registry.npmmirror.com/preact/-/preact-10.10.0.tgz#7434750a24b59dae1957d95dc0aa47a4a8e9a180"
530 | integrity sha512-fszkg1iJJjq68I4lI8ZsmBiaoQiQHbxf1lNq+72EmC/mZOsFF5zn3k1yv9QGoFgIXzgsdSKtYymLJsrJPoamjQ==
531 |
532 | resolve@^1.22.0:
533 | version "1.22.1"
534 | resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
535 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
536 | dependencies:
537 | is-core-module "^2.9.0"
538 | path-parse "^1.0.7"
539 | supports-preserve-symlinks-flag "^1.0.0"
540 |
541 | rollup@^2.59.0:
542 | version "2.77.2"
543 | resolved "https://registry.npmmirror.com/rollup/-/rollup-2.77.2.tgz#6b6075c55f9cc2040a5912e6e062151e42e2c4e3"
544 | integrity sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==
545 | optionalDependencies:
546 | fsevents "~2.3.2"
547 |
548 | shiki@^0.10.1:
549 | version "0.10.1"
550 | resolved "https://registry.npmmirror.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14"
551 | integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==
552 | dependencies:
553 | jsonc-parser "^3.0.0"
554 | vscode-oniguruma "^1.6.1"
555 | vscode-textmate "5.2.0"
556 |
557 | source-map-js@^1.0.2:
558 | version "1.0.2"
559 | resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
560 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
561 |
562 | source-map@^0.6.1:
563 | version "0.6.1"
564 | resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
565 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
566 |
567 | sourcemap-codec@^1.4.8:
568 | version "1.4.8"
569 | resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
570 | integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
571 |
572 | supports-preserve-symlinks-flag@^1.0.0:
573 | version "1.0.0"
574 | resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
575 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
576 |
577 | vite@^2.9.7:
578 | version "2.9.14"
579 | resolved "https://registry.npmmirror.com/vite/-/vite-2.9.14.tgz#c438324c6594afd1050df3777da981dee988bb1b"
580 | integrity sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==
581 | dependencies:
582 | esbuild "^0.14.27"
583 | postcss "^8.4.13"
584 | resolve "^1.22.0"
585 | rollup "^2.59.0"
586 | optionalDependencies:
587 | fsevents "~2.3.2"
588 |
589 | vitepress@^1.0.0-alpha.4:
590 | version "1.0.0-alpha.4"
591 | resolved "https://registry.npmmirror.com/vitepress/-/vitepress-1.0.0-alpha.4.tgz#2d9929e2cade3d98f57f61848c01968fb386cee0"
592 | integrity sha512-bOAA4KW6vYGlkbcrPLZLTKWTgXVroObU+o9xj9EENyEl6yg26WWvfN7DGA4BftjdM5O8nR93Z5khPQ3W/tFE7Q==
593 | dependencies:
594 | "@docsearch/css" "^3.0.0"
595 | "@docsearch/js" "^3.0.0"
596 | "@vitejs/plugin-vue" "^2.3.2"
597 | "@vue/devtools-api" "^6.1.4"
598 | "@vueuse/core" "^8.5.0"
599 | body-scroll-lock "^4.0.0-beta.0"
600 | shiki "^0.10.1"
601 | vite "^2.9.7"
602 | vue "^3.2.33"
603 |
604 | vscode-oniguruma@^1.6.1:
605 | version "1.6.2"
606 | resolved "https://registry.npmmirror.com/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz#aeb9771a2f1dbfc9083c8a7fdd9cccaa3f386607"
607 | integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==
608 |
609 | vscode-textmate@5.2.0:
610 | version "5.2.0"
611 | resolved "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e"
612 | integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==
613 |
614 | vue-demi@*:
615 | version "0.13.6"
616 | resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.6.tgz#f9433cbd75e68a970dec066647f4ba6c08ced48f"
617 | integrity sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==
618 |
619 | vue@^3.2.33, vue@^3.2.37:
620 | version "3.2.37"
621 | resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
622 | integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==
623 | dependencies:
624 | "@vue/compiler-dom" "3.2.37"
625 | "@vue/compiler-sfc" "3.2.37"
626 | "@vue/runtime-dom" "3.2.37"
627 | "@vue/server-renderer" "3.2.37"
628 | "@vue/shared" "3.2.37"
629 |
--------------------------------------------------------------------------------