diff --git a/settings.js b/settings.js index 99adb90ae..4d3050558 100644 --- a/settings.js +++ b/settings.js @@ -37,9 +37,6 @@ let settings = { ], showIncludedSourceFiles: true, - dirIncludeFilename: 'particle.include', - dirExcludeFilename: 'particle.ignore', - cloudKnownApps: { 'tinker': true }, diff --git a/src/cmd/cloud.js b/src/cmd/cloud.js index c59789f7c..68f9cd2ab 100644 --- a/src/cmd/cloud.js +++ b/src/cmd/cloud.js @@ -779,11 +779,24 @@ module.exports = class CloudCommand extends CLICommandBase { */ _processDirIncludes(fileMapping, dirname, { followSymlinks } = {}){ dirname = path.resolve(dirname); + let files = new Set(); - const includesFile = path.join(dirname, settings.dirIncludeFilename); - const ignoreFile = path.join(dirname, settings.dirExcludeFilename); - let hasIncludeFile = false; + this._getDefaultIncludes(files, dirname, { followSymlinks }); + this._getDefaultIgnores(files, dirname, { followSymlinks }); + this._getCustomIncludes(files, dirname, { followSymlinks }); + this._getCustomIgnores(files, dirname, { followSymlinks }); + // Add files to fileMapping + const sortedFiles = Array.from(files.values()).sort(); + sortedFiles.forEach((file) => { + // source relative to the base directory of the fileMapping (current directory) + const source = path.relative(fileMapping.basePath, file); + const target = path.relative(dirname, file); + fileMapping.map[target] = source; + }); + } + + _getDefaultIncludes(files, dirname, { followSymlinks }) { // Recursively find source files let includes = [ '**/*.h', @@ -793,45 +806,51 @@ module.exports = class CloudCommand extends CLICommandBase { '**/*.ino', '**/*.cpp', '**/*.c', + '**/build.mk', 'project.properties' ]; - if (fs.existsSync(includesFile)){ - //grab and process all the files in the include file. + const result = utilities.globList(dirname, includes, { followSymlinks }); + result.forEach((file) => files.add(file)); + } - includes = utilities.trimBlankLinesAndComments( - utilities.readAndTrimLines(includesFile) - ); - hasIncludeFile = true; + _getCustomIncludes(files, dirname, { followSymlinks }) { + const includeFiles = utilities.globList(dirname, ['**/particle.include'], { followSymlinks }); + for (const includeFile of includeFiles) { + const includeDir = path.dirname(includeFile); + const globsToInclude = utilities.trimBlankLinesAndComments(utilities.readAndTrimLines(includeFile)); + if (!globsToInclude || !globsToInclude.length) { + continue; + } + const includePaths = utilities.globList(includeDir, globsToInclude, { followSymlinks }); + includePaths.forEach((file) => files.add(file)); } + } - let files = utilities.globList(dirname, includes, { followSymlinks }); - - if (fs.existsSync(ignoreFile)){ - const ignores = utilities.trimBlankLinesAndComments( - utilities.readAndTrimLines(ignoreFile) - ); + _getDefaultIgnores(files, dirname, { followSymlinks }) { + // Recursively find default ignore files + let ignores = [ + 'lib/*/examples/**/*.*' + ]; - const ignoredFiles = utilities.globList(dirname, ignores, { followSymlinks }); - files = utilities.compliment(files, ignoredFiles); - } + const result = utilities.globList(dirname, ignores, { followSymlinks }); + result.forEach((file) => files.delete(file)); + } - // Add files to fileMapping - files.forEach((file) => { - // source relative to the base directory of the fileMapping (current directory) - const source = path.relative(fileMapping.basePath, file); + _getCustomIgnores(files, dirname, { followSymlinks }) { + const ignoreFiles = utilities.globList(dirname, ['**/particle.ignore'], { followSymlinks }); - // If using an include file, only base names are supported since people are using those to - // link across relative folders - let target; - if (hasIncludeFile){ - target = path.basename(file); - } else { - target = path.relative(dirname, file); + for (const ignoreFile of ignoreFiles) { + const ignoreDir = path.dirname(ignoreFile); + const globsToIgnore = utilities.trimBlankLinesAndComments(utilities.readAndTrimLines(ignoreFile)); + if (!globsToIgnore || !globsToIgnore.length) { + continue; } - fileMapping.map[target] = source; - }); + const globList = globsToIgnore.map(g => g); + const ignoredPaths = utilities.globList(ignoreDir, globList, { followSymlinks }); + ignoredPaths.forEach((file) => files.delete(file)); + } } @@ -843,7 +862,7 @@ module.exports = class CloudCommand extends CLICommandBase { _handleLibraryExample(fileMapping){ return Promise.resolve().then(() => { const list = _.values(fileMapping.map); - if (list.length === 1){ + if (list.length >= 1){ return require('particle-library-manager').isLibraryExample(list[0]); } }).then(example => { diff --git a/src/cmd/cloud.test.js b/src/cmd/cloud.test.js index 4e0dbf5d9..9d1163123 100644 --- a/src/cmd/cloud.test.js +++ b/src/cmd/cloud.test.js @@ -1,9 +1,10 @@ const proxyquire = require('proxyquire'); const os = require('os'); const path = require('path'); +const fs = require('fs-extra'); const { expect } = require('../../test/setup'); const sandbox = require('sinon').createSandbox(); -const { PATH_FIXTURES_THIRDPARTY_OTA_DIR } = require('../../test/lib/env'); +const { PATH_FIXTURES_THIRDPARTY_OTA_DIR, PATH_TMP_DIR } = require('../../test/lib/env'); const stubs = { api: { @@ -234,7 +235,6 @@ describe('Cloud Commands', () => { })); }); - function stubForLogin(cloud, stubs){ const { api, prompts, settings } = stubs; sandbox.spy(cloud, 'login'); @@ -351,5 +351,523 @@ describe('Cloud Commands', () => { expect(error).to.have.property('message', 'saveTo must have a .zip extension when project includes assets'); }); }); + + describe('_processDirIncludes', () => { + it('gets the list of files', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h' + ], {}, async (dir) => { + const fileMapping = { basePath: dir, map: {} }; + + await cloud._processDirIncludes(fileMapping, dir); + + expect(fileMapping.map).to.eql({ + [path.join('src/app.cpp')]: path.join('src/app.cpp'), + [path.join('lib/spi/src/spi.c')]: path.join('lib/spi/src/spi.c'), + [path.join('lib/spi/src/spi.h')]: path.join('lib/spi/src/spi.h') + }); + }); + }); + + it('gets the list of files with include and ignore configs', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'src/app.def', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/src/spi.def', + 'lib/spi/src/spi.cmd', + 'lib/spi/examples/sensor/spi_example.cpp', + 'lib/spi/examples/sensor/spi_example.h', + 'lib/spi/particle.include', + 'lib/i2c/src/i2c.c', + 'lib/i2c/particle.ignore' + ], { + 'particle.include': '**/*.def', + 'lib/spi/particle.include': '**/*.cmd', + 'lib/i2c/particle.ignore': '**/*.c' + }, async (dir) => { + const fileMapping = { basePath: dir, map: {} }; + + await cloud._processDirIncludes(fileMapping, dir); + + expect(fileMapping.map).to.eql({ + [path.join('src/app.cpp')]: path.join('src/app.cpp'), + [path.join('src/app.def')]: path.join('src/app.def'), + [path.join('lib/spi/src/spi.c')]: path.join('lib/spi/src/spi.c'), + [path.join('lib/spi/src/spi.h')]: path.join('lib/spi/src/spi.h'), + [path.join('lib/spi/src/spi.def')]: path.join('lib/spi/src/spi.def'), + [path.join('lib/spi/src/spi.cmd')]: path.join('lib/spi/src/spi.cmd') + }); + }); + }); + + it('does not return files that are not included', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/src/spi.txt' + ], {}, async (dir) => { + const fileMapping = { basePath: dir, map: {} }; + + await cloud._processDirIncludes(fileMapping, dir); + + expect(fileMapping.map).to.eql({ + [path.join('src/app.cpp')]: path.join('src/app.cpp'), + [path.join('lib/spi/src/spi.c')]: path.join('lib/spi/src/spi.c'), + [path.join('lib/spi/src/spi.h')]: path.join('lib/spi/src/spi.h') + }); + }); + }); + + it('returns files that are included', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/src/spi.txt', + 'lib/particle.include' + ], { + 'lib/particle.include': '**/*.txt' + }, async (dir) => { + const fileMapping = { basePath: dir, map: {} }; + + await cloud._processDirIncludes(fileMapping, dir); + + expect(fileMapping.map).to.eql({ + [path.join('src/app.cpp')]: path.join('src/app.cpp'), + [path.join('lib/spi/src/spi.c')]: path.join('lib/spi/src/spi.c'), + [path.join('lib/spi/src/spi.h')]: path.join('lib/spi/src/spi.h'), + [path.join('lib/spi/src/spi.txt')]: path.join('lib/spi/src/spi.txt') + }); + }); + }); + + it('removes duplicates if included multiple times', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/src/spi.txt', + 'lib/particle.include' + ], { + 'particle.include': '**/*.cpp', + 'lib/particle.include': '**/*.txt' + }, async (dir) => { + const fileMapping = { basePath: dir, map: {} }; + + await cloud._processDirIncludes(fileMapping, dir); + + expect(fileMapping.map).to.eql({ + [path.join('src/app.cpp')]: path.join('src/app.cpp'), + [path.join('lib/spi/src/spi.c')]: path.join('lib/spi/src/spi.c'), + [path.join('lib/spi/src/spi.h')]: path.join('lib/spi/src/spi.h'), + [path.join('lib/spi/src/spi.txt')]: path.join('lib/spi/src/spi.txt') + }); + }); + }); + + it('removes files which are in ignore list', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.ignore', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/src/spi.txt', + 'lib/particle.include' + ], { + 'particle.ignore': '**/*.cpp', + 'lib/particle.include': '**/*.txt' + }, async (dir) => { + const fileMapping = { basePath: dir, map: {} }; + + await cloud._processDirIncludes(fileMapping, dir); + + expect(fileMapping.map).to.eql({ + [path.join('lib/spi/src/spi.c')]: path.join('lib/spi/src/spi.c'), + [path.join('lib/spi/src/spi.h')]: path.join('lib/spi/src/spi.h'), + [path.join('lib/spi/src/spi.txt')]: path.join('lib/spi/src/spi.txt') + }); + }); + }); + }); + + describe('_getDefaultIncludes', () => { + it('gets the list of files to include by default', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'src/app.ino', + 'src/app.cpp', + 'src/app.hpp', + 'src/app.hh', + 'src/app.hxx', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/src/build.mk' + ], {}, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getDefaultIncludes(files, dir, {}); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.ino'), + path.resolve(dir, 'src/app.cpp'), + path.resolve(dir, 'src/app.hpp'), + path.resolve(dir, 'src/app.hh'), + path.resolve(dir, 'src/app.hxx'), + path.resolve(dir, 'lib/spi/src/spi.c'), + path.resolve(dir, 'lib/spi/src/spi.h'), + path.resolve(dir, 'lib/spi/src/build.mk') + ]); + }); + }); + + it('filters out files which are not in the default blob', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'src/app.txt', + 'lib/spi/src/spi.txt', + ], {}, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getDefaultIncludes(files, dir, {} ); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.cpp'), + path.resolve(dir, 'lib/spi/src/spi.c'), + path.resolve(dir, 'lib/spi/src/spi.h') + ]); + }); + }); + }); + + describe('_getCustomIncludes', () => { + it('gets the list of files to include via particle.include', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'src/app.def' + ], { 'particle.include': '**/*.def' }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.def') + ]); + }); + }); + + it('gets the list of nested files to include via particle.include', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'src/app.def', + 'src/file.txt', + 'src/particle.include', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h' + ], { + 'particle.include': '**/*.def', + 'src/particle.include': '**/*.txt\n**/*.def' + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.def'), + path.resolve(dir, 'src/file.txt') + ]); + }); + }); + + it('gets the list of files from nested directories', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'src/app.def', + 'lib/particle.include', + 'lib/file.txt', + 'lib/file.def', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h' + ], { + 'particle.include': '**/*.def', + 'lib/particle.include': '**/*.txt\n**/*.def' + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.def'), + path.resolve(dir, 'lib/file.txt'), + path.resolve(dir, 'lib/file.def') + ]); + }); + }); + + it('handles repeated files from nested directories', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'src/app.def', + 'lib/particle.include', + 'lib/file.txt', + 'lib/file.def', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h' + ], { + 'particle.include': '**/*.def', + 'lib/particle.include': '**/*.txt\n**/*.def' + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.def'), + path.resolve(dir, 'lib/file.txt'), + path.resolve(dir, 'lib/file.def') + ]); + }); + }); + + it('handles an empty particle.include', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'src/app.def' + ], {}, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + + it('handles empty particle.include in a nested dir', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'src/app.def', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/particle.include' + ], { + 'particle.include': '**/*.def', + 'lib/particle.include': '' + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.have.same.members([ + path.resolve(dir, 'src/app.def') + ]); + }); + }); + + it('handles multiple empty particle.include files', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'src/app.def', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/particle.include' + ], { + 'particle.include': '', + 'lib/particle.include': '' + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + + it('should not error if files are not found', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.include', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + ], { + 'particle.include': '**/*.def', + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIncludes(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + }); + + describe('_getDefaultIgnores', () => { + it('gets the list of files to ignore', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/spi/examples/sensor/init.ino' + ], {}, async (dir) => { + dir = path.resolve(dir); + // hardcode a set with 'lib/spi/examples/sensor/init.ino' + let files = new Set([ + path.join(dir, 'lib/spi/examples/sensor/init.ino') + ]); + + cloud._getDefaultIgnores(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + }); + + describe('_getCustomIgnores', () => { + it('gets the list of files to ignore', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.ignore', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + ], { + 'particle.ignore': '**/*.cpp', + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set([ + path.join(dir, 'src/app.cpp') + ]); + + cloud._getCustomIgnores(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + + it('handles multiple particle.ignore files', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.ignore', + 'lib/particle.ignore', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + ], { + 'particle.ignore': '**/*.cpp', + 'lib/particle.ignore': '**/*.h', + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set([ + path.join(dir, 'src/app.cpp'), + path.join(dir, 'lib/spi/src/spi.h') + ]); + + cloud._getCustomIgnores(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + + it('handles an empty particle.ignore', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.ignore', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + ], { + 'particle.ignore': '', + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set(); + + cloud._getCustomIgnores(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + + it('handles empty particle.ignore in a nested dir', async () => { + const { cloud } = stubForLogin(new CloudCommands(), stubs); + await createTmpDir([ + 'particle.ignore', + 'src/app.cpp', + 'lib/spi/src/spi.c', + 'lib/spi/src/spi.h', + 'lib/particle.ignore' + ], { + 'particle.ignore': '**/*.cpp', + 'lib/particle.ignore': '' + }, async (dir) => { + dir = path.resolve(dir); + let files = new Set([ + path.join(dir, 'src/app.cpp') + ]); + + cloud._getCustomIgnores(files, dir, {} ); + + expect([...files]).to.be.empty; + }); + }); + }); + + async function createTmpDir(files, fileContents, handler) { + const tmpDir = path.join(PATH_TMP_DIR, 'tmpDir'); + await fs.mkdir(tmpDir); + for (const file of files) { + const filePath = path.join(tmpDir, file); + await fs.outputFile(filePath, fileContents[file] || ''); + } + + try { + await handler(tmpDir); + } finally { + await fs.remove(tmpDir); + } + } }); diff --git a/src/lib/utilities.js b/src/lib/utilities.js index e188f2958..457ef850c 100644 --- a/src/lib/utilities.js +++ b/src/lib/utilities.js @@ -28,6 +28,7 @@ License along with this program; if not, see . const fs = require('fs'); const _ = require('lodash'); +const os = require('os'); const path = require('path'); const glob = require('glob'); const VError = require('verror'); @@ -205,6 +206,10 @@ module.exports = { line = path.join(basepath, line); } found = glob.sync(line, { nodir: true, follow: !!followSymlinks }); + if (os.platform() === 'win32') { + // because glob pattern is always in posix format + found = found.map(file => path.win32.normalize(file)); + } if (found && (found.length > 0)){ files = files.concat(found); diff --git a/test/__fixtures__/projects/legacy-include/main/particle.include b/test/__fixtures__/projects/legacy-include/main/particle.include deleted file mode 100644 index 89df5d762..000000000 --- a/test/__fixtures__/projects/legacy-include/main/particle.include +++ /dev/null @@ -1,3 +0,0 @@ -app.ino -../helper/helper.cpp -../helper/helper.h diff --git a/test/__fixtures__/projects/legacy-include/helper/helper.cpp b/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper.cpp similarity index 100% rename from test/__fixtures__/projects/legacy-include/helper/helper.cpp rename to test/__fixtures__/projects/proj-ignore/lib/helper/src/helper.cpp diff --git a/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper.def b/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper.def new file mode 100644 index 000000000..e69de29bb diff --git a/test/__fixtures__/projects/legacy-include/helper/helper.h b/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper.h similarity index 100% rename from test/__fixtures__/projects/legacy-include/helper/helper.h rename to test/__fixtures__/projects/proj-ignore/lib/helper/src/helper.h diff --git a/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper2.cpp b/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper2.cpp new file mode 100644 index 000000000..a3bdd716e --- /dev/null +++ b/test/__fixtures__/projects/proj-ignore/lib/helper/src/helper2.cpp @@ -0,0 +1 @@ +const int DOIT2 = 0; diff --git a/test/__fixtures__/projects/proj-ignore/particle.ignore b/test/__fixtures__/projects/proj-ignore/particle.ignore new file mode 100644 index 000000000..e90064198 --- /dev/null +++ b/test/__fixtures__/projects/proj-ignore/particle.ignore @@ -0,0 +1 @@ +**/helper2.cpp \ No newline at end of file diff --git a/test/__fixtures__/projects/proj-ignore/project.properties b/test/__fixtures__/projects/proj-ignore/project.properties new file mode 100644 index 000000000..55aece9f3 --- /dev/null +++ b/test/__fixtures__/projects/proj-ignore/project.properties @@ -0,0 +1 @@ +name=legacy-include diff --git a/test/__fixtures__/projects/legacy-include/main/app.ino b/test/__fixtures__/projects/proj-ignore/src/app.ino similarity index 100% rename from test/__fixtures__/projects/legacy-include/main/app.ino rename to test/__fixtures__/projects/proj-ignore/src/app.ino diff --git a/test/__fixtures__/projects/legacy-nested/helper/helper.cpp b/test/__fixtures__/projects/proj-include/lib/helper/src/helper.cpp similarity index 100% rename from test/__fixtures__/projects/legacy-nested/helper/helper.cpp rename to test/__fixtures__/projects/proj-include/lib/helper/src/helper.cpp diff --git a/test/__fixtures__/projects/proj-include/lib/helper/src/helper.def b/test/__fixtures__/projects/proj-include/lib/helper/src/helper.def new file mode 100644 index 000000000..e69de29bb diff --git a/test/__fixtures__/projects/legacy-nested/helper/helper.h b/test/__fixtures__/projects/proj-include/lib/helper/src/helper.h similarity index 100% rename from test/__fixtures__/projects/legacy-nested/helper/helper.h rename to test/__fixtures__/projects/proj-include/lib/helper/src/helper.h diff --git a/test/__fixtures__/projects/proj-include/particle.include b/test/__fixtures__/projects/proj-include/particle.include new file mode 100644 index 000000000..8fe2f8375 --- /dev/null +++ b/test/__fixtures__/projects/proj-include/particle.include @@ -0,0 +1 @@ +**/*.def \ No newline at end of file diff --git a/test/__fixtures__/projects/proj-include/project.properties b/test/__fixtures__/projects/proj-include/project.properties new file mode 100644 index 000000000..55aece9f3 --- /dev/null +++ b/test/__fixtures__/projects/proj-include/project.properties @@ -0,0 +1 @@ +name=legacy-include diff --git a/test/__fixtures__/projects/legacy-nested/app.ino b/test/__fixtures__/projects/proj-include/src/app.ino similarity index 63% rename from test/__fixtures__/projects/legacy-nested/app.ino rename to test/__fixtures__/projects/proj-include/src/app.ino index d93a487ec..2ee2cd31d 100644 --- a/test/__fixtures__/projects/legacy-nested/app.ino +++ b/test/__fixtures__/projects/proj-include/src/app.ino @@ -1,5 +1,5 @@ -// Demo app with a nested structure -#include "helper/helper.h" +// Demo app with a flat structure +#include "helper.h" void setup() { if (DOIT) { diff --git a/test/e2e/compile.e2e.js b/test/e2e/compile.e2e.js index 0bca38d22..f6ef2e030 100644 --- a/test/e2e/compile.e2e.js +++ b/test/e2e/compile.e2e.js @@ -152,21 +152,23 @@ describe('Compile Commands', () => { expect(exitCode).to.equal(0); }); - it('Compiles a legacy nested project', async () => { - const name = 'legacy-nested'; + it('Compiles a project which uses `particle.include` file', async () => { + const name = 'proj-include'; const platform = 'photon'; const cwd = path.join(PATH_FIXTURES_PROJECTS_DIR, name); const destination = path.join(PATH_TMP_DIR, `${name}-${platform}.bin`); - const args = ['compile', platform, '--saveTo', destination]; + const args = ['compile', platform, cwd, '--saveTo', destination]; const { stdout, stderr, exitCode, start, end } = await cliRunWithTimer(args, { cwd }); const file = await fs.stat(destination); const log = [ `Compiling code for ${platform}`, '', 'Including:', - ' helper/helper.h', - ' app.ino', - ' helper/helper.cpp', + ' lib/helper/src/helper.h', + ' src/app.ino', + ' lib/helper/src/helper.cpp', + ' project.properties', + ' lib/helper/src/helper.def', '', 'attempting to compile firmware', '', // don't assert against memory stats since they may change based on current default Device OS version @@ -184,21 +186,22 @@ describe('Compile Commands', () => { expect(exitCode).to.equal(0); }); - it('Compiles a legacy project which uses `particle.include` file', async () => { - const name = 'legacy-include'; + it('Compiles a project which uses `particle.ignore` file', async () => { + const name = 'proj-ignore'; const platform = 'photon'; const cwd = path.join(PATH_FIXTURES_PROJECTS_DIR, name); const destination = path.join(PATH_TMP_DIR, `${name}-${platform}.bin`); - const args = ['compile', platform, 'main', '--saveTo', destination]; + const args = ['compile', platform, cwd, '--saveTo', destination]; const { stdout, stderr, exitCode, start, end } = await cliRunWithTimer(args, { cwd }); const file = await fs.stat(destination); const log = [ `Compiling code for ${platform}`, '', 'Including:', - ' main/app.ino', - ' helper/helper.cpp', - ' helper/helper.h', + ' lib/helper/src/helper.h', + ' src/app.ino', + ' lib/helper/src/helper.cpp', + ' project.properties', '', 'attempting to compile firmware', '', // don't assert against memory stats since they may change based on current default Device OS version