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

AliasMangler #95

Merged
merged 3 commits into from
Aug 30, 2024
Merged

AliasMangler #95

merged 3 commits into from
Aug 30, 2024

Conversation

sergiosalvatore
Copy link
Contributor

@sergiosalvatore sergiosalvatore commented Aug 22, 2024

AliasMangler

Add a new mangler that allows us to have aliases for dials tags to
facilitate migrating from one name to another seamlessly. If both the
old name and the new name are set, an error will be returned because the
expectation is that you're using one or the other exclusively.

Also, fix a bug in ez where an error thrown by a Source may cause the
process to hang.

And, lastly, specifically exclude TextUnmarshaler implementing types
from mangling.

@sergiosalvatore sergiosalvatore changed the title wip AliasMangler Aug 23, 2024
@sergiosalvatore sergiosalvatore marked this pull request as ready for review August 23, 2024 20:14
Copy link
Contributor

@dfinkel dfinkel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few comments

ez/ez_test.go Outdated
Comment on lines 66 to 68
envErr := os.Setenv("ALTCONFIGPATH", "../testhelper/testconfig.yaml")
require.NoError(t, envErr)
defer os.Unsetenv("ALTCONFIGPATH")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use t.SetEnv here. (available since go 1.17)

README.md Outdated
Comment on lines 287 to 289
and `dialspflag` as well by appending "alias" to the flag name. The `ez`
package also wraps the appropriate file source so config files can also make use
of aliases.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
and `dialspflag` as well by appending "alias" to the flag name. The `ez`
package also wraps the appropriate file source so config files can also make use
of aliases.
and `dialspflag` as well by appending "alias" to the flag name. The `ez`
package also wraps the appropriate file source's decoder so config files can also make use
of aliases.

Comment on lines +280 to +283
Dials supports aliases for fields where you want to change the name and support
an orderly transition from an old name to a new name. Just as there is a
`dials` struct tag there is also a `dialsalias` struct tag that you can use as
an alternate name. Any other casing or transformation rules on the original
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should mention that this functionality is provided by a mangler upfront, so anyone who doesn't use the ez package isn't confused when it doesn't work out of the box.
(I think there's a section in the README that you can link to that describes manglers -- we should add on if there isn't)

Comment on lines +192 to +201
// If file-watching is not enabled, we should shutdown the monitor
// goroutine when exiting this function.
// Usually `dials.Config` is smart enough not to start a monitor when
// there are no `Watcher` implementations in the source-list, but the
// `Blank` source uses `Watcher` for its core functionality, so we need
// to shutdown the blank source to actually clean up resources.
if !params.WatchConfigFile {
defer blank.Done(ctx)
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split this (unrelated) bug-fix into a different commit? (it can be the same PR, but it's super-confusing to have a move that's fixing a bug in the middle of a commit introducing a new feature)

ez/ez.go Outdated
@@ -219,7 +219,8 @@ func ConfigFileEnvFlagDecoderFactoryParams[T any, TP ConfigWithConfigPath[T]](ct
return nil, fmt.Errorf("decoderFactory provided a nil decoder for path: %s", cfgPath)
}

manglers := make([]transform.Mangler, 0, 2)
manglers := make([]transform.Mangler, 0, 3)
manglers = append(manglers, &transform.AliasMangler{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: drop the &.
AliasMangler is a zero-size struct, and doesn't need an address.
The go runtime/compiler will dedup zero-size-typed addresses in a lot of cases, including interface assignments. Storing the pointer type does us zero good here.

// conveniently.
type AliasMangler struct{}

// Mangle implements the Mangler interface. If an alias tag is defined, the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/an/any/. (an is a little ambiguous in the case where multiple tags are set)

Name: desc.Name + " (alias of `" + originalVals[tag] + "`)",
}
if setErr := tags.Set(newDesc); setErr != nil {
return nil, fmt.Errorf("error setting amended dialsdesc for tag %q: %w", tag, setErr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate it when people try to make APIs too "safe".
The only existing case where tags.Set returns an error is when the Key field is empty .

I wonder how much code we'd be able to delete if we used a library that paniced when you do something that stupid instead of forcing everyone to handle an error that cannot happen in any case where you have the least bit of control.

Comment on lines 93 to 99
// update dialsdesc if there is one
if desc, getErr := tags.Get("dialsdesc"); getErr == nil {
newDesc := &structtag.Tag{
Key: "dialsdesc",
Name: desc.Name + " (alias of `" + originalVals[tag] + "`)",
}
if setErr := tags.Set(newDesc); setErr != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this dialsdesc handling should probably be outside the tag loop. I think as-is, it'll clobber the tag multiple times if several of the alias tags are set at once. (which I think we want to allow)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on Slack, I need to leave some accumulation in the loop and then concatenate all the options for the dialsdesc tag afterwards.

}
}

// set the new flags on the alias field
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/flags/tags/

Comment on lines +134 to +137
// also don't recurse into TextUnarshaler types
if ft.Implements(textMReflectType) || reflect.PointerTo(ft).Implements(textMReflectType) {
continue
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should split this into a separate commit.

This fixes a bug in ez where an error thrown by a Source may cause the
process to hang.
We shouldn't ever mangle types that implement TextUnmarshaler.
Copy link
Contributor

@dfinkel dfinkel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one nit

README.md Outdated

Aliases are implemented using the
[Mangler](https://github.com/vimeo/dials/blob/402b4821e3f191d96580b9933583f1651325381d/transform/transformer.go#L17-L32)
interface. The `env`, `flag`, and `pflag` support aliasing without any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
interface. The `env`, `flag`, and `pflag` support aliasing without any
interface. The `env`, `flag`, and `pflag` sources support aliasing without any

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed.

Add a new mangler that allows us to have aliases for dials tags to
facilitate migrating from one name to another seamlessly. If both the
old name and the new name are set, an error will be returned because the
expectation is that you're using one or the other exclusively.
@sergiosalvatore sergiosalvatore merged commit 2e8ffb1 into master Aug 30, 2024
8 checks passed
@sergiosalvatore sergiosalvatore deleted the alias-tag branch August 30, 2024 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants