Skip to content

Commit 162a918

Browse files
committed
Deduplicate bundled PHP binary helpers
1 parent 0df35c0 commit 162a918

5 files changed

Lines changed: 60 additions & 98 deletions

File tree

apps/cli/lib/dependency-management/php-binary.ts

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import path from 'path';
55
import { downloadFile } from '@studio/common/lib/download-file';
66
import { extractZip } from '@studio/common/lib/extract-zip';
77
import { isErrnoException } from '@studio/common/lib/is-errno-exception';
8+
import {
9+
findBundledPhpBinary,
10+
verifyBundledPhpBinaryHash,
11+
} from '@studio/common/lib/php-binary-bundle';
812
import {
913
buildPhpBinaryUrl,
10-
getBundledPhpBinaryRelativePath,
1114
getPhpBinaryHash,
1215
validateNativePhpVersion,
1316
PHP_PATCH_VERSIONS,
@@ -72,7 +75,12 @@ async function claimInstallSlot( destDir: string, destPath: string ): Promise< b
7275
async function installBundledBinaryIfAvailable(
7376
version: NativePhpSupportedVersion
7477
): Promise< boolean > {
75-
const sourcePath = findBundledBinary( version, process.platform, process.arch );
78+
const sourcePath = findBundledPhpBinary( version, process.platform, process.arch, [
79+
// Built CLI bundle: dist/cli/bin/php/...
80+
path.join( import.meta.dirname, 'bin', 'php' ),
81+
// Source tree fallback for local development before the Vite build runs.
82+
path.resolve( import.meta.dirname, '..', '..', 'bin', 'php' ),
83+
] );
7684
if ( ! sourcePath ) {
7785
return false;
7886
}
@@ -85,7 +93,7 @@ async function installBundledBinaryIfAvailable(
8593
}
8694

8795
try {
88-
await verifyBundledHash( sourcePath );
96+
await verifyBundledPhpBinaryHash( sourcePath );
8997
fs.copyFileSync( sourcePath, destPath );
9098
if ( process.platform !== 'win32' ) {
9199
fs.chmodSync( destPath, 0o755 );
@@ -97,43 +105,6 @@ async function installBundledBinaryIfAvailable(
97105
}
98106
}
99107

100-
function findBundledBinary(
101-
version: NativePhpSupportedVersion,
102-
platform: NodeJS.Platform,
103-
arch: string
104-
): string | undefined {
105-
const relativePath = getBundledPhpBinaryRelativePath( version, platform, arch );
106-
const roots = [
107-
path.join( import.meta.dirname, 'bin', 'php' ),
108-
path.resolve( import.meta.dirname, '..', '..', 'bin', 'php' ),
109-
];
110-
111-
for ( const root of roots ) {
112-
const sourcePath = path.join( root, relativePath );
113-
if ( fs.existsSync( sourcePath ) ) {
114-
return sourcePath;
115-
}
116-
}
117-
}
118-
119-
async function verifyBundledHash( sourcePath: string ): Promise< void > {
120-
const hashPath = `${ sourcePath }.sha256`;
121-
if ( ! fs.existsSync( hashPath ) ) {
122-
throw new Error( `No pinned SHA-256 hash for bundled PHP binary at ${ sourcePath }.` );
123-
}
124-
125-
const [ expected ] = ( await fs.promises.readFile( hashPath, 'utf8' ) ).trim().split( /\s+/ );
126-
const data = await fs.promises.readFile( sourcePath );
127-
const actual = crypto.createHash( 'sha256' ).update( data ).digest( 'hex' );
128-
if ( actual !== expected ) {
129-
throw new Error(
130-
`SHA-256 mismatch for bundled PHP binary at ${ sourcePath }:\n` +
131-
` expected ${ expected }\n` +
132-
` got ${ actual }`
133-
);
134-
}
135-
}
136-
137108
async function downloadAndInstall(
138109
version: NativePhpSupportedVersion,
139110
onProgress?: ( downloaded: number, total: number ) => void

scripts/build-php-cli-macos.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ patch(
236236
)
237237
PY
238238

239-
php bin/spc doctor
240239
php bin/spc download --with-php="$PHP_MINOR" --for-extensions="$EXTENSIONS" --retry=2
241240

242241
build_arch() {

scripts/download-php-binary.ts

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@ import { z } from 'zod';
2626
import { downloadFile } from '../tools/common/lib/download-file';
2727
import { extractZip } from '../tools/common/lib/extract-zip';
2828
import { isErrnoException } from '../tools/common/lib/is-errno-exception';
29+
import {
30+
findBundledPhpBinary,
31+
verifyBundledPhpBinaryHash,
32+
} from '../tools/common/lib/php-binary-bundle';
2933
import {
3034
buildPhpBinaryUrl,
31-
getBundledPhpBinaryRelativePath,
3235
getPhpBinaryHash,
3336
getPhpBinaryFilename,
3437
getPhpBinaryPlatformArch,
@@ -119,12 +122,14 @@ async function main(): Promise< void > {
119122
}
120123

121124
try {
122-
const bundledPath = findBundledBinary( version, args.platform, args.arch );
125+
const bundledPath = findBundledPhpBinary( version, args.platform, args.arch, [
126+
path.join( __dirname, '..', 'apps', 'cli', 'bin', 'php' ),
127+
] );
123128
if ( bundledPath ) {
124129
console.log(
125130
`Installing bundled PHP ${ version } (${ patchVersion }) for ${ platformKey }…`
126131
);
127-
await verifyBundledHash( bundledPath );
132+
await verifyBundledPhpBinaryHash( bundledPath );
128133
fs.copyFileSync( bundledPath, destPath );
129134
if ( ! isWindows ) {
130135
fs.chmodSync( destPath, 0o755 );
@@ -203,33 +208,6 @@ async function main(): Promise< void > {
203208
}
204209
}
205210

206-
function findBundledBinary(
207-
bundledVersion: NativePhpSupportedVersion,
208-
platform: NodeJS.Platform,
209-
arch: string
210-
): string | undefined {
211-
const sourcePath = path.join(
212-
__dirname,
213-
'..',
214-
'apps',
215-
'cli',
216-
'bin',
217-
'php',
218-
getBundledPhpBinaryRelativePath( bundledVersion, platform, arch )
219-
);
220-
return fs.existsSync( sourcePath ) ? sourcePath : undefined;
221-
}
222-
223-
async function verifyBundledHash( sourcePath: string ): Promise< void > {
224-
const hashPath = `${ sourcePath }.sha256`;
225-
const [ expected ] = ( await fs.promises.readFile( hashPath, 'utf8' ) ).trim().split( /\s+/ );
226-
const data = await fs.promises.readFile( sourcePath );
227-
const actual = crypto.createHash( 'sha256' ).update( data ).digest( 'hex' );
228-
if ( actual !== expected ) {
229-
throw new Error( `SHA-256 mismatch:\n expected ${ expected }\n got ${ actual }` );
230-
}
231-
}
232-
233211
function logInstalledBinary( destPath: string ): void {
234212
const stats = fs.statSync( destPath );
235213
console.log(
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import crypto from 'crypto';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import {
5+
getBundledPhpBinaryRelativePath,
6+
type NativePhpSupportedVersion,
7+
} from './php-binary-metadata';
8+
9+
export function findBundledPhpBinary(
10+
version: NativePhpSupportedVersion,
11+
platform: NodeJS.Platform,
12+
arch: string,
13+
roots: string[]
14+
): string | undefined {
15+
const relativePath = getBundledPhpBinaryRelativePath( version, platform, arch );
16+
17+
for ( const root of roots ) {
18+
const sourcePath = path.join( root, relativePath );
19+
if ( fs.existsSync( sourcePath ) ) {
20+
return sourcePath;
21+
}
22+
}
23+
}
24+
25+
export async function verifyBundledPhpBinaryHash( sourcePath: string ): Promise< void > {
26+
const hashPath = `${ sourcePath }.sha256`;
27+
if ( ! fs.existsSync( hashPath ) ) {
28+
throw new Error( `No pinned SHA-256 hash for bundled PHP binary at ${ sourcePath }.` );
29+
}
30+
31+
const [ expected ] = ( await fs.promises.readFile( hashPath, 'utf8' ) ).trim().split( /\s+/ );
32+
const data = await fs.promises.readFile( sourcePath );
33+
const actual = crypto.createHash( 'sha256' ).update( data ).digest( 'hex' );
34+
if ( actual !== expected ) {
35+
throw new Error(
36+
`SHA-256 mismatch for bundled PHP binary at ${ sourcePath }:\n` +
37+
` expected ${ expected }\n` +
38+
` got ${ actual }`
39+
);
40+
}
41+
}

tools/common/lib/tests/php-binary-metadata.test.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)