Skip to content

Commit

Permalink
feat: Add build run fs utils
Browse files Browse the repository at this point in the history
  • Loading branch information
3y3 committed Dec 5, 2024
1 parent b9b90c6 commit ecff64a
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 34 deletions.
10 changes: 10 additions & 0 deletions src/commands/build/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ var resolveConfig: Mock;

vi.mock('shelljs');
vi.mock('../handler');
vi.mock('../run', async (importOriginal) => {
return {
...((await importOriginal()) as {}),
copy: vi.fn(),
};
});
vi.mock('~/config', async (importOriginal) => {
resolveConfig = vi.fn((_path, {defaults, fallback}) => {
return defaults || fallback;
Expand All @@ -28,6 +34,10 @@ export async function runBuild(args: string) {
const build = new Build();

build.apply();
build.hooks.BeforeAnyRun.tap('Tests', (run) => {
run.copy = vi.fn();
run.write = vi.fn();
});

await build.parse(['node', 'index'].concat(args.split(' ')));
}
Expand Down
25 changes: 0 additions & 25 deletions src/commands/build/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import type {Run} from './run';

import 'threads/register';

import glob from 'glob';
import shell from 'shelljs';

import OpenapiIncluder from '@diplodoc/openapi-extension/includer';

import {ArgvService, Includers, SearchService} from '~/services';
Expand All @@ -19,13 +16,8 @@ import {
processServiceFiles,
} from '~/steps';
import {prepareMapFile} from '~/steps/processMapFile';
import {copyFiles} from '~/utils';

export async function handler(run: Run) {
if (typeof VERSION !== 'undefined') {
console.log(`Using v${VERSION} version`);
}

try {
ArgvService.init(run.legacyConfig);
SearchService.init();
Expand All @@ -35,8 +27,6 @@ export async function handler(run: Run) {

const {lintDisabled, buildDisabled, addMapFile} = ArgvService.getConfig();

preparingTemporaryFolders(run);

await processServiceFiles();
processExcludedFiles();

Expand Down Expand Up @@ -72,18 +62,3 @@ export async function handler(run: Run) {
processLogs(run.input);
}
}

function preparingTemporaryFolders(run: Run) {
copyFiles(
run.originalInput,
run.input,
glob.sync('**', {
cwd: run.originalInput,
nodir: true,
follow: true,
ignore: ['node_modules/**', '*/node_modules/**'],
}),
);

shell.chmod('-R', 'u+w', run.input);
}
17 changes: 9 additions & 8 deletions src/commands/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {DocAnalytics} from '@diplodoc/client';

import {ok} from 'node:assert';
import {join} from 'node:path';
import glob from 'glob';
import {pick} from 'lodash';
import {AsyncParallelHook, AsyncSeriesHook, HookMap} from 'tapable';

Expand Down Expand Up @@ -270,6 +269,10 @@ export class Build
}

async action() {
if (typeof VERSION !== 'undefined') {
console.log(`Using v${VERSION} version`);
}

const run = new Run(this.config);

run.logger.pipe(this.logger);
Expand All @@ -280,17 +283,15 @@ export class Build

await this.hooks.BeforeAnyRun.promise(run);
await this.hooks.BeforeRun.for(this.config.outputFormat).promise(run);

await run.copy(run.originalInput, run.input, ['node_modules/**', '*/node_modules/**']);

await Promise.all([handler(run), this.hooks.Run.promise(run)]);

await this.hooks.AfterRun.for(this.config.outputFormat).promise(run);
await this.hooks.AfterAnyRun.promise(run);

// Copy all generated files to user' output folder
shell.mkdir('-p', run.originalOutput);
shell.cp('-r', join(run.output, '*'), run.originalOutput);

if (glob.sync('.*', {cwd: run.output}).length) {
shell.cp('-r', join(run.output, '.*'), run.originalOutput);
}
await run.copy(run.output, run.originalOutput);

shell.rm('-rf', run.input, run.output);
}
Expand Down
78 changes: 77 additions & 1 deletion src/commands/build/run.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type {YfmArgv} from '~/models';

import {join, resolve} from 'path';
// import {ok} from 'node:assert';
import {dirname, join, resolve} from 'node:path';
import {access, link, mkdir, readFile, stat, unlink, writeFile} from 'node:fs/promises';
import {glob} from 'glob';

import {configPath} from '~/config';
import {
BUNDLE_FOLDER,
Expand All @@ -11,6 +15,17 @@ import {
} from '~/constants';
import {Logger} from '~/logger';
import {BuildConfig} from '.';
// import {InsecureAccessError} from './errors';

type FileSystem = {
access: typeof access;
stat: typeof stat;
link: typeof link;
unlink: typeof unlink;
mkdir: typeof mkdir;
readFile: typeof readFile;
writeFile: typeof writeFile;
};

/**
* This is transferable context for build command.
Expand All @@ -31,6 +46,8 @@ export class Run {

readonly config: BuildConfig;

readonly fs: FileSystem = {access, stat, link, unlink, mkdir, readFile, writeFile};

get bundlePath() {
return join(this.output, BUNDLE_FOLDER);
}
Expand All @@ -43,6 +60,8 @@ export class Run {
return join(this.originalInput, REDIRECTS_FILENAME);
}

private _copyMap: Record<AbsolutePath, AbsolutePath> = {};

constructor(config: BuildConfig) {
this.config = config;
this.originalInput = config.input;
Expand Down Expand Up @@ -105,4 +124,61 @@ export class Run {
(_level, message) => message.replace(new RegExp(this.input, 'ig'), ''),
]);
}

write = async (path: AbsolutePath, content: string | Buffer) => {
await this.fs.mkdir(dirname(path), {recursive: true});
await this.fs.writeFile(path, content, 'utf8');
};

copy = async (from: AbsolutePath, to: AbsolutePath, ignore?: string[]) => {
const isFile = (await this.fs.stat(from)).isFile();
const hardlink = async (from: AbsolutePath, to: AbsolutePath) => {
// const realpath = this.realpath(from);
//
// ok(
// realpath[0].startsWith(this.originalInput),
// new InsecureAccessError(realpath[0], realpath),
// );

await this.fs.unlink(to).catch(() => {});
await this.fs.link(from, to);
this._copyMap[to] = from;
};

if (isFile) {
await this.fs.mkdir(dirname(to), {recursive: true});
await hardlink(from, to);

return;
}

const dirs = new Set();
// TODO: check dotfiles copy
const files = (await glob('*/**', {
cwd: from,
nodir: true,
follow: true,
ignore,
})) as RelativePath[];

for (const file of files) {
const dir = join(to, dirname(file));
if (!dirs.has(dir)) {
await this.fs.mkdir(dir, {recursive: true});
dirs.add(dir);
}

await hardlink(join(from, file), join(to, file));
}
};

realpath = (path: AbsolutePath): AbsolutePath[] => {
const stack = [path];
while (this._copyMap[path]) {
path = this._copyMap[path];
stack.unshift(path);
}

return stack;
};
}

0 comments on commit ecff64a

Please sign in to comment.