metro-bundler: recreate temp dir if does not exist

Summary: That happens after a reboot on macOS for example, because temp dir is wiped.

Reviewed By: davidaurelio

Differential Revision: D5236249

fbshipit-source-id: be19cd97a7488850e3195b3fc419779ed0df2c38
This commit is contained in:
Jean Lauliac 2017-06-14 04:32:45 -07:00 committed by Facebook Github Bot
parent 32e0d2c0d7
commit 7e9f368ee5
2 changed files with 43 additions and 13 deletions

View File

@ -25,7 +25,7 @@ class CannotCreateTempDirError extends Error {
* Claim a temporary directory that doesn't exist already and that cannot be
* predicted, so that nobody can race us to it. This is similar to `mkdtemp(3)`.
*/
function create(pathPrefix: string): string {
function create(pathPrefix: string, mode: number): string {
let resultPath;
let i = 0;
do {
@ -34,7 +34,7 @@ function create(pathPrefix: string): string {
if (++i === 10) {
throw new CannotCreateTempDirError();
}
} while (!tryMkdirSync(resultPath));
} while (!tryMkdirSync(resultPath, mode));
return resultPath;
}

View File

@ -446,27 +446,57 @@ function useTempDir(): TransformCache {
* clone gets a fresh cache, and so that the temp dir used cannot be predicted.
* Sometimes a different user build the same project, in which case we use a
* different subfolder of the temp directory.
*
* If the directory specified in the `.metro-bundler` doesn't exist anymore
* (ex. after a machine reboot and `/tmp` has been cleaned), we just create
* a new one.
*/
function useProjectDir(projectPath: string): TransformCache {
const metaDirPath = readMetaDirPath(projectPath);
invariant(path.isAbsolute(projectPath), 'project path must be absolute');
const metaFilePath = path.resolve(projectPath, '.metro-bundler');
const metaDirPath = readMetaDirPath(metaFilePath);
if (metaDirPath != null) {
try {
return useMetaDirPath(metaDirPath);
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
}
return useMetaDirPath(createMetaDir(metaFilePath));
}
/**
* Use the specified path as cache, by creating a subdirectory specific to the
* current user ID. This could fail if `metaDirPath` doesn't exist.
*/
function useMetaDirPath(metaDirPath: string): TransformCache {
const uidStr = process.getuid != null ? process.getuid().toString() : 'g';
const finalPath = path.join(metaDirPath, '_' + uidStr);
TempDirs.tryMkdirSync(finalPath, 448 /* == 0700 */);
TempDirs.tryMkdirSync(finalPath, 0o700);
return new FileBasedCache(finalPath);
}
function readMetaDirPath(projectPath: string): string {
invariant(path.isAbsolute(projectPath), 'project path must be absolute');
const metaFilePath = path.resolve(projectPath, '.metro-bundler');
/**
* Return the path of the cache directory, if it's already been set for that
* project, in the shape of a `.metro-bundler` file.
*/
function readMetaDirPath(metaFilePath: string): ?string {
const metaFile = tryReadFileSync(metaFilePath);
if (metaFile != null) {
const metaDirPath = metaFile.split('\n')[0];
if (metaDirPath != null) {
return metaDirPath;
}
if (metaFile == null) {
return null;
}
return metaFile.split('\n')[0];
}
/**
* Create a new top-level directory to be used for the cache. We give all
* permissions because different users might share that directory.
*/
function createMetaDir(metaFilePath: string): string {
const tmpDirPath = tmpdir();
const metaDirPath = TempDirs.create(path.join(tmpDirPath, 'mb-'));
const metaDirPath = TempDirs.create(path.join(tmpDirPath, 'mb-'), 0o777);
fs.writeFileSync(metaFilePath, metaDirPath + '\n');
return metaDirPath;
}