-
Notifications
You must be signed in to change notification settings - Fork 528
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
[Xamarin.Android.Build.Tasks] Emit an Error if a custom view cannot be fixed up. #1720
Conversation
Log.LogDebugMessage (" ResourceNameCaseMap: {0}", ResourceNameCaseMap); | ||
|
||
if (ResourceNameCaseMap != null) | ||
foreach (var arr in ResourceNameCaseMap.Split (';').Select (l => l.Split ('|')).Where (a => a.Length == 2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This same code is also in Aapt.cs
. We should move this to a utility method.
c714a42
to
c2563fa
Compare
build |
bb55a7c
to
c818aa0
Compare
@jonpryor @jonathanpeppers this should be good to go now. |
string targetfile = file; | ||
if (targetfile.StartsWith (resdir, StringComparison.InvariantCultureIgnoreCase)) { | ||
targetfile = file.Substring (resdir.Length).TrimStart (Path.DirectorySeparatorChar); | ||
targetfile = resource_name_case_map.ContainsKey (targetfile) ? resource_name_case_map [targetfile] : targetfile; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth using TryGetValue
so the dictionary lookup doesn't happen twice: ContainsKey
and indexer
.
I'm guessing resource_name_case_map
, could be big?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure. We would need to add a temp variable since it seems TryGetValue
will null
the output if it failed.
When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.
So we can't do
resource_name_case_map.TryGetValue (targetfile, out targetfile);
we would need to do
string temp;
if (resource_name_case_map.TryGetValue (targetfile, out temp))
targetfile = temp;
not sure which is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, stuff it. Gonna change to TryGetValue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could make it a little better:
if (resource_name_case_map.TryGetValue (targetfile, out string temp))
targetfile = temp;
// we have elements with slightly different casing. | ||
// lets issue a error. | ||
logMessage (TraceLevel.Error, $"We found a matching key '{matchingKey.Key}' for '{elem.Name.ToString ()}'. But the casing was incorrect. Please correct the casing"); | ||
} | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this method calls XElement.Name.ToString ()
alot, maybe calling it once and storing in a variable would be good?
c818aa0
to
2bbaa3f
Compare
elem.Name = acwMap[elem.Name.ToString ()]; | ||
string name = elem.Name.ToString (); | ||
if (acwMap.ContainsKey (name)) { | ||
elem.Name = acwMap[name]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one could also use TryGetValue
, sorry I didn't see it before.
if (targetfile.StartsWith (resdir, StringComparison.InvariantCultureIgnoreCase)) { | ||
targetfile = file.Substring (resdir.Length).TrimStart (Path.DirectorySeparatorChar); | ||
string temp; | ||
if (resource_name_case_map.TryGetValue (targetfile, out temp)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might try the new out
syntax:
if (resource_name_case_map.TryGetValue (targetfile, out string temp))
var result = new Dictionary<string, string> (); | ||
if (resourceCaseMap != null) { | ||
foreach (var arr in resourceCaseMap.Split (';').Select (l => l.Split ('|')).Where (a => a.Length == 2)) | ||
result [arr [1]] = arr [0]; // lowercase -> original |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably for the future, but I wonder if we could use Span<T>
here to make this faster.
This current code looks like it would allocate a lot of strings.
aee8785
to
9253468
Compare
@jonathanpeppers fixed up the TryGetValue bits :) |
021433e
to
5ab03c2
Compare
fb50b19
to
c03d6ec
Compare
…e fixed up. Context dotnet#1711 When using a custom view within a layout file we replace the `namespace.classname` with an `md5hash.classname`. We do this by using the `acwmap.txt` file to make known types onto the `md5` hashed ones. We do this in a case sensitive manner. We also only support Camel case and lower case type names. ClassLibrary1.CustomView=md5d6f7135293df7527c983d45d07471c5e.CustomTextView classlibrary1.CustomView=md5d6f7135293df7527c983d45d07471c5e.CustomTextView Given that a user is able to type these manually it is highly probable that typo's will occur. If for example a user types Classlibrary1.CustomView this will NOT be fixed up. Instead the user will recieve the following error at runtime. FATAL UNHANDLED EXCEPTION: Android.Views.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class Classlibrary1.CustomTextView ---> Android.Views.InflateException: Binary XML file line #1: Error inflating class Classlibrary1.CustomTextView ---> Java.Lang.ClassNotFoundException: Didn't find class "Classlibrary1.CustomTextView" if you are using the control in a number of places this runtime error does nothing to help track down the problem. Instead what we should be doing is detecting these issues and emitting a build error. This will provide the user not only the problem but also a link to the file causing the probem. TODO ---- [ ] Fix up the name so it points to the file in `Resources` not `res` [ ] Add a Unit test. [ ] Add Error code and document.
c03d6ec
to
1eae104
Compare
…e fixed up. (#1720) Context: #1711 When using a custom view within a layout file we replace the `namespace.classname` with an `md5hash.classname`. We do this by using the `acwmap.txt` file to map known types onto the `md5` hashed ones. This is done in a case sensitive manner. We also only support identically-cased and lower-cased namespace/package names: ClassLibrary1.CustomView=md5d6f7135293df7527c983d45d07471c5e.CustomTextView classlibrary1.CustomView=md5d6f7135293df7527c983d45d07471c5e.CustomTextView Given that a user is able to type these manually it is possible that typo's will occur. If for example a user types Classlibrary1.CustomView this will NOT be fixed up, due to the lowercase `l` in `library`. Instead the user will see the following error at runtime. FATAL UNHANDLED EXCEPTION: Android.Views.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class Classlibrary1.CustomTextView ---> Android.Views.InflateException: Binary XML file line #1: Error inflating class Classlibrary1.CustomTextView ---> Java.Lang.ClassNotFoundException: Didn't find class "Classlibrary1.CustomTextView" If the control is used in a number of places this runtime error does nothing to help track down the problem. Improve this scenario by detecting these issues and emitting an XA1002 build error. This will not only inform the user about the problem but also provide a link to the file causing the problem.
Context #1711
When using a custom view within a layout file we replace the
namespace.classname
with anmd5hash.classname
. We do thisby using the
acwmap.txt
file to make known types onto themd5
hashed ones. We do this in a case sensitive manner. Wealso only support Camel case and lower case type names.
Given that a user is able to type these manually it is highly
probable that typo's will occur. If for example a user types
(Note the lower case
L
) this will NOT be fixed up. Instead the user will recieve thefollowing error at runtime.
if you are using the control in a number of places this runtime error
does nothing to help track down the problem.
Instead what we should be doing is detecting these issues and emitting
a build error. This will provide the user not only the problem but
also a link to the file causing the probem.
TODO
Resources
notres