Livepush: Ignore paths set in .dockerignore files

Change-type: minor
Signed-off-by: Josh Bowling <josh@balena.io>
This commit is contained in:
Josh Bowling 2020-11-10 10:08:22 +09:00 committed by Paulo Castro
parent 0831e5fa17
commit 02a5466746
3 changed files with 65 additions and 22 deletions

View File

@ -552,7 +552,7 @@ async function loadBuildMetatada(
* @param sourceDir Project source directory (project root)
* @param composition Optional previously parsed composition object
*/
async function getServiceDirsFromComposition(
export async function getServiceDirsFromComposition(
sourceDir: string,
composition?: Composition,
): Promise<Dictionary<string>> {

View File

@ -20,6 +20,8 @@ import {
import { BuildError } from './errors';
import { getServiceColourFn } from './logs';
import { delay } from '../helpers';
import { getServiceDirsFromComposition } from '../compose_ts';
import { getDockerignoreByDir } from '../ignore';
// How often do we want to check the device state
// engine has settled (delay in ms)
@ -162,11 +164,31 @@ export class LivepushManager {
eventQueue.push(changedPath);
this.getDebouncedEventHandler(serviceName)();
};
// Prepare dockerignore data for file watcher
const serviceDirsByService = this.deployOpts.multiDockerignore
? await getServiceDirsFromComposition(
this.deployOpts.source,
this.composition,
)
: {};
const { ignoreByDir, serviceDirs } = await getDockerignoreByDir(
this.deployOpts.source,
serviceDirsByService,
);
// TODO: Memoize this for containers which share a context
const monitor = chokidar.watch('.', {
cwd: context,
ignoreInitial: true,
ignored: '.git',
ignored: (filePath: string) => {
for (const dir of serviceDirs) {
if (filePath.startsWith(dir)) {
return ignoreByDir[dir].ignores(filePath.substring(dir.length));
}
}
return ignoreByDir['.'].ignores(filePath);
},
});
monitor.on('add', (changedPath: string) =>
addEvent(this.updateEventsWaiting[serviceName], changedPath),

View File

@ -21,6 +21,7 @@ import * as MultiBuild from 'resin-multibuild';
import dockerIgnore = require('@zeit/dockerignore');
import ignore from 'ignore';
import { Ignore } from '@balena/dockerignore';
import { ExpectedError } from '../errors';
@ -254,7 +255,7 @@ async function readDockerIgnoreFile(projectDir: string): Promise<string> {
* a set of default/hardcoded patterns.
* @param directory Directory where to look for a .dockerignore file
*/
async function getDockerIgnoreInstance(
export async function getDockerIgnoreInstance(
directory: string,
): Promise<import('@balena/dockerignore').Ignore> {
const dockerIgnoreStr = await readDockerIgnoreFile(directory);
@ -295,25 +296,10 @@ export async function filterFilesWithDockerignore(
projectDir: string,
serviceDirsByService?: ServiceDirs,
): Promise<{ filteredFileList: FileStats[]; dockerignoreFiles: FileStats[] }> {
// path.resolve() also converts forward slashes to backslashes on Windows
projectDir = path.resolve(projectDir);
// ignoreByDir stores an instance of the dockerignore filter for each service dir
const ignoreByDir: {
[serviceDir: string]: import('@balena/dockerignore').Ignore;
} = {
'.': await getDockerIgnoreInstance(projectDir),
};
const serviceDirs: string[] = Object.values(serviceDirsByService || {})
// filter out the project source/root dir
.filter((dir) => dir && dir !== '.')
// add a trailing '/' (or '\' on Windows) to the path
.map((dir) => (dir.endsWith(path.sep) ? dir : dir + path.sep));
for (const serviceDir of serviceDirs) {
ignoreByDir[serviceDir] = await getDockerIgnoreInstance(
path.join(projectDir, serviceDir),
);
}
const { ignoreByDir, serviceDirs } = await getDockerignoreByDir(
projectDir,
serviceDirsByService,
);
const files = await listFiles(projectDir);
const dockerignoreFiles: FileStats[] = [];
const filteredFileList = files.filter((file: FileStats) => {
@ -329,3 +315,38 @@ export async function filterFilesWithDockerignore(
});
return { filteredFileList, dockerignoreFiles };
}
/**
* Get dockerignore instances for root and all service directories in the project.
* Also return the list of service directories found.
* @param projectDir Source directory to
* @param serviceDirsByService Map of service names to their subdirectories.
*/
export async function getDockerignoreByDir(
projectDir: string,
serviceDirsByService?: ServiceDirs,
): Promise<{
ignoreByDir: { [serviceDir: string]: Ignore };
serviceDirs: string[];
}> {
// path.resolve() also converts forward slashes to backslashes on Windows
projectDir = path.resolve(projectDir);
// ignoreByDir stores an instance of the dockerignore filter for each service dir
const ignoreByDir: {
[serviceDir: string]: Ignore;
} = {
'.': await getDockerIgnoreInstance(projectDir),
};
const serviceDirs: string[] = Object.values(serviceDirsByService || {})
// filter out the project source/root dir
.filter((dir) => dir && dir !== '.')
// add a trailing '/' (or '\' on Windows) to the path
.map((dir) => (dir.endsWith(path.sep) ? dir : dir + path.sep));
for (const serviceDir of serviceDirs) {
ignoreByDir[serviceDir] = await getDockerIgnoreInstance(
path.join(projectDir, serviceDir),
);
}
return { serviceDirs, ignoreByDir };
}