diff --git a/ghost/package-json/lib/package-json.js b/ghost/package-json/lib/package-json.js index 95b13c2f19..5eb35f299e 100644 --- a/ghost/package-json/lib/package-json.js +++ b/ghost/package-json/lib/package-json.js @@ -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'); } diff --git a/ghost/package-json/test/read.test.js b/ghost/package-json/test/read.test.js index 7d125ae310..f587ef83b5 100644 --- a/ghost/package-json/test/read.test.js +++ b/ghost/package-json/test/read.test.js @@ -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 () {