Fixed listing all themes when a theme path is invalid

- in the event one of the theme paths is invalid (a symlink that goes to
  a non-existent path), Ghost currently bails out of listing all themes
  because `fs.stat` throws an error
- in that case, we should just ignore the theme and continue
- this helps us prepare new symlinks whilst their source is not valid
- this commit wraps the code with try-catch to protect against that
- also adds a test
This commit is contained in:
Daniel Lockyer 2023-09-26 12:51:11 +02:00 committed by Daniel Lockyer
parent ec9b668e02
commit 8e83836de9
2 changed files with 36 additions and 3 deletions

View File

@ -132,8 +132,13 @@ async function readPackages(packagePath) {
}
if (file.isSymbolicLink()) {
const packageFileOrig = await fs.stat(join(packagePath, file.name));
return packageFileOrig.isDirectory();
try {
const packageFileOrig = await fs.stat(join(packagePath, file.name));
return packageFileOrig.isDirectory();
} catch (err) {
// if there's an error reading the symlink, we should just return false
return false;
}
}
// Check the remaining items to ensure they are a directory
@ -144,7 +149,7 @@ async function readPackages(packagePath) {
const absolutePath = join(packagePath, packageFile.name);
return processPackage(absolutePath, packageFile.name);
})));
return _.keyBy(packages, 'name');
}

View File

@ -137,6 +137,34 @@ describe('package-json read', function () {
.catch(done)
.finally(packagePath.removeCallback);
});
it('should read directory and ignore invalid symlinks', async function () {
const packagePath = tmp.dirSync({unsafeCleanup: true});
const pkgJson = JSON.stringify({
name: 'test'
});
// create example theme
fs.mkdirSync(join(packagePath.name, 'testtheme'));
fs.writeFileSync(join(packagePath.name, 'testtheme', 'package.json'), pkgJson);
fs.writeFileSync(join(packagePath.name, 'testtheme', 'index.hbs'), '');
// Create a symlink that has a missing source dir
fs.symlinkSync(join(packagePath.name, 'missing-dir'), join(packagePath.name, 'source'));
try {
const pkgs = await packageJSON.readPackages(packagePath.name);
pkgs.should.eql({
testtheme: {
name: 'testtheme',
path: join(packagePath.name, 'testtheme'),
'package.json': null
}
});
} finally {
await packagePath.removeCallback();
}
});
});
describe('readPackage', function () {