Build rework checkpoint
This commit is contained in:
@ -1,63 +0,0 @@
|
|||||||
import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
|
|
||||||
import { promptKeycloakVersion } from "./shared/promptKeycloakVersion";
|
|
||||||
import { getBuildContext } from "./shared/buildContext";
|
|
||||||
import { downloadKeycloakDefaultTheme } from "./shared/downloadKeycloakDefaultTheme";
|
|
||||||
import { transformCodebase } from "./tools/transformCodebase";
|
|
||||||
import type { CliCommandOptions } from "./main";
|
|
||||||
import chalk from "chalk";
|
|
||||||
|
|
||||||
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
|
|
||||||
const { cliCommandOptions } = params;
|
|
||||||
|
|
||||||
const buildContext = getBuildContext({
|
|
||||||
cliCommandOptions
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
chalk.cyan(
|
|
||||||
"Select the Keycloak version from which you want to download the builtins theme:"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const { keycloakVersion } = await promptKeycloakVersion({
|
|
||||||
startingFromMajor: undefined,
|
|
||||||
cacheDirPath: buildContext.cacheDirPath
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`→ ${keycloakVersion}`);
|
|
||||||
|
|
||||||
const destDirPath = pathJoin(
|
|
||||||
buildContext.keycloakifyBuildDirPath,
|
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme"
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
[
|
|
||||||
`Downloading builtins theme of Keycloak ${keycloakVersion} here:`,
|
|
||||||
`- ${chalk.bold(
|
|
||||||
`.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "base")}`
|
|
||||||
)}`,
|
|
||||||
`- ${chalk.bold(
|
|
||||||
`.${pathSep}${pathJoin(
|
|
||||||
pathRelative(process.cwd(), destDirPath),
|
|
||||||
"keycloak"
|
|
||||||
)}`
|
|
||||||
)}`
|
|
||||||
].join("\n")
|
|
||||||
);
|
|
||||||
|
|
||||||
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
|
|
||||||
keycloakVersion,
|
|
||||||
buildContext
|
|
||||||
});
|
|
||||||
|
|
||||||
transformCodebase({
|
|
||||||
srcDirPath: defaultThemeDirPath,
|
|
||||||
destDirPath
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(chalk.green(`✓ done`));
|
|
||||||
}
|
|
@ -32,12 +32,14 @@ export async function buildJar(params: {
|
|||||||
jarFileBasename: string;
|
jarFileBasename: string;
|
||||||
keycloakAccountV1Version: KeycloakAccountV1Version;
|
keycloakAccountV1Version: KeycloakAccountV1Version;
|
||||||
keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion;
|
keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion;
|
||||||
|
resourcesDirPath: string;
|
||||||
buildContext: BuildContextLike;
|
buildContext: BuildContextLike;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const {
|
const {
|
||||||
jarFileBasename,
|
jarFileBasename,
|
||||||
keycloakAccountV1Version,
|
keycloakAccountV1Version,
|
||||||
keycloakThemeAdditionalInfoExtensionVersion,
|
keycloakThemeAdditionalInfoExtensionVersion,
|
||||||
|
resourcesDirPath,
|
||||||
buildContext
|
buildContext
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ export async function buildJar(params: {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
fileRelativePath ===
|
fileRelativePath ===
|
||||||
getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath: "." })
|
getMetaInfKeycloakThemesJsonFilePath({ resourcesDirPath: "." })
|
||||||
) {
|
) {
|
||||||
return { modifiedSourceCode: sourceCode };
|
return { modifiedSourceCode: sourceCode };
|
||||||
}
|
}
|
||||||
@ -65,7 +67,7 @@ export async function buildJar(params: {
|
|||||||
for (const themeName of [...buildContext.themeNames, accountV1ThemeName]) {
|
for (const themeName of [...buildContext.themeNames, accountV1ThemeName]) {
|
||||||
if (
|
if (
|
||||||
isInside({
|
isInside({
|
||||||
dirPath: pathJoin("src", "main", "resources", "theme", themeName),
|
dirPath: pathJoin("theme", themeName),
|
||||||
filePath: fileRelativePath
|
filePath: fileRelativePath
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
@ -87,13 +89,7 @@ export async function buildJar(params: {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
isInside({
|
isInside({
|
||||||
dirPath: pathJoin(
|
dirPath: pathJoin("theme", accountV1ThemeName),
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
|
||||||
accountV1ThemeName
|
|
||||||
),
|
|
||||||
filePath: fileRelativePath
|
filePath: fileRelativePath
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
@ -103,7 +99,7 @@ export async function buildJar(params: {
|
|||||||
if (
|
if (
|
||||||
fileRelativePath ===
|
fileRelativePath ===
|
||||||
getMetaInfKeycloakThemesJsonFilePath({
|
getMetaInfKeycloakThemesJsonFilePath({
|
||||||
keycloakifyBuildDirPath: "."
|
resourcesDirPath: "."
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
const keycloakThemesJsonParsed = JSON.parse(
|
const keycloakThemesJsonParsed = JSON.parse(
|
||||||
@ -128,15 +124,7 @@ export async function buildJar(params: {
|
|||||||
for (const themeName of buildContext.themeNames) {
|
for (const themeName of buildContext.themeNames) {
|
||||||
if (
|
if (
|
||||||
fileRelativePath ===
|
fileRelativePath ===
|
||||||
pathJoin(
|
pathJoin("theme", themeName, "account", "theme.properties")
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
|
||||||
themeName,
|
|
||||||
"account",
|
|
||||||
"theme.properties"
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
const modifiedSourceCode = Buffer.from(
|
const modifiedSourceCode = Buffer.from(
|
||||||
sourceCode
|
sourceCode
|
||||||
@ -160,8 +148,8 @@ export async function buildJar(params: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
srcDirPath: buildContext.keycloakifyBuildDirPath,
|
srcDirPath: resourcesDirPath,
|
||||||
destDirPath: keycloakifyBuildTmpDirPath,
|
destDirPath: pathJoin(keycloakifyBuildTmpDirPath, "src", "main", "resources"),
|
||||||
transformSourceCode: params => {
|
transformSourceCode: params => {
|
||||||
const resultCommon = transformCodebase_common(params);
|
const resultCommon = transformCodebase_common(params);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar";
|
|||||||
import { buildJar, BuildContextLike as BuildContextLike_buildJar } from "./buildJar";
|
import { buildJar, BuildContextLike as BuildContextLike_buildJar } from "./buildJar";
|
||||||
import type { BuildContext } from "../../shared/buildContext";
|
import type { BuildContext } from "../../shared/buildContext";
|
||||||
import { getJarFileBasename } from "../../shared/getJarFileBasename";
|
import { getJarFileBasename } from "../../shared/getJarFileBasename";
|
||||||
import { readMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
|
import { readMetaInfKeycloakThemes_fromResourcesDirPath } from "../../shared/metaInfKeycloakThemes";
|
||||||
import { accountV1ThemeName } from "../../shared/constants";
|
import { accountV1ThemeName } from "../../shared/constants";
|
||||||
|
|
||||||
export type BuildContextLike = BuildContextLike_buildJar & {
|
export type BuildContextLike = BuildContextLike_buildJar & {
|
||||||
@ -18,12 +18,13 @@ export type BuildContextLike = BuildContextLike_buildJar & {
|
|||||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||||
|
|
||||||
export async function buildJars(params: {
|
export async function buildJars(params: {
|
||||||
|
resourcesDirPath: string;
|
||||||
buildContext: BuildContextLike;
|
buildContext: BuildContextLike;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { buildContext } = params;
|
const { resourcesDirPath, buildContext } = params;
|
||||||
|
|
||||||
const doesImplementAccountTheme = readMetaInfKeycloakThemes({
|
const doesImplementAccountTheme = readMetaInfKeycloakThemes_fromResourcesDirPath({
|
||||||
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath
|
resourcesDirPath: buildContext.keycloakifyBuildDirPath
|
||||||
}).themes.some(({ name }) => name === accountV1ThemeName);
|
}).themes.some(({ name }) => name === accountV1ThemeName);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -71,6 +72,7 @@ export async function buildJars(params: {
|
|||||||
jarFileBasename,
|
jarFileBasename,
|
||||||
keycloakAccountV1Version,
|
keycloakAccountV1Version,
|
||||||
keycloakThemeAdditionalInfoExtensionVersion,
|
keycloakThemeAdditionalInfoExtensionVersion,
|
||||||
|
resourcesDirPath,
|
||||||
buildContext
|
buildContext
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -13,13 +13,15 @@ import { transformCodebase } from "../../tools/transformCodebase";
|
|||||||
export type BuildContextLike = {
|
export type BuildContextLike = {
|
||||||
cacheDirPath: string;
|
cacheDirPath: string;
|
||||||
npmWorkspaceRootDirPath: string;
|
npmWorkspaceRootDirPath: string;
|
||||||
keycloakifyBuildDirPath: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||||
|
|
||||||
export async function bringInAccountV1(params: { buildContext: BuildContextLike }) {
|
export async function bringInAccountV1(params: {
|
||||||
const { buildContext } = params;
|
resourcesDirPath: string;
|
||||||
|
buildContext: BuildContextLike;
|
||||||
|
}) {
|
||||||
|
const { resourcesDirPath, buildContext } = params;
|
||||||
|
|
||||||
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
|
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
|
||||||
keycloakVersion: lastKeycloakVersionWithAccountV1,
|
keycloakVersion: lastKeycloakVersionWithAccountV1,
|
||||||
@ -27,10 +29,7 @@ export async function bringInAccountV1(params: { buildContext: BuildContextLike
|
|||||||
});
|
});
|
||||||
|
|
||||||
const accountV1DirPath = pathJoin(
|
const accountV1DirPath = pathJoin(
|
||||||
buildContext.keycloakifyBuildDirPath,
|
resourcesDirPath,
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
"theme",
|
||||||
accountV1ThemeName,
|
accountV1ThemeName,
|
||||||
"account"
|
"account"
|
||||||
|
@ -5,6 +5,8 @@ import {
|
|||||||
type BuildContextLike as BuildContextLike_generateSrcMainResourcesForMainTheme
|
type BuildContextLike as BuildContextLike_generateSrcMainResourcesForMainTheme
|
||||||
} from "./generateSrcMainResourcesForMainTheme";
|
} from "./generateSrcMainResourcesForMainTheme";
|
||||||
import { generateSrcMainResourcesForThemeVariant } from "./generateSrcMainResourcesForThemeVariant";
|
import { generateSrcMainResourcesForThemeVariant } from "./generateSrcMainResourcesForThemeVariant";
|
||||||
|
import fs from "fs";
|
||||||
|
import { rmSync } from "../../tools/fs.rmSync";
|
||||||
|
|
||||||
export type BuildContextLike = BuildContextLike_generateSrcMainResourcesForMainTheme & {
|
export type BuildContextLike = BuildContextLike_generateSrcMainResourcesForMainTheme & {
|
||||||
themeNames: string[];
|
themeNames: string[];
|
||||||
@ -14,21 +16,27 @@ assert<BuildContext extends BuildContextLike ? true : false>();
|
|||||||
|
|
||||||
export async function generateSrcMainResources(params: {
|
export async function generateSrcMainResources(params: {
|
||||||
buildContext: BuildContextLike;
|
buildContext: BuildContextLike;
|
||||||
|
resourcesDirPath: string;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { buildContext } = params;
|
const { resourcesDirPath, buildContext } = params;
|
||||||
|
|
||||||
const [themeName, ...themeVariantNames] = buildContext.themeNames;
|
const [themeName, ...themeVariantNames] = buildContext.themeNames;
|
||||||
|
|
||||||
|
if (fs.existsSync(resourcesDirPath)) {
|
||||||
|
rmSync(resourcesDirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
await generateSrcMainResourcesForMainTheme({
|
await generateSrcMainResourcesForMainTheme({
|
||||||
|
resourcesDirPath,
|
||||||
themeName,
|
themeName,
|
||||||
buildContext
|
buildContext
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const themeVariantName of themeVariantNames) {
|
for (const themeVariantName of themeVariantNames) {
|
||||||
generateSrcMainResourcesForThemeVariant({
|
generateSrcMainResourcesForThemeVariant({
|
||||||
|
resourcesDirPath,
|
||||||
themeName,
|
themeName,
|
||||||
themeVariantName,
|
themeVariantName
|
||||||
buildContext
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,14 +43,10 @@ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForProper
|
|||||||
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
|
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
|
||||||
BuildContextLike_downloadKeycloakStaticResources &
|
BuildContextLike_downloadKeycloakStaticResources &
|
||||||
BuildContextLike_bringInAccountV1 & {
|
BuildContextLike_bringInAccountV1 & {
|
||||||
bundler: "vite" | "webpack";
|
|
||||||
extraThemeProperties: string[] | undefined;
|
extraThemeProperties: string[] | undefined;
|
||||||
loginThemeResourcesFromKeycloakVersion: string;
|
loginThemeResourcesFromKeycloakVersion: string;
|
||||||
projectBuildDirPath: string;
|
|
||||||
assetsDirPath: string;
|
|
||||||
urlPathname: string | undefined;
|
|
||||||
projectDirPath: string;
|
projectDirPath: string;
|
||||||
keycloakifyBuildDirPath: string;
|
projectBuildDirPath: string;
|
||||||
environmentVariables: { name: string; default: string }[];
|
environmentVariables: { name: string; default: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,9 +54,10 @@ assert<BuildContext extends BuildContextLike ? true : false>();
|
|||||||
|
|
||||||
export async function generateSrcMainResourcesForMainTheme(params: {
|
export async function generateSrcMainResourcesForMainTheme(params: {
|
||||||
themeName: string;
|
themeName: string;
|
||||||
|
resourcesDirPath: string;
|
||||||
buildContext: BuildContextLike;
|
buildContext: BuildContextLike;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { themeName, buildContext } = params;
|
const { themeName, resourcesDirPath, buildContext } = params;
|
||||||
|
|
||||||
const { themeSrcDirPath } = getThemeSrcDirPath({
|
const { themeSrcDirPath } = getThemeSrcDirPath({
|
||||||
projectDirPath: buildContext.projectDirPath
|
projectDirPath: buildContext.projectDirPath
|
||||||
@ -68,15 +65,7 @@ export async function generateSrcMainResourcesForMainTheme(params: {
|
|||||||
|
|
||||||
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
|
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
|
||||||
const { themeType } = params;
|
const { themeType } = params;
|
||||||
return pathJoin(
|
return pathJoin(resourcesDirPath, "theme", themeName, themeType);
|
||||||
buildContext.keycloakifyBuildDirPath,
|
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
|
||||||
themeName,
|
|
||||||
themeType
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const cssGlobalsToDefine: Record<string, string> = {};
|
const cssGlobalsToDefine: Record<string, string> = {};
|
||||||
@ -207,8 +196,6 @@ export async function generateSrcMainResourcesForMainTheme(params: {
|
|||||||
].forEach(pageId => {
|
].forEach(pageId => {
|
||||||
const { ftlCode } = generateFtlFilesCode({ pageId });
|
const { ftlCode } = generateFtlFilesCode({ pageId });
|
||||||
|
|
||||||
fs.mkdirSync(themeTypeDirPath, { recursive: true });
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
pathJoin(themeTypeDirPath, pageId),
|
pathJoin(themeTypeDirPath, pageId),
|
||||||
Buffer.from(ftlCode, "utf8")
|
Buffer.from(ftlCode, "utf8")
|
||||||
@ -291,6 +278,7 @@ export async function generateSrcMainResourcesForMainTheme(params: {
|
|||||||
|
|
||||||
if (implementedThemeTypes.account) {
|
if (implementedThemeTypes.account) {
|
||||||
await bringInAccountV1({
|
await bringInAccountV1({
|
||||||
|
resourcesDirPath,
|
||||||
buildContext
|
buildContext
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -313,7 +301,7 @@ export async function generateSrcMainResourcesForMainTheme(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeMetaInfKeycloakThemes({
|
writeMetaInfKeycloakThemes({
|
||||||
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath,
|
resourcesDirPath,
|
||||||
metaInfKeycloakThemes
|
metaInfKeycloakThemes
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { join as pathJoin, extname as pathExtname, sep as pathSep } from "path";
|
|||||||
import { transformCodebase } from "../../tools/transformCodebase";
|
import { transformCodebase } from "../../tools/transformCodebase";
|
||||||
import type { BuildContext } from "../../shared/buildContext";
|
import type { BuildContext } from "../../shared/buildContext";
|
||||||
import {
|
import {
|
||||||
readMetaInfKeycloakThemes,
|
readMetaInfKeycloakThemes_fromResourcesDirPath,
|
||||||
writeMetaInfKeycloakThemes
|
writeMetaInfKeycloakThemes
|
||||||
} from "../../shared/metaInfKeycloakThemes";
|
} from "../../shared/metaInfKeycloakThemes";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
@ -14,20 +14,13 @@ export type BuildContextLike = {
|
|||||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||||
|
|
||||||
export function generateSrcMainResourcesForThemeVariant(params: {
|
export function generateSrcMainResourcesForThemeVariant(params: {
|
||||||
|
resourcesDirPath: string;
|
||||||
themeName: string;
|
themeName: string;
|
||||||
themeVariantName: string;
|
themeVariantName: string;
|
||||||
buildContext: BuildContextLike;
|
|
||||||
}) {
|
}) {
|
||||||
const { themeName, themeVariantName, buildContext } = params;
|
const { resourcesDirPath, themeName, themeVariantName } = params;
|
||||||
|
|
||||||
const mainThemeDirPath = pathJoin(
|
const mainThemeDirPath = pathJoin(resourcesDirPath, "theme", themeName);
|
||||||
buildContext.keycloakifyBuildDirPath,
|
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
|
||||||
themeName
|
|
||||||
);
|
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
srcDirPath: mainThemeDirPath,
|
srcDirPath: mainThemeDirPath,
|
||||||
@ -57,9 +50,10 @@ export function generateSrcMainResourcesForThemeVariant(params: {
|
|||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
const updatedMetaInfKeycloakThemes = readMetaInfKeycloakThemes({
|
const updatedMetaInfKeycloakThemes =
|
||||||
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath
|
readMetaInfKeycloakThemes_fromResourcesDirPath({
|
||||||
});
|
resourcesDirPath
|
||||||
|
});
|
||||||
|
|
||||||
updatedMetaInfKeycloakThemes.themes.push({
|
updatedMetaInfKeycloakThemes.themes.push({
|
||||||
name: themeVariantName,
|
name: themeVariantName,
|
||||||
@ -73,7 +67,7 @@ export function generateSrcMainResourcesForThemeVariant(params: {
|
|||||||
});
|
});
|
||||||
|
|
||||||
writeMetaInfKeycloakThemes({
|
writeMetaInfKeycloakThemes({
|
||||||
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath,
|
resourcesDirPath,
|
||||||
metaInfKeycloakThemes: updatedMetaInfKeycloakThemes
|
metaInfKeycloakThemes: updatedMetaInfKeycloakThemes
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
import * as fs from "fs";
|
|
||||||
import {
|
|
||||||
join as pathJoin,
|
|
||||||
relative as pathRelative,
|
|
||||||
basename as pathBasename
|
|
||||||
} from "path";
|
|
||||||
import { assert } from "tsafe/assert";
|
|
||||||
import type { BuildContext } from "../shared/buildContext";
|
|
||||||
import { accountV1ThemeName } from "../shared/constants";
|
|
||||||
|
|
||||||
export type BuildContextLike = {
|
|
||||||
keycloakifyBuildDirPath: string;
|
|
||||||
themeNames: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
|
||||||
|
|
||||||
generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh";
|
|
||||||
|
|
||||||
const containerName = "keycloak-testing-container";
|
|
||||||
const keycloakVersion = "24.0.4";
|
|
||||||
|
|
||||||
/** Files for being able to run a hot reload keycloak container */
|
|
||||||
export function generateStartKeycloakTestingContainer(params: {
|
|
||||||
jarFilePath: string;
|
|
||||||
doesImplementAccountTheme: boolean;
|
|
||||||
buildContext: BuildContextLike;
|
|
||||||
}) {
|
|
||||||
const { jarFilePath, doesImplementAccountTheme, buildContext } = params;
|
|
||||||
|
|
||||||
const themeRelativeDirPath = pathJoin("src", "main", "resources", "theme");
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
pathJoin(
|
|
||||||
buildContext.keycloakifyBuildDirPath,
|
|
||||||
generateStartKeycloakTestingContainer.basename
|
|
||||||
),
|
|
||||||
Buffer.from(
|
|
||||||
[
|
|
||||||
"#!/usr/bin/env bash",
|
|
||||||
"",
|
|
||||||
`docker rm ${containerName} || true`,
|
|
||||||
"",
|
|
||||||
`cd "${buildContext.keycloakifyBuildDirPath}"`,
|
|
||||||
"",
|
|
||||||
"docker run \\",
|
|
||||||
" -p 8080:8080 \\",
|
|
||||||
` --name ${containerName} \\`,
|
|
||||||
" -e KEYCLOAK_ADMIN=admin \\",
|
|
||||||
" -e KEYCLOAK_ADMIN_PASSWORD=admin \\",
|
|
||||||
` -v "${pathJoin(
|
|
||||||
"$(pwd)",
|
|
||||||
pathRelative(buildContext.keycloakifyBuildDirPath, jarFilePath)
|
|
||||||
)}":"/opt/keycloak/providers/${pathBasename(jarFilePath)}" \\`,
|
|
||||||
[
|
|
||||||
...(doesImplementAccountTheme ? [accountV1ThemeName] : []),
|
|
||||||
...buildContext.themeNames
|
|
||||||
].map(
|
|
||||||
themeName =>
|
|
||||||
` -v "${pathJoin(
|
|
||||||
"$(pwd)",
|
|
||||||
themeRelativeDirPath,
|
|
||||||
themeName
|
|
||||||
).replace(/\\/g, "/")}":"/opt/keycloak/themes/${themeName}":rw \\`
|
|
||||||
),
|
|
||||||
` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`,
|
|
||||||
` start-dev`,
|
|
||||||
""
|
|
||||||
].join("\n"),
|
|
||||||
"utf8"
|
|
||||||
),
|
|
||||||
{ mode: 0o755 }
|
|
||||||
);
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ import type { CliCommandOptions } from "../main";
|
|||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
|
import { rmSync } from "../tools/fs.rmSync";
|
||||||
|
|
||||||
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
|
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
|
||||||
exit_if_maven_not_installed: {
|
exit_if_maven_not_installed: {
|
||||||
@ -76,7 +77,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await generateSrcMainResources({ buildContext });
|
const resourcesDirPath = pathJoin(buildContext.keycloakifyBuildDirPath, "resources");
|
||||||
|
|
||||||
|
await generateSrcMainResources({
|
||||||
|
resourcesDirPath,
|
||||||
|
buildContext
|
||||||
|
});
|
||||||
|
|
||||||
run_post_build_script: {
|
run_post_build_script: {
|
||||||
if (buildContext.bundler !== "vite") {
|
if (buildContext.bundler !== "vite") {
|
||||||
@ -84,7 +90,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
}
|
}
|
||||||
|
|
||||||
child_process.execSync("npx vite", {
|
child_process.execSync("npx vite", {
|
||||||
cwd: buildContext.projectDirPath,
|
cwd: resourcesDirPath,
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
[vitePluginSubScriptEnvNames.runPostBuildScript]:
|
[vitePluginSubScriptEnvNames.runPostBuildScript]:
|
||||||
@ -98,7 +104,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
break build_jars;
|
break build_jars;
|
||||||
}
|
}
|
||||||
|
|
||||||
await buildJars({ buildContext });
|
await buildJars({ resourcesDirPath, buildContext });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Date.now() === 0) {
|
||||||
|
rmSync(resourcesDirPath, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
|
@ -134,20 +134,6 @@ program
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
program
|
|
||||||
.command({
|
|
||||||
name: "download-keycloak-default-theme",
|
|
||||||
description: "Download the built-in Keycloak theme."
|
|
||||||
})
|
|
||||||
.task({
|
|
||||||
skip,
|
|
||||||
handler: async cliCommandOptions => {
|
|
||||||
const { command } = await import("./download-keycloak-default-theme");
|
|
||||||
|
|
||||||
await command({ cliCommandOptions });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
program
|
program
|
||||||
.command({
|
.command({
|
||||||
name: "eject-page",
|
name: "eject-page",
|
||||||
|
@ -12,7 +12,7 @@ import { vitePluginSubScriptEnvNames } from "./constants";
|
|||||||
export type BuildContext = {
|
export type BuildContext = {
|
||||||
bundler: "vite" | "webpack";
|
bundler: "vite" | "webpack";
|
||||||
themeVersion: string;
|
themeVersion: string;
|
||||||
themeNames: string[];
|
themeNames: [string, ...string[]];
|
||||||
extraThemeProperties: string[] | undefined;
|
extraThemeProperties: string[] | undefined;
|
||||||
groupId: string;
|
groupId: string;
|
||||||
artifactId: string;
|
artifactId: string;
|
||||||
@ -147,7 +147,7 @@ export function getBuildContext(params: {
|
|||||||
...resolvedViteConfig?.buildOptions
|
...resolvedViteConfig?.buildOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
const themeNames = (() => {
|
const themeNames = ((): [string, ...string[]] => {
|
||||||
if (buildOptions.themeName === undefined) {
|
if (buildOptions.themeName === undefined) {
|
||||||
return [
|
return [
|
||||||
parsedPackageJson.name
|
parsedPackageJson.name
|
||||||
@ -161,7 +161,11 @@ export function getBuildContext(params: {
|
|||||||
return [buildOptions.themeName];
|
return [buildOptions.themeName];
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildOptions.themeName;
|
const [mainThemeName, ...themeVariantNames] = buildOptions.themeName;
|
||||||
|
|
||||||
|
assert(mainThemeName !== undefined);
|
||||||
|
|
||||||
|
return [mainThemeName, ...themeVariantNames];
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const projectBuildDirPath = (() => {
|
const projectBuildDirPath = (() => {
|
||||||
|
@ -1,50 +1,73 @@
|
|||||||
import { join as pathJoin, dirname as pathDirname } from "path";
|
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||||
import type { ThemeType } from "./constants";
|
import type { ThemeType } from "./constants";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import { extractArchive } from "../tools/extractArchive";
|
||||||
|
|
||||||
export type MetaInfKeycloakTheme = {
|
export type MetaInfKeycloakTheme = {
|
||||||
themes: { name: string; types: (ThemeType | "email")[] }[];
|
themes: { name: string; types: (ThemeType | "email")[] }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getMetaInfKeycloakThemesJsonFilePath(params: {
|
export function getMetaInfKeycloakThemesJsonFilePath(params: {
|
||||||
keycloakifyBuildDirPath: string;
|
resourcesDirPath: string;
|
||||||
}) {
|
}) {
|
||||||
const { keycloakifyBuildDirPath } = params;
|
const { resourcesDirPath } = params;
|
||||||
|
|
||||||
return pathJoin(
|
return pathJoin(
|
||||||
keycloakifyBuildDirPath === "." ? "" : keycloakifyBuildDirPath,
|
resourcesDirPath === "." ? "" : resourcesDirPath,
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"META-INF",
|
"META-INF",
|
||||||
"keycloak-themes.json"
|
"keycloak-themes.json"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readMetaInfKeycloakThemes(params: {
|
export function readMetaInfKeycloakThemes_fromResourcesDirPath(params: {
|
||||||
keycloakifyBuildDirPath: string;
|
resourcesDirPath: string;
|
||||||
}): MetaInfKeycloakTheme {
|
}) {
|
||||||
const { keycloakifyBuildDirPath } = params;
|
const { resourcesDirPath } = params;
|
||||||
|
|
||||||
return JSON.parse(
|
return JSON.parse(
|
||||||
fs
|
fs
|
||||||
.readFileSync(
|
.readFileSync(
|
||||||
getMetaInfKeycloakThemesJsonFilePath({
|
getMetaInfKeycloakThemesJsonFilePath({
|
||||||
keycloakifyBuildDirPath
|
resourcesDirPath
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.toString("utf8")
|
.toString("utf8")
|
||||||
) as MetaInfKeycloakTheme;
|
) as MetaInfKeycloakTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function readMetaInfKeycloakThemes_fromJar(params: {
|
||||||
|
jarFilePath: string;
|
||||||
|
}): Promise<MetaInfKeycloakTheme> {
|
||||||
|
const { jarFilePath } = params;
|
||||||
|
let metaInfKeycloakThemes: MetaInfKeycloakTheme | undefined = undefined;
|
||||||
|
|
||||||
|
await extractArchive({
|
||||||
|
archiveFilePath: jarFilePath,
|
||||||
|
onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => {
|
||||||
|
if (
|
||||||
|
relativeFilePathInArchive ===
|
||||||
|
getMetaInfKeycloakThemesJsonFilePath({ resourcesDirPath: "." })
|
||||||
|
) {
|
||||||
|
metaInfKeycloakThemes = JSON.parse((await readFile()).toString("utf8"));
|
||||||
|
earlyExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(metaInfKeycloakThemes !== undefined);
|
||||||
|
|
||||||
|
return metaInfKeycloakThemes;
|
||||||
|
}
|
||||||
|
|
||||||
export function writeMetaInfKeycloakThemes(params: {
|
export function writeMetaInfKeycloakThemes(params: {
|
||||||
keycloakifyBuildDirPath: string;
|
resourcesDirPath: string;
|
||||||
metaInfKeycloakThemes: MetaInfKeycloakTheme;
|
metaInfKeycloakThemes: MetaInfKeycloakTheme;
|
||||||
}) {
|
}) {
|
||||||
const { keycloakifyBuildDirPath, metaInfKeycloakThemes } = params;
|
const { resourcesDirPath, metaInfKeycloakThemes } = params;
|
||||||
|
|
||||||
const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({
|
const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({
|
||||||
keycloakifyBuildDirPath
|
resourcesDirPath
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@ import { getBuildContext } from "../shared/buildContext";
|
|||||||
import { exclude } from "tsafe/exclude";
|
import { exclude } from "tsafe/exclude";
|
||||||
import type { CliCommandOptions as CliCommandOptions_common } from "../main";
|
import type { CliCommandOptions as CliCommandOptions_common } from "../main";
|
||||||
import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
|
import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
|
||||||
import { readMetaInfKeycloakThemes } from "../shared/metaInfKeycloakThemes";
|
import { readMetaInfKeycloakThemes_fromJar } from "../shared/metaInfKeycloakThemes";
|
||||||
import { accountV1ThemeName, containerName } from "../shared/constants";
|
import { accountV1ThemeName, containerName } from "../shared/constants";
|
||||||
import { SemVer } from "../tools/SemVer";
|
import { SemVer } from "../tools/SemVer";
|
||||||
import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange";
|
import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange";
|
||||||
@ -21,6 +21,9 @@ import * as runExclusive from "run-exclusive";
|
|||||||
import { extractArchive } from "../tools/extractArchive";
|
import { extractArchive } from "../tools/extractArchive";
|
||||||
import { appBuild } from "./appBuild";
|
import { appBuild } from "./appBuild";
|
||||||
import { keycloakifyBuild } from "./keycloakifyBuild";
|
import { keycloakifyBuild } from "./keycloakifyBuild";
|
||||||
|
import { isInside } from "../tools/isInside";
|
||||||
|
import { existsAsync } from "../tools/fs.existsAsync";
|
||||||
|
import { rm } from "../tools/fs.rm";
|
||||||
|
|
||||||
export type CliCommandOptions = CliCommandOptions_common & {
|
export type CliCommandOptions = CliCommandOptions_common & {
|
||||||
port: number;
|
port: number;
|
||||||
@ -112,13 +115,31 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const metaInfKeycloakThemes = readMetaInfKeycloakThemes({
|
const { doesImplementAccountTheme } = await (async () => {
|
||||||
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath
|
const latestJarFilePath = fs
|
||||||
});
|
.readdirSync(buildContext.keycloakifyBuildDirPath)
|
||||||
|
.filter(fileBasename => fileBasename.endsWith(".jar"))
|
||||||
|
.map(fileBasename =>
|
||||||
|
pathJoin(buildContext.keycloakifyBuildDirPath, fileBasename)
|
||||||
|
)
|
||||||
|
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0];
|
||||||
|
|
||||||
const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some(
|
assert(latestJarFilePath !== undefined);
|
||||||
({ name }) => name === accountV1ThemeName
|
|
||||||
);
|
const metaInfKeycloakThemes = await readMetaInfKeycloakThemes_fromJar({
|
||||||
|
jarFilePath: latestJarFilePath
|
||||||
|
});
|
||||||
|
|
||||||
|
const mainThemeEntry = metaInfKeycloakThemes.themes.find(
|
||||||
|
({ name }) => name === buildContext.themeNames[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(mainThemeEntry !== undefined);
|
||||||
|
|
||||||
|
const doesImplementAccountTheme = mainThemeEntry.types.includes("account");
|
||||||
|
|
||||||
|
return { doesImplementAccountTheme };
|
||||||
|
})();
|
||||||
|
|
||||||
const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } =
|
const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } =
|
||||||
await (async function getKeycloakMajor(): Promise<{
|
await (async function getKeycloakMajor(): Promise<{
|
||||||
@ -262,65 +283,30 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
|
|
||||||
const jarFilePath = pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename);
|
const jarFilePath = pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename);
|
||||||
|
|
||||||
const { doUseBuiltInAccountV1Theme } = await (async () => {
|
async function extractThemeResourcesFromJar() {
|
||||||
let doUseBuiltInAccountV1Theme = false;
|
|
||||||
|
|
||||||
await extractArchive({
|
await extractArchive({
|
||||||
archiveFilePath: jarFilePath,
|
archiveFilePath: jarFilePath,
|
||||||
onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => {
|
onArchiveFile: async ({ relativeFilePathInArchive, writeFile }) => {
|
||||||
for (const themeName of buildContext.themeNames) {
|
if (isInside({ dirPath: "theme", filePath: relativeFilePathInArchive })) {
|
||||||
if (
|
await writeFile({
|
||||||
relativeFilePathInArchive ===
|
filePath: pathJoin(
|
||||||
pathJoin("theme", themeName, "account", "theme.properties")
|
buildContext.keycloakifyBuildDirPath,
|
||||||
) {
|
relativeFilePathInArchive
|
||||||
if (
|
)
|
||||||
(await readFile())
|
});
|
||||||
.toString("utf8")
|
|
||||||
.includes("parent=keycloak")
|
|
||||||
) {
|
|
||||||
doUseBuiltInAccountV1Theme = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
earlyExit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return { doUseBuiltInAccountV1Theme };
|
{
|
||||||
})();
|
const destDirPath = pathJoin(buildContext.keycloakifyBuildDirPath, "theme");
|
||||||
|
if (await existsAsync(destDirPath)) {
|
||||||
|
await rm(destDirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const accountThemePropertyPatch = !doUseBuiltInAccountV1Theme
|
await extractThemeResourcesFromJar();
|
||||||
? undefined
|
|
||||||
: () => {
|
|
||||||
for (const themeName of buildContext.themeNames) {
|
|
||||||
const filePath = pathJoin(
|
|
||||||
buildContext.keycloakifyBuildDirPath,
|
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
|
||||||
themeName,
|
|
||||||
"account",
|
|
||||||
"theme.properties"
|
|
||||||
);
|
|
||||||
|
|
||||||
const sourceCode = fs.readFileSync(filePath);
|
|
||||||
|
|
||||||
const modifiedSourceCode = Buffer.from(
|
|
||||||
sourceCode
|
|
||||||
.toString("utf8")
|
|
||||||
.replace(`parent=${accountV1ThemeName}`, "parent=keycloak"),
|
|
||||||
"utf8"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert(Buffer.compare(modifiedSourceCode, sourceCode) !== 0);
|
|
||||||
|
|
||||||
fs.writeFileSync(filePath, modifiedSourceCode);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
accountThemePropertyPatch?.();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
child_process.execSync(`docker rm --force ${containerName}`, {
|
child_process.execSync(`docker rm --force ${containerName}`, {
|
||||||
@ -348,14 +334,19 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
: []),
|
: []),
|
||||||
...[
|
...[
|
||||||
...buildContext.themeNames,
|
...buildContext.themeNames,
|
||||||
...(doUseBuiltInAccountV1Theme ? [] : [accountV1ThemeName])
|
...(fs.existsSync(
|
||||||
|
pathJoin(
|
||||||
|
buildContext.keycloakifyBuildDirPath,
|
||||||
|
"theme",
|
||||||
|
accountV1ThemeName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
? [accountV1ThemeName]
|
||||||
|
: [])
|
||||||
]
|
]
|
||||||
.map(themeName => ({
|
.map(themeName => ({
|
||||||
localDirPath: pathJoin(
|
localDirPath: pathJoin(
|
||||||
buildContext.keycloakifyBuildDirPath,
|
buildContext.keycloakifyBuildDirPath,
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"theme",
|
"theme",
|
||||||
themeName
|
themeName
|
||||||
),
|
),
|
||||||
@ -459,7 +450,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
accountThemePropertyPatch?.();
|
await extractThemeResourcesFromJar();
|
||||||
|
|
||||||
console.log(chalk.green("Theme rebuilt and updated in Keycloak."));
|
console.log(chalk.green("Theme rebuilt and updated in Keycloak."));
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user