Conversation
I'm doing this in stages so that we can identify when I'm off in the weeds or need to make more decisions about the config file format.
- Vendor https://github.com/pelletier/go-toml.
- Write manifest and lock in TOML format.
- Read manifest and lock in TOML format (all tests but diff should pass)
- Remove old JSON files and logic.
- Fix output of dry-run to use TOML (diff test and all others should pass)
- (Optional) Bike-shed the look of the generated TOML, e.g. inline tables, indenting, key sorting, etc.
@carolynvs hmm...that puts me on the fence about it, as I'd generally rather have the (presumably cross-TOML implementation portable) struct tags as the canonical way of expressing this information, to minimize effort in the event that we switch TOML libs later. idk how much work that's really saving, though, so it seems like a soft requirement at worst.
Maybe some input from @pelletier here would be good - any plans to add reflection-based struct tag support to go-toml? Would you accept such a change, if offered?
Eh, that was too wishy-washy, sorry. If we can have struct tags and reflection-based parsing, great. If not, well, it seems like the one-off implementation here isn't too awful. Either way, not a reason to derail the current track.
Is there are reason you're keeping the JSON struct tags around?
@sdboyer yes, reflection-based (un)marshaling is the next thing that I'd like to implement in go-toml. no eta on that though, but pull requests are welcome :)
@pelletier - I have some time coming up the next few weeks. Mind if I take a crack at the reflection-based marshaling? If so, I'll open an issue at go-toml and get you a WIP PR in the short term to make sure you approve of the structure before I dive in too deep. Thoughts?
@sdboyer No reason, just hadn't gotten around to removing all the json stuff yet. 😃 I've added a task to the PR to make that more clear.
-
Changed manifest format.
dependenciesandoverridesuse an array of tables instead of maps now, which is easier to work with.ignores = ["github.com/foo/bar"] [[dependencies]] name = "github.com/sdboyer/gps" version = ">=0.12.0, <1.0.0" [[dependencies]] name = "github.com/babble/brook" revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" [[overrides]] branch = "master" name = "github.com/sdboyer/gps" source = "https://github.com/sdboyer/gps"
-
Update all the test files from JSON to TOML
-
Poor man's mapping from TOML to structs. Can't wait for Reflection-based marshaling / unmarshaling pelletier/go-toml#149! ❤️
Next up I'm fixing the lock diff format and looking sorting bug (tests pass then fail due to sorting).
@omeid Let's not make changes to the config file structure in this PR, beyond the initial scope of switching from JSON to TOML. 😀 It's already a pretty big change, and I want to limit the amount of regressions/confusion it may cause.
For generated TOML, I think it would be nice to use inline tables to get each dependency onto a single line.
I'm think that may work better for diffs/merges, though I'm not totally sure. Also it's nice for rearranging the dependencies by movings lines up/down in an editor (for super organized types).
I can imagine counter arguments though, as lines could get pretty long when there are a number of options specified.
@nathany I think that depends on how we feel about long lines in the file. Personally, I find it hard to read.
For example, here's what I think the lock would look like with inline tables. Note, I am cheating a bit by using "." for the package list, to make the shortest possible entry.
memo = ""
projects = [
{ name = "github.com/sdboyer/deptest", packages = ["."], revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", version = "v0.8.0" }
{ name = "github.com/sdboyer/deptestdos", packages = ["."], revision = "a0196baa11ea047dd65037287451d36b861b00ea", version = "1.0.0" }
]
Though I'm not 100% sure that's how an array of inline tables should look? Either way support for changing the formatter in go-toml would be needed, not sure about the parser.
Okay. Those are some pretty long lines.
It's probably best to just use it for a while to see how well diffs/merges work with the multi-line syntax. Thanks
I've updated the lock diff to output matching TOML. I've also tried out @tro3 's reflection based mapping, it's super close and I think it's worth waiting for it, removes a TON of code. 😃
We need to roll the file name change into this, too, so that we minimize the amount of change that goes in at once. We're still pondering those, but...
Cursory look has me thinking this is pretty good. I'll look more soon, I hope later tonight :)
carolynvs
changed the title
[WIP] Move to TOML for manifest and lock
Move to TOML for manifest and lock
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly nits, a couple slightly bigger things.
Sorry for the slow action on this!
|
|
||
| h.TempDir("dep") | ||
| golden := "analyzer/manifest.json" | ||
| golden := "analyzer/manifest.toml" |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize you didn't introduce this, but now that I'm seeing it, I believe it should be filepath.Join("analyzer", ManifestName).
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, being a PC guy, I've found Go does a startingly good job of using '/' in a platform-independent manner in path strings. But filepath.Join is still likely more robust.
| memo = "63510efb9632ec69c1164ce396d7ebea4ad3884b4fa508373da17226d5a39739" | ||
|
|
||
| [[projects]] | ||
| name = "github.com/sdboyer/deptest" |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm...yeah, I hate to bikeshed, but these indents are kinda making me twitch. What's your thinking behind indenting vs. not? Are there any typical standards out there for it? Do we know anything about, say, widespread editor defaults for indentation in TOML files?
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The go-toml package will indent on -update. (It will read fine with or without indent.) Don't know if there is a setting to stop it - never looked.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, preferably go-toml would let us specify formatting options. I'll double-check that doesn't exist already and see if it's an easy thing to add.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, it's not exposed but seems like it wouldn't be hard to add a flag to control the auto-indentation that it's currently doing. I'll submit a PR to go-toml for that.
| @@ -0,0 +1,12 @@ | |||
| memo = "" | |||
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any idea how this one ended up without a memo? Mostly just curious.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Marshaler is the interface implemented by types that | ||
| // can marshal themselves into valid TOML. | ||
| // TODO(carolynvs) Consider adding this to go-toml? | ||
| type Marshaler interface { |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably better not to export this as an interface, unless we have to. As your TODO notes, if it's going to be exported, that should be done by go-toml. If we can get away with exporting, marshaler, or better tomlMarshaler would be preferable.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for noticing this! I had intended to put it in go-toml but that slipped my mind... 😊
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up needing this to use reflection for the LockDiff. Here's the go-toml PR: pelletier/go-toml#151
| for n, pp := range rm.Dependencies { | ||
| m.Dependencies[gps.ProjectRoot(n)], err = toProps(n, pp) | ||
| for i := 0; i < len(raw.Dependencies); i++ { | ||
| name, prj, err := toProject(raw.Dependencies[i]) |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cost of moving to an array from a map is that it's now possible for users to express the same project more than once. This loop has to validate that each entry in the input is unique, and fail hard otherwise.
|
|
||
| for n, pp := range m.Ovr { | ||
| raw.Overrides[string(n)] = toPossible(pp) | ||
| // TODO(carolynvs) when gps is moved, we can use the unexported gps.sortedConstraints |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'll still be unexported within the gps package, so probably not 😄
| // ReadManifest returns the manifest in the current directory. | ||
| func (h *Helper) ReadManifest() string { | ||
| m := filepath.Join(h.pwd(), "manifest.json") | ||
| m := filepath.Join(h.pwd(), "manifest.toml") |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the constant
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe I can use the constant here (in the test pkg) because that would create a circular dependency?
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhh, totally, yes. my bad :)
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's create a local constant in this test package too, and use that. it's not as good as one constant, but it's still better than string literals all over.
| // ReadLock returns the lock in the current directory. | ||
| func (h *Helper) ReadLock() string { | ||
| l := filepath.Join(h.pwd(), "lock.json") | ||
| l := filepath.Join(h.pwd(), "lock.toml") |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the constant
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hot diggity damn these look so much better 😄
| Branch *StringDiff `json:"branch,omitempty"` | ||
| Revision *StringDiff `json:"revision,omitempty"` | ||
| Packages []StringDiff `json:"packages,omitempty"` | ||
| Name gps.ProjectRoot |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these don't need toml struct tags?
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry an emergency came up and I stopped mid review. I'll start back on this today. The current toml mapper doesn't yet support allowing a nested type to use a custom marshal function, so it was manual. I started adding that this weekend and hopefully can submit that to go-toml soon and use it.
github.com/pelletier/go-toml@fee7787d3f811af92276f5ff10107092e95b7a1d - Can't use latest release, it has a show-stopping bug in ToTomlString github.com/pelletier/go-buffruneio@v0.2.0
Using the project root as a key in TOML makes our life harder. This siplifies the manifest format and parsing.
@sdboyer @tro3 Right now go-toml doesn't preserve the ordering of the fields when marshaling, instead simply outputting them in alphabetical order:
[[projects]] branch = "master" name = "github.com/pelletier/go-buffruneio" packages = ["."] revision = "c37440a7cf42ac63b919c752ca73a85067e05992"
instead of this (which matches the ordering of the fields as defined on the struct which is what encoding/json does)
[[projects]] name = "github.com/pelletier/go-buffruneio" branch = "master" revision = "c37440a7cf42ac63b919c752ca73a85067e05992" packages = ["."]
Is this something that I need to address as part of this PR, in the name of not changing the file structure again later? It may be a big change to how the TomlTree is represented internally and could be a lot of work, so I wanted to get your thoughts (or maybe @tro3 you see a clean way of supporting that)?
- Rebased, resolving the merge conflicts from updating
gps - Added constants for the file names to the lock package
- Updated LockDiff formatting to the toml struct tags
Looking into making the auto-indentation configurable next.
Is it really needed? Don't know if he key order is important. In any case, I think it's an easy tweak to go-toml, as I recall an explicit sorting of the keys. If correct, this would just have to be bypassed with a configure option of some sort. I'm on vacation though, so if it needs to be me, it will have to wait a while.
I spoke with @sdboyer and we will leave off trying to make the toml file format "pretty", so I am not going to try to tackle the indenting or sorting in this PR. I believe I've hit all the rest of the review feedback so it's ready for another look.
Is it possible, or was it already decided not, to read the old format and update the relevant files?
As the migration path, as I understand it, would be to remove the old files and generate new lock files - which would lock to different revisions?
Detecting existing files, reading them and rewriting to new files and new format would obviously be ideal from an early user's perspective. Perhaps a flag, or a separate application (depfix)?
I don't see this as a major requirement at all, just asking.
Sorry for delay on merge, here. I was trying to get things together with a blog for dep (re: #294), and I put this in the queue behind doing that. Looks like I should have that blog done tonight, and I plan to merge this once it's all set up 😄
smira
mentioned this pull request
smira
mentioned this pull request
ibrasho pushed a commit to ibrasho-forks/dep that referenced this pull request