github.com/please-build/puku@v1.7.3-0.20240516143641-f7d7f4941f57/README.md (about) 1 # Puku 2 3 Puku is a tool for maintaining your go rules, similar to gazelle. It's named after puku, which is an antelope native to 4 Southern Africa. This tool is still under development but is rapidly approaching a generally available release! 5 6 ## Quick start 7 8 The easiest way to get started is to install puku with go: 9 ```bash 10 $ go install github.com/please-build/puku/cmd/puku 11 ``` 12 13 Then make sure `$GOPATH/bin` is in `$PATH`. This can be done by adding `export PATH=$PATH:$GOROOT/bin:$GOPATH/bin` to 14 your `~/.bashrc`, or similar. 15 16 ### Running puku with Please 17 18 Add a remote file to your repo under `third_party/binary/BUILD` 19 ```python 20 version = "9.9.9" 21 remote_file( 22 name = "puku", 23 url = f"https://github.com/please-build/puku/releases/download/v{version}/puku-{version}-{CONFIG.OS}_{CONFIG.ARCH}", 24 binary = True, 25 ) 26 ``` 27 28 Then add an alias to your `.plzconfig`, or for personal usage, your `.plzconfig.local`: 29 ``` 30 [Alias "puku"] 31 Cmd = run //third_party/binary:puku -- 32 PositionalLabels = true 33 Desc = A tool to update BUILD files in Go packages 34 ``` 35 36 Then you can use `plz puku` in place of `puku`. 37 38 ## Usage 39 40 Running `puku fmt` with no args will format all your source files. It has sensible defaults, reading your 41 `.plzconfig` file to avoid unnecessary configuration, however it can be configured via `puku.json` files throughout the 42 repository. It supports both `go_module()` and `go_repo()` options for third party code, however it can also generate 43 new `go_repo()` targets to satisfy new dependencies. 44 45 Puku can also format files under specific paths using a similar wildcard syntax to Please: 46 47 ``` 48 $ puku fmt //src/... 49 ``` 50 51 Puku supports `go_library`, `go_test`, `go_binary`, `go_benchmark`, `proto_library`, and `grpc_library` out of the box, but can be 52 configured to support other rules. See the configuration section below for more information. 53 54 ### Updating and adding third party dependencies with go.mod (optional) 55 56 Puku will attempt to resolve new imports and add `go_repo` rules to satisfy them. This works most of the time, however 57 setting `ModFile = //:gomod` in your Go plugin, is far more robust and highly recommended. Without this, you may just 58 have to pass in modules via `requirements = ["github.com/example/module"]`, to help resolve imports to the correct module path. 59 60 This approach facilitates using standard go tooling i.e. `go get` to resolve dependencies. Puku will then sync new 61 dependencies from your `go.mod` to `third_party/go/BUILD` automatically as necessary, or on demand via `puku sync` 62 63 To do this, add a filegroup in your repo root: 64 65 ```python 66 filegroup( 67 name = "gomod", 68 srcs = ["go.mod"], 69 visibility = ["PUBLIC"], 70 ) 71 ``` 72 73 And configure the Go plugin like so: 74 ``` 75 [Plugin "go"] 76 Target = //plugins:go 77 ModFile = //:gomod 78 ... 79 ``` 80 81 Then when adding a new module, run `go get github.com/foo/bar` and puku will sync this across when you next run 82 `puku fmt` or `puku sync`. Updating modules can be done similarly via `go get -u`, and `puku sync`. Puku currently 83 does **not** clear out old dependencies no longer found in the `go.mod`. 84 85 ### Migration 86 87 Use `puku migrate` to migrate your third party rules from `go_module()` to `go_repo`. This subcommand will create 88 build rules that mimic the behaviour of `go_module()` so this should be a drop in replacement. This command optionally 89 takes modules as positional arguments, allowing a piecemeal migration e.g. `puku migrate github.com/example/module`. 90 91 ### Watch mode 92 93 To run puku in watch mode, use `puku watch`. Puku will then watch all directories matched by the wildcards passed, 94 and automatically update rules as `.go` sources change. 95 96 ### Lint mode 97 98 By running `puku lint`, puku will run in a lint-only mode. It will exit without output if everything linted fine, 99 otherwise, it will print the desired state to stdout. This can be useful to integrate with tools like arcanist that can 100 prompt users with a preview before applying auto-fixes. 101 102 ## Supporting custom build definitions 103 104 Puku treats targets as one of three types: `library`, `binary`, or `test` targets. Sources are allocated to these 105 targets based on their type. Targets that are `library` types are additionally used to satisfy imports from other 106 targets. 107 108 For example, if you have the following `BUILD` file: 109 110 ``` 111 my_go_library( 112 name = "foo", 113 srcs = ["foo.go"], 114 ) 115 116 go_test( 117 name = "foo_test", 118 srcs = ["foo_test.go"], 119 deps = [":foo"], 120 ) 121 ``` 122 123 Puku can be configured to treat custom types as one of these three kinds by adding some configuration to `puku.json` 124 files. These can be checked in throughout the repo, and the kinds will apply to all subdirectories. For example, the 125 following will make puku treat `my_go_library()` the same way it treats `go_library()`. 126 127 ``` 128 libKinds": { 129 "my_go_library": { 130 "providedDeps": ["//common/go:some_common_lib"] 131 }, 132 } 133 ``` 134 135 Provided deps are assumed to be added to the list of deps provided to the build rule. Puku will avoid adding these when 136 it sees an import that's satisfied by them. 137 138 ### Non-go sources 139 Puku will try and determine the dependencies of a target by parsing their sources. Sometimes a target produces a go 140 package without taking in go sources directly, for example `proto_library()`. If we want to introduce a new protoc 141 plugin, say `grcp_gateway()`, we can teach puku about this like so: 142 143 ``` 144 libKinds": { 145 "grcp_gateway": { 146 "nonGoSources": true 147 }, 148 } 149 ``` 150 151 When puku sees a target like this: 152 ``` 153 grpc_gateway( 154 name = "foo", 155 srcs = ["foo.proto"], 156 ) 157 ``` 158 159 Puku will avoid trying to parse `foo.proto` as a go source, and will not attempt to remove dependencies from the target, 160 but it will still resolve imports for that path to that target. 161 162 ## Configuration 163 164 Puku can be configured via `puku.json` files that are loaded as puku walks the directory structure. Configuration values 165 are overridden as new files are discovered at a deeper level in the source tree. 166 167 ```yaml 168 { 169 // The directory to load and write third party rules to. If using `go_repo`, puku will update this package to satisfy 170 // new imports 171 "thirdPartyDir": "third_party/go", 172 // The path to the please binary 173 "pleasePath": "plz", 174 // A mapping between import paths and targets for any special cases that puku doesn't currently support 175 "knownTargets": { 176 "github.com/some/module": "//third_party/go:module" 177 }, 178 // Any kinds that can satisfy an import. These will be treated much the same way puku treats go_library. Right now 179 // puku assumes that the rules will use name, srcs, deps, and visibility arguments in the same way go_library does. 180 // Puku will attempt to allocate production (i.e. non-test) sources to these targets. 181 "libKinds": { 182 "my_go_library": { 183 // Any deps that the build definition will add to the target. Puku will avoid adding these dependencies via 184 // deps. 185 "providedDeps": ["//common/go:some_common_lib"], 186 // The visibility of the target if no visibility arg is passed 187 "defaultVisibility": ["PUBLIC"] 188 }, 189 "my_proto_library": { 190 // Setting this to true indicates to puku that these targets don't operate on Go sources, so it shouldn't try 191 // to parse the sources to figure out the dependencies. These targets must still satisfy an import for the 192 // package directory they're in. 193 "nonGoSources": true 194 } 195 }, 196 // These are any kinds that behave like tests. Similar to lib kinds, puku assumes they have arguments that are similar 197 // to go_test. Puku will try and assign test sources to targets of this kind. 198 "testKinds": { 199 "testify_test": { 200 // Any deps that the build definition will add to the target. Puku will avoid adding these dependencies via 201 // deps. 202 "providedDeps": ["//third_party/go:testify"], 203 }, 204 } 205 // Again, these are similar to lib and test kinds except they are treated as binary targets. Puku assumes a similar 206 // set of arguments to go_binary and will allocate binary sources to these targets. 207 "binKinds": { 208 "testify_test": { 209 // Any deps that the build definition will add to the target. Puku will avoid adding these dependencies via 210 // deps. 211 "providedDeps": ["//third_party/go:testify"], 212 }, 213 } 214 215 // Setting this to true will stop puku from touching this directory and all directories under it. By default, puku 216 // will skip over plz-out and .git, however this can be useful to extend that to other directories. 217 "stop": false, 218 219 // Puku will try and add a subinclude for the Go rules if it's not already subincluded. Setting this to false will 220 // disable this behavior. 221 "ensureSubincludes": false, 222 223 // If you have changed the behavior of the default kinds, you may exclude them here so Puku stops treating them as a 224 // known kind. This can be useful for cases where you have changed proto_library to output .go files, rather than to 225 // generate the go_library for that package. 226 "excludeBuiltinKinds": ["proto_library"], 227 } 228 ``` 229 230 ## Overview of the algorithm 231 232 Puku will attempt to allocate any .go files in a directory to rules based on their type. There are 3 types: 233 library, test, and binary. These sources are allocated to rules based on the rules kind type, as configured in the 234 `puku.json` files. 235 236 Once puku has determined the kind type for each source, it will parse the BUILD file to discover the existing build 237 rules. It will parse the `srcs` arguments of each rule, evaluating `glob()`s as necessary in order to determine any 238 unallocated sources. 239 240 Sources are then allocated to existing rules where possible based on their kind type. If no rule can be found, then a 241 new rule will be created. The kind type that puku chooses for new rules are the built-in base types i.e. `go_library`, 242 `go_test`, and `go_binary`. 243 244 Once all sources have been allocated, the imports for each source file are collected and resolved. Puku will resolve 245 imports in the following order: 246 247 1) Known imports as defined in the configuration file 248 2) Installed packages from `go_module` or `go_repo` 249 3) If using `go_repo`, by the module package naming convention (run `plz help go_repo` for more information) 250 4) If using `go_repo`, by checking the go module proxy, or by reading the `go.mod` file 251 252 When using `go_repo`, puku will attempt to automatically add new modules to the build graph, updating the existing 253 modules as necessary. 254 255 ## Contributing 256 257 Contributions are more than welcome. Please make sure to raise an issue first, so we can avoid wasted effort. This 258 project and it's contributions are licensed under the Apache-2 licence.