Cleanup
This commit is contained in:
parent
81037f8ac5
commit
7a07cada25
@ -40,6 +40,8 @@ public partial class MycroForge
|
||||
|
||||
private async Task ExecuteAsync(string name)
|
||||
{
|
||||
_context.AssertDirectoryExists("api/routers");
|
||||
|
||||
var moduleName = name.Underscore();
|
||||
await _context.CreateFile($"api/routers/{moduleName}.py", Template);
|
||||
|
||||
|
66
MycroForge.CLI/Commands/MycroForge.Generate.Service.cs
Normal file
66
MycroForge.CLI/Commands/MycroForge.Generate.Service.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System.CommandLine;
|
||||
using Humanizer;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
public partial class MycroForge
|
||||
{
|
||||
public partial class Generate
|
||||
{
|
||||
public class Service : Command, ISubCommandOf<Generate>
|
||||
{
|
||||
private static readonly Argument<string> NameArgument =
|
||||
new(name: "name", description: "The name of the service");
|
||||
|
||||
private static readonly Option<bool> WithSession =
|
||||
new(name: "--with-session", description: "Create a service that uses database sessions");
|
||||
|
||||
|
||||
private static readonly string[] DefaultTemplate =
|
||||
[
|
||||
"class %class_name%:",
|
||||
"",
|
||||
"\tdef do_stuff(self, stuff: str) -> str:",
|
||||
"\t\treturn f\"Hey, I'm doing stuff!\""
|
||||
];
|
||||
|
||||
private static readonly string[] WithSessionTemplate =
|
||||
[
|
||||
"from orm.engine.async_session import async_session",
|
||||
"# from orm.entities.user import User",
|
||||
"",
|
||||
"class %class_name%:",
|
||||
"",
|
||||
"\tasync def do_stuff(self, stuff: str) -> str:",
|
||||
"\t\tasync with async_session() as session():",
|
||||
"\t\t\t# stmt = select(User).where(User.firstname == \"John\")",
|
||||
"\t\t\t# results = await session.scalars(stmt).all()",
|
||||
"\t\t\t# print(len(results))",
|
||||
"\t\t\tpass",
|
||||
"\t\treturn f\"Hey, I'm doing stuff!\""
|
||||
];
|
||||
|
||||
private readonly ProjectContext _context;
|
||||
|
||||
public Service(ProjectContext context) : base("service", "Generate a service")
|
||||
{
|
||||
_context = context;
|
||||
AddAlias("s");
|
||||
AddOption(WithSession);
|
||||
this.SetHandler(ExecuteAsync, NameArgument, WithSession);
|
||||
}
|
||||
|
||||
private async Task ExecuteAsync(string name, bool withSession)
|
||||
{
|
||||
_context.AssertDirectoryExists("services");
|
||||
|
||||
var className = Path.GetFileName(name).Pascalize();
|
||||
var code = string.Join('\n', withSession ? WithSessionTemplate : DefaultTemplate)
|
||||
.Replace("%class_name%", className);
|
||||
|
||||
await _context.CreateFile($"services/{name.Underscore().ToLower()}.py", code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
MycroForge.CLI/Commands/MycroForge.Generate.Venv.cs
Normal file
23
MycroForge.CLI/Commands/MycroForge.Generate.Venv.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System.CommandLine;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
public partial class MycroForge
|
||||
{
|
||||
public partial class Generate
|
||||
{
|
||||
public class Venv : Command, ISubCommandOf<Generate>
|
||||
{
|
||||
private readonly ProjectContext _context;
|
||||
|
||||
public Venv(ProjectContext context) : base("venv", "Generate a venv")
|
||||
{
|
||||
_context = context;
|
||||
this.SetHandler(ExecuteAsync);
|
||||
}
|
||||
|
||||
private async Task ExecuteAsync() => await _context.Bash("python3 -m venv .venv");
|
||||
}
|
||||
}
|
||||
}
|
18
MycroForge.CLI/Commands/MycroForge.Generate.cs
Normal file
18
MycroForge.CLI/Commands/MycroForge.Generate.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.CommandLine;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
public partial class MycroForge
|
||||
{
|
||||
public partial class Generate : Command, ISubCommandOf<MycroForge>
|
||||
{
|
||||
public Generate(IEnumerable<ISubCommandOf<Generate>> commands)
|
||||
: base("generate", "Generate common items")
|
||||
{
|
||||
AddAlias("g");
|
||||
foreach (var command in commands.Cast<Command>())
|
||||
AddCommand(command);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,53 @@ namespace MycroForge.CLI.Commands;
|
||||
|
||||
public partial class MycroForge
|
||||
{
|
||||
#region GitIgnore
|
||||
|
||||
private static readonly string[] GitIgnore =
|
||||
[
|
||||
"# Byte-compiled / optimized / DLL files", "__pycache__/", "*.py[cod]", "*$py.class", "# C extensions",
|
||||
"*.so", "# Distribution / packaging", ".Python", "build/", "develop-eggs/", "dist/", "downloads/", "eggs/",
|
||||
".eggs/", "lib/", "lib64/", "parts/", "sdist/", "var/", "wheels/", "share/python-wheels/", "*.egg-info/",
|
||||
".installed.cfg", "*.egg", "MANIFEST", "# PyInstaller",
|
||||
"# Usually these files are written by a python script from a template",
|
||||
"# before PyInstaller builds the exe, so as to inject date/other infos into it.", "*.manifest", "*.spec",
|
||||
"# Installer logs", "pip-log.txt", "pip-delete-this-directory.txt", "# Unit test / coverage reports",
|
||||
"htmlcov/", ".tox/", ".nox/", ".coverage", ".coverage.*", ".cache", "nosetests.xml", "coverage.xml",
|
||||
"*.cover", "*.py,cover", ".hypothesis/", ".pytest_cache/", "cover/", "# Translations", "*.mo", "*.pot",
|
||||
"# Django stuff:", "*.log", "local_settings.py", "db.sqlite3", "db.sqlite3-journal", "# Flask stuff:",
|
||||
"instance/", ".webassets-cache", "# Scrapy stuff:", ".scrapy", "# Sphinx documentation", "docs/_build/",
|
||||
"# PyBuilder", ".pybuilder/", "target/", "# Jupyter Notebook", ".ipynb_checkpoints", "# IPython",
|
||||
"profile_default/", "ipython_config.py", "# pyenv",
|
||||
"# For a library or package, you might want to ignore these files since the code is",
|
||||
"# intended to run in multiple environments; otherwise, check them in:", "# .python-version", "# pipenv",
|
||||
"# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.",
|
||||
"# However, in case of collaboration, if having platform-specific dependencies or dependencies",
|
||||
"# having no cross-platform support, pipenv may install dependencies that don't work, or not",
|
||||
"# install all needed dependencies.", "#Pipfile.lock", "# poetry",
|
||||
"# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.",
|
||||
"# This is especially recommended for binary packages to ensure reproducibility, and is more",
|
||||
"# commonly ignored for libraries.",
|
||||
"# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control",
|
||||
"#poetry.lock", "# pdm",
|
||||
"# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.",
|
||||
"#pdm.lock",
|
||||
"# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it",
|
||||
"# in version control.", "# https://pdm.fming.dev/#use-with-ide", ".pdm.toml",
|
||||
"# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm", "__pypackages__/",
|
||||
"# Celery stuff", "celerybeat-schedule", "celerybeat.pid", "# SageMath parsed files", "*.sage.py",
|
||||
"# Environments", ".env", ".venv", "env/", "venv/", "ENV/", "env.bak/", "venv.bak/",
|
||||
"# Spyder project settings", ".spyderproject", ".spyproject", "# Rope project settings", ".ropeproject",
|
||||
"# mkdocs documentation", "/site", "# mypy", ".mypy_cache/", ".dmypy.json", "dmypy.json",
|
||||
"# Pyre type checker", ".pyre/", "# pytype static type analyzer", ".pytype/", "# Cython debug symbols",
|
||||
"cython_debug/", "# PyCharm",
|
||||
"# JetBrains specific template is maintained in a separate JetBrains.gitignore that can",
|
||||
"# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore",
|
||||
"# and can be added to the global gitignore or merged into this file. For a more nuclear",
|
||||
"# option (not recommended) you can uncomment the following to ignore the entire idea folder.", "#.idea/"
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
public class Init : Command, ISubCommandOf<MycroForge>
|
||||
{
|
||||
private static readonly string[] DefaultFeatures =
|
||||
@ -20,7 +67,9 @@ public partial class MycroForge
|
||||
|
||||
private static readonly Option<IEnumerable<string>> WithoutOption =
|
||||
new Option<IEnumerable<string>>(name: "--without", description: "Features to exclude")
|
||||
.FromAmong(DefaultFeatures);
|
||||
{
|
||||
AllowMultipleArgumentsPerToken = true
|
||||
}.FromAmong(DefaultFeatures);
|
||||
|
||||
private readonly ProjectContext _context;
|
||||
private readonly List<IFeature> _features;
|
||||
@ -54,6 +103,9 @@ public partial class MycroForge
|
||||
// Create the entrypoint file
|
||||
await _context.CreateFile("main.py");
|
||||
|
||||
// Create the default .gitignore folder
|
||||
await _context.CreateFile(".gitignore", GitIgnore);
|
||||
|
||||
// Create the venv
|
||||
await _context.Bash($"python3 -m venv {Path.Combine(projectRoot, ".venv")}");
|
||||
|
||||
|
@ -43,6 +43,8 @@ public partial class MycroForge
|
||||
|
||||
private async Task ExecuteAsync(string name)
|
||||
{
|
||||
_context.AssertDirectoryExists("orm");
|
||||
|
||||
var className = name.Underscore().Pascalize();
|
||||
var moduleName = name.Underscore();
|
||||
var code = string.Join('\n', Template);
|
||||
|
@ -26,6 +26,8 @@ public partial class MycroForge
|
||||
|
||||
private async Task ExecuteAsync(string name)
|
||||
{
|
||||
_context.AssertDirectoryExists("orm/versions");
|
||||
|
||||
await _context.Bash(
|
||||
"source .venv/bin/activate",
|
||||
$"alembic revision --autogenerate -m \"{name}\" --rev-id $(date -u +\"%Y%m%d%H%M%S\")"
|
||||
|
@ -24,6 +24,11 @@ public static class ServiceCollectionExtensions
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge>, Commands.MycroForge.Install>();
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge>, Commands.MycroForge.Uninstall>();
|
||||
|
||||
// Register "m4g generate"
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge>, Commands.MycroForge.Generate>();
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge.Generate>, Commands.MycroForge.Generate.Service>();
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge.Generate>, Commands.MycroForge.Generate.Venv>();
|
||||
|
||||
// Register "m4g api"
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge>, Commands.MycroForge.Api>();
|
||||
services.AddScoped<ISubCommandOf<Commands.MycroForge.Api>, Commands.MycroForge.Api.Run>();
|
||||
|
13
MycroForge.CLI/Extensions/StringExtensions.cs
Normal file
13
MycroForge.CLI/Extensions/StringExtensions.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Humanizer;
|
||||
|
||||
namespace MycroForge.CLI.Extensions;
|
||||
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string NormalizePath(this string name)
|
||||
{
|
||||
var directoryPath = Path.GetDirectoryName(name).Underscore();
|
||||
var filePath = Path.Join(directoryPath, name.Underscore().ToLower());
|
||||
return filePath;
|
||||
}
|
||||
}
|
@ -36,12 +36,6 @@ public sealed class Api : IFeature
|
||||
{
|
||||
var config = await context.LoadConfig();
|
||||
|
||||
if (config.Features.Contains(FeatureName))
|
||||
{
|
||||
Console.WriteLine($"Feature {FeatureName} has already been initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.Bash(
|
||||
"source .venv/bin/activate",
|
||||
"python3 -m pip install fastapi uvicorn[standard]",
|
||||
@ -54,8 +48,11 @@ public sealed class Api : IFeature
|
||||
main = string.Join('\n', Main) + main;
|
||||
await context.WriteFile("main.py", main);
|
||||
|
||||
config.Features.Add(FeatureName);
|
||||
|
||||
config.Api = new()
|
||||
{
|
||||
Port = 8000
|
||||
};
|
||||
|
||||
await context.SaveConfig(config);
|
||||
}
|
||||
}
|
@ -2,59 +2,11 @@ namespace MycroForge.CLI.Features;
|
||||
|
||||
public class Git : IFeature
|
||||
{
|
||||
#region GitIgnore
|
||||
|
||||
private static readonly string[] GitIgnore =
|
||||
[
|
||||
"# Byte-compiled / optimized / DLL files", "__pycache__/", "*.py[cod]", "*$py.class", "# C extensions",
|
||||
"*.so", "# Distribution / packaging", ".Python", "build/", "develop-eggs/", "dist/", "downloads/", "eggs/",
|
||||
".eggs/", "lib/", "lib64/", "parts/", "sdist/", "var/", "wheels/", "share/python-wheels/", "*.egg-info/",
|
||||
".installed.cfg", "*.egg", "MANIFEST", "# PyInstaller",
|
||||
"# Usually these files are written by a python script from a template",
|
||||
"# before PyInstaller builds the exe, so as to inject date/other infos into it.", "*.manifest", "*.spec",
|
||||
"# Installer logs", "pip-log.txt", "pip-delete-this-directory.txt", "# Unit test / coverage reports",
|
||||
"htmlcov/", ".tox/", ".nox/", ".coverage", ".coverage.*", ".cache", "nosetests.xml", "coverage.xml",
|
||||
"*.cover", "*.py,cover", ".hypothesis/", ".pytest_cache/", "cover/", "# Translations", "*.mo", "*.pot",
|
||||
"# Django stuff:", "*.log", "local_settings.py", "db.sqlite3", "db.sqlite3-journal", "# Flask stuff:",
|
||||
"instance/", ".webassets-cache", "# Scrapy stuff:", ".scrapy", "# Sphinx documentation", "docs/_build/",
|
||||
"# PyBuilder", ".pybuilder/", "target/", "# Jupyter Notebook", ".ipynb_checkpoints", "# IPython",
|
||||
"profile_default/", "ipython_config.py", "# pyenv",
|
||||
"# For a library or package, you might want to ignore these files since the code is",
|
||||
"# intended to run in multiple environments; otherwise, check them in:", "# .python-version", "# pipenv",
|
||||
"# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.",
|
||||
"# However, in case of collaboration, if having platform-specific dependencies or dependencies",
|
||||
"# having no cross-platform support, pipenv may install dependencies that don't work, or not",
|
||||
"# install all needed dependencies.", "#Pipfile.lock", "# poetry",
|
||||
"# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.",
|
||||
"# This is especially recommended for binary packages to ensure reproducibility, and is more",
|
||||
"# commonly ignored for libraries.",
|
||||
"# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control",
|
||||
"#poetry.lock", "# pdm",
|
||||
"# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.",
|
||||
"#pdm.lock",
|
||||
"# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it",
|
||||
"# in version control.", "# https://pdm.fming.dev/#use-with-ide", ".pdm.toml",
|
||||
"# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm", "__pypackages__/",
|
||||
"# Celery stuff", "celerybeat-schedule", "celerybeat.pid", "# SageMath parsed files", "*.sage.py",
|
||||
"# Environments", ".env", ".venv", "env/", "venv/", "ENV/", "env.bak/", "venv.bak/",
|
||||
"# Spyder project settings", ".spyderproject", ".spyproject", "# Rope project settings", ".ropeproject",
|
||||
"# mkdocs documentation", "/site", "# mypy", ".mypy_cache/", ".dmypy.json", "dmypy.json",
|
||||
"# Pyre type checker", ".pyre/", "# pytype static type analyzer", ".pytype/", "# Cython debug symbols",
|
||||
"cython_debug/", "# PyCharm",
|
||||
"# JetBrains specific template is maintained in a separate JetBrains.gitignore that can",
|
||||
"# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore",
|
||||
"# and can be added to the global gitignore or merged into this file. For a more nuclear",
|
||||
"# option (not recommended) you can uncomment the following to ignore the entire idea folder.", "#.idea/"
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
public const string FeatureName = "git";
|
||||
public string Name => FeatureName;
|
||||
|
||||
public async Task ExecuteAsync(ProjectContext context)
|
||||
{
|
||||
await context.CreateFile(".gitignore", GitIgnore);
|
||||
await context.Bash($"git -c init.defaultBranch=main init {context.RootDirectory}");
|
||||
}
|
||||
}
|
@ -60,12 +60,6 @@ public sealed class Orm : IFeature
|
||||
{
|
||||
var config = await context.LoadConfig();
|
||||
|
||||
if (config.Features.Contains(FeatureName))
|
||||
{
|
||||
Console.WriteLine($"Feature {FeatureName} has already been initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.Bash(
|
||||
"source .venv/bin/activate",
|
||||
"python3 -m pip install asyncmy sqlalchemy alembic",
|
||||
@ -86,8 +80,6 @@ public sealed class Orm : IFeature
|
||||
|
||||
await context.CreateFile("orm/entities/user.py", User);
|
||||
|
||||
config.Features.Add(FeatureName);
|
||||
|
||||
await context.SaveConfig(config);
|
||||
}
|
||||
}
|
@ -15,7 +15,8 @@ using var host = Host
|
||||
|
||||
try
|
||||
{
|
||||
await host.Services.GetRequiredService<MycroForge.CLI.Commands.MycroForge>().InvokeAsync(args);
|
||||
await host.Services.GetRequiredService<MycroForge.CLI.Commands.MycroForge>()
|
||||
.InvokeAsync(args.Length == 0 ? ["--help"] : args);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
9
MycroForge.CLI/ProjectConfig.ApiConfig.cs
Normal file
9
MycroForge.CLI/ProjectConfig.ApiConfig.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace MycroForge.CLI;
|
||||
|
||||
public partial class ProjectConfig
|
||||
{
|
||||
public class ApiConfig
|
||||
{
|
||||
public int Port { get; set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
namespace MycroForge.CLI;
|
||||
|
||||
public class ProjectConfig
|
||||
public partial class ProjectConfig
|
||||
{
|
||||
public List<string> Features { get; set; } = new();
|
||||
public ApiConfig Api { get; set; } = default!;
|
||||
}
|
@ -32,6 +32,18 @@ public class ProjectContext
|
||||
RootDirectory = path;
|
||||
}
|
||||
|
||||
public void AssertDirectoryExists(string path)
|
||||
{
|
||||
var fullPath = Path.Combine(RootDirectory, path);
|
||||
|
||||
if (Directory.Exists(fullPath))
|
||||
{
|
||||
throw new(string.Join('\n',
|
||||
$"{path} does not exist, make sure your in the correct directory."
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateFile(string path, params string[] content)
|
||||
{
|
||||
var fullPath = Path.Combine(RootDirectory, path);
|
||||
|
@ -1,6 +1,11 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Make sure to run this script form the MyrcoForge.CLI directory with sudo!
|
||||
# Make sure to run this script from the MycroForge.CLI directory and prefixed with sudo!
|
||||
# Example:
|
||||
# sudo ./scripts/publish-linux.sh
|
||||
|
||||
dotnet publish --self-contained -r linux-x64
|
||||
sudo cp bin/Release/net8.0/linux-x64 /usr/share/m4g
|
||||
sudo ln -s /usr/share/m4g/MycroForge.CLI /usr/bin/local/m4g
|
||||
sudo rm -rf /usr/share/m4g
|
||||
sudo cp -r bin/Release/net8.0/linux-x64 /usr/share/m4g
|
||||
sudo unlink /usr/local/bin/m4g
|
||||
sudo ln -s /usr/share/m4g/MycroForge.CLI /usr/local/bin/m4g
|
||||
|
Loading…
Reference in New Issue
Block a user