233 lines
8.1 KiB
TypeScript
Raw Normal View History

import { assert, type Equals } from "tsafe/assert";
2024-05-20 15:48:51 +02:00
import type {
KeycloakAccountV1Version,
KeycloakThemeAdditionalInfoExtensionVersion
} from "./extensionVersions";
import { join as pathJoin, dirname as pathDirname } from "path";
2024-05-13 00:40:16 +02:00
import { transformCodebase } from "../../tools/transformCodebase";
2024-06-09 09:15:16 +02:00
import type { BuildContext } from "../../shared/buildContext";
2024-05-13 00:40:16 +02:00
import * as fs from "fs/promises";
2024-05-20 15:48:51 +02:00
import {
generatePom,
2024-06-09 09:15:16 +02:00
BuildContextLike as BuildContextLike_generatePom
2024-05-20 15:48:51 +02:00
} from "./generatePom";
import { readFileSync } from "fs";
2024-05-13 00:40:16 +02:00
import { isInside } from "../../tools/isInside";
import child_process from "child_process";
import { rmSync } from "../../tools/fs.rmSync";
import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
import { existsAsync } from "../../tools/fs.existsAsync";
2024-05-13 00:40:16 +02:00
2024-06-09 09:15:16 +02:00
export type BuildContextLike = BuildContextLike_generatePom & {
2024-05-13 00:40:16 +02:00
keycloakifyBuildDirPath: string;
themeNames: string[];
artifactId: string;
themeVersion: string;
cacheDirPath: string;
implementedThemeTypes: BuildContext["implementedThemeTypes"];
2024-05-13 00:40:16 +02:00
};
2024-06-09 09:15:16 +02:00
assert<BuildContext extends BuildContextLike ? true : false>();
export async function buildJar(params: {
jarFileBasename: string;
keycloakAccountV1Version: KeycloakAccountV1Version;
keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion;
2024-06-10 07:57:12 +02:00
resourcesDirPath: string;
2024-07-07 18:45:14 +02:00
doesImplementAccountV1Theme: boolean;
2024-06-09 09:15:16 +02:00
buildContext: BuildContextLike;
}): Promise<void> {
2024-05-20 15:48:51 +02:00
const {
jarFileBasename,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion,
2024-06-10 07:57:12 +02:00
resourcesDirPath,
2024-07-07 18:45:14 +02:00
doesImplementAccountV1Theme,
2024-06-09 09:15:16 +02:00
buildContext
2024-05-20 15:48:51 +02:00
} = params;
2024-07-13 09:26:48 +02:00
const keycloakifyBuildCacheDirPath = pathJoin(
2024-06-09 09:15:16 +02:00
buildContext.cacheDirPath,
2024-07-13 09:26:48 +02:00
"maven",
2024-05-20 15:48:51 +02:00
jarFileBasename.replace(".jar", "")
);
2024-05-13 00:40:16 +02:00
const tmpResourcesDirPath = pathJoin(
2024-07-13 09:26:48 +02:00
keycloakifyBuildCacheDirPath,
"src",
"main",
"resources"
);
2024-07-13 09:26:48 +02:00
rmSync(tmpResourcesDirPath, { recursive: true, force: true });
transformCodebase({
srcDirPath: resourcesDirPath,
destDirPath: tmpResourcesDirPath,
transformSourceCode:
2024-07-07 18:45:14 +02:00
!doesImplementAccountV1Theme || keycloakAccountV1Version !== null
2024-05-26 12:38:00 +02:00
? undefined
: (params: {
fileRelativePath: string;
sourceCode: Buffer;
}): { modifiedSourceCode: Buffer } | undefined => {
const { fileRelativePath, sourceCode } = params;
if (
isInside({
2024-09-08 12:00:07 +02:00
dirPath: pathJoin("theme", "account-v1"),
2024-05-26 12:38:00 +02:00
filePath: fileRelativePath
})
) {
return undefined;
}
2024-06-09 09:15:16 +02:00
for (const themeName of buildContext.themeNames) {
2024-05-26 12:38:00 +02:00
if (
fileRelativePath ===
2024-06-10 07:57:12 +02:00
pathJoin("theme", themeName, "account", "theme.properties")
2024-05-26 12:38:00 +02:00
) {
const modifiedSourceCode = Buffer.from(
sourceCode
.toString("utf8")
2024-09-08 12:00:07 +02:00
.replace(`parent=account-v1`, "parent=keycloak"),
2024-05-26 12:38:00 +02:00
"utf8"
);
assert(
Buffer.compare(modifiedSourceCode, sourceCode) !== 0
);
return { modifiedSourceCode };
}
}
return { modifiedSourceCode: sourceCode };
}
});
2024-05-13 00:40:16 +02:00
2024-07-07 18:45:14 +02:00
remove_account_v1_in_meta_inf: {
if (!doesImplementAccountV1Theme) {
// NOTE: We do not have account v1 anyway
break remove_account_v1_in_meta_inf;
}
if (keycloakAccountV1Version !== null) {
// NOTE: No, we need to keep account-v1 in meta-inf
break remove_account_v1_in_meta_inf;
}
writeMetaInfKeycloakThemes({
resourcesDirPath: tmpResourcesDirPath,
getNewMetaInfKeycloakTheme: ({ metaInfKeycloakTheme }) => {
assert(metaInfKeycloakTheme !== undefined);
metaInfKeycloakTheme.themes = metaInfKeycloakTheme.themes.filter(
2024-09-08 12:00:07 +02:00
({ name }) => name !== "account-v1"
);
return metaInfKeycloakTheme;
}
});
}
route_legacy_pages: {
if (!buildContext.implementedThemeTypes.login.isImplemented) {
2024-07-13 18:17:21 +02:00
break route_legacy_pages;
}
await Promise.all(
(["register.ftl", "login-update-profile.ftl"] as const)
.map(pageId =>
buildContext.themeNames.map(async themeName => {
const ftlFilePath = pathJoin(
tmpResourcesDirPath,
"theme",
themeName,
"login",
pageId
);
// NOTE: https://github.com/keycloakify/keycloakify/issues/665
if (!(await existsAsync(ftlFilePath))) {
return;
}
const ftlFileContent = readFileSync(ftlFilePath).toString("utf8");
const ftlFileBasename = (() => {
switch (pageId) {
case "register.ftl":
return "register-user-profile.ftl";
case "login-update-profile.ftl":
return "update-user-profile.ftl";
}
assert<Equals<typeof pageId, never>>(false);
})();
const modifiedFtlFileContent = ftlFileContent.replace(
`"ftlTemplateFileName": "${pageId}"`,
`"ftlTemplateFileName": "${ftlFileBasename}"`
);
assert(modifiedFtlFileContent !== ftlFileContent);
await fs.writeFile(
pathJoin(pathDirname(ftlFilePath), ftlFileBasename),
Buffer.from(modifiedFtlFileContent, "utf8")
);
})
)
.flat()
);
}
2024-05-13 00:40:16 +02:00
{
const { pomFileCode } = generatePom({
2024-06-09 09:15:16 +02:00
buildContext,
2024-05-13 00:40:16 +02:00
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion
});
2024-05-20 15:48:51 +02:00
await fs.writeFile(
2024-07-13 09:26:48 +02:00
pathJoin(keycloakifyBuildCacheDirPath, "pom.xml"),
2024-05-20 15:48:51 +02:00
Buffer.from(pomFileCode, "utf8")
);
2024-05-13 00:40:16 +02:00
}
await new Promise<void>((resolve, reject) =>
2024-05-20 15:48:51 +02:00
child_process.exec(
2024-10-04 16:56:02 +02:00
`mvn clean install -Dmaven.repo.local="${pathJoin(keycloakifyBuildCacheDirPath, ".m2")}"`,
2024-07-13 09:26:48 +02:00
{ cwd: keycloakifyBuildCacheDirPath },
2024-05-20 15:48:51 +02:00
error => {
if (error !== null) {
console.error(
`Build jar failed: ${JSON.stringify(
{
jarFileBasename,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion
},
null,
2
)}`
);
2024-05-13 23:39:18 +02:00
2024-05-20 15:48:51 +02:00
reject(error);
return;
}
resolve();
2024-05-13 00:40:16 +02:00
}
2024-05-20 15:48:51 +02:00
)
2024-05-13 00:40:16 +02:00
);
await fs.rename(
2024-05-20 15:48:51 +02:00
pathJoin(
2024-07-13 09:26:48 +02:00
keycloakifyBuildCacheDirPath,
2024-05-20 15:48:51 +02:00
"target",
2024-06-09 09:15:16 +02:00
`${buildContext.artifactId}-${buildContext.themeVersion}.jar`
2024-05-20 15:48:51 +02:00
),
2024-06-09 09:15:16 +02:00
pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename)
2024-05-13 00:40:16 +02:00
);
}