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

Eclipse resource filters #846

Merged
merged 2 commits into from Jan 31, 2017
Merged

Conversation

kpage
Copy link
Contributor

@kpage kpage commented Nov 12, 2016

Hi @oehme ! This is a draft pull request for the first phase of the eclipse resource filters, adding the EclipseProject DSL support for filters with a basic custom matcher. I am still cleaning up the documentation, but I wanted to open this so you could start to take a look.

Any of the checked boxes below indicate that I took action:

For all non-trivial changes that modify the behavior or public API:

@kpage
Copy link
Contributor Author

kpage commented Nov 12, 2016

Some notes:

  • Deviation from spec: I used random UUIDs for the resource filters instead of epoch time, as the filters were all created at about the same time and it looked like collisions were likely.
  • I tried a few methods of testing the generated filter XML. In the end, as the XML can get pretty complex, it seemed like the easiest way was to just assert a block of XML directly in the EclipseProjectIntegrationTest. Because the filter ids are autogenerated, they are stripped out before asserting if they were not passed in the expected XML.
  • Still need to implement reading filters from an existing .project file

@eriwen eriwen added a:feature A new functionality cla:yes labels Nov 14, 2016
Copy link
Contributor

@oehme oehme left a comment

Choose a reason for hiding this comment

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

Thank you for the great work so far! This just needs a bit of polishing and the "read previously existing filters" feature and we're good to go for a first iteration.

@@ -242,6 +259,63 @@ private void addLinkedResourcesToXml() {
}
}

private void addResourceFiltersToXml() {
// other nodes like linkedResources are appended even if they are empty, but as
Copy link
Contributor

Choose a reason for hiding this comment

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

I wouldn't change the behavior compared to the other ones here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I will update the old failing tests that were not expecting this empty node.


private int getResourceFilterType(ResourceFilter resourceFilter) {
int type = 0;
if (resourceFilter == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should never happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I will pick and document some default values and prevent nulls in the ResourceFilter setters.

if (resourceFilter == null) {
return type;
}
if (resourceFilter.getType() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

null should not be allowed in the first place

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

break;
}
}
if (resourceFilter.getAppliesTo() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

null should not be allowed in the first place

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

break;
}
}
if (resourceFilter.getRecursive() != null && resourceFilter.getRecursive()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

null should not be allowed in the first place

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

*
* @since NEXT_VERSION
*/
public class ResourceFilterMatcher extends GroovyObjectSupport {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do not extend GroovyObjectSupport. This is only there in other classes for backwards compatibility and not needed for newly added classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok.

void assertHasReferencedProjects(String... referencedProjects) {
assert this.project.projects.project*.text() == referencedProjects as List
}

void assertHasResourceFilterXml(String expectedFilteredResourcesXml) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's move these methods into a FilteredResourcesFixture

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now that the ids are sequential and predictable, most of this code is now unnecessary as we can just put the expected id in the xml. I will remove it.

public Set<ResourceFilter> getResourceFilters() {
return resourceFilterSet;
}
// setResourceFilters is not supported because ResourceFilterSet is a special DSL type
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove implementation comment. This is obvious from the type signature.

@@ -124,6 +124,8 @@

private Set<Link> linkedResources = Sets.newLinkedHashSet();

private ResourceFilterSet resourceFilterSet = new ResourceFilterSet();
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's do the same as for linkedResources: Have the resourceFilter method directly on EclipseProject and get rid of the additional nesting level in the DSL. Then you also no longer need ResourceFilterSet

eclipse.project {
  resourceFilter {
     type = ...
  }
}

instead of the current

eclipse.project {
  resourceFilters {
    filter {
      type = ... 
    }
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, sounds good.

*
* @since NEXT_VERSION
*/
public class ResourceFilter extends GroovyObjectSupport {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do not extend GroovyObjectSupport

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok

@kpage
Copy link
Contributor Author

kpage commented Nov 16, 2016

Hi @oehme , I have addressed your comments with a new commit. We can squash later before merging. I will work on the reading of the existing .project filteredResources next and add as a new commit here.

@kpage
Copy link
Contributor Author

kpage commented Dec 4, 2016

Hi @oehme , I have now added the support for reading filteredResources from an existing .project file and documentation for the new features. Would you please take another look?

  • Let me know if you want to do anything about the target/appliesTo (files/folders) naming. I made them all consistent (“appliesTo”) for now, but we can change it if you wish.
  • I wasn’t sure how the gradle team manages @SInCE tags. For now I used the placeholder NEXT_VERSION. Please let me know if I need to update these.
  • I added extra commits to make the changes easier to review, but we can squash and rebase before merging.

Copy link
Contributor

@oehme oehme left a comment

Choose a reason for hiding this comment

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

This is shaping up really great! I'm missing one test case (maybe I just overlooked it): If the matchers are still the same, the .project file is not changed at all.

/**
* The gradle DSL model of an Eclipse resource filter.
*
* Later this will be extended with additional helpers, but for now it just allows specifying a filter with a custom matcher
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not talk about the future here, we never know when we get around to it :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, removed :)

*
* eclipse {
* project {
* // the following closure configures the ResourceFilter
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 the code is pretty self-explanatory, no comment required

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed comment

* type = 'EXCLUDE_ALL'
* matcher {
* id = 'org.eclipse.ui.ide.multiFilter'
* arguments = '1.0-name-matches-false-false-node_modules'
Copy link
Contributor

Choose a reason for hiding this comment

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

This might need some explanation, like "to find out which arguments to use, configure the desired filter with Eclipse's UI and copy the argument String over"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added comment

private boolean recursive = true;
private ResourceFilterMatcher matcher;

// Needed for DSL configuration Actions
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, will remove the comment. I was trying to find a way to make sure the class was in a valid state by validating the setters and requiring a constructor with all arguments, but this doesn't seem to work well with configuration by closure/Action.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we can't validate this up-front, we can only give reasonable defaults (or fail later on if the user forgot something)

}

/**
* Sets the ResourceFilterAppliesTo
Copy link
Contributor

Choose a reason for hiding this comment

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

should have the same documentation as the getter

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, copied the getter documentation to the setter also

/**
* The model of an Eclipse resource filter matcher.
* <p>
* The matcher configures the behavior of its parent ResourceFilter. The matcher configures
Copy link
Contributor

Choose a reason for hiding this comment

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

The matcher does not configure the behavior. The matcher decides when the containing filter (or containing matcher) applies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

private String arguments;
private Set<ResourceFilterMatcher> children = Sets.newLinkedHashSet();

// Needed for DSL configuration Actions
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed comment

@kpage
Copy link
Contributor Author

kpage commented Dec 7, 2016

Ok, I have added test "existing project file with equivalent resource filters is unchanged" to test that an existing .project file with two resource filters is unchanged after the "eclipse" task is run on a gradle project that defines two equivalent filters.

One thing to note is that the ids of the filters will possibly change if Eclipse had generated the filters, as it will use a timestamp instead of sequential integers. As we do not store the id in our model, we can't recreate it, so the id will just change to a sequential number. But subsequent runs of the "eclipse" task will keep the same filter ordering and numbering. Do you think this will be an issue?

@kpage
Copy link
Contributor Author

kpage commented Dec 7, 2016

Hi @oehme , I have completed the latest round of code review changes, would you please have another look? Thanks!

@oehme
Copy link
Contributor

oehme commented Dec 7, 2016

One thing to note is that the ids of the filters will possibly change if Eclipse had generated the filters, as it will use a timestamp instead of sequential integers.

I think we can live with that, yes. Can you check that Eclipse doesn't change the id back when you import the project? Otherwise it could become an annoying back-and-forth.

Apart from that, this looks really great to me and I can merge it as soon as the question above is clarified.

@kpage
Copy link
Contributor Author

kpage commented Dec 8, 2016

Hi @oehme , I tested importing the generated .project file into Eclipse, and Eclipse does not change the identifiers. It will only change the ids if the filters are modified in the UI, and in that case it rewrites all of them (sometimes the ids are actually not unique, they are the same exact timestamp...). So I think this behavior is fine.

I have squashed the code review commits and rebased onto the latest master, you can merge when you are ready.

@oehme
Copy link
Contributor

oehme commented Dec 9, 2016

Thanks for the great work @kpage! I'll be out for a week, but will merge this when I'm back. It will be part of Gradle 3.4, so if you have some time to adjust the "NEXT_VERSION" tags that would help.

@kpage
Copy link
Contributor Author

kpage commented Dec 25, 2016

Hi @oehme , I changed the NEXT_VERSIONs to 3.4 and rebased onto latest master.

@eriwen eriwen self-assigned this Jan 9, 2017
@eriwen
Copy link
Contributor

eriwen commented Jan 21, 2017

Hi @kpage. This change looks good but we do have an outstanding test failure on Windows EclipseProjectIntegrationTest.existing project file with equivalent resource filters is unchanged. Would you please look into fixing it?

Failure details Condition not satisfied:

projectFileOriginalText == projectFile.text
| | | |
| | |
| | |
| | | root
| | |
| | |
| | |
| | | org.eclipse.jdt.core.javanature
| | |
| | |
| | |
| | | org.eclipse.jdt.core.javabuilder
| | |
| | |
| | |
| | |
| | |
| | |
| | | 1
| | | 9
| | |
| | |
| | | org.eclipse.some.custom.matcher
| | | foobar
| | |
| | |
| | |
| | | 2
| | | 30
| | |
| | |
| | | org.eclipse.some.custom.matcher
| | | barfoo
| | |
| | |
| | |
| | |
| | C:\tcagent1\work\4b92f910977a653d\subprojects\ide\build\tmp\test files\EclipseProjectIntegrationTest\existing_project_fi...unchanged\j33k8.project
| false
| 36 differences (95% similarity)
| (-)\n(-)\n\troot(-)\n\t(-)\n\t(-)\n\t(-)\n\t\torg.eclipse.jdt.core.javanature(-)\n\t(-)\n\t(-)\n\t\t(-)\n\t\t\torg.eclipse.jdt.core.javabuilder(-)\n\t\t\t(-)\n\t\t(-)\n\t(-)\n\t(-)\n\t(-)\n\t\t(-)\n\t\t\t1(-)\n\t\t\t9(-)\n\t\t\t(-)\n\t\t\t(-)\n\t\t\t\torg.eclipse.some.custom.matcher(-)\n\t\t\t\tfoobar(-)\n\t\t\t(-)\n\t\t(-)\n\t\t(-)\n\t\t\t2(-)\n\t\t\t30(-)\n\t\t\t(-)\n\t\t\t(-)\n\t\t\t\torg.eclipse.some.custom.matcher(-)\n\t\t\t\tbarfoo(-)\n\t\t\t(-)\n\t\t(-)\n\t(-)\n(-)\n
| (\r)\n(\r)\n\troot(\r)\n\t(\r)\n\t(\r)\n\t(\r)\n\t\torg.eclipse.jdt.core.javanature(\r)\n\t(\r)\n\t(\r)\n\t\t(\r)\n\t\t\torg.eclipse.jdt.core.javabuilder(\r)\n\t\t\t(\r)\n\t\t(\r)\n\t(\r)\n\t(\r)\n\t(\r)\n\t\t(\r)\n\t\t\t1(\r)\n\t\t\t9(\r)\n\t\t\t(\r)\n\t\t\t(\r)\n\t\t\t\torg.eclipse.some.custom.matcher(\r)\n\t\t\t\tfoobar(\r)\n\t\t\t(\r)\n\t\t(\r)\n\t\t(\r)\n\t\t\t2(\r)\n\t\t\t30(\r)\n\t\t\t(\r)\n\t\t\t(\r)\n\t\t\t\torg.eclipse.some.custom.matcher(\r)\n\t\t\t\tbarfoo(\r)\n\t\t\t(\r)\n\t\t(\r)\n\t(\r)\n(\r)\n

root org.eclipse.jdt.core.javanature org.eclipse.jdt.core.javabuilder 1 9 org.eclipse.some.custom.matcher foobar 2 30 org.eclipse.some.custom.matcher barfoo
at org.gradle.plugins.ide.eclipse.EclipseProjectIntegrationTest.existing project file with equivalent resource filters is unchanged(EclipseProjectIntegrationTest.groovy:555)

------- Stdout: -------
:eclipseClasspath

:eclipseJdt

:eclipseProject

:eclipse

BUILD SUCCESSFUL

Total time: 0.089 secs

------- Stderr: -------
Warning: org.apache.xerces.parsers.SAXParser: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.

Warning: org.apache.xerces.parsers.SAXParser: Property 'http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit' is not recognized.


'''
project.assertHasResourceFilterXml(resourceFilterXml)
projectFileOriginalText == projectFile.text
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the reason for the test failure. You need to normalize line separators if you want to compare a String and the content from a file.

@kpage
Copy link
Contributor Author

kpage commented Jan 24, 2017

Thanks @eriwen and @oehme , I have fixed the test and rebased onto the latest master.

Does gradle org have a public CI for pull requests? I ran the tests locally before on Linux but did not have a Windows machine available.

@eriwen
Copy link
Contributor

eriwen commented Jan 27, 2017

@kpage Yeah, I kicked off CI for your PR here: https://builds.gradle.org/viewQueued.html?itemId=2197344&tab=queuedBuildOverviewTab

I'm afraid this didn't make it into 3.4. Could you please update the @since annotations to 3.5 in the meantime?

@kpage
Copy link
Contributor Author

kpage commented Jan 28, 2017

Hi @eriwen , I have updated the new @since annotations to 3.5

@eriwen
Copy link
Contributor

eriwen commented Jan 31, 2017

@kpage The CI build passed and with @oehme's +1 I'm going to merge this. Thanks very much for your contributions!

@eriwen eriwen merged commit 623c90c into gradle:master Jan 31, 2017
@oehme
Copy link
Contributor

oehme commented Jan 31, 2017

@kpage Would you like to follow up with the Tooling API part next so we have a complete story for 3.5?

Copy link
Member

@big-guy big-guy left a comment

Choose a reason for hiding this comment

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

@eriwen @oehme I left a few comments...

We need to remove the new Closure-taking methods.

*
* @param configureClosure The closure to use to configure the resource filter.
*/
public ResourceFilter resourceFilter(@DelegatesTo(value=ResourceFilter.class, strategy = Closure.DELEGATE_FIRST) Closure configureClosure) {
Copy link
Member

Choose a reason for hiding this comment

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

We don't need to add Closure taking methods. Just the Action method is enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in #1328

*
* @param configureClosure The closure to use to configure the matcher.
*/
public ResourceFilterMatcher matcher(@DelegatesTo(value=ResourceFilterMatcher.class, strategy = Closure.DELEGATE_FIRST) Closure configureClosure) {
Copy link
Member

Choose a reason for hiding this comment

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

We can remove this one too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in #1328

*
* @param configureClosure The closure to use to configure the matcher.
*/
public ResourceFilterMatcher matcher(@DelegatesTo(value=ResourceFilterMatcher.class, strategy = Closure.DELEGATE_FIRST) Closure configureClosure) {
Copy link
Member

Choose a reason for hiding this comment

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

And this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in #1328

return children;
}

public void setChildren(Set<ResourceFilterMatcher> children) {
Copy link
Member

Choose a reason for hiding this comment

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

Is there an example of when this would be useful?

One weird thing about the way this is done is matcher {} at this level adds a new matcher, but matcher {} in the resource filter configures an existing one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @big-guy , are you asking why nested ResourceFilterMatchers are supported?

This is required by the existing Eclipse model of filters/matchers. Nested matchers are actually a pretty common use case. Suppose you wanted to filter out either of two folders from showing in Eclipse, this would be modeled as an or matcher with nested matchers for the folder names:

eclipse {
  project {
    resourceFilter {
      matcher {
        id = 'org.eclipse.ui.ide.orFilterMatcher'
        matcher {
          id = 'org.eclipse.ui.ide.multiFilter'
          arguments = '1.0-name-matches-false-false-node_modules'
        }
        matcher {
          id = 'org.eclipse.ui.ide.multiFilter'
          arguments = '1.0-name-matches-false-false-build'
        }
      }
    }
  }
}

Regarding the DSL issue you mention where matcher at the filter level creates/configures a single matcher whereas matcher at the matcher level creates a new nested matcher, that is something I struggled with as well.

I took a look at other examples in the gradle code where the DSL configures single objects vs. collections of objects, and this seemed to be how it was done elsewhere (EclipseProject.linkedResource, for example, creates a new Link and adds to the set whereas EclipseClasspath.file configures the single XmlFileContentMerger).

The confusion here just seems to stem from the required domain complexity that a filter can have exactly one matcher but matchers themselves can have multiple nested matchers. I guess the method names could be differentiated (matcher vs nestedMatcher?), but that might also cause another confusion as to why the same object type is constructed with different keywords depending on its placement in the DSL tree. Let me know if you have any suggestions.

Please keep in mind that the current implementation is just the "raw" domain model that gets gradle to parity with the Eclipse resource filters, but @oehme has spec'd a much more intuitive extension to the DSL that can be layered on top of this.

private String arguments;
private Set<ResourceFilterMatcher> children = Sets.newLinkedHashSet();

public ResourceFilterMatcher() {
Copy link
Member

Choose a reason for hiding this comment

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

Several of these new classes have 2 constructors, but it seems like only one of them is useful/used often?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The default constructor was required to initialize an empty object that is configured by the Action while the full constructor is useful to construct instances for tests (ProjectTest, ResourceFilterTest, ResourceFilterMatcherTest). Please let me know if you have a more idiomatic way of constructing the DSL objects for Actions, etc.

this.children = children;
}

public String getId() {
Copy link
Member

Choose a reason for hiding this comment

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

This isn't marked as @Nullable, but it seems like we expect it could be null sometimes (see hashCode)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The id is required by Eclipse for the matcher to work, I could add validation logic in setId to throw InvalidUserDataException if null is passed like we do for "children". I added the null check in hashCode because these are mutable DSL objects that are constructed empty and then populated later by Action or from reading an existing .project file, so it is possible that hashCode might be called and throw NPE before the object is fully/correctly configured. EqualsVerifier pointed out the NPE when I was testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Null check on setter added in #1328

@@ -30,6 +30,7 @@ dependencies {
compile libraries.inject

testCompile libraries.xmlunit
testCompile libraries.equalsVerifier
Copy link
Member

Choose a reason for hiding this comment

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

This is a nit-picky thing, but we only use this in two tests and I think we could capture about the same thing by checking that the effect of a bad equals/hashCode method is caught in the integration tests (for the generated Eclipse metadata files).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I had added this for myself to catch errors with the manually written equals/hashCode required by the DSL and decided to leave it in case the gradle team found it useful.

I've found EqualsVerifier quite useful on other projects as a low-effort way to catch issues with Java hashCode/equals (it catches things like possible NPEs, fields that were recently added without updating hashCode/equals, using a field in hashCode but forgetting it in equals, the semantics of getClass() vs instanceof in the presence of inheritance, and a few other useful things). To check these edge cases in the integration tests might run over 1000 more lines of test code and take longer to execute.

If you think you will not use it often, I can remove it. Please let me know what you decide.

@kpage kpage deleted the eclipse-resource-filters branch February 4, 2017 07:07
@kpage
Copy link
Contributor Author

kpage commented Feb 4, 2017

Hi @big-guy , as this branch has already merged, I have opened a new pull request to address changes from your comments: #1328

@oehme sure, after the new code review comments are finalized, I can look at the Tooling API.

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.

None yet

4 participants