-
Notifications
You must be signed in to change notification settings - Fork 0
V.0.4.0 #65
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
V.0.4.0 #65
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,12 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <key>com.apple.security.cs.allow-jit</key> | ||
| <true/> | ||
| <key>com.apple.security.cs.allow-unsigned-executable-memory</key> | ||
| <true/> | ||
| <key>com.apple.security.cs.disable-library-validation</key> | ||
| <true/> | ||
| </dict> | ||
| </plist> | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,12 @@ | ||||||||||||||||||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||||||||||||||||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||||||||||||||||
| <plist version="1.0"> | ||||||||||||||||||||
| <dict> | ||||||||||||||||||||
| <key>com.apple.security.cs.allow-jit</key> | ||||||||||||||||||||
| <true/> | ||||||||||||||||||||
| <key>com.apple.security.cs.allow-unsigned-executable-memory</key> | ||||||||||||||||||||
| <true/> | ||||||||||||||||||||
| <key>com.apple.security.cs.disable-library-validation</key> | ||||||||||||||||||||
| <true/> | ||||||||||||||||||||
|
Comment on lines
+5
to
+10
|
||||||||||||||||||||
| <key>com.apple.security.cs.allow-jit</key> | |
| <true/> | |
| <key>com.apple.security.cs.allow-unsigned-executable-memory</key> | |
| <true/> | |
| <key>com.apple.security.cs.disable-library-validation</key> | |
| <true/> | |
| <!-- Electron/V8 requires JIT; keep this minimal hardened runtime relaxation. --> | |
| <key>com.apple.security.cs.allow-jit</key> | |
| <true/> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,15 +10,75 @@ const rootDir = path.resolve(__dirname, '..'); | |
| const buildDir = path.join(rootDir, 'build'); | ||
|
|
||
| const sourcePng = path.join(buildDir, 'icon-source.png'); | ||
| const sourceWinPng = path.join(buildDir, 'icon-source-win.png'); | ||
| const budgetSourcePng = path.join(buildDir, 'budget-icon-source.png'); | ||
| const budgetSourceWinPng = path.join(buildDir, 'budget-icon-source-win.png'); | ||
| const skipIfMissing = process.argv.includes('--if-present'); | ||
|
|
||
| function fail(message) { | ||
| console.error(`❌ ${message}`); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| function generateIconSet(inputBuffer, outputBaseName) { | ||
| function getPngDimensions(buffer, label) { | ||
| if (!buffer || buffer.length < 24) { | ||
| fail(`Invalid PNG data for ${label}: file is too small.`); | ||
| } | ||
|
|
||
| // PNG signature (8 bytes) | ||
| const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; | ||
| const hasValidSignature = signature.every((value, index) => buffer[index] === value); | ||
| if (!hasValidSignature) { | ||
| fail(`Invalid PNG data for ${label}: missing PNG signature.`); | ||
| } | ||
|
|
||
| const width = buffer.readUInt32BE(16); | ||
| const height = buffer.readUInt32BE(20); | ||
|
|
||
| if (!width || !height) { | ||
| fail(`Invalid PNG dimensions for ${label}: width=${width}, height=${height}.`); | ||
| } | ||
|
|
||
| return { width, height }; | ||
| } | ||
|
|
||
| function assertSquareIcon(buffer, label) { | ||
| const { width, height } = getPngDimensions(buffer, label); | ||
| if (width !== height) { | ||
| fail( | ||
| [ | ||
| `${label} must be a square PNG for reliable .ico/.icns output.`, | ||
| `Found ${width}x${height}.`, | ||
| 'Please export a square image (recommended 1024x1024) and try again.', | ||
| ].join(' ') | ||
| ); | ||
| } | ||
|
|
||
| if (width < 256) { | ||
| fail( | ||
| [ | ||
| `${label} is too small (${width}x${height}).`, | ||
| 'Use at least 256x256 (recommended 1024x1024) for crisp icon variants.', | ||
| ].join(' ') | ||
| ); | ||
| } | ||
|
|
||
| return { width, height }; | ||
| } | ||
|
|
||
| function readValidatedSquarePng(filePath, label) { | ||
| const buffer = fs.readFileSync(filePath); | ||
|
|
||
| if (!buffer || buffer.length === 0) { | ||
| fail(`Source icon file is empty: ${label}`); | ||
| } | ||
|
|
||
| assertSquareIcon(buffer, label); | ||
| return buffer; | ||
| } | ||
|
|
||
| function generateIconSet(inputBuffer, outputBaseName, options = {}) { | ||
| const { icoInputBuffer = inputBuffer, sourceFilePath, icoSourceLabel } = options; | ||
| const outputPng = path.join(buildDir, `${outputBaseName}.png`); | ||
| const outputIco = path.join(buildDir, `${outputBaseName}.ico`); | ||
| const outputIcns = path.join(buildDir, `${outputBaseName}.icns`); | ||
|
|
@@ -28,19 +88,21 @@ function generateIconSet(inputBuffer, outputBaseName) { | |
| fail(`Failed to generate ICNS file for ${outputBaseName}`); | ||
| } | ||
|
|
||
| const icoBuffer = png2icons.createICO(inputBuffer, png2icons.BICUBIC2, 0, false, true); | ||
| // Use BMP payloads for all ICO entries to maximize compatibility across | ||
| // shell previews and older Windows icon decoders. | ||
| const icoBuffer = png2icons.createICO(icoInputBuffer, png2icons.BICUBIC2, 0, false, false); | ||
| if (!icoBuffer) { | ||
| fail(`Failed to generate ICO file for ${outputBaseName}`); | ||
| } | ||
|
|
||
| fs.copyFileSync( | ||
| outputBaseName === 'icon' ? sourcePng : budgetSourcePng, | ||
| outputPng | ||
| ); | ||
| fs.copyFileSync(sourceFilePath, outputPng); | ||
| fs.writeFileSync(outputIcns, icnsBuffer); | ||
|
Comment on lines
80
to
99
|
||
| fs.writeFileSync(outputIco, icoBuffer); | ||
|
|
||
| console.log(`✓ Generated icon files for ${outputBaseName}:`); | ||
| if (icoSourceLabel) { | ||
| console.log(` - Windows ICO source: ${icoSourceLabel}`); | ||
| } | ||
| console.log(` - ${path.relative(rootDir, outputPng)}`); | ||
| console.log(` - ${path.relative(rootDir, outputIcns)}`); | ||
| console.log(` - ${path.relative(rootDir, outputIco)}`); | ||
|
|
@@ -60,24 +122,48 @@ if (!fs.existsSync(sourcePng)) { | |
| ); | ||
| } | ||
|
|
||
| const inputBuffer = fs.readFileSync(sourcePng); | ||
|
|
||
| if (!inputBuffer || inputBuffer.length === 0) { | ||
| fail('Source icon file is empty: build/icon-source.png'); | ||
| } | ||
| const inputBuffer = readValidatedSquarePng(sourcePng, 'build/icon-source.png'); | ||
| const inputWinBuffer = fs.existsSync(sourceWinPng) | ||
| ? readValidatedSquarePng(sourceWinPng, 'build/icon-source-win.png') | ||
| : inputBuffer; | ||
|
|
||
| fs.mkdirSync(buildDir, { recursive: true }); | ||
|
|
||
| generateIconSet(inputBuffer, 'icon'); | ||
| generateIconSet(inputBuffer, 'icon', { | ||
| icoInputBuffer: inputWinBuffer, | ||
| sourceFilePath: sourcePng, | ||
| icoSourceLabel: fs.existsSync(sourceWinPng) ? 'build/icon-source-win.png' : 'build/icon-source.png', | ||
| }); | ||
|
|
||
| if (fs.existsSync(budgetSourcePng)) { | ||
| const budgetInputBuffer = fs.readFileSync(budgetSourcePng); | ||
|
|
||
| if (!budgetInputBuffer || budgetInputBuffer.length === 0) { | ||
| fail('Source icon file is empty: build/budget-icon-source.png'); | ||
| const budgetInputBuffer = readValidatedSquarePng(budgetSourcePng, 'build/budget-icon-source.png'); | ||
| const budgetWinInputBuffer = fs.existsSync(budgetSourceWinPng) | ||
| ? readValidatedSquarePng(budgetSourceWinPng, 'build/budget-icon-source-win.png') | ||
| : budgetInputBuffer; | ||
|
|
||
| const { width, height } = getPngDimensions(budgetInputBuffer, 'build/budget-icon-source.png'); | ||
|
|
||
| if (width !== height) { | ||
| console.warn( | ||
| [ | ||
| '⚠️ build/budget-icon-source.png is not square', | ||
| `(${width}x${height}).`, | ||
| 'Using app icon for .budget file associations to avoid corrupted icon output.', | ||
| ].join(' ') | ||
| ); | ||
|
|
||
| fs.copyFileSync(path.join(buildDir, 'icon.png'), path.join(buildDir, 'budget-file-icon.png')); | ||
| fs.copyFileSync(path.join(buildDir, 'icon.icns'), path.join(buildDir, 'budget-file-icon.icns')); | ||
| fs.copyFileSync(path.join(buildDir, 'icon.ico'), path.join(buildDir, 'budget-file-icon.ico')); | ||
| } else { | ||
| generateIconSet(budgetInputBuffer, 'budget-file-icon', { | ||
| icoInputBuffer: budgetWinInputBuffer, | ||
| sourceFilePath: budgetSourcePng, | ||
| icoSourceLabel: fs.existsSync(budgetSourceWinPng) | ||
| ? 'build/budget-icon-source-win.png' | ||
| : 'build/budget-icon-source.png', | ||
| }); | ||
| } | ||
|
|
||
| generateIconSet(budgetInputBuffer, 'budget-file-icon'); | ||
| } else { | ||
| // Fallback so file association always has a valid icon set. | ||
| fs.copyFileSync(path.join(buildDir, 'icon.png'), path.join(buildDir, 'budget-file-icon.png')); | ||
|
|
||
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.
This inherit entitlements file is added but (based on the current electron-builder config) nothing references it. If helpers need distinct entitlements, add
mac.entitlementsInherittopackage.jsonbuild config; otherwise consider removing this file to avoid dead configuration that can drift over time.