2024-05-13 03:35:24 +02:00
|
|
|
import { assert, type Equals } from "tsafe/assert";
|
2024-05-20 15:48:51 +02:00
|
|
|
import type {
|
|
|
|
KeycloakAccountV1Version,
|
|
|
|
KeycloakThemeAdditionalInfoExtensionVersion
|
|
|
|
} from "./extensionVersions";
|
2024-05-13 03:35:24 +02:00
|
|
|
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";
|
2024-05-17 00:54:54 +02:00
|
|
|
import { readFileSync } from "fs";
|
2024-05-13 00:40:16 +02:00
|
|
|
import { isInside } from "../../tools/isInside";
|
|
|
|
import child_process from "child_process";
|
2024-05-17 00:54:54 +02:00
|
|
|
import { rmSync } from "../../tools/fs.rmSync";
|
2024-06-15 14:23:35 +02:00
|
|
|
import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
|
2024-09-24 19:46:36 +02:00
|
|
|
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;
|
2024-05-17 00:54:54 +02:00
|
|
|
cacheDirPath: string;
|
2024-07-20 22:43:14 +02:00
|
|
|
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>();
|
2024-05-12 19:16:59 +02:00
|
|
|
|
|
|
|
export async function buildJar(params: {
|
|
|
|
jarFileBasename: string;
|
2024-05-12 21:41:49 +02:00
|
|
|
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;
|
2024-05-12 19:16:59 +02:00
|
|
|
}): 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
|
|
|
|
2024-06-15 14:23:35 +02:00
|
|
|
const tmpResourcesDirPath = pathJoin(
|
2024-07-13 09:26:48 +02:00
|
|
|
keycloakifyBuildCacheDirPath,
|
2024-06-15 14:23:35 +02:00
|
|
|
"src",
|
|
|
|
"main",
|
|
|
|
"resources"
|
|
|
|
);
|
|
|
|
|
2024-07-13 09:26:48 +02:00
|
|
|
rmSync(tmpResourcesDirPath, { recursive: true, force: true });
|
|
|
|
|
2024-06-10 19:35:56 +02:00
|
|
|
transformCodebase({
|
|
|
|
srcDirPath: resourcesDirPath,
|
2024-06-15 14:23:35 +02:00
|
|
|
destDirPath: tmpResourcesDirPath,
|
2024-06-10 19:35:56 +02:00
|
|
|
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-06-10 19:35:56 +02:00
|
|
|
}
|
|
|
|
});
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-15 14:23:35 +02:00
|
|
|
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"
|
2024-06-15 14:23:35 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
return metaInfKeycloakTheme;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-05-13 03:35:24 +02:00
|
|
|
route_legacy_pages: {
|
2024-07-20 22:43:14 +02:00
|
|
|
if (!buildContext.implementedThemeTypes.login.isImplemented) {
|
2024-07-13 18:17:21 +02:00
|
|
|
break route_legacy_pages;
|
|
|
|
}
|
|
|
|
|
2024-09-24 19:46:36 +02:00
|
|
|
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 03:35:24 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
);
|
2024-05-12 19:16:59 +02:00
|
|
|
}
|