Skip to content

Commit

Permalink
APPS-7 : Automatically detect package manager and install dependencie…
Browse files Browse the repository at this point in the history
…s on init (#72)
  • Loading branch information
achaaoui-yc authored Nov 21, 2024
1 parent 351f080 commit 7c3487a
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 12 deletions.
25 changes: 25 additions & 0 deletions packages/cli-kit/lib/node/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function buildExec(command: string, args: string[], options?: ExecOptions): Exec

export async function exec(command: string, args: string[], options?: ExecOptions): Promise<void> {
const commandProcess = buildExec(command, args, options);

if (options?.stderr && options.stderr !== 'inherit') {
commandProcess.stderr?.pipe(options.stderr, { end: false });
}
Expand Down Expand Up @@ -90,3 +91,27 @@ export async function open(url: string): Promise<void> {

await _open.default(url);
}

export type PackageManagerType =
| 'pnpm'
| 'npm'
| 'yarn';

export function inferUserPackageManager(): PackageManagerType {
const defaultPackageManager = 'npm';
const packageManagersMap: Record<string, PackageManagerType> = {
'^npm/.*': 'npm',
'^pnpm/.*': 'pnpm',
'^yarn/.*': 'yarn',
};

const packageManagerUserAgent = process.env.npm_config_user_agent as string;

for (const key in packageManagersMap) {
if (new RegExp(key).test(packageManagerUserAgent)) {
return packageManagersMap[key];
}
}

return defaultPackageManager;
}
27 changes: 19 additions & 8 deletions packages/cli-kit/lib/node/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface Task<T = unknown> {
errors?: Error[]
skip?: (ctx: T) => boolean
task: (context: T, task: Task<T>) => Promise<void | Task<T>[]>
loadable?: false
}

async function runTask<T>(task: Task<T>, ctx: T) {
Expand All @@ -16,18 +17,28 @@ async function runTask<T>(task: Task<T>, ctx: T) {
return await task.task(ctx, task);
}

export async function run<T = unknown>(ctx: T, tasks: Task<T>[]) {
export async function run<T = unknown>(ctx: T, tasks: Task<T>[]): Promise<T> {
for await (const task of tasks) {
await Loader.exec(task.title, async (loader) => {
try {
const subtasks = await runTask<T>(task, ctx);
const runner = async () => {
const subtasks = await runTask<T>(task, ctx);

if (Array.isArray(subtasks) && subtasks.length > 0 && subtasks.every(t => 'task' in t)) {
for await (const subtask of subtasks) {
await runTask(subtask, ctx);
}
if (Array.isArray(subtasks) && subtasks.length > 0 && subtasks.every(t => 'task' in t)) {
for await (const subtask of subtasks) {
await runTask(subtask, ctx);
}
}
};

if (task.loadable === false) {
process.stdout.write(`${task.title}\n`);
await runner();

return ctx;
}

await Loader.exec(task.title, async (loader) => {
try {
await runner();
loader.stop();
}
catch (err) {
Expand Down
3 changes: 2 additions & 1 deletion packages/create-app/lib/commands/init.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cwd } from 'process';
import { Flags } from '@oclif/core';
import { Cli, Path } from '@youcan/cli-kit';
import { Cli, Path, System } from '@youcan/cli-kit';
import initPrompt from '@/prompts/init';
import initService from '@/services/init';

Expand Down Expand Up @@ -35,6 +35,7 @@ export default class Init extends Cli.Command {
name: response.name,
directory: flags.path,
template: response.template,
packageManager: System.inferUserPackageManager(),
});
}
}
23 changes: 20 additions & 3 deletions packages/create-app/lib/services/init.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import path from 'path';
import type { Cli } from '@youcan/cli-kit';
import { Filesystem, Git, Github, Path, String, Tasks } from '@youcan/cli-kit';
import { Filesystem, Git, Github, Path, String, System, Tasks } from '@youcan/cli-kit';
import type { inferUserPackageManager } from '@youcan/cli-kit/dist/node/system';

interface InitServiceOptions {
name: string
directory: string
template?: string
packageManager: ReturnType<typeof inferUserPackageManager>
}

async function initService(command: Cli.Command, options: InitServiceOptions) {
const slug = String.hyphenate(options.name);
const outdir = Path.join(options.directory, slug);
const relativeOutdir = path.relative(process.cwd(), outdir);

await assertDirectoryAvailability(outdir, slug);

Expand Down Expand Up @@ -48,18 +52,31 @@ async function initService(command: Cli.Command, options: InitServiceOptions) {
},
},
{
title: `Copying files to ${outdir}...`,
title: `Copying files to ${relativeOutdir}...`,
task: async () => {
await Filesystem.move(templateDownloadDirectory, outdir);
},
},
{
title: 'Installing dependencies...',
loadable: false,
task: async () => {
await System.exec(options.packageManager, ['install'], {
stdout: 'inherit',
stderr: 'inherit',
cwd: outdir,
});
},
},
]);
});

command.output.info(`${slug} is ready for your to develop! Head to the docs for more information`);
command.output.info(' Developer Docs: https://developer.youcan.shop\n\n');

command.output.info(' To preview your app, run `pnpm dev`');
command.output.info(' To preview your app, run');
command.output.info(` cd ${relativeOutdir}`);
command.output.info(` ${options.packageManager} dev`);
command.output.info(' For an overview of all the command, run `pnpm youcan app help`');
}

Expand Down

0 comments on commit 7c3487a

Please sign in to comment.