Skip to content
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

packer should use separate go.mod files for different packages #38

Open
stapelberg opened this issue Sep 4, 2022 · 5 comments
Open
Assignees

Comments

@stapelberg
Copy link
Contributor

Creating this issue for discussion / reporting issues with this change.

@stapelberg stapelberg self-assigned this Sep 4, 2022
stapelberg added a commit that referenced this issue Sep 4, 2022
Before

Before this commit, gokr-packer was building all Go binaries to include in the
gokrazy root file system from the same working directory, meaning the same
go.mod and go.sum files were used for all packages.

This wasn’t really an intentional choice, instead it was the easiest way to get
things working when Go switched from GOPATH to modules.

The downside of that approach is that updates in one package can result in other
packages no longer building. In the most extreme cases, it can mean that two
packages cannot be built into the same gokrazy root file system at all.

After

With this commit, gokr-packer will build each package in a subdirectory of the
new builddir/ directory in your gokrazy instance directory,
e.g. ~/gokrazy/scan2drive/builddir.

If there is no go.mod file in the builddir yet, gokr-packer will copy the
top-level go.mod/go.sum files into the builddir to keep your current module
selection, and hopefully build exactly the same binary as before.

Influencing the granularity

Often, one Go package will be the only package you use from a certain Go
module. But this isn’t always the case: for example, the system packages
github.com/gokrazy/gokrazy/cmd/dhcp and github.com/gokrazy/gokrazy/cmd/ntp both
come from the github.com/gokrazy/gokrazy module.

gokr-packer will by default create a separate builddir, including a separate
go.mod and go.sum, for each package, even when they come from the same module.

If you want to add module-wide replace directives to your go.mod file,
you can influence the granularity at which gokr-packer works as follows.

Move the go.mod/go.sum files to the directory level within the builddir/
hierarchy at which you would like to work. gokr-packer will look for
go.mod/go.sum files at the package level, going one level up until it finds the
files.

Hence, you can use the following locations, ordered from finest to coarsest
granularity:

1. per-package builddir (default), e.g.:
   builddir/github.com/gokrazy/gokrazy/cmd/dhcp/go.mod

2. per-module builddir (convenient when working with replace directives), e.g.:
   builddir/github.com/gokrazy/gokrazy/go.mod

3. per-org builddir (convenient for wide-reaching replace directives), e.g.:
   builddir/github.com/gokrazy/go.mod

4. single builddir, preserving the previous behavior, e.g.:
   builddir/go.mod

related to #38
stapelberg added a commit that referenced this issue Sep 4, 2022
Before

Before this commit, gokr-packer was building all Go binaries to include in the
gokrazy root file system from the same working directory, meaning the same
go.mod and go.sum files were used for all packages.

This wasn’t really an intentional choice, instead it was the easiest way to get
things working when Go switched from GOPATH to modules.

The downside of that approach is that updates in one package can result in other
packages no longer building. In the most extreme cases, it can mean that two
packages cannot be built into the same gokrazy root file system at all.

After

With this commit, gokr-packer will build each package in a subdirectory of the
new builddir/ directory in your gokrazy instance directory,
e.g. ~/gokrazy/scan2drive/builddir.

If there is no go.mod file in the builddir yet, gokr-packer will copy the
top-level go.mod/go.sum files into the builddir to keep your current module
selection, and hopefully build exactly the same binary as before.

Influencing the granularity

Often, one Go package will be the only package you use from a certain Go
module. But this isn’t always the case: for example, the system packages
github.com/gokrazy/gokrazy/cmd/dhcp and github.com/gokrazy/gokrazy/cmd/ntp both
come from the github.com/gokrazy/gokrazy module.

gokr-packer will by default create a separate builddir, including a separate
go.mod and go.sum, for each package, even when they come from the same module.

If you want to add module-wide replace directives to your go.mod file,
you can influence the granularity at which gokr-packer works as follows.

Move the go.mod/go.sum files to the directory level within the builddir/
hierarchy at which you would like to work. gokr-packer will look for
go.mod/go.sum files at the package level, going one level up until it finds the
files.

Hence, you can use the following locations, ordered from finest to coarsest
granularity:

1. per-package builddir (default), e.g.:
   builddir/github.com/gokrazy/gokrazy/cmd/dhcp/go.mod

2. per-module builddir (convenient when working with replace directives), e.g.:
   builddir/github.com/gokrazy/gokrazy/go.mod

3. per-org builddir (convenient for wide-reaching replace directives), e.g.:
   builddir/github.com/gokrazy/go.mod

4. single builddir, preserving the previous behavior, e.g.:
   builddir/go.mod

related to #38
@mhofstetter
Copy link

Hi @stapelberg

Even though I understand and welcome the idea behind these changes - I'd like to share my thoughts and experience with it.

At first I realised these changes when trying to update a GoKrazy package of my GoKrazy instance. Before updating the version of the package, I already executed a remote deployment (via -update) with the old state to ensure that everything was still working as expected. This also created this new builddir directory with the copies of the go.mod files from the root. I wasn't paying that much attention to this folder - not before I realised that my following remote deployments with the updated GoKrazy package version in the root go.mod are still deployed with the old versions - of course due to the fact that now my root go.mod file with the updated versions isn't of any interest for gokr-packer.

My solution was to delete the root go.mod as this is no longer necessary (because new packages wouldn't need this as a starting point anyway) - and cleanup & manage the GoKrazy package versions of my instance in the go.mod files in the corresponding builddir subdirectory (also having them under version control).

I'm aware that this aproach of having this instance directory for each GoKrazy instance is only one use case how gokr-packer can be used. There's also the use case of packaging the GoKrazy instance directly from the workspace of a package itself - as you do with router7 which is often mentioned in the comments of your changes related to this builddir changes.

From the perspective of the instance directory use case (which is also the way how it's documented in the userguide quickstart) I have some questions & thoughts:

Naming

Why is this directory called builddir and not something like packages or modules? IMO builddir indicates that it's something temporary which gets overwritten by gokr-packer on every run (which it doesn't) and which doesn't need to be under version control.

The current naming might feel right for the "router7" use case but maybe isn't ideal for the instance directory one.

An alternative workaround would be to keep the root go.mod file and treat the builddir as temporary directory by deleting it before each deplolyment - but this is against the whole idea of this change of having the possibility to have different go.mod files for each package.

Combine with flags & env

Now having three directories (builddir, flags & env) with the directory structure of the packages, it might be worth a thought of merging them under the builddir (-> packages?) directory - of course in a backwards compatible way of still respecting the old directories for some time.

Migration

From a user perspective, copying the root go.mod into the builddir subdirectories is a migration. Probably gokr-packer should threat it like this and output this to the user - maybe even with the possibility to delete root go.mod afterwards to prevent missunderstandings like mine in the first place. But again, this might differ between the use cases.

Flag for use cases

All mentioned aspects feel right or wrong depending on these two main use cases of how to use gokr-packer. They might not even be all I'm aware of :) Would it make sense to introduce a flag for the second (router7 etc) use case where someone isn't building from within a "instance directory".

It might would help in handling the mentioned aspects - whether it's naming, flags & envs or the migration part.

Documentation

This needs to be documented in the userguide :D I guess somewhere around https://gokrazy.org/development/modules/. I would even propose to bring this topic in general a little bit closer to the quickstart section. It's not really about how to develop a package, rather than how to package & deploy a GoKrazy instance.


I hope this helps to see into the head of one happy GoKrazy user :D Thanks!

@stapelberg
Copy link
Contributor Author

Hey, thanks for the feedback!

I wasn't paying that much attention to this folder - not before I realised that my following remote deployments with the updated GoKrazy package version in the root go.mod are still deployed with the old versions - of course due to the fact that now my root go.mod file with the updated versions isn't of any interest for gokr-packer.

Right, you’ll need to update the individual respective go.mod files. The root go.mod file is still used when you add new packages, though.

My solution was to delete the root go.mod as this is no longer necessary (because new packages wouldn't need this as a starting point anyway)

If you have replace directives in there that you want to apply to future new packages, too, it can still make sense to use this as a starting point.

I'm aware that this aproach of having this instance directory for each GoKrazy instance is only one use case how gokr-packer can be used. There's also the use case of packaging the GoKrazy instance directly from the workspace of a package itself - as you do with router7 which is often mentioned in the comments of your changes related to this builddir changes.

I actually no longer do that in router7 (all my gokrazy deployments are now instance directories, and that is the single recommended way going forward), and being able to separate the project directory from the instance directory was one of the motivations for this whole change.

Why is this directory called builddir and not something like packages or modules? IMO builddir indicates that it's something temporary which gets overwritten by gokr-packer on every run (which it doesn't) and which doesn't need to be under version control.

The directory is named builddir because it’s the directory that’s used when building — the packer is literally running go build, and now it runs go build from that directory. gokrazy always operates on packages, so calling the directory packages is not very descriptive either. I don’t have the association that builddir sounds temporary, but I can understand that you do.

Renaming the directory will cause extra churn / confusion, so I’d rather avoid a rename.

An alternative workaround would be to keep the root go.mod file and treat the builddir as temporary directory by deleting it before each deplolyment - but this is against the whole idea of this change of having the possibility to have different go.mod files for each package.

Exactly — I considered making the builddir temporary originally and even had a prototype that worked like that, but discarded it quickly. To achieve the goal of different dependency versions in different packages, you’d need to strip require directives from the file and let the go tool re-resolve, which is slow and not reproducible. Managing replace directives would still need to happen in the root go.mod file, which makes it awkward / convoluted. Also, having temporary files that the user can’t see or work with (e.g. with the gopls LSP support of your editor) isn’t very transparent.

Now having three directories (builddir, flags & env) with the directory structure of the packages, it might be worth a thought of merging them under the builddir (-> packages?) directory - of course in a backwards compatible way of still respecting the old directories for some time.

Yes, I know. I’m actually looking into a more unified structure for this as we speak, so stay tuned :)

From a user perspective, copying the root go.mod into the builddir subdirectories is a migration. Probably gokr-packer should threat it like this and output this to the user - maybe even with the possibility to delete root go.mod afterwards to prevent missunderstandings like mine in the first place. But again, this might differ between the use cases.

Yeah, we could probably make this process more explicit via better log messages.

This needs to be documented in the userguide :D I guess somewhere around https://gokrazy.org/development/modules/. I would even propose to bring this topic in general a little bit closer to the quickstart section. It's not really about how to develop a package, rather than how to package & deploy a GoKrazy instance.

Yep, agreed that we should update the documentation. I wanted to give this change a little time to bake, but you’re right that we’re currently not doing a good job of explaining the new way. I’ll try to come back to this over the next few days.

@mhofstetter
Copy link

Thank you very much for your answers and insights!

I actually no longer do that in router7 (all my gokrazy deployments are now instance directories, and that is the single recommended way going forward), and being able to separate the project directory from the instance directory was one of the motivations for this whole change.

Good to hear that :)

Yes, I know. I’m actually looking into a more unified structure for this as we speak, so stay tuned :)

Curious what's the idea on this side :) Maybe even something into the direction of a declarative definition of the GoKrazy instance deployment?

Sometimes i wish that one could define the "packages" and all their config (flags, envvars, ...) - and the other relevant flags of gokr-packer in a "config file". To get rid of the long argument list when executing gokr-packer :)

@stapelberg
Copy link
Contributor Author

Curious what's the idea on this side :) Maybe even something into the direction of a declarative definition of the GoKrazy instance deployment?

Sometimes i wish that one could define the "packages" and all their config (flags, envvars, ...) - and the other relevant flags of gokr-packer in a "config file". To get rid of the long argument list when executing gokr-packer :)

Yep, that’s pretty much it! See gokrazy/gokrazy#147 for more details, and comment over there in case you have any feedback. Thanks :)

stapelberg added a commit to gokrazy/gokrazy that referenced this issue Sep 29, 2022
stapelberg added a commit to gokrazy/gokrazy that referenced this issue Sep 29, 2022
The old content was pretty obsolete — by now all GOPATH users will have
transitioned to modules.

related to gokrazy/tools#38
@stapelberg
Copy link
Contributor Author

https://gokrazy.org/quickstart/ and https://gokrazy.org/development/modules/ are now updated :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants