Skip to content

Commit

Permalink
fix(vcs): don't fork a process for every untracked file
Browse files Browse the repository at this point in the history
This solves an issue where Garden would flood spawned processes with
a huge amount of source files. This could happen, for example, when
library directories (e.g. node_modules) weren't ignored.
  • Loading branch information
edvald committed Apr 26, 2019
1 parent e81ca82 commit ef43992
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 2 deletions.
14 changes: 14 additions & 0 deletions garden-service/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions garden-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"fs-extra": "^7.0.1",
"get-port": "^4.0.0",
"has-ansi": "^3.0.0",
"hasha": "^5.0.0",
"ignore": "^5.0.4",
"indent-string": "^3.2.0",
"inquirer": "^6.2.1",
Expand Down
17 changes: 15 additions & 2 deletions garden-service/src/vcs/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

import * as execa from "execa"
import { join, resolve } from "path"
import { ensureDir, pathExists } from "fs-extra"
import { ensureDir, pathExists, stat, createReadStream } from "fs-extra"
import { PassThrough } from "stream"
import * as hasha from "hasha"

import { VcsHandler, RemoteSourceParams, VcsFile } from "./vcs"
import { ConfigurationError, RuntimeError } from "../exceptions"
Expand Down Expand Up @@ -115,7 +117,7 @@ export class GitHandler extends VcsHandler {
// If we can't compute the hash, i.e. the file is gone, we filter it out below
let hash = ""
try {
hash = (await git("hash-object", resolvedPath))[0]
hash = await this.hashObject(resolvedPath) || ""
} catch (err) {
// 128 = File no longer exists
if (err.code !== 128) {
Expand Down Expand Up @@ -191,4 +193,15 @@ export class GitHandler extends VcsHandler {
}
}

/**
* Replicates the `git hash-object` behavior. See https://stackoverflow.com/a/5290484/3290965
*/
async hashObject(path: string) {
const info = await stat(path)
const stream = new PassThrough()
const output = hasha.fromStream(stream, { algorithm: "sha1" })
stream.push(`blob ${info.size}\0`)
createReadStream(path).pipe(stream)
return output
}
}
11 changes: 11 additions & 0 deletions garden-service/test/unit/src/vcs/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ describe("GitHandler", () => {
])
})
})

describe("hashObject", () => {
it("should return the same result as `git hash-object` for a file", async () => {
const path = resolve(tmpPath, "foo.txt")
await createFile(path)

const expected = (await git("hash-object", path))[0]

expect(await handler.hashObject(path)).to.equal(expected)
})
})
})

describe("git", () => {
Expand Down

0 comments on commit ef43992

Please sign in to comment.