mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fix: Implement controlled end of script in happy case
Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
parent
c0c714db71
commit
1d4ae4cdd1
12
package-lock.json
generated
12
package-lock.json
generated
@ -36448,9 +36448,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/infrastructure/lens-link": {
|
"packages/infrastructure/lens-link": {
|
||||||
|
"name": "@k8slens/lens-link",
|
||||||
"version": "1.0.0-alpha.0",
|
"version": "1.0.0-alpha.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {}
|
"dependencies": {
|
||||||
|
"@ogre-tools/fp": "^15.3.1",
|
||||||
|
"@ogre-tools/injectable": "^15.3.1",
|
||||||
|
"@ogre-tools/injectable-extension-for-auto-registration": "^15.3.1",
|
||||||
|
"fast-glob": "^3.2.12",
|
||||||
|
"fs-extra": "^9.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@async-fn/jest": "^1.6.4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"packages/infrastructure/typescript": {
|
"packages/infrastructure/typescript": {
|
||||||
"name": "@k8slens/typescript",
|
"name": "@k8slens/typescript",
|
||||||
|
|||||||
@ -24,7 +24,8 @@
|
|||||||
"@ogre-tools/fp": "^15.3.1",
|
"@ogre-tools/fp": "^15.3.1",
|
||||||
"@ogre-tools/injectable": "^15.3.1",
|
"@ogre-tools/injectable": "^15.3.1",
|
||||||
"@ogre-tools/injectable-extension-for-auto-registration": "^15.3.1",
|
"@ogre-tools/injectable-extension-for-auto-registration": "^15.3.1",
|
||||||
"fs-extra": "^9.0.1"
|
"fs-extra": "^9.0.1",
|
||||||
|
"fast-glob": "^3.2.12"
|
||||||
},
|
},
|
||||||
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import glob from "fast-glob";
|
||||||
|
|
||||||
|
export type Glob = typeof glob;
|
||||||
|
|
||||||
|
export const globInjectable = getInjectable({
|
||||||
|
id: "glob",
|
||||||
|
instantiate: (): Glob => glob,
|
||||||
|
});
|
||||||
@ -1,6 +1,7 @@
|
|||||||
|
import { partition } from "lodash/fp";
|
||||||
import { dirname } from "path";
|
import { dirname } from "path";
|
||||||
import { pipeline } from "@ogre-tools/fp";
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { flatMap, map } from "lodash/fp";
|
import { flatten, map } from "lodash/fp";
|
||||||
import { removeExistingLensLinkDirectoriesInjectable } from "./remove-existing-lens-link-directories.injectable";
|
import { removeExistingLensLinkDirectoriesInjectable } from "./remove-existing-lens-link-directories.injectable";
|
||||||
import { createLensLinkDirectoriesInjectable } from "./create-lens-link-directories.injectable";
|
import { createLensLinkDirectoriesInjectable } from "./create-lens-link-directories.injectable";
|
||||||
import { getMissingPackageJsonsInjectable } from "./get-missing-package-jsons.injectable";
|
import { getMissingPackageJsonsInjectable } from "./get-missing-package-jsons.injectable";
|
||||||
@ -13,9 +14,16 @@ import { existsInjectable } from "./fs/exists.injectable";
|
|||||||
import { writeJsonFileInjectable } from "./fs/write-json-file.injectable";
|
import { writeJsonFileInjectable } from "./fs/write-json-file.injectable";
|
||||||
import { createSymlinkInjectable } from "./fs/create-symlink.injectable";
|
import { createSymlinkInjectable } from "./fs/create-symlink.injectable";
|
||||||
import { workingDirectoryInjectable } from "./working-directory.injectable";
|
import { workingDirectoryInjectable } from "./working-directory.injectable";
|
||||||
|
import { globInjectable } from "./fs/glob.injectable";
|
||||||
|
import { awaitAll } from "./await-all";
|
||||||
|
|
||||||
export type LensLink = () => Promise<void>;
|
export type LensLink = () => Promise<void>;
|
||||||
|
|
||||||
|
const shouldBeGlobbed = (possibleGlobString: string) => possibleGlobString.includes("*");
|
||||||
|
|
||||||
|
const simplifyGlobbing = new RegExp("(\\/\\*\\/\\*\\*|\\/\\*\\*|\\/\\*\\*\\/\\*|\\/\\*)$");
|
||||||
|
const toAvoidableGlobStrings = (reference: string) => reference.replace(simplifyGlobbing, "");
|
||||||
|
|
||||||
const lensLinkInjectable = getInjectable({
|
const lensLinkInjectable = getInjectable({
|
||||||
id: "lens-link",
|
id: "lens-link",
|
||||||
|
|
||||||
@ -31,6 +39,7 @@ const lensLinkInjectable = getInjectable({
|
|||||||
const writeJsonFile = di.inject(writeJsonFileInjectable);
|
const writeJsonFile = di.inject(writeJsonFileInjectable);
|
||||||
const createSymlink = di.inject(createSymlinkInjectable);
|
const createSymlink = di.inject(createSymlinkInjectable);
|
||||||
const workingDirectory = di.inject(workingDirectoryInjectable);
|
const workingDirectory = di.inject(workingDirectoryInjectable);
|
||||||
|
const glob = di.inject(globInjectable);
|
||||||
|
|
||||||
return async () => {
|
return async () => {
|
||||||
const configFilePath = resolvePath(workingDirectory, ".lens-links.json");
|
const configFilePath = resolvePath(workingDirectory, ".lens-links.json");
|
||||||
@ -61,12 +70,24 @@ const lensLinkInjectable = getInjectable({
|
|||||||
|
|
||||||
await createLensLinkDirectories(packageJsons);
|
await createLensLinkDirectories(packageJsons);
|
||||||
|
|
||||||
pipeline(
|
await pipeline(
|
||||||
packageJsons,
|
packageJsons,
|
||||||
|
|
||||||
flatMap(({ packageJsonPath, content }) => {
|
map(async ({ packageJsonPath, content }) => {
|
||||||
const lensLinkDirectory = getLensLinkDirectory(content.name);
|
const lensLinkDirectory = getLensLinkDirectory(content.name);
|
||||||
|
|
||||||
|
const fileStrings = content.files.map(toAvoidableGlobStrings);
|
||||||
|
|
||||||
|
const [toBeGlobbed, toNotBeGlobbed] = partition(shouldBeGlobbed)(fileStrings);
|
||||||
|
|
||||||
|
const moduleDirectory = dirname(packageJsonPath);
|
||||||
|
|
||||||
|
let globbeds: string[] = [];
|
||||||
|
|
||||||
|
if (toBeGlobbed.length) {
|
||||||
|
globbeds = await glob(toBeGlobbed, { cwd: moduleDirectory });
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
target: packageJsonPath,
|
target: packageJsonPath,
|
||||||
@ -74,15 +95,27 @@ const lensLinkInjectable = getInjectable({
|
|||||||
type: "file" as const,
|
type: "file" as const,
|
||||||
},
|
},
|
||||||
|
|
||||||
...content.files.map((x) => ({
|
...globbeds.map((fileString) => ({
|
||||||
target: resolvePath(dirname(packageJsonPath), x),
|
target: resolvePath(moduleDirectory, fileString),
|
||||||
source: resolvePath(lensLinkDirectory, x),
|
source: resolvePath(lensLinkDirectory, fileString),
|
||||||
|
type: "file" as const,
|
||||||
|
})),
|
||||||
|
|
||||||
|
...toNotBeGlobbed.map((fileOrDirectory) => ({
|
||||||
|
target: resolvePath(moduleDirectory, fileOrDirectory),
|
||||||
|
source: resolvePath(lensLinkDirectory, fileOrDirectory),
|
||||||
type: "dir" as const,
|
type: "dir" as const,
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
awaitAll,
|
||||||
|
|
||||||
|
flatten,
|
||||||
|
|
||||||
map(({ target, source, type }) => createSymlink(target, source, type)),
|
map(({ target, source, type }) => createSymlink(target, source, type)),
|
||||||
|
|
||||||
|
awaitAll,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -19,6 +19,8 @@ import { createSymlinkInjectable } from "./fs/create-symlink.injectable";
|
|||||||
import { ensureDirectoryInjectable } from "./fs/ensure-directory.injectable";
|
import { ensureDirectoryInjectable } from "./fs/ensure-directory.injectable";
|
||||||
import { removeDirectoryInjectable } from "./fs/remove-directory.injectable";
|
import { removeDirectoryInjectable } from "./fs/remove-directory.injectable";
|
||||||
import { getDi } from "./get-di";
|
import { getDi } from "./get-di";
|
||||||
|
import type { Glob } from "./fs/glob.injectable";
|
||||||
|
import { globInjectable } from "./fs/glob.injectable";
|
||||||
|
|
||||||
describe("lens-link", () => {
|
describe("lens-link", () => {
|
||||||
let lensLink: LensLink;
|
let lensLink: LensLink;
|
||||||
@ -28,6 +30,7 @@ describe("lens-link", () => {
|
|||||||
let createSymlinkMock: AsyncFnMock<CreateSymlink>;
|
let createSymlinkMock: AsyncFnMock<CreateSymlink>;
|
||||||
let ensureDirectoryMock: AsyncFnMock<EnsureDirectory>;
|
let ensureDirectoryMock: AsyncFnMock<EnsureDirectory>;
|
||||||
let removeDirectoryMock: AsyncFnMock<RemoveDirectory>;
|
let removeDirectoryMock: AsyncFnMock<RemoveDirectory>;
|
||||||
|
let globMock: AsyncFnMock<Glob>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
existsMock = asyncFn();
|
existsMock = asyncFn();
|
||||||
@ -36,6 +39,7 @@ describe("lens-link", () => {
|
|||||||
createSymlinkMock = asyncFn();
|
createSymlinkMock = asyncFn();
|
||||||
ensureDirectoryMock = asyncFn();
|
ensureDirectoryMock = asyncFn();
|
||||||
removeDirectoryMock = asyncFn();
|
removeDirectoryMock = asyncFn();
|
||||||
|
globMock = asyncFn();
|
||||||
|
|
||||||
const di = getDi();
|
const di = getDi();
|
||||||
|
|
||||||
@ -47,6 +51,7 @@ describe("lens-link", () => {
|
|||||||
di.override(createSymlinkInjectable, () => createSymlinkMock);
|
di.override(createSymlinkInjectable, () => createSymlinkMock);
|
||||||
di.override(ensureDirectoryInjectable, () => ensureDirectoryMock);
|
di.override(ensureDirectoryInjectable, () => ensureDirectoryMock);
|
||||||
di.override(removeDirectoryInjectable, () => removeDirectoryMock);
|
di.override(removeDirectoryInjectable, () => removeDirectoryMock);
|
||||||
|
di.override(globInjectable, () => globMock);
|
||||||
|
|
||||||
lensLink = di.inject(lensLinkInjectable);
|
lensLink = di.inject(lensLinkInjectable);
|
||||||
});
|
});
|
||||||
@ -264,6 +269,112 @@ describe("lens-link", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("given some of the packages have globs as files, when all contents resolve", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
existsMock.mockClear();
|
||||||
|
|
||||||
|
await readJsonFileMock.resolveSpecific(([path]) => path === "/some-directory/some-module/package.json", {
|
||||||
|
name: "@some-scope/some-module",
|
||||||
|
files: [
|
||||||
|
"some-build-directory-with-asterisk/*",
|
||||||
|
"some-build-directory-with-wild-card/**",
|
||||||
|
"some-build-directory-with-wild-card-before-asterisk/**/*",
|
||||||
|
"some-build-directory-with-asterisk-and-file-suffix/*.some-file-suffix",
|
||||||
|
"some-build-directory-with-file-name-and-asterisk/some-filename.*",
|
||||||
|
"some-build-directory-with-wild-card-and-asterisk-and-file-suffix/**/*.some-file-suffix",
|
||||||
|
],
|
||||||
|
main: "some-build-directory/index.js",
|
||||||
|
});
|
||||||
|
|
||||||
|
await readJsonFileMock.resolveSpecific(
|
||||||
|
([path]) => path === "/some-other-directory/some-other-module/package.json",
|
||||||
|
{
|
||||||
|
name: "@some-scope/some-other-module",
|
||||||
|
files: [],
|
||||||
|
main: "some-other-build-directory/index.js",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given Lens link directories are handled", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await existsMock.resolve(false);
|
||||||
|
await existsMock.resolve(false);
|
||||||
|
|
||||||
|
await ensureDirectoryMock.resolve();
|
||||||
|
await ensureDirectoryMock.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not create symlinks yet", () => {
|
||||||
|
expect(createSymlinkMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls for glob of file-strings for which glob cannot be avoided", () => {
|
||||||
|
expect(globMock.mock.calls).toEqual([
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"some-build-directory-with-asterisk-and-file-suffix/*.some-file-suffix",
|
||||||
|
"some-build-directory-with-file-name-and-asterisk/some-filename.*",
|
||||||
|
"some-build-directory-with-wild-card-and-asterisk-and-file-suffix/**/*.some-file-suffix",
|
||||||
|
],
|
||||||
|
|
||||||
|
{ cwd: "/some-directory/some-module" },
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't create symlinks yet", () => {
|
||||||
|
expect(createSymlinkMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when globbing resolves", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await globMock.resolve(["/some-directory/some-module/some-file-from-glob.txt"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("creates the symlinks to files and directories that were both globbed and that avoided globbing", () => {
|
||||||
|
expect(createSymlinkMock.mock.calls).toEqual([
|
||||||
|
[
|
||||||
|
"/some-directory/some-module/package.json",
|
||||||
|
"/some-directory/some-project/node_modules/@some-scope/some-module/package.json",
|
||||||
|
"file",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-directory/some-module/some-file-from-glob.txt",
|
||||||
|
"/some-directory/some-module/some-file-from-glob.txt",
|
||||||
|
"file",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-directory/some-module/some-build-directory-with-asterisk",
|
||||||
|
"/some-directory/some-project/node_modules/@some-scope/some-module/some-build-directory-with-asterisk",
|
||||||
|
"dir",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-directory/some-module/some-build-directory-with-wild-card",
|
||||||
|
"/some-directory/some-project/node_modules/@some-scope/some-module/some-build-directory-with-wild-card",
|
||||||
|
"dir",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-directory/some-module/some-build-directory-with-wild-card-before-asterisk",
|
||||||
|
"/some-directory/some-project/node_modules/@some-scope/some-module/some-build-directory-with-wild-card-before-asterisk",
|
||||||
|
"dir",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-other-directory/some-other-module/package.json",
|
||||||
|
"/some-directory/some-project/node_modules/@some-scope/some-other-module/package.json",
|
||||||
|
"file",
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("when all contents resolve", () => {
|
describe("when all contents resolve", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
existsMock.mockClear();
|
existsMock.mockClear();
|
||||||
@ -375,6 +486,27 @@ describe("lens-link", () => {
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("given all symlink creations have not resolved, does not resolve yet", async () => {
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
|
||||||
|
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||||
|
|
||||||
|
expect(promiseStatus.fulfilled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when symlink creations resolve, ends script", async () => {
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
|
||||||
|
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||||
|
|
||||||
|
expect(promiseStatus.fulfilled).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user