Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,47 @@ and this project adheres to
file, and artifacts are linked concurrently.
- A `--meta` file's name, version, and description now feed the built wheel (flags take precedence over the meta file,
which takes precedence over `pyproject.toml`).
- Answering `n` when `state publish` asks to confirm now offers to edit the ingredient meta data in your editor or save
it to a meta file to edit and publish later with `--meta`, instead of only cancelling.
- When `state publish --build` cannot determine the ingredient name or version, the error now says which is missing,
why `pyproject.toml` did not provide it (for example, a version listed in `[project].dynamic`), and how to set it.
- Without `--namespace`, `state publish --build` now defaults to `private/<org>/python` when the source has a
`pyproject.toml` (otherwise `private/<org>`, as before).
- The namespace of a new ingredient can now be changed in the `state publish` editor. The new namespace is checked like
one passed with `--namespace`; if it can't be used, the previous one is kept and the reason is shown. The confirmation
and the editor now say up front which fields can't be changed and why, and when one of them is edited anyway (the
name or version with `--build`, or the namespace, name or version with `--edit`), the error names it.
- The ingredient meta data `state publish` shows for confirmation and opens in the editor no longer has a help comment
on each field. The fields are described in the publish guide instead.

### Fixed

- `state publish --edit` no longer overwrites the meta file's dependencies and authors with the previous revision's,
keeps inherited dependency types and conditions, and rejects author or description changes on an existing version
up front.
keeps inherited dependency types and conditions, and rejects author changes on an existing version up front.
- `state publish --edit --meta` with an exported meta file now edits the version named in the file rather than the
latest version.
- `state export ingredient-meta` now writes plain YAML without help comments or line wrapping, so its output can be
passed back with `--meta` as is.
- `state export ingredient-meta` now includes the ingredient's description instead of leaving it empty. When
`state publish --edit` is given a different description for an existing version, it no longer refuses to publish:
the confirmation says the description can't be changed, shows the current one, and the change is ignored.
- `state publish` of a new ingredient without a namespace (such as with `--editor` outside a project) no longer searches
every namespace for its name, which could time out with "Could not search for ingredient" before the editor opened.
- `state publish --editor` no longer fails with "Could not publish ingredient. Error received: <no value>" when no editor
can be opened (no `EDITOR` set and no `xdg-open`, as on many headless machines). It says so and waits for the file to
be edited by hand instead.
- Dependencies and conditions without a version range (such as a bare `requests` in `pyproject.toml`) are now published
as accepting any version instead of failing with "Expecting an OBJECT with a field named 'versionRequirements'".
- Fields removed in the `state publish --editor` file are now removed from the publish instead of keeping their
previous values, and publish API errors are shown instead of `<no value>`.

### Security

- Updated `github.com/klauspost/compress` to v1.18.7 to remediate CVE-2026-63209 (GHSA-259r-337f-4rfw).
- Updated to Go 1.26.10 and `golang.org/x/net` v0.60.0 to remediate 14 CVEs in the Go standard library and HTTP/2 handling.
- Updated `golang.org/x/net` to v0.62.0 to remediate CVE-2026-78661 and CVE-2026-97045.
- Updated `github.com/labstack/echo/v4` to v4.16.1 to remediate GHSA-cxf3-9h37-7rr8, GHSA-9969-6676-49h5,
GHSA-f48p-c9v4-h7xv and GHSA-h7wr-284f-5qvc.

## 0.48.1

Expand Down
18 changes: 8 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ require (
github.com/jarcoal/httpmock v1.0.3
github.com/jessevdk/go-flags v1.4.0
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d
github.com/labstack/echo/v4 v4.15.4
github.com/labstack/echo/v4 v4.16.1
github.com/mash/go-tempfile-suffix v0.0.0-20150731093933-48f0f8a3a5ab
github.com/mattn/go-runewidth v0.0.15
github.com/nicksnyder/go-i18n v1.10.0
Expand All @@ -51,11 +51,11 @@ require (
github.com/thoas/go-funk v0.8.0
github.com/vbauerster/mpb/v7 v7.1.5
github.com/vektah/gqlparser/v2 v2.5.16
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/net v0.60.0
golang.org/x/sys v0.48.0
golang.org/x/term v0.46.0
golang.org/x/text v0.42.0
golang.org/x/crypto v0.58.0 // indirect
golang.org/x/net v0.62.0
golang.org/x/sys v0.49.0
golang.org/x/term v0.47.0
golang.org/x/text v0.43.0
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -76,7 +76,6 @@ require (
github.com/gowebpki/jcs v1.0.1
github.com/mark3labs/mcp-go v0.33.0
github.com/mholt/archives v0.1.5
github.com/zijiren233/yaml-comment v0.2.1
)

require (
Expand Down Expand Up @@ -118,7 +117,6 @@ require (
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kr/pty v1.1.8 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/maruel/natural v1.1.0 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.1 // indirect
Expand All @@ -136,7 +134,7 @@ require (
github.com/spf13/afero v1.15.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/sync v0.23.0 // indirect
golang.org/x/sync v0.24.0 // indirect
)

require (
Expand Down Expand Up @@ -191,7 +189,7 @@ require (
go.mongodb.org/mongo-driver v1.17.7 // indirect
golang.org/x/mod v0.41.0
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.49.0 // indirect
golang.org/x/tools v0.51.0 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
Expand Down
36 changes: 16 additions & 20 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.15.4 h1:DL45vVYa+BWE+XuW+zZNd9H0YEdZ80UAWJGcTVW4EVs=
github.com/labstack/echo/v4 v4.15.4/go.mod h1:CuMetKIRwsuO/qlAgMq+KTAalwGoB/h4tC+yPdrTj1g=
github.com/labstack/echo/v4 v4.16.1 h1:h05NuF1GvNu6jSAZxOv++AdjD/NJK+mZdGy0thiiuns=
github.com/labstack/echo/v4 v4.16.1/go.mod h1:V/EQaTVHYJH92QhbQe7kFQ4mjgcjxLQQUQtAN87zZdw=
github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c=
github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
Expand All @@ -520,8 +520,6 @@ github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvT
github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ=
github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ=
github.com/mash/go-tempfile-suffix v0.0.0-20150731093933-48f0f8a3a5ab h1:2lWb5W+cZTlTIrJUuzVMrs6vcEvY0ydkkMH66EdPaqc=
github.com/mash/go-tempfile-suffix v0.0.0-20150731093933-48f0f8a3a5ab/go.mod h1:oBJAJTenVXse2frk3J4anZ7funxla2ZdJHFQShkD43k=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
Expand Down Expand Up @@ -745,8 +743,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zijiren233/yaml-comment v0.2.1 h1:/ymMfauuR6zPme+c59FvGNmvxmjOS+BRZSU9YEM82g4=
github.com/zijiren233/yaml-comment v0.2.1/go.mod h1:Cps/tIAJVNoG6TpNN1Aaht/O1QGthZzOgUMQXXTxlBs=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
Expand Down Expand Up @@ -784,8 +780,8 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54=
golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -850,8 +846,8 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU=
golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
golang.org/x/net v0.62.0 h1:18ELalfM5+XNRwzM2nYqXsZQ9ByS1uhj2O/U7+5jqRY=
golang.org/x/net v0.62.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand All @@ -866,8 +862,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA=
golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -914,13 +910,13 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA=
golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
golang.org/x/term v0.47.0 h1:cpyOwQkr2Nzxe2p6KnrTG7Ei2wtzjsuSjhpXXepZ/BM=
golang.org/x/term v0.47.0/go.mod h1:efAfAuG6RKABvg1ArGebRkvX6LXul14SM67o2e4mUCY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -931,8 +927,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc=
golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
Expand Down Expand Up @@ -974,8 +970,8 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
golang.org/x/tools v0.51.0 h1:k4Xc/1Om9jwkBJBo4NVLMSARBoWtK10mx+W5BnXCeAI=
golang.org/x/tools v0.51.0/go.mod h1:9eEncMayCV6zRMGhR5eZEC2iBx98qWcF1HZ9Z7wJOoA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
7 changes: 6 additions & 1 deletion internal/hail/hail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ func TestOpen(t *testing.T) {

file = tempFile.Name()
rcvs, err := Open(ctx, file)
require.NoError(t, err)
defer func() {
// Stop the watcher and wait for it to finish before removing the file: it reads the file on every event, and
// on Windows a file that is still open can't be removed.
cancel()
for range rcvs {
}
_ = tempFile.Close()
assert.NoError(t, os.Remove(file))
}()
require.NoError(t, err)

postOpen := time.Now()
data := []byte("some data")
Expand Down
65 changes: 53 additions & 12 deletions internal/python/wheel/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,40 @@ import (
"os"
"path/filepath"
"regexp"
"slices"
"strings"

"github.com/ActiveState/cli/internal/errs"
"github.com/BurntSushi/toml"
)

// MissingMetadataError reports which of name and version neither the caller nor
// pyproject.toml supplied, and what pyproject.toml said about them, so the user
// can be told how to provide them.
type MissingMetadataError struct {
Fields []string
// Pyproject is the pyproject.toml that was read, or empty when there is none.
Pyproject string
// Dynamic holds the missing fields pyproject.toml lists in [project].dynamic,
// which a build backend computes and so cannot be read from the file.
Dynamic []string
}

func (e *MissingMetadataError) Error() string {
return "package " + strings.Join(e.Fields, " and ") + " could not be determined"
}

func (e *MissingMetadataError) Is(target error) bool {
return target == ErrMissingMetadata
}

// ResolveMetadata reads srcDir's pyproject.toml [project] table and applies the
// non-empty fields of override on top, producing the metadata to pack with. It
// errors when neither source supplies a name or version. Requires always comes
// from pyproject.toml's dependencies.
// returns a *MissingMetadataError when neither source supplies a name or
// version. Requires always comes from pyproject.toml's dependencies.
func ResolveMetadata(srcDir string, override Metadata) (*Metadata, error) {
proj, err := readPyProject(filepath.Join(srcDir, "pyproject.toml"))
path := filepath.Join(srcDir, "pyproject.toml")
proj, found, err := readPyProject(path)
if err != nil {
return nil, err
}
Expand All @@ -26,8 +48,23 @@ func ResolveMetadata(srcDir string, override Metadata) (*Metadata, error) {
Summary: firstNonEmpty(override.Summary, proj.Description),
Requires: proj.Dependencies,
}
if meta.Name == "" || meta.Version == "" {
return nil, ErrMissingMetadata
missing := &MissingMetadataError{}
if found {
missing.Pyproject = path
}
for field, value := range map[string]string{"name": meta.Name, "version": meta.Version} {
if value != "" {
continue
}
missing.Fields = append(missing.Fields, field)
if slices.Contains(proj.Dynamic, field) {
missing.Dynamic = append(missing.Dynamic, field)
}
}
if len(missing.Fields) > 0 {
slices.Sort(missing.Fields) // "name" before "version", regardless of map order
slices.Sort(missing.Dynamic)
return nil, missing
}
return &meta, nil
}
Expand All @@ -37,17 +74,19 @@ type pyProject struct {
Version string
Description string
Dependencies []string
Dynamic []string
}

// readPyProject reads the [project] table from a pyproject.toml. A missing file
// is not an error; caller-supplied metadata may stand in for it.
func readPyProject(path string) (pyProject, error) {
// readPyProject reads the [project] table from a pyproject.toml and reports
// whether the file exists. A missing file is not an error; caller-supplied
// metadata may stand in for it.
func readPyProject(path string) (pyProject, bool, error) {
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return pyProject{}, nil
return pyProject{}, false, nil
}
return pyProject{}, errs.Wrap(err, "could not read pyproject.toml")
return pyProject{}, false, errs.Wrap(err, "could not read %s", path)
}

var parsed struct {
Expand All @@ -56,17 +95,19 @@ func readPyProject(path string) (pyProject, error) {
Version string `toml:"version"`
Description string `toml:"description"`
Dependencies []string `toml:"dependencies"`
Dynamic []string `toml:"dynamic"`
} `toml:"project"`
}
if err := toml.Unmarshal(data, &parsed); err != nil {
return pyProject{}, errs.Wrap(err, "could not parse pyproject.toml")
return pyProject{}, true, errs.Wrap(err, "could not parse %s", path)
}
return pyProject{
Name: parsed.Project.Name,
Version: parsed.Project.Version,
Description: parsed.Project.Description,
Dependencies: parsed.Project.Dependencies,
}, nil
Dynamic: parsed.Project.Dynamic,
}, true, nil
}

func firstNonEmpty(values ...string) string {
Expand Down
Loading
Loading