Skip to content

Commit

Permalink
fix(remote-sources): ensure Garden also watches linked repos
Browse files Browse the repository at this point in the history
  • Loading branch information
eysi09 committed Aug 7, 2019
1 parent a71a815 commit 060075f
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 25 deletions.
2 changes: 1 addition & 1 deletion garden-service/src/commands/unlink/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class UnlinkModuleCommand extends Command<Args, Opts> {

const linkedModuleSources = await removeLinkedSources({ garden, sourceType, names: modules })

log.info(`Unlinked module(s) ${module}`)
log.info(`Unlinked module(s) ${modules.join(" ")}`)

return { result: linkedModuleSources }
}
Expand Down
2 changes: 1 addition & 1 deletion garden-service/src/commands/unlink/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class UnlinkSourceCommand extends Command<Args, Opts> {

const linkedProjectSources = await removeLinkedSources({ garden, sourceType, names: sources })

log.info(`Unlinked source(s) ${sources}`)
log.info(`Unlinked source(s) ${sources.join(" ")}`)

return { result: linkedProjectSources }
}
Expand Down
10 changes: 8 additions & 2 deletions garden-service/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ export class Garden {
const buildDir = await BuildDir.factory(projectRoot, gardenDirPath)
const workingCopyId = await getWorkingCopyId(gardenDirPath)

// We always exclude the garden dir
const gardenDirExcludePattern = `${relative(projectRoot, gardenDirPath)}/**/*`
const moduleExcludePatterns = [...((config.modules || {}).exclude || []), gardenDirExcludePattern]

const garden = new this({
projectRoot,
projectName,
Expand All @@ -231,10 +235,10 @@ export class Garden {
opts,
plugins,
providerConfigs: providers,
moduleExcludePatterns,
workingCopyId,
dotIgnoreFiles: config.dotIgnoreFiles,
moduleIncludePatterns: (config.modules || {}).include,
moduleExcludePatterns: (config.modules || {}).exclude,
}) as InstanceType<T>

return garden
Expand Down Expand Up @@ -265,7 +269,9 @@ export class Garden {
*/
async startWatcher(graph: ConfigGraph) {
const modules = await graph.getModules()
this.watcher = new Watcher(this, this.log, modules)
const linkedPaths = (await getLinkedSources(this)).map(s => s.path)
const paths = [this.projectRoot, ...linkedPaths]
this.watcher = new Watcher(this, this.log, paths, modules)
}

private registerPlugin(name: string, moduleOrFactory: RegisterPluginParam) {
Expand Down
21 changes: 14 additions & 7 deletions garden-service/src/util/ext-source-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,21 @@ export function isModuleLinked(module: Module, garden: Garden) {
return !pathIsInside(module.path, garden.projectRoot) && !isPluginModule
}

export async function getLinkedSources(
garden: Garden,
type: ExternalSourceType,
): Promise<LinkedSource[]> {
/**
* Returns an array of linked sources by type, as read from the local config store.
* Returns all linked sources if typed not specified.
*/
export async function getLinkedSources(garden: Garden, type?: ExternalSourceType): Promise<LinkedSource[]> {
const localConfig = await garden.configStore.get()
return (type === "project"
? localConfig.linkedProjectSources
: localConfig.linkedModuleSources) || []
const linkedModuleSources = localConfig.linkedModuleSources || []
const linkedProjectSources = localConfig.linkedProjectSources || []
if (type === "module") {
return linkedModuleSources
} else if (type === "project") {
return linkedProjectSources
} else {
return [...linkedModuleSources, ...linkedProjectSources]
}
}

export async function addLinkedSources({ garden, sourceType, sources }: {
Expand Down
2 changes: 1 addition & 1 deletion garden-service/src/util/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { VcsHandler } from "../vcs/vcs"
const VALID_CONFIG_FILENAMES = ["garden.yml", "garden.yaml"]
const metadataFilename = "metadata.json"
export const defaultDotIgnoreFiles = [".gitignore", ".gardenignore"]
export const fixedExcludes = [".git", ".garden", "debug-info*/**"]
export const fixedExcludes = [".git", ".garden/**/*", "debug-info*/**"]

/*
Warning: Don't make any async calls in the loop body when using this function, since this may cause
Expand Down
9 changes: 5 additions & 4 deletions garden-service/src/vcs/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,14 @@ export class GitHandler extends VcsHandler {
* We need to exclude .garden to avoid errors when path is the project root. This happens e.g. for modules
* whose config is colocated with the project config, and that don't specify include paths/patterns.
*/
lines = await git("ls-files", "-s", "--other", "--exclude=.garden", path)
// FIXME: We should use `garden.gardenDirPath` instead of ".garden" since the dir name can be variable
lines = await git("ls-files", "-s", "--others", "--exclude=.garden", path)

// List ignored files from .gardenignore. We need to run ls-files twice to get both tracked and untracked files.
const lsFilesCmd = ["ls-files", "--ignored", ...this.ignoreFiles.map(f => `--exclude-per-directory=${f}`)]
const lsFilesUntrackedCmd = [...lsFilesCmd, "--others"]
const lsIgnoredFiles = ["ls-files", "--ignored", ...this.ignoreFiles.map(f => `--exclude-per-directory=${f}`)]
const lsUntrackedIgnoredFiles = [...lsIgnoredFiles, "--others"]

ignored = flatten(await Bluebird.map([lsFilesCmd, lsFilesUntrackedCmd], async (cmd) => git(...cmd, path)))
ignored = flatten(await Bluebird.map([lsIgnoredFiles, lsUntrackedIgnoredFiles], async (cmd) => git(...cmd, path)))
} catch (err) {
// if we get 128 we're not in a repo root, so we get no files
if (err.code !== 128) {
Expand Down
18 changes: 9 additions & 9 deletions garden-service/src/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ import { isConfigFilename } from "./util/fs"
// IMPORTANT: We must use a single global instance of the watcher, because we may otherwise get
// segmentation faults on macOS! See https://github.com/fsevents/fsevents/issues/273
let watcher: FSWatcher | undefined
let projectRoot: string

// The process hangs after tests if we don't do this
registerCleanupFunction("stop watcher", () => {
// Export so that we can clean up the global watcher instance when running tests
export function cleanUp() {
if (watcher) {
watcher.close()
watcher = undefined
}
})
}

// The process hangs after tests if we don't do this
registerCleanupFunction("stop watcher", cleanUp)

export type ChangeHandler = (module: Module | null, configChanged: boolean) => Promise<void>

Expand All @@ -39,13 +41,11 @@ export type ChangeHandler = (module: Module | null, configChanged: boolean) => P
export class Watcher {
private watcher: FSWatcher

constructor(private garden: Garden, private log: LogEntry, modules: Module[]) {
projectRoot = this.garden.projectRoot

this.log.debug(`Watcher: Watching ${projectRoot}`)
constructor(private garden: Garden, private log: LogEntry, paths: string[], modules: Module[]) {
log.debug(`Watcher: Watching paths ${paths.join(", ")}`)

if (watcher === undefined) {
watcher = watch(projectRoot, {
watcher = watch(paths, {
ignoreInitial: true,
persistent: true,
})
Expand Down
9 changes: 9 additions & 0 deletions garden-service/test/unit/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ describe("Garden", () => {
expect(garden).to.be.ok
})

it("should always exclude the garden dir", async () => {
const gardenA = await makeTestGardenA()
const gardenCustomDir = await makeTestGarden(getDataDir("test-project-a"), {
gardenDirPath: "custom/garden-dir",
})
expect(gardenA.moduleExcludePatterns).to.include(".garden/**/*")
expect(gardenCustomDir.moduleExcludePatterns).to.include("custom/garden-dir/**/*")
})

it("should throw if a project has config files with yaml and yml extensions in the same dir", async () => {
const path = getDataDir("test-project-duplicate-yaml-file-extensions")
await expectError(async () => makeTestGarden(path), "validation")
Expand Down

0 comments on commit 060075f

Please sign in to comment.