-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
go module type preliminary/prototype #1271
Conversation
@ellenkorbes FYI: You can flag PRs as drafts if you don't intend to merge them as is. |
specs: { | ||
darwin: macos, | ||
linux: penguin, | ||
// Is the "32" here really 32 or is it just the name? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just a relic, standard Node.js platform names that we match.
} | ||
|
||
// What was this for? | ||
// await copy(resolvedJarPath, resolve(module.buildPath, "app.jar")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was needed in the maven-container
module type, because the Jar file there is generated inside the user's source folder.
|
||
// If they did, update the vendor directory | ||
console.log(`Downloading new dependencies...`) | ||
if (tidy.stdout != "") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should always use !==
, but you can also just use if (tidy.stdout)
here.
try { | ||
await ensureDir(resolve(module.path, "bin")) | ||
} catch (err) { | ||
console.error(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe ensureDir()
should ever error, no need for the try/catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'll error if it tries to create a directory one doesn't have the permissions to create (e.g. https://runkit.com/57ebc041d4a27f140028fd78/5a33f49ef88d280012b07780) But you're right, this it too much of an edge case.
.example("false"), | ||
// compress: joi.alternatives().try( | ||
// joi.boolean(), | ||
// joi.number(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can further specify the allowed numeric values: joi.number().integer().min(1).max(9)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think we should omit this option entirely. It adds unnecessary complexity. Compression is anyway applied in container images, and when syncing during hot-reloading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave it there commented out until the whole thing is fully functional and I can benchmark it. I suspect it could make a significant difference for large binaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth trying as a stretch goal, but I'd be quite surprised if it made a meaningful difference, since data is anyway compressed when going over the wire.
// joi.boolean(), | ||
// joi.number(), | ||
// ).description(dedent` | ||
// "By default, Garden will compress the resulting Go binary with UPX \(upx.github.io\). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra quote-mark at the start. And the escaping is not needed on the parentheses.
// For this functionality to work with macOS, UPX needs | ||
// to first be installed with Homebrew using \`brew install upx\`. | ||
// `) | ||
// .example("1"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example should be an actual value, e.g. 1
and not "1"
, since the example value is actually validated when the schema is defined. You can also set the default here (.default(9)
).
}) | ||
} catch (err) { | ||
console.log(err.stderr) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see these spacing issues here and there. I highly recommend installing the TSLint plugin in VSCode, which will automatically correct these.
log.setState(`Starting Go build process...`) | ||
|
||
// Check if any imports have changed | ||
console.log(`Checking for new dependencies...`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend adding a status subline for these logs:
const status = log.info("Checking for new dependencies...")
// And then for the next status message below
...
status.setState("Downloading new dependencies...")
By default, Garden passes the '-w' flag to the linker to omit this information and make the resulting binaries smaller. | ||
If you do want this information, set this option to \`true\`. | ||
`) | ||
.example("false"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change to .example(true)
(no quotes)
And add .default(false)
RUN apk add entr ca-certificates | ||
RUN mkdir app | ||
WORKDIR /app | ||
EXPOSE 8080 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The EXPOSE
directive is not necessary, easier to just omit it.
@@ -0,0 +1,9 @@ | |||
FROM alpine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should definitely specify an Alpine version (just go with whatever is most recent).
|
||
COPY bin/ /app/ | ||
|
||
CMD ls binary | entr -r ./binary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize this is more of a placeholder, but we should use ENTRYPOINT
instead of CMD
here and make it simply ENTRYPOINT [/app/bin]
. When we use hot reloading, we'll anyway override the command in the manifest.
directory. | ||
|
||
To use it, make sure to add the \`maven-container\` provider to your project configuration. | ||
The provider will automatically fetch and cache Maven and the appropriate OpenJDK version ahead of building. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remember to update this text, and also to add the module type to our reference docs.
env: { | ||
CGO_ENABLED: "0", | ||
GOOS: "linux", | ||
GOCACHE: resolve(module.buildPath, "cache"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we override the cache?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go's default cache location is ~/.cache/
. Since we're keeping the Go install compartmentalized inside the module, I figured we should do the same for the compiler cache.
Which raises an interesting question. If a user has 10 Go projects, they'll have 10 copies of Go in their machine. Should we keep this in a central location e.g. ~/.garden/go
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We download Go once for each user. So that won't be an issue.
And I don't really see a reason to partition the cache by module. If different modules vendor the same libraries it's just less efficient to cache separately. Unless there's some concern specific to Go that I'm not aware of?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That refers to the compiler cache, for .a
files and such.
Libraries are vendored separately by default. We could come up with a hack to have a central location for all of them, but that'd cause version conflicts e.g. when one project uses version v1
of a library and the other one uses v2
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not suggesting doing anything unusual, just to leave the default GOCACHE setting. The default is "central" anyway, in that there's a shared cache directory. Unless there are known issues with the default (which would be pretty odd) I still don't see a reason to override it.
debug: boolean | ||
compress: boolean | number | ||
run: string | ||
buildFlags: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both run
and buildFlags
should be string[]
// await prepareBuild(module, log) | ||
|
||
return base!(params) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove this handler.
// } catch (err) { | ||
// console.log(err) | ||
// } | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite messy. Better to use the buildArgs
field on the container module type. See the maven-container
module type configure handler for how to do it:
containerConfig.spec.buildArgs = { |
You'd do something like
containerConfig.spec.buildArgs = {
EXTRA_RUN: moduleConfig.spec.build.run.join(" ") || "echo"
}
And then add RUN ${EXTRA_RUN}
at the bottom of the Dockerfile.
Re: Adding hot-reloading, it should actually be reasonably simple. First override the containerConfig.spec.hotReload = containerConfig.spec.hotReload || {
sync: [{ source: "./bin", target: "/app/bin" }],
}
for (const service of containerConfig.spec.services || []) {
service.hotReloadCommand = service.hotReloadCommand || [<the entr base command>]
} Then you need to ensure the binary is built before the hot reloading happens: async function hotReload(params: HotReloadServiceParams<GoContainerModule>) {
const { base, module, log } = params
// Need to extract the binary build from the build handler into a separate function
await buildBinary(module, log)
// Defer the rest of it to the kubernetes provider (or whatever other provider applies, technically)
return base!(params)
} The kubernetes provider will then take care of the rest. |
} | ||
|
||
const goContainerModuleSpecSchema = containerModuleSpecSchema.keys({ | ||
build: baseBuildSpecSchema.keys(goKeys), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The module spec should be top level, not under the build key. So basically: const goContainerModuleSpecSchema = containerModuleSpecSchema.keys(goKeys)
. Fixes the validation error we were seeing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was intentional, since all those parameters have to do with the build. It's admittedly clumsy to handle the schema this way, but we'll deal with that later at the framework level.
98209ff
to
ed4eac3
Compare
You can now rebase this branch off master, since the branch it depended on has been merged. Will also make this easier to review and iterate on. |
Closing in favour of #1511. |
This is very preliminary work. Do not merge.
I'll fill out this PR tomorrow.
@edvald I'm currently studying
garden-service/src/types/plugin/service/deployService.ts
andgarden-service/src/plugins/kubernetes/container/deployment.ts
to try and figure out how to do the hot reload part. Any direction there is welcome. (Thanks!)What this PR does / why we need it:
Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer: