Skip to content

Commit

Permalink
Add code to keep only required files for dependencies (facebook#49360)
Browse files Browse the repository at this point in the history
Summary:

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.

Differential Revision: D69518656
  • Loading branch information
cipolleschi authored and facebook-github-bot committed Feb 12, 2025
1 parent 78667d4 commit 7b06ae4
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 16 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
109 changes: 95 additions & 14 deletions scripts/releases/prepare-ios-prebuilds.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}>;
*/

Expand All @@ -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!');
}
Expand Down

0 comments on commit 7b06ae4

Please sign in to comment.