From 84c774503d7efc087e150c48a4cfaef59a3c6aa9 Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Mon, 10 Jun 2024 07:57:12 +0200 Subject: [PATCH] Build rework checkpoint --- src/bin/download-keycloak-default-theme.ts | 63 ---------- src/bin/keycloakify/buildJars/buildJar.ts | 30 ++--- src/bin/keycloakify/buildJars/buildJars.ts | 10 +- .../bringInAccountV1.ts | 13 +- .../generateSrcMainResources.ts | 14 ++- .../generateSrcMainResourcesForMainTheme.ts | 24 +--- ...generateSrcMainResourcesForThemeVariant.ts | 24 ++-- .../generateStartKeycloakTestingContainer.ts | 74 ----------- src/bin/keycloakify/keycloakify.ts | 16 ++- src/bin/main.ts | 14 --- src/bin/shared/buildContext.ts | 10 +- src/bin/shared/metaInfKeycloakThemes.ts | 51 +++++--- src/bin/start-keycloak/start-keycloak.ts | 119 ++++++++---------- 13 files changed, 159 insertions(+), 303 deletions(-) delete mode 100644 src/bin/download-keycloak-default-theme.ts delete mode 100644 src/bin/keycloakify/generateStartKeycloakTestingContainer.ts diff --git a/src/bin/download-keycloak-default-theme.ts b/src/bin/download-keycloak-default-theme.ts deleted file mode 100644 index 886b4170..00000000 --- a/src/bin/download-keycloak-default-theme.ts +++ /dev/null @@ -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`)); -} diff --git a/src/bin/keycloakify/buildJars/buildJar.ts b/src/bin/keycloakify/buildJars/buildJar.ts index 429824d4..024698b1 100644 --- a/src/bin/keycloakify/buildJars/buildJar.ts +++ b/src/bin/keycloakify/buildJars/buildJar.ts @@ -32,12 +32,14 @@ export async function buildJar(params: { jarFileBasename: string; keycloakAccountV1Version: KeycloakAccountV1Version; keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion; + resourcesDirPath: string; buildContext: BuildContextLike; }): Promise { const { jarFileBasename, keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, + resourcesDirPath, buildContext } = params; @@ -57,7 +59,7 @@ export async function buildJar(params: { if ( fileRelativePath === - getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath: "." }) + getMetaInfKeycloakThemesJsonFilePath({ resourcesDirPath: "." }) ) { return { modifiedSourceCode: sourceCode }; } @@ -65,7 +67,7 @@ export async function buildJar(params: { for (const themeName of [...buildContext.themeNames, accountV1ThemeName]) { if ( isInside({ - dirPath: pathJoin("src", "main", "resources", "theme", themeName), + dirPath: pathJoin("theme", themeName), filePath: fileRelativePath }) ) { @@ -87,13 +89,7 @@ export async function buildJar(params: { if ( isInside({ - dirPath: pathJoin( - "src", - "main", - "resources", - "theme", - accountV1ThemeName - ), + dirPath: pathJoin("theme", accountV1ThemeName), filePath: fileRelativePath }) ) { @@ -103,7 +99,7 @@ export async function buildJar(params: { if ( fileRelativePath === getMetaInfKeycloakThemesJsonFilePath({ - keycloakifyBuildDirPath: "." + resourcesDirPath: "." }) ) { const keycloakThemesJsonParsed = JSON.parse( @@ -128,15 +124,7 @@ export async function buildJar(params: { for (const themeName of buildContext.themeNames) { if ( fileRelativePath === - pathJoin( - "src", - "main", - "resources", - "theme", - themeName, - "account", - "theme.properties" - ) + pathJoin("theme", themeName, "account", "theme.properties") ) { const modifiedSourceCode = Buffer.from( sourceCode @@ -160,8 +148,8 @@ export async function buildJar(params: { }; transformCodebase({ - srcDirPath: buildContext.keycloakifyBuildDirPath, - destDirPath: keycloakifyBuildTmpDirPath, + srcDirPath: resourcesDirPath, + destDirPath: pathJoin(keycloakifyBuildTmpDirPath, "src", "main", "resources"), transformSourceCode: params => { const resultCommon = transformCodebase_common(params); diff --git a/src/bin/keycloakify/buildJars/buildJars.ts b/src/bin/keycloakify/buildJars/buildJars.ts index d7939780..f67b5677 100644 --- a/src/bin/keycloakify/buildJars/buildJars.ts +++ b/src/bin/keycloakify/buildJars/buildJars.ts @@ -8,7 +8,7 @@ import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar"; import { buildJar, BuildContextLike as BuildContextLike_buildJar } from "./buildJar"; import type { BuildContext } from "../../shared/buildContext"; import { getJarFileBasename } from "../../shared/getJarFileBasename"; -import { readMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes"; +import { readMetaInfKeycloakThemes_fromResourcesDirPath } from "../../shared/metaInfKeycloakThemes"; import { accountV1ThemeName } from "../../shared/constants"; export type BuildContextLike = BuildContextLike_buildJar & { @@ -18,12 +18,13 @@ export type BuildContextLike = BuildContextLike_buildJar & { assert(); export async function buildJars(params: { + resourcesDirPath: string; buildContext: BuildContextLike; }): Promise { - const { buildContext } = params; + const { resourcesDirPath, buildContext } = params; - const doesImplementAccountTheme = readMetaInfKeycloakThemes({ - keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath + const doesImplementAccountTheme = readMetaInfKeycloakThemes_fromResourcesDirPath({ + resourcesDirPath: buildContext.keycloakifyBuildDirPath }).themes.some(({ name }) => name === accountV1ThemeName); await Promise.all( @@ -71,6 +72,7 @@ export async function buildJars(params: { jarFileBasename, keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, + resourcesDirPath, buildContext }) ) diff --git a/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts b/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts index f2a9de6f..adfaedf9 100644 --- a/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts +++ b/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts @@ -13,13 +13,15 @@ import { transformCodebase } from "../../tools/transformCodebase"; export type BuildContextLike = { cacheDirPath: string; npmWorkspaceRootDirPath: string; - keycloakifyBuildDirPath: string; }; assert(); -export async function bringInAccountV1(params: { buildContext: BuildContextLike }) { - const { buildContext } = params; +export async function bringInAccountV1(params: { + resourcesDirPath: string; + buildContext: BuildContextLike; +}) { + const { resourcesDirPath, buildContext } = params; const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({ keycloakVersion: lastKeycloakVersionWithAccountV1, @@ -27,10 +29,7 @@ export async function bringInAccountV1(params: { buildContext: BuildContextLike }); const accountV1DirPath = pathJoin( - buildContext.keycloakifyBuildDirPath, - "src", - "main", - "resources", + resourcesDirPath, "theme", accountV1ThemeName, "account" diff --git a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts index 4e7035ee..5dc44922 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts @@ -5,6 +5,8 @@ import { type BuildContextLike as BuildContextLike_generateSrcMainResourcesForMainTheme } from "./generateSrcMainResourcesForMainTheme"; import { generateSrcMainResourcesForThemeVariant } from "./generateSrcMainResourcesForThemeVariant"; +import fs from "fs"; +import { rmSync } from "../../tools/fs.rmSync"; export type BuildContextLike = BuildContextLike_generateSrcMainResourcesForMainTheme & { themeNames: string[]; @@ -14,21 +16,27 @@ assert(); export async function generateSrcMainResources(params: { buildContext: BuildContextLike; + resourcesDirPath: string; }): Promise { - const { buildContext } = params; + const { resourcesDirPath, buildContext } = params; const [themeName, ...themeVariantNames] = buildContext.themeNames; + if (fs.existsSync(resourcesDirPath)) { + rmSync(resourcesDirPath, { recursive: true }); + } + await generateSrcMainResourcesForMainTheme({ + resourcesDirPath, themeName, buildContext }); for (const themeVariantName of themeVariantNames) { generateSrcMainResourcesForThemeVariant({ + resourcesDirPath, themeName, - themeVariantName, - buildContext + themeVariantName }); } } diff --git a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts index a979c8eb..66709f4a 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts @@ -43,14 +43,10 @@ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForProper export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode & BuildContextLike_downloadKeycloakStaticResources & BuildContextLike_bringInAccountV1 & { - bundler: "vite" | "webpack"; extraThemeProperties: string[] | undefined; loginThemeResourcesFromKeycloakVersion: string; - projectBuildDirPath: string; - assetsDirPath: string; - urlPathname: string | undefined; projectDirPath: string; - keycloakifyBuildDirPath: string; + projectBuildDirPath: string; environmentVariables: { name: string; default: string }[]; }; @@ -58,9 +54,10 @@ assert(); export async function generateSrcMainResourcesForMainTheme(params: { themeName: string; + resourcesDirPath: string; buildContext: BuildContextLike; }): Promise { - const { themeName, buildContext } = params; + const { themeName, resourcesDirPath, buildContext } = params; const { themeSrcDirPath } = getThemeSrcDirPath({ projectDirPath: buildContext.projectDirPath @@ -68,15 +65,7 @@ export async function generateSrcMainResourcesForMainTheme(params: { const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => { const { themeType } = params; - return pathJoin( - buildContext.keycloakifyBuildDirPath, - "src", - "main", - "resources", - "theme", - themeName, - themeType - ); + return pathJoin(resourcesDirPath, "theme", themeName, themeType); }; const cssGlobalsToDefine: Record = {}; @@ -207,8 +196,6 @@ export async function generateSrcMainResourcesForMainTheme(params: { ].forEach(pageId => { const { ftlCode } = generateFtlFilesCode({ pageId }); - fs.mkdirSync(themeTypeDirPath, { recursive: true }); - fs.writeFileSync( pathJoin(themeTypeDirPath, pageId), Buffer.from(ftlCode, "utf8") @@ -291,6 +278,7 @@ export async function generateSrcMainResourcesForMainTheme(params: { if (implementedThemeTypes.account) { await bringInAccountV1({ + resourcesDirPath, buildContext }); } @@ -313,7 +301,7 @@ export async function generateSrcMainResourcesForMainTheme(params: { } writeMetaInfKeycloakThemes({ - keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath, + resourcesDirPath, metaInfKeycloakThemes }); } diff --git a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts index 4a343c53..1e8b752e 100644 --- a/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts +++ b/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts @@ -2,7 +2,7 @@ import { join as pathJoin, extname as pathExtname, sep as pathSep } from "path"; import { transformCodebase } from "../../tools/transformCodebase"; import type { BuildContext } from "../../shared/buildContext"; import { - readMetaInfKeycloakThemes, + readMetaInfKeycloakThemes_fromResourcesDirPath, writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes"; import { assert } from "tsafe/assert"; @@ -14,20 +14,13 @@ export type BuildContextLike = { assert(); export function generateSrcMainResourcesForThemeVariant(params: { + resourcesDirPath: string; themeName: string; themeVariantName: string; - buildContext: BuildContextLike; }) { - const { themeName, themeVariantName, buildContext } = params; + const { resourcesDirPath, themeName, themeVariantName } = params; - const mainThemeDirPath = pathJoin( - buildContext.keycloakifyBuildDirPath, - "src", - "main", - "resources", - "theme", - themeName - ); + const mainThemeDirPath = pathJoin(resourcesDirPath, "theme", themeName); transformCodebase({ srcDirPath: mainThemeDirPath, @@ -57,9 +50,10 @@ export function generateSrcMainResourcesForThemeVariant(params: { }); { - const updatedMetaInfKeycloakThemes = readMetaInfKeycloakThemes({ - keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath - }); + const updatedMetaInfKeycloakThemes = + readMetaInfKeycloakThemes_fromResourcesDirPath({ + resourcesDirPath + }); updatedMetaInfKeycloakThemes.themes.push({ name: themeVariantName, @@ -73,7 +67,7 @@ export function generateSrcMainResourcesForThemeVariant(params: { }); writeMetaInfKeycloakThemes({ - keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath, + resourcesDirPath, metaInfKeycloakThemes: updatedMetaInfKeycloakThemes }); } diff --git a/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts b/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts deleted file mode 100644 index 98cf0c5b..00000000 --- a/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +++ /dev/null @@ -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(); - -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 } - ); -} diff --git a/src/bin/keycloakify/keycloakify.ts b/src/bin/keycloakify/keycloakify.ts index c7513c3d..296d57e9 100644 --- a/src/bin/keycloakify/keycloakify.ts +++ b/src/bin/keycloakify/keycloakify.ts @@ -9,6 +9,7 @@ import type { CliCommandOptions } from "../main"; import chalk from "chalk"; import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion"; import * as os from "os"; +import { rmSync } from "../tools/fs.rmSync"; export async function command(params: { cliCommandOptions: CliCommandOptions }) { 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: { if (buildContext.bundler !== "vite") { @@ -84,7 +90,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } child_process.execSync("npx vite", { - cwd: buildContext.projectDirPath, + cwd: resourcesDirPath, env: { ...process.env, [vitePluginSubScriptEnvNames.runPostBuildScript]: @@ -98,7 +104,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) break build_jars; } - await buildJars({ buildContext }); + await buildJars({ resourcesDirPath, buildContext }); + } + + if (Date.now() === 0) { + rmSync(resourcesDirPath, { recursive: true }); } console.log( diff --git a/src/bin/main.ts b/src/bin/main.ts index 354b121b..84125409 100644 --- a/src/bin/main.ts +++ b/src/bin/main.ts @@ -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 .command({ name: "eject-page", diff --git a/src/bin/shared/buildContext.ts b/src/bin/shared/buildContext.ts index 6973a403..d6de61a5 100644 --- a/src/bin/shared/buildContext.ts +++ b/src/bin/shared/buildContext.ts @@ -12,7 +12,7 @@ import { vitePluginSubScriptEnvNames } from "./constants"; export type BuildContext = { bundler: "vite" | "webpack"; themeVersion: string; - themeNames: string[]; + themeNames: [string, ...string[]]; extraThemeProperties: string[] | undefined; groupId: string; artifactId: string; @@ -147,7 +147,7 @@ export function getBuildContext(params: { ...resolvedViteConfig?.buildOptions }; - const themeNames = (() => { + const themeNames = ((): [string, ...string[]] => { if (buildOptions.themeName === undefined) { return [ parsedPackageJson.name @@ -161,7 +161,11 @@ export function getBuildContext(params: { return [buildOptions.themeName]; } - return buildOptions.themeName; + const [mainThemeName, ...themeVariantNames] = buildOptions.themeName; + + assert(mainThemeName !== undefined); + + return [mainThemeName, ...themeVariantNames]; })(); const projectBuildDirPath = (() => { diff --git a/src/bin/shared/metaInfKeycloakThemes.ts b/src/bin/shared/metaInfKeycloakThemes.ts index db0a4fce..61b62fc3 100644 --- a/src/bin/shared/metaInfKeycloakThemes.ts +++ b/src/bin/shared/metaInfKeycloakThemes.ts @@ -1,50 +1,73 @@ import { join as pathJoin, dirname as pathDirname } from "path"; import type { ThemeType } from "./constants"; import * as fs from "fs"; +import { assert } from "tsafe/assert"; +import { extractArchive } from "../tools/extractArchive"; export type MetaInfKeycloakTheme = { themes: { name: string; types: (ThemeType | "email")[] }[]; }; export function getMetaInfKeycloakThemesJsonFilePath(params: { - keycloakifyBuildDirPath: string; + resourcesDirPath: string; }) { - const { keycloakifyBuildDirPath } = params; + const { resourcesDirPath } = params; return pathJoin( - keycloakifyBuildDirPath === "." ? "" : keycloakifyBuildDirPath, - "src", - "main", - "resources", + resourcesDirPath === "." ? "" : resourcesDirPath, "META-INF", "keycloak-themes.json" ); } -export function readMetaInfKeycloakThemes(params: { - keycloakifyBuildDirPath: string; -}): MetaInfKeycloakTheme { - const { keycloakifyBuildDirPath } = params; +export function readMetaInfKeycloakThemes_fromResourcesDirPath(params: { + resourcesDirPath: string; +}) { + const { resourcesDirPath } = params; return JSON.parse( fs .readFileSync( getMetaInfKeycloakThemesJsonFilePath({ - keycloakifyBuildDirPath + resourcesDirPath }) ) .toString("utf8") ) as MetaInfKeycloakTheme; } +export async function readMetaInfKeycloakThemes_fromJar(params: { + jarFilePath: string; +}): Promise { + 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: { - keycloakifyBuildDirPath: string; + resourcesDirPath: string; metaInfKeycloakThemes: MetaInfKeycloakTheme; }) { - const { keycloakifyBuildDirPath, metaInfKeycloakThemes } = params; + const { resourcesDirPath, metaInfKeycloakThemes } = params; const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({ - keycloakifyBuildDirPath + resourcesDirPath }); { diff --git a/src/bin/start-keycloak/start-keycloak.ts b/src/bin/start-keycloak/start-keycloak.ts index ae7abf3e..00233234 100644 --- a/src/bin/start-keycloak/start-keycloak.ts +++ b/src/bin/start-keycloak/start-keycloak.ts @@ -2,7 +2,7 @@ import { getBuildContext } from "../shared/buildContext"; import { exclude } from "tsafe/exclude"; import type { CliCommandOptions as CliCommandOptions_common } from "../main"; import { promptKeycloakVersion } from "../shared/promptKeycloakVersion"; -import { readMetaInfKeycloakThemes } from "../shared/metaInfKeycloakThemes"; +import { readMetaInfKeycloakThemes_fromJar } from "../shared/metaInfKeycloakThemes"; import { accountV1ThemeName, containerName } from "../shared/constants"; import { SemVer } from "../tools/SemVer"; import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange"; @@ -21,6 +21,9 @@ import * as runExclusive from "run-exclusive"; import { extractArchive } from "../tools/extractArchive"; import { appBuild } from "./appBuild"; 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 & { port: number; @@ -112,13 +115,31 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } } - const metaInfKeycloakThemes = readMetaInfKeycloakThemes({ - keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath - }); + const { doesImplementAccountTheme } = await (async () => { + 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( - ({ name }) => name === accountV1ThemeName - ); + assert(latestJarFilePath !== undefined); + + 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 } = await (async function getKeycloakMajor(): Promise<{ @@ -262,65 +283,30 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const jarFilePath = pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename); - const { doUseBuiltInAccountV1Theme } = await (async () => { - let doUseBuiltInAccountV1Theme = false; - + async function extractThemeResourcesFromJar() { await extractArchive({ archiveFilePath: jarFilePath, - onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => { - for (const themeName of buildContext.themeNames) { - if ( - relativeFilePathInArchive === - pathJoin("theme", themeName, "account", "theme.properties") - ) { - if ( - (await readFile()) - .toString("utf8") - .includes("parent=keycloak") - ) { - doUseBuiltInAccountV1Theme = true; - } - - earlyExit(); - } + onArchiveFile: async ({ relativeFilePathInArchive, writeFile }) => { + if (isInside({ dirPath: "theme", filePath: relativeFilePathInArchive })) { + await writeFile({ + filePath: pathJoin( + buildContext.keycloakifyBuildDirPath, + relativeFilePathInArchive + ) + }); } } }); + } - return { doUseBuiltInAccountV1Theme }; - })(); + { + const destDirPath = pathJoin(buildContext.keycloakifyBuildDirPath, "theme"); + if (await existsAsync(destDirPath)) { + await rm(destDirPath, { recursive: true }); + } + } - const accountThemePropertyPatch = !doUseBuiltInAccountV1Theme - ? 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?.(); + await extractThemeResourcesFromJar(); try { child_process.execSync(`docker rm --force ${containerName}`, { @@ -348,14 +334,19 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) : []), ...[ ...buildContext.themeNames, - ...(doUseBuiltInAccountV1Theme ? [] : [accountV1ThemeName]) + ...(fs.existsSync( + pathJoin( + buildContext.keycloakifyBuildDirPath, + "theme", + accountV1ThemeName + ) + ) + ? [accountV1ThemeName] + : []) ] .map(themeName => ({ localDirPath: pathJoin( buildContext.keycloakifyBuildDirPath, - "src", - "main", - "resources", "theme", themeName ), @@ -459,7 +450,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) return; } - accountThemePropertyPatch?.(); + await extractThemeResourcesFromJar(); console.log(chalk.green("Theme rebuilt and updated in Keycloak.")); });