Better m3 init

This commit is contained in:
Dinhero21 2024-09-11 20:16:29 -03:00
parent 9647a00fac
commit 48b0615aaa
3 changed files with 114 additions and 8 deletions

View file

@ -1,6 +1,6 @@
<!-- <!--
I probably won't actually make this into its own repo I probably won't actually make this into its own repo.
don't think that because there is a README.md file, Don't think that because there is a README.md file,
it's its own git repo. it's its own git repo.
--> -->

View file

@ -1,6 +1,6 @@
import { confirm, input } from '@inquirer/prompts'; import { confirm, input } from '@inquirer/prompts';
import { Argument } from 'commander'; import { Argument } from 'commander';
import { mkdir, readFile, writeFile } from 'fs/promises'; import { cp, mkdir, readFile, writeFile } from 'fs/promises';
import type { ListrTask } from 'listr2'; import type { ListrTask } from 'listr2';
import { Listr } from 'listr2'; import { Listr } from 'listr2';
import { resolve } from 'path'; import { resolve } from 'path';
@ -19,13 +19,21 @@ import {
program program
.command('init') .command('init')
.description('Initialize a new module') .description('Initialize a new module')
.option('-f, --override', 'Overwrite existing module')
.addArgument(new Argument('[name]', 'Name of the module').default(moduleDir)) .addArgument(new Argument('[name]', 'Name of the module').default(moduleDir))
.option('--author <author>', 'Author of the module') .option('--author <author>', 'Author of the module')
.option('--license <license>', 'License of the module') .option('--license <license>', 'License of the module')
.option('--description <description>', 'Description of the module') .option('--description <description>', 'Description of the module')
.option('-f, --override', 'Overwrite existing module')
.option('--git', 'Create a git repository') .option('--git', 'Create a git repository')
.option('--npm', 'Create a package.json file') .option('--npm', 'Create a package.json file')
.option('--gitattributes', 'Create a .gitattributes file')
.option('--gitignore', 'Create a .gitignore file')
.option('--readme', 'Create a README.md file')
.action( .action(
async ( async (
name: string | undefined, name: string | undefined,
@ -38,6 +46,10 @@ program
git?: boolean; git?: boolean;
npm?: boolean; npm?: boolean;
gitattributes?: boolean;
gitignore?: boolean;
readme?: boolean;
}, },
) => { ) => {
const override = options.override ?? false; const override = options.override ?? false;
@ -77,6 +89,25 @@ program
default: true, default: true,
})); }));
const gitattributes =
options.gitattributes ??
(await confirm({
message: 'Create a .gitattributes file?',
default: true,
}));
const gitignore =
options.gitignore ??
(await confirm({
message: 'Create a .gitignore file?',
default: true,
}));
const readme =
options.readme ??
(await confirm({
message: 'Create a README.md file?',
default: true,
}));
await init({ await init({
override, override,
@ -88,6 +119,10 @@ program
git, git,
npm, npm,
m3: true, m3: true,
gitattributes,
gitignore,
readme,
}); });
}, },
); );
@ -103,6 +138,10 @@ interface InitOptions {
git: boolean; git: boolean;
npm: boolean; npm: boolean;
m3: boolean; m3: boolean;
gitattributes: boolean;
gitignore: boolean;
readme: boolean;
} }
async function init(options: InitOptions): Promise<void> { async function init(options: InitOptions): Promise<void> {
@ -120,11 +159,13 @@ async function init(options: InitOptions): Promise<void> {
tasks.push({ tasks.push({
title: 'Initialize git', title: 'Initialize git',
task: async (_ctx, task) => { task: async (_ctx, task) => {
const stdout = task.stdout() as Writable;
await run( await run(
'git', 'git',
['init', '--initial-branch=main'], ['init', '--initial-branch=main'],
{ cwd: directory }, { cwd: directory },
{ stdout: task.stdout() as Writable }, { stdout, stderr: stdout },
); );
}, },
}); });
@ -134,11 +175,13 @@ async function init(options: InitOptions): Promise<void> {
tasks.push({ tasks.push({
title: 'Initialize npm', title: 'Initialize npm',
task: async (_ctx, task) => { task: async (_ctx, task) => {
const stdout = task.stdout() as Writable;
await run( await run(
'npm', 'npm',
['init', '-y'], ['init', '-y'],
{ cwd: directory }, { cwd: directory },
{ stdout: task.stdout() as Writable }, { stdout, stderr: stdout },
); );
task.output = 'reading file...'; task.output = 'reading file...';
@ -193,8 +236,65 @@ async function init(options: InitOptions): Promise<void> {
}); });
} }
// <repo>/src/modules/ <--
const mmpDir = resolve(modulesDir, '../..');
if (options.gitattributes) {
tasks.push({
title: 'Create .gitattributes',
task: async () => {
await cp(
resolve(mmpDir, '.gitattributes'),
resolve(directory, '.gitattributes'),
);
},
});
}
if (options.gitignore) {
tasks.push({
title: 'Create .gitignore',
task: async (_ctx, task) => {
task.output = 'Fetching .gitignore... (awaiting response)';
const response = await fetch(
'https://raw.githubusercontent.com/github/gitignore/master/Node.gitignore',
);
task.output = 'Fetching .gitignore... (awaiting text)';
let gitignore = await response.text();
// I personally do not like how Prettier un-inlined
// this but don't know an easy way to change it
gitignore += ['', '# M3', 'm3.local.json', ''].join('\n');
task.output = 'Writing file...';
await writeFile(resolve(directory, '.gitignore'), gitignore);
},
});
}
if (options.readme) {
tasks.push({
title: 'Create README.md',
task: async () => {
const readmeName = options.name.split('.').pop()!;
const readme = [
`# ${readmeName}`,
'',
'This is an [MMP](https://github.com/DinheroDevelopmentGroup/modular-minecraft-proxy) module.',
'Generated using [M3](https://github.com/DinheroDevelopmentGroup/modular-minecraft-proxy/tree/main/src/m3) init.',
'',
].join('\n');
await writeFile(resolve(directory, 'README.md'), readme);
},
});
}
await new Listr(tasks, { await new Listr(tasks, {
concurrent: true, concurrent: true,
exitOnError: false, exitOnError: false,
collectErrors: 'minimal',
}).run(); }).run();
} }

View file

@ -2,18 +2,24 @@ import type { ChildProcess, SpawnOptions } from 'child_process';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import type { Readable, Writable } from 'stream'; import type { Readable, Writable } from 'stream';
export interface Stdio {
stdin?: Readable;
stdout?: Writable;
stderr?: Writable;
}
export async function run( export async function run(
command: string, command: string,
args: string[], args: string[],
options: SpawnOptions, options: SpawnOptions,
stdio?: { stdin?: Readable; stdout?: Writable; stderr?: Writable }, stdio?: Stdio,
): Promise<ChildProcess> { ): Promise<ChildProcess> {
const child = spawn(command, args, options); const child = spawn(command, args, options);
if (stdio !== undefined) { if (stdio !== undefined) {
if (child.stdin !== null) stdio.stdin?.pipe(child.stdin); if (child.stdin !== null) stdio.stdin?.pipe(child.stdin);
if (stdio.stdout !== undefined) child.stdout?.pipe(stdio.stdout); if (stdio.stdout !== undefined) child.stdout?.pipe(stdio.stdout);
if (stdio.stderr !== null) stdio.stderr?.pipe(stdio.stderr); if (stdio.stderr !== undefined) child.stderr?.pipe(stdio.stderr);
} }
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {