Easier-to-parse diff
lutzky opened this issue · 11 comments
Currently gmailctl diff can sometimes show output like this:
- to: {long@gmail.com list@gmail.com of@gmail.com aliases@gmail.com that@gmail.com apply@gmail.com to@gmail.com this@gmail.com rule@gmail.com}
+ to: {long@gmail.com list@gmail.com of@gmail.com aliases@gmail.com that@gmail.com apply@gmail.com this@gmail.com rule@gmali.com}
...it's not fun figuring out what's missing there.
The cmp package does what I mean, I think: https://go.dev/play/p/E5RwmDYIsvX -
main.WithSlices{
To: []string{
... // 4 identical elements
"that@gmail.com",
"apply@gmail.com",
- "to@gmail.com",
"this@gmail.com",
"rule@gmail.com",
},
}
This is not easy to do, because the diff is done at the lowest level of filters, where all the fields are simple strings. This allows for easy comparison with whatever is currently set in Gmail, without having to parse and back-translate upstream filters to higher level representations.
The line you report (to: {long@gmail.comt .... }
) is effectively just a string, so the cmp
package would report the same result.
Yep, my process definitely started with "I'll just send a pull request" and quickly turned into "this is nontrivial and should be a feature request".
Is there a reasonable place to say "here are all the filters before, here are all the filters after, throw it at cmp.Diff
and see how bad it looks"? Should serve as a reasonable starting point.
Alright, I found a place and ran it, lutzky@f3264ab. The output doesn't look great.
Yeah indeed. It's a bunch of strings not very different from what's existing. To make it better you really need a parser for Gmail filter expressions.
Yep. Now, even if I were to write such a parser, the output for cmp.Diff
on imagined parsed filters doesn't look great:
main.FilterNode{
And: []main.FilterNode{
{
And: nil,
Or: []main.FilterNode{
{From: "person1"},
{From: "person2"},
- {From: "person3"},
{From: "person4"},
},
Not: nil,
From: "",
},
{
And: nil,
Or: nil,
Not: &main.FilterNode{
And: nil,
Or: []main.FilterNode{
{From: "person5"},
{
And: nil,
Or: nil,
Not: nil,
- From: "person6",
+ From: "person7",
},
},
Not: nil,
From: "",
},
From: "",
},
},
Or: nil,
Not: nil,
From: "",
}
Even if we hide all the nil
and ""
entries, what we actually want is more like this:
before: {person1 person2 person3 person4} -{person5 person6}
after: {person1 person2 person4} -{person5 person7}
diff:
{
person1
person2
- person3
person4
}
-{
person5
- person6
+ person7
}
So, essentially, it's a matter of adding newlines and indentation in a few places, and running a traditional diff. I'll see if I can mock something up.
It's quick-and-dirty, but perhaps not entirely useless: https://go.dev/play/p/EREXFY8gTwR
It's certainly a start. There are a lot more cases to consider though. From the top of my head:
- quotes:
from:"foo bar"
- parenthesis:
(a b) subject:(foo bar)
- nested expressions:
-(x {y -z} k)
And combinations of those.
This issue is stale because it has been open for 30 days without activity.
This will be closed in 7 days, unless you add the 'lifecycle/keep-alive' label or comment.
Tweaked it a bit to handle your example cases: https://go.dev/play/p/qNFzmtFEWCo
WDYT?
Cool! I tried a couple more nasty cases (colons outside operators) and the results still seem good! https://go.dev/play/p/LtIy47e5eY7.