From 963019285ca118cee46d23da27147112b362343e Mon Sep 17 00:00:00 2001 From: Thorarinn Sigurdsson Date: Wed, 13 Mar 2019 17:12:06 +0100 Subject: [PATCH] fix(build): remove deleted files/dirs during sync Before this fix, removing non-ignored files or folders from a module during the execution of a watch-mode command would not result in those files/folders being removed from the module's build directory. This was fixed by adding the --delete option to the rsync call used by BuildDir, and moving the .garden-version file from the module's build directory to a new subdirectory of .garden, build-metadata/[module-name]. In general, the build-metadata directory can be used by plugins to persistently store build-related metadata. --- garden-service/src/build-dir.ts | 19 ++++++++++++++++--- garden-service/src/constants.ts | 2 +- garden-service/src/plugins/exec.ts | 4 ++-- garden-service/src/types/module.ts | 6 ++++++ garden-service/test/unit/src/plugins/exec.ts | 8 ++++---- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/garden-service/src/build-dir.ts b/garden-service/src/build-dir.ts index 52502ef4a5..17f6320174 100644 --- a/garden-service/src/build-dir.ts +++ b/garden-service/src/build-dir.ts @@ -34,14 +34,17 @@ import { ModuleConfig } from "./config/module" // Lazily construct a directory of modules inside which all build steps are performed. const buildDirRelPath = join(GARDEN_DIR_NAME, "build") +const buildMetadataDirRelPath = join(GARDEN_DIR_NAME, "build-metadata") export class BuildDir { - constructor(private projectRoot: string, public buildDirPath: string) { } + constructor(private projectRoot: string, public buildDirPath: string, public buildMetadataDirPath) { } static async factory(projectRoot: string) { const buildDirPath = join(projectRoot, buildDirRelPath) + const buildMetadataDirPath = join(projectRoot, buildMetadataDirRelPath) await ensureDir(buildDirPath) - return new BuildDir(projectRoot, buildDirPath) + await ensureDir(buildMetadataDirPath) + return new BuildDir(projectRoot, buildDirPath, buildMetadataDirPath) } async syncFromSrc(module: ModuleConfig) { @@ -95,6 +98,16 @@ export class BuildDir { return path } + /** + * This directory can be used to store build-related metadata for a given module, for example the last built + * version for exec modules. + */ + async buildMetadataPath(moduleName: string): Promise { + const path = resolve(this.buildMetadataDirPath, moduleName) + await ensureDir(path) + return path + } + private async sync(sourcePath: string, destinationPath: string): Promise { const destinationDir = parse(destinationPath).dir await ensureDir(destinationDir) @@ -110,7 +123,7 @@ export class BuildDir { destinationPath = stripWildcard(destinationPath) // --exclude is required for modules where the module and project are in the same directory - await execa("rsync", ["-rptgo", `--exclude=${GARDEN_DIR_NAME}`, sourcePath, destinationPath]) + await execa("rsync", ["-rptgo", "--delete", `--exclude=${GARDEN_DIR_NAME}`, sourcePath, destinationPath]) } } diff --git a/garden-service/src/constants.ts b/garden-service/src/constants.ts index 166ec59525..80919370ec 100644 --- a/garden-service/src/constants.ts +++ b/garden-service/src/constants.ts @@ -21,7 +21,7 @@ export const LOGS_DIR = join(GARDEN_DIR_NAME, "logs") export const ERROR_LOG_FILENAME = "error.log" export const PROJECT_SOURCES_DIR_NAME = join(GARDEN_DIR_NAME, "sources", "project") export const MODULE_SOURCES_DIR_NAME = join(GARDEN_DIR_NAME, "sources", "module") -export const GARDEN_BUILD_VERSION_FILENAME = ".garden-build-version" +export const GARDEN_BUILD_VERSION_FILENAME = "garden-build-version" export const GARDEN_VERSIONFILE_NAME = ".garden-version" export const DEFAULT_NAMESPACE = "default" export const DEFAULT_PORT_PROTOCOL = "TCP" diff --git a/garden-service/src/plugins/exec.ts b/garden-service/src/plugins/exec.ts index b4f5ccad52..2b0df09f4f 100644 --- a/garden-service/src/plugins/exec.ts +++ b/garden-service/src/plugins/exec.ts @@ -128,7 +128,7 @@ export async function configureExecModule( } export async function getExecModuleBuildStatus({ module }: GetBuildStatusParams): Promise { - const buildVersionFilePath = join(module.buildPath, GARDEN_BUILD_VERSION_FILENAME) + const buildVersionFilePath = join(module.buildMetadataPath, GARDEN_BUILD_VERSION_FILENAME) let builtVersion: ModuleVersion | null = null try { @@ -162,7 +162,7 @@ export async function buildExecModule({ module }: BuildModuleParams) } // keep track of which version has been built - const buildVersionFilePath = join(buildPath, GARDEN_BUILD_VERSION_FILENAME) + const buildVersionFilePath = join(module.buildMetadataPath, GARDEN_BUILD_VERSION_FILENAME) await writeModuleVersionFile(buildVersionFilePath, module.version) return output diff --git a/garden-service/src/types/module.ts b/garden-service/src/types/module.ts index f619da6479..a68f09619e 100644 --- a/garden-service/src/types/module.ts +++ b/garden-service/src/types/module.ts @@ -32,6 +32,7 @@ export interface Module< W extends TaskSpec = any, > extends ModuleConfig { buildPath: string + buildMetadataPath: string version: ModuleVersion buildDependencies: ModuleMap @@ -51,6 +52,10 @@ export const moduleSchema = moduleConfigSchema .required() .uri({ relativeOnly: true }) .description("The path to the build staging directory for the module."), + buildMetadataPath: Joi.string() + .required() + .uri({ relativeOnly: true }) + .description("The path to the build metadata directory for the module."), version: moduleVersionSchema .required(), buildDependencies: joiIdentifierMap(Joi.lazy(() => moduleSchema)) @@ -83,6 +88,7 @@ export async function moduleFromConfig(garden: Garden, graph: ConfigGraph, confi ...cloneDeep(config), buildPath: await garden.buildDir.buildPath(config.name), + buildMetadataPath: await garden.buildDir.buildMetadataPath(config.name), version: await garden.resolveVersion(config.name, config.build.dependencies), buildDependencies: {}, diff --git a/garden-service/test/unit/src/plugins/exec.ts b/garden-service/test/unit/src/plugins/exec.ts index 59aeeef8d6..c9b36120f3 100644 --- a/garden-service/test/unit/src/plugins/exec.ts +++ b/garden-service/test/unit/src/plugins/exec.ts @@ -140,8 +140,8 @@ describe("exec plugin", () => { it("should read a build version file if it exists", async () => { const module = await graph.getModule(moduleName) const version = module.version - const buildPath = module.buildPath - const versionFilePath = join(buildPath, GARDEN_BUILD_VERSION_FILENAME) + const buildMetadataPath = module.buildMetadataPath + const versionFilePath = join(buildMetadataPath, GARDEN_BUILD_VERSION_FILENAME) await writeModuleVersionFile(versionFilePath, version) @@ -155,8 +155,8 @@ describe("exec plugin", () => { it("should write a build version file after building", async () => { const module = await graph.getModule(moduleName) const version = module.version - const buildPath = module.buildPath - const versionFilePath = join(buildPath, GARDEN_BUILD_VERSION_FILENAME) + const buildMetadataPath = module.buildMetadataPath + const versionFilePath = join(buildMetadataPath, GARDEN_BUILD_VERSION_FILENAME) await garden.actions.build({ log, module })