Add code to keep only required files for dependencies (#49360)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/49360

We don't need the whole dependencies archiveto build the dependencies. But usually we only need a subset of them.

This change add a functionality to the script to remove the unnecessary files.

## Changelog:
[Internal] - Add feature to remove unnecessary files from 3p dependencies.

Reviewed By: cortinico

Differential Revision: D69518656

fbshipit-source-id: b071626a1894261b75023023b7f7eeb2730282a2
This commit is contained in:
Riccardo Cipolleschi
2025-02-13 13:55:51 -08:00
committed by Facebook GitHub Bot
parent 7db0abf61b
commit b98362e311
2 changed files with 98 additions and 16 deletions
+3 -2
View File
@@ -142,8 +142,9 @@ vendor/
/packages/react-native/sdks/hermes-engine/hermes-engine-from-local-source-dir.tar.gz
# iOS prebuilds
/packages/react-native/third-party/
fix_glog_0.3.5_apple_silicon.patch
/packages/react-native/third-party/glog
/packages/react-native/third-party/.swiftpm
.patch
# Visual Studio Code (config dir - if present, this merges user defined
# workspace settings on top of react-native.code-workspace)
+95 -14
View File
@@ -19,11 +19,22 @@ const util = require('util');
const exec = util.promisify(require('child_process').exec);
/*::
type Folder = RegExp;
// We need to pass through the downloaded files and only keep the ones highlighted here.
// We can delete the rest of the files.
type FilesToKeep = $ReadOnly<{
headers: Folder | $ReadOnlyArray<string>,
sources: $ReadOnlyArray<string>,
}>;
type Dependency = $ReadOnly<{
name: string,
version: string,
url: URL,
prepareScript?: string,
filesToKeep: FilesToKeep,
}>;
*/
@@ -35,44 +46,114 @@ const dependencies /*: $ReadOnlyArray<Dependency> */ = [
'https://github.com/google/glog/archive/refs/tags/v0.3.5.tar.gz',
),
prepareScript: './packages/react-native/scripts/ios-configure-glog.sh',
filesToKeep: {
headers: /src(\/(glog|base))?\/[a-zA-Z0-9_-]+\.h$/, // Keep all headers in src, src/glog and src/base
sources: [
'src/demangle.cc',
'src/logging.cc',
'src/raw_logging.cc',
'src/signalhandler.cc',
'src/symbolize.cc',
'src/utilities.cc',
'src/vlog_is_on.cc',
],
},
},
];
async function downloadDependency(
dependency /*: Dependency*/,
) /*: Promise<void> */ {
const {name, url} = dependency;
async function _downloadDependency(
name /*: string*/,
url /*: URL*/,
destination /*: string*/,
) {
const filename = `${name}.tgz`;
const archiveDestination = `/tmp/${filename}`;
const command = `curl -L ${url.toString()} --output ${archiveDestination}`;
console.log(`Downloading ${filename}...`);
await exec(command);
const destination = `packages/react-native/third-party/${name}`;
fs.mkdirSync(destination, {recursive: true});
console.log(`Extracting ${filename} to ${destination}...`);
await exec(
`tar -xzf ${archiveDestination} -C ${destination} --strip-components 1`,
);
console.log(`Cleaning up ${filename}...`);
await exec(`rm ${archiveDestination}`);
}
function _prepareDependency(scriptPath /*: string*/, destination /*: string*/) {
console.log(`Running ${scriptPath}...`);
const finalPath = path.join(destination, 'prepare.sh');
fs.copyFileSync(scriptPath, finalPath);
execSync('./prepare.sh', {cwd: destination, stdio: 'inherit'});
}
function _removeUnnecessaryFiles(
filesToKeep /*: FilesToKeep*/,
destination /*: string*/,
) {
const backupPath = `${destination}_backup`;
fs.mkdirSync(backupPath, {recursive: true});
console.log('Moving headers to backup folder...');
const headers = filesToKeep.headers;
if (headers instanceof RegExp) {
const files = execSync(`find ${destination} -type f -name "*.h"`)
.toString()
.trim()
.split('\n');
for (const file of files) {
if (headers.test(file)) {
const relativeFilePath = path
.relative(backupPath, file)
.split('/')
.slice(2)
.join('/');
const destinationFile = `${backupPath}/${relativeFilePath}`;
fs.mkdirSync(path.dirname(destinationFile), {recursive: true});
fs.copyFileSync(file, destinationFile);
}
}
} else {
for (const file of headers) {
const filePath = path.join(destination, file);
const destFilePath = path.join(`${destination}_backup`, file);
fs.copyFileSync(filePath, destFilePath);
}
}
console.log('Moving sources to backup folder...');
for (const file of filesToKeep.sources) {
const filePath = path.join(destination, file);
const destFilePath = path.join(`${destination}_backup`, file);
fs.copyFileSync(filePath, destFilePath);
}
console.log('Cleaning up...');
fs.rmSync(destination, {recursive: true, force: true});
fs.renameSync(`${destination}_backup`, destination);
}
async function setupDependency(
dependency /*: Dependency*/,
) /*: Promise<void> */ {
const {name, url} = dependency;
const destination = `packages/react-native/third-party/${name}`;
await _downloadDependency(name, url, destination);
if (dependency.prepareScript) {
const scriptPath = dependency.prepareScript;
console.log(`Running ${scriptPath}...`);
const finalPath = path.join(destination, 'prepare.sh');
fs.copyFileSync(scriptPath, finalPath);
execSync('./prepare.sh', {cwd: destination, stdio: 'inherit'});
_prepareDependency(dependency.prepareScript, destination);
}
_removeUnnecessaryFiles(dependency.filesToKeep, destination);
}
async function main() {
console.log('Starting iOS prebuilds preparation...');
await Promise.all(dependencies.map(downloadDependency));
await Promise.all(dependencies.map(setupDependency));
console.log('Done!');
}