As long as these things are bugs and not "that's not how it works or will ever work", I have some hope. This is a back-burner exploration for me, so I am not in a panic. Every now and again I will circle back and see if anything new happens :)
On Wed, Jan 20, 2021 at 10:50 AM Jay Conrod <jaycon...@google.com> wrote: > You appear to have discovered another new bug. Sorry for that. I've opened > #43806 <https://github.com/golang/go/issues/43806> to track it. > > With that bug, it doesn't look like `go list` with local paths (relative > or absolute) in a repository with nested replacement directories will work > (at least not yet). > > `go list` should still work on full packages paths, but I'm not sure > there's an easy way to resolve directory paths to package paths, other than > by walking up the directory tree to the nearest go.mod and reading the > module path from there. > > On Tue, Jan 19, 2021 at 8:06 PM Tim Hockin <thoc...@google.com> wrote: > >> >> >> On Tue, Jan 19, 2021 at 7:54 AM Jay Conrod <jaycon...@google.com> wrote: >> >>> By the way, I'm not sure if you're already doing this, but if you can >>> batch all of the `go list` runs (or go/packages >>> <https://goto.google.com/packages>.Load) together per module (passing >>> an argument per package), that will be much faster than loading individual >>> packages with separate `go list` calls. It will save `go list` from having >>> to load the module graph and common sets of dependencies multiple times. >>> >>> If you need to load all the packages in a module, you can also use an >>> argument like ./... from the root directory of the module to load >>> everything there (excluding modules in subdirectories). >>> >> >> Yeah, I am trying that but tripping on the "does not contain package" >> error. >> >> >>> >>> On Tue, Jan 19, 2021 at 10:02 AM Jay Conrod <jaycon...@google.com> >>> wrote: >>> >>>> > Interesting - is the difference the absolute paths vs relative? >>>> >>>> It looks like the bug has to do with whether the directory is below the >>>> main module root directory or not. If it is, the go command takes a path >>>> that assumes it's part of the main module, which it's not. >>>> >>>> > I hoped maybe `-modfile` would do the same trick, but alas not: >>>> >>>> -modfile lets you change the effective content of go.mod but not the >>>> module root directory. Unfortunately it doesn't look like that can be used >>>> to work around the issue. >>>> >>>> > It seems that is because the "main" (top-level dir) go.mod has >>>> > `replace` directives with relative paths, which kubernetes really >>>> > does. >>>> >>>> You may need to copy those over to the tmp go.mod and adjust the paths. >>>> Sorry this has gotten pretty involved. >>>> >>>> > Yeah, I noticed. When GO111MODULE=off, everything I am doing is much >>>> > faster. I'm wary of depending on that forever, though. >>>> >>>> Module-aware mode is quite a bit more complicated than GOPATH mode, so >>>> to some degree it's not surprising it's slower... it's surprising that it's >>>> a LOT slower though. I expect there's some optimization work for us to do >>>> in the next development cycle. >>>> >>>> We would eventually like to deprecate GOPATH mode though, so it's a >>>> good idea not to depend on it in new tooling today. 'go list' should be >>>> fine to get package dependency info in either module mode or GOPATH mode. >>>> go/packages <https://goto.google.com/packages> is useful if you need >>>> additional information on top of that (parsed syntax trees, type info). >>>> >>>> > I want to run a slow codegen process only if the packages it depends >>>> > on have ACTUALLY changed (mtime is a good enough proxy) and I don't >>>> > know a priori which packages need codegen. I want to scan the file >>>> > tree, find the files that need codegen, check their deps, and only >>>> > then run the codegen. >>>> >>>> How much dependency info do you need? If the codegen is only within >>>> packages with files that have changed, 'go list' might be overkill (it >>>> always loads dependencies, even if they aren't printed). If you need >>>> dependencies or reverse dependencies, 'go list' or go/packages >>>> <https://goto.google.com/packages> are probably the right tools. >>>> >>>> On Fri, Jan 15, 2021 at 6:43 PM Tim Hockin <thoc...@google.com> wrote: >>>> >>>>> On Fri, Jan 15, 2021 at 2:17 PM Jay Conrod <jaycon...@google.com> >>>>> wrote: >>>>> > >>>>> > I was initially going to suggest adding the module subdirectories as >>>>> requirements to the main go.mod, then replacing those with the >>>>> subdirectories. >>>>> > >>>>> > module example.com/m >>>>> > >>>>> > go 1.15 >>>>> > >>>>> > require ( >>>>> > example.com/other1 v0.0.0 >>>>> > example.com/other2 v0.0.0 >>>>> > example.com/m/submod v0.0.0 >>>>> > ) >>>>> > >>>>> > replace ( >>>>> > example.com/other1 => ./staging/src/example.com/other1 >>>>> > example.com/other2 => ./staging/src/example.com/other2 >>>>> > example.com/m/submod v0.0.0 => ./submod >>>>> > ) >>>>> > >>>>> > >>>>> > I think you might have tried this already. It gives the same "main >>>>> module ... does not contain package" error. I believe that's a bug. I've >>>>> opened #43733 to track it. >>>>> >>>>> Interesting. If that's a bug, then maybe I'll be able to do what I >>>>> need once fixed. >>>>> >>>>> > In general, it should be possible to give 'go list' an absolute or >>>>> relative path (starting with ./ or ../) to any directory containing a >>>>> package which is part of any module in the build list. For example, some >>>>> tools list directories in the module cache to find out what package a .go >>>>> file belongs to. >>>>> > >>>>> > As a workaround, you could put a go.mod in an otherwise empty >>>>> directory (in /tmp or something), then require the relevant modules from >>>>> the repo and replace them with absolute paths. Then you can run 'go list' >>>>> in that directory with absolute paths of package directories. >>>>> >>>>> Interesting - is the difference the absolute paths vs relative? >>>>> >>>>> I hoped maybe `-modfile` would do the same trick, but alas not: >>>>> >>>>> ``` >>>>> $ (cd /tmp/gomodhack/; go list /tmp/go-list-modules/submod/used/) >>>>> example.com/m/submod/used >>>>> >>>>> $ go list --modfile /tmp/gomodhack/go.mod >>>>> /tmp/go-list-modules/submod/used/ >>>>> main module (tmp) does not contain package tmp/submod/used >>>>> ``` >>>>> >>>>> It also fails some cases: >>>>> >>>>> ``` >>>>> (cd /tmp/gomodhack/; go list /tmp/go-list-modules/submod/used/) >>>>> example.com/m/submod/used >>>>> thockin@thockin-glaptop4 go-list-modules main /$ (cd /tmp/gomodhack/; >>>>> go list /tmp/go-list-modules/staging/src/example.com/other1/used/) >>>>> go: finding module for package >>>>> example.com/m/staging/src/example.com/other1/used >>>>> cannot find module providing package >>>>> example.com/m/staging/src/example.com/other1/used: unrecognized import >>>>> path "example.com/m/staging/src/example.com/other1/used": reading >>>>> https://example.com/m/staging/src/example.com/other1/used?go-get=1: >>>>> 404 Not Found >>>>> ``` >>>>> >>>>> It seems that is because the "main" (top-level dir) go.mod has >>>>> `replace` directives with relative paths, which kubernetes really >>>>> does. >>>>> >>>>> > Incidentally, golang.org/x/tools/go/packages will call 'go list' >>>>> under the hood in module mode. go/build >>>>> <https://goto.google.com/build> might do the same, depending on how >>>>> it's invoked. 'go list' may be the best thing to use if it gives the >>>>> information you need. >>>>> >>>>> Yeah, I noticed. When GO111MODULE=off, everything I am doing is much >>>>> faster. I'm wary of depending on that forever, though. >>>>> >>>>> Stepping back, I fear I am pushing the square peg into a round hole. >>>>> Let me restate what I am trying to do. >>>>> >>>>> I want to run a slow codegen process only if the packages it depends >>>>> on have ACTUALLY changed (mtime is a good enough proxy) and I don't >>>>> know a priori which packages need codegen. I want to scan the file >>>>> tree, find the files that need codegen, check their deps, and only >>>>> then run the codegen. >>>>> >>>>> We do this today with `go list` and GO111MODULE=off, but I was advised >>>>> at some point that x/tools/go/packages was the future-safe approach. >>>>> >>>>> If there's a better way, I am all ears. >>>>> >>>>> Tim >>>>> GO111MODULE=off >>>>> > On Fri, Jan 15, 2021 at 11:59 AM 'Tim Hockin' via golang-nuts < >>>>> golang-nuts@googlegroups.com> wrote: >>>>> >> >>>>> >> Hi. This isn't exactly burning urgent, but it is a long-term issue >>>>> >> for Kubernetes. If there's anything I can do to catalyze the >>>>> >> discussion - tests to run, info to dig up, etc - please let me know. >>>>> >> >>>>> >> On Wed, Dec 23, 2020 at 10:48 AM Tim Hockin <thoc...@google.com> >>>>> wrote: >>>>> >> > >>>>> >> > Hi Paul! >>>>> >> > >>>>> >> > On Wed, Dec 23, 2020 at 4:23 AM Paul Jolly <p...@myitcv.io> >>>>> wrote: >>>>> >> > > >>>>> >> > > > I just can't figure out how to do this. Maybe it can't be >>>>> done in `go >>>>> >> > > > list` ? Or maybe we're just missing some detail of go >>>>> modules.. >>>>> >> > > >>>>> >> > > go list operates in the context of a single module (in the mode >>>>> you >>>>> >> > > are interested in), so you cannot do this with a single command >>>>> across >>>>> >> > > multiple modules. >>>>> >> > >>>>> >> > This might be a real problem for us. For this post I am reducing >>>>> it >>>>> >> > to `go list`, but in actuality we have a small program that we >>>>> wrote >>>>> >> > which does what we need in terms of `go/build`. It works great >>>>> when >>>>> >> > `GO111MODULE=off` but is more than 100x slower normally. I >>>>> thought it >>>>> >> > was finally time to rewrite it in terms of `go/packages` and get >>>>> rid >>>>> >> > of GO111MODULE=off. That didn't pan out, hence this post. >>>>> >> > >>>>> >> > More inline and below >>>>> >> > >>>>> >> > > > First I do a `find` for any file that has a specific comment >>>>> tag, >>>>> >> > > > indicating that the package needs codegen. The results span >>>>> several >>>>> >> > > > of the in-repo submodules. >>>>> >> > > >>>>> >> > > Just to check, I'm assuming the results of this find command >>>>> are being >>>>> >> > > translated to a list of packages? Because the transitive >>>>> dependencies >>>>> >> > > of a list of packages within a module can be done via a single >>>>> go list >>>>> >> > > command. >>>>> >> > >>>>> >> > The trick is "within a module". I'll update >>>>> >> > https://github.com/thockin/go-list-modules to reflect the process >>>>> >> > more. I've added a >>>>> >> > get_codegen_deps.sh that models the behavior. Note that I really >>>>> want >>>>> >> > files, not packages, so I can express the dep-graph. >>>>> >> > >>>>> >> > What do you mean by "translated to a list of packages" - which >>>>> specific syntax? >>>>> >> > >>>>> >> > What I end up with is something like `go list ./path/to/dir1 >>>>> >> > ./path/to/dir2 ./path/to/dir3`. Any of those dirs might be in >>>>> >> > different modules. So `go list` tells me "main module ( >>>>> example.com/m) >>>>> >> > does not contain package example.com/m/path/to/dir1" and so on. >>>>> >> > Setting `GO111MODULE=off` does work, but I fear the future of >>>>> that. >>>>> >> > >>>>> >> > > > For each target package, I want to get the list of all deps >>>>> and >>>>> >> > > > extract the GoFiles. Then I can use that to determine if the >>>>> codegen >>>>> >> > > > needs to run. >>>>> >> > > >>>>> >> > > FWIW I wrote a tool to do just this: >>>>> >> > > >>>>> https://pkg.go.dev/myitcv.io@v0.0.0-20201125173645-a7167afc9e13/cmd/gogenerate >>>>> >> > > which might work in your situation. >>>>> >> > >>>>> >> > I will take a look - it seems I will need to restructure a bunch >>>>> of >>>>> >> > tooling to prove it works for us or doesn't :) >>>>> >> > >>>>> >> > > > Where it breaks down is that I can't seem to `go list` all at >>>>> once: >>>>> >> > > > >>>>> >> > > > ``` >>>>> >> > > > # This works within the "root" module >>>>> >> > > > $ go list -f '{{.GoFiles}}' ./subdir >>>>> >> > > > [file.go] >>>>> >> > > >>>>> >> > > This will work. >>>>> >> > > >>>>> >> > > > # This does not work across modules >>>>> >> > > > $ go list -f '{{.GoFiles}}' ./submod/used ./submod/unused >>>>> >> > > > main module (example.com/m) does not contain package >>>>> example.com/m/submod/used >>>>> >> > > > main module (example.com/m) does not contain package >>>>> example.com/m/submod/unused >>>>> >> > > >>>>> >> > > Per above, this will not work across module boundaries. >>>>> >> > >>>>> >> > It works with `GO111MODULE=off` which means that introducing >>>>> modules >>>>> >> > is a breaking change. Can I depend on GO111MODULE=off to work the >>>>> >> > same way forever? >>>>> >> > >>>>> >> > > > # Nor does this work, even with module replacements >>>>> >> > > > $ go list -f '{{.GoFiles}}' ./staging/src/ >>>>> example.com/other1/used >>>>> >> > > > ./staging/src/example.com/other1/unused >>>>> >> > > > main module (example.com/m) does not contain package >>>>> >> > > > example.com/m/staging/src/example.com/other1/used >>>>> >> > > > main module (example.com/m) does not contain package >>>>> >> > > > example.com/m/staging/src/example.com/other1/unused >>>>> >> > > > ``` >>>>> >> > > >>>>> >> > > With replace directives in place this should work, but you >>>>> won't be >>>>> >> > > able to use the relative path to the modules (which is in fact >>>>> >> > > interpreted as a directory): it will need to be the full >>>>> >> > > module/package path. >>>>> >> > >>>>> >> > Given a "./path/to/pkg" - how do I convert that to a >>>>> module/package >>>>> >> > path? I can run `(cd $dir && go list -m)` but that is super slow. >>>>> >> > Running JUST that for each directory that needs codegen in >>>>> kubernetes >>>>> >> > takes 20+ seconds. Is there a better way, short of writing my own >>>>> >> > directory-climb and parsing go.mod? >>>>> >> > >>>>> >> > > > I can run `go list` multiple times, but that's INCREDIBLY >>>>> slow - most >>>>> >> > > > of these submodules have common deps that are large. This >>>>> re-parses >>>>> >> > > > everything over and over. It takes almost 60 seconds just to >>>>> do `cd >>>>> >> > > > $dir; go list` (on the real kubernetes repo). >>>>> >> > > >>>>> >> > > Do you have a repro of this taking 60 seconds? Because that >>>>> really >>>>> >> > > shouldn't be the case with a populated local module cache. >>>>> >> > >>>>> >> > github.com/kubernetes/kubernetes >>>>> >> > >>>>> >> > ``` >>>>> >> > $ time \ >>>>> >> > find . -type f -name \*.go \ >>>>> >> > | xargs grep -l "^// *+k8s:" \ >>>>> >> > | xargs -n 1 dirname \ >>>>> >> > | sort \ >>>>> >> > | uniq \ >>>>> >> > | while read X; do \ >>>>> >> > (cd $X; go list -f '{{.Deps}}'); \ >>>>> >> > done \ >>>>> >> > > /dev/null >>>>> >> > >>>>> >> > real 0m50.488s >>>>> >> > user 0m46.686s >>>>> >> > sys 0m18.416s >>>>> >> > ``` >>>>> >> > >>>>> >> > Just running that inner `go list` with GO111MODULE=off cuts the >>>>> run >>>>> >> > time in half. >>>>> >> > >>>>> >> > Compare to: >>>>> >> > >>>>> >> > ``` >>>>> >> > time \ >>>>> >> > ( \ >>>>> >> > export GO111MODULE=off; \ >>>>> >> > find . -type f -name \*.go \ >>>>> >> > | xargs grep -l "^// *+k8s:" \ >>>>> >> > | xargs -n 1 dirname \ >>>>> >> > | sort \ >>>>> >> > | uniq \ >>>>> >> > | xargs go list -e -f '{{.Deps}}' \ >>>>> >> > ) \ >>>>> >> > > /dev/null >>>>> >> > >>>>> >> > real 0m1.323s >>>>> >> > user 0m1.174s >>>>> >> > sys 0m0.567s >>>>> >> > ``` >>>>> >> > >>>>> >> > The model repo doesn't show so significantly because it is small. >>>>> >> > Kubernetes is not small. >>>>> >> > >>>>> >> > I'm happy to hear better approaches - I really don't like relying >>>>> on >>>>> >> > GO111MODULE=off forever - it seems like the sort of thing that >>>>> will >>>>> >> > eventually get removed. >>>>> >> >>>>> >> -- >>>>> >> You received this message because you are subscribed to the Google >>>>> Groups "golang-nuts" group. >>>>> >> To unsubscribe from this group and stop receiving emails from it, >>>>> send an email to golang-nuts+unsubscr...@googlegroups.com. >>>>> >> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/golang-nuts/CAO_Rewa6rMW79iBHj2Jz6HfJ-tCFLFhNAhYiwDh%3DNy6M35Y91Q%40mail.gmail.com >>>>> . >>>>> >>>> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAO_RewZV%3DwqfjxbfTwR6VuOaHpqHx8QsAi%2Bur%3DAvHm7vjDFpUw%40mail.gmail.com.