-
Notifications
You must be signed in to change notification settings - Fork 7
RU-T50 Build fix #255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RU-T50 Build fix #255
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| const { mkdir, rm, stat } = require('node:fs/promises'); | ||
| const path = require('node:path'); | ||
|
|
||
| const Jimp = require('jimp'); | ||
| const { addBadge } = require('app-icon-badge'); | ||
|
|
||
| const MAX_IMAGE_READ_ATTEMPTS = 200; | ||
| const IMAGE_READ_RETRY_DELAY_MS = 25; | ||
|
|
||
| const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)); | ||
|
|
||
| const waitForReadableImage = async (destinationPath) => { | ||
| let previousSize = -1; | ||
|
|
||
| for (let attempt = 0; attempt < MAX_IMAGE_READ_ATTEMPTS; attempt += 1) { | ||
| try { | ||
| const file = await stat(destinationPath); | ||
| if (file.size > 0 && file.size === previousSize) { | ||
| const image = await Jimp.read(destinationPath); | ||
| if (image.bitmap.width > 0 && image.bitmap.height > 0) { | ||
| return; | ||
| } | ||
| } | ||
| previousSize = file.size; | ||
| } catch { | ||
| previousSize = -1; | ||
| } | ||
|
|
||
| await delay(IMAGE_READ_RETRY_DELAY_MS); | ||
| } | ||
|
|
||
| throw new Error(`Generated app icon is not a readable image: ${destinationPath}`); | ||
| }; | ||
|
|
||
| const generateBadge = async ({ badges, destinationPath, isAdaptiveIcon, sourcePath }) => { | ||
| await mkdir(path.dirname(destinationPath), { recursive: true }); | ||
| await rm(destinationPath, { force: true }); | ||
| await addBadge({ | ||
| badges, | ||
| dstPath: destinationPath, | ||
| icon: sourcePath, | ||
| isAdaptiveIcon, | ||
| }); | ||
| await waitForReadableImage(destinationPath); | ||
| }; | ||
|
|
||
| const main = async () => { | ||
| const payload = JSON.parse(process.argv[2] ?? '{}'); | ||
| if (!Array.isArray(payload.tasks)) { | ||
| throw new Error('Expected an app icon badge task list'); | ||
| } | ||
|
|
||
| for (const task of payload.tasks) { | ||
| await generateBadge(task); | ||
| } | ||
| }; | ||
|
|
||
| main().catch((error) => { | ||
| const message = error instanceof Error ? (error.stack ?? error.message) : String(error); | ||
| process.stderr.write(`${path.basename(__filename)}: ${message}\n`); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unstructured error logging occurs because Kody rule violation: Include error context in structured logs Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
| process.exitCode = 1; | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| const { execFileSync } = require('node:child_process'); | ||
| const path = require('node:path'); | ||
|
|
||
| const OUTPUT_DIRECTORY = '.expo/app-icon-badge'; | ||
| const GENERATOR_SCRIPT = path.join(__dirname, 'generate-app-icon-badges.js'); | ||
|
|
||
| const resolveProjectPath = (projectRoot, filePath) => path.resolve(projectRoot, filePath); | ||
|
|
||
| const createBadgeTask = ({ projectRoot, sourcePath, destinationPath, badges, isAdaptiveIcon = false }) => ({ | ||
| badges, | ||
| destinationPath: resolveProjectPath(projectRoot, destinationPath), | ||
| isAdaptiveIcon, | ||
| sourcePath: resolveProjectPath(projectRoot, sourcePath), | ||
| }); | ||
|
|
||
| const generateBadgedIcons = (projectRoot, tasks) => { | ||
| // The upstream config plugin starts image writes without awaiting them. A child | ||
| // process lets Expo block until every generated icon has been fully validated. | ||
| execFileSync(process.execPath, [GENERATOR_SCRIPT, JSON.stringify({ tasks })], { | ||
| cwd: projectRoot, | ||
| stdio: 'inherit', | ||
| }); | ||
|
Comment on lines
+19
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opaque build failures occur because the Also found in:
Kody rule violation: Add try-catch blocks for external calls Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
| }; | ||
|
|
||
| const withAppIconBadge = (config, options = {}) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Render performance degradation occurs because Kody rule violation: Avoid using .bind() or arrow functions in JSX props Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
| const { badges = [], enabled = true } = options; | ||
| if (!enabled) { | ||
| return config; | ||
| } | ||
|
|
||
| const projectRoot = config._internal?.projectRoot ?? process.cwd(); | ||
| const tasks = []; | ||
| const iconSource = config.icon; | ||
| const iosIconSource = config.ios?.icon; | ||
| const adaptiveIconSource = config.android?.adaptiveIcon?.foregroundImage; | ||
|
|
||
| if (typeof iconSource === 'string') { | ||
| const destinationPath = `${OUTPUT_DIRECTORY}/icon.png`; | ||
| tasks.push(createBadgeTask({ projectRoot, sourcePath: iconSource, destinationPath, badges })); | ||
| config.icon = destinationPath; | ||
| } | ||
|
|
||
| if (typeof iosIconSource === 'string') { | ||
| const destinationPath = iosIconSource === iconSource ? `${OUTPUT_DIRECTORY}/icon.png` : `${OUTPUT_DIRECTORY}/ios-icon.png`; | ||
| if (iosIconSource !== iconSource) { | ||
| tasks.push(createBadgeTask({ projectRoot, sourcePath: iosIconSource, destinationPath, badges })); | ||
| } | ||
| config.ios.icon = destinationPath; | ||
| } | ||
|
|
||
| if (typeof adaptiveIconSource === 'string') { | ||
| const destinationPath = `${OUTPUT_DIRECTORY}/foreground-image.png`; | ||
| tasks.push(createBadgeTask({ projectRoot, sourcePath: adaptiveIconSource, destinationPath, badges, isAdaptiveIcon: true })); | ||
| config.android.adaptiveIcon.foregroundImage = destinationPath; | ||
| } | ||
|
|
||
| if (tasks.length > 0) { | ||
| generateBadgedIcons(projectRoot, tasks); | ||
| } | ||
|
|
||
| return config; | ||
| }; | ||
|
|
||
| module.exports = withAppIconBadge; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sequential task execution bottleneck occurs because the first
awaitloop failure aborts all remaining independent badge tasks. Useawait Promise.allSettled(payload.tasks.map(generateBadge))to attempt all tasks, collect per-task errors, and report them together.Kody rule violation: Use Promise.allSettled for batch operations with partial failures
Prompt for LLM
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.