Defining a property designed to be overridden?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Defining a property designed to be overridden?

Mark Raynsford
Hello.

I'm looking to move to an organization-wide parent POM but am not sure
how to handle the following configuration case.

The japicmp [0] plugin takes a configuration parameter that specifies
the previous version of a module against which the current version of
the module will be checked for API compatibility. I believe it can
sometimes infer the correct version by itself, but for the sake of
explanation here, let's assume that it can't and that I need to specify
it myself. This isn't a japicmp plugin issue, it's just a specific
example of a more general problem regarding the scope and definitions
of properties.

I have a parent pom:

https://github.com/io7m/maven-parent-properties-20170301/blob/develop/pom.xml

... which contains a definition like this:

<project>
  ...
  <properties>
    <io7m.previousVersion></io7m.previousVersion>
  </properties>

  ...

  <build>
    <pluginManagement>
      <plugins>
        <!-- Verify API compatibility -->
        <plugin>
          <groupId>com.github.siom79.japicmp</groupId>
          <artifactId>japicmp-maven-plugin</artifactId>
          <version>0.9.4</version>
          <executions>
            <execution>
              <phase>verify</phase>
              <goals>
                <goal>cmp</goal>
              </goals>
              <configuration>
                <oldVersion>
                  <dependency>
                    <groupId>${project.groupId}</groupId>
                    <artifactId>${project.artifactId}</artifactId>
                    <version>${io7m.previousVersion}</version>
                    <type>jar</type>
                  </dependency>
                </oldVersion>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

I then have an example project that inherits from the parent:

https://github.com/io7m/maven-parent-properties-20170301/blob/develop/mod-a/pom.xml

<project>
  <parent>
    <groupId>com.io7m.experimental</groupId>
    <artifactId>maven-parent-properties-20170301</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>mod-a</artifactId>
  <properties>
    <io7m.previousVersion>0.9.0</io7m.previousVersion>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>com.github.siom79.japicmp</groupId>
        <artifactId>japicmp-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

Note that the child project must override the io7m.previousVersion
property from the parent. Is this the correct way to handle this? The
downside to this is that if a project forgets to override the property
value, it won't get a sensible "You didn't define this property" error
because it's already defined with an empty value in the parent. If I
don't define the property in the parent, many IDEs get upset at the
presence of an undefined property in the POM.

Any advice would be appreciated.

M

[0] https://siom79.github.io/japicmp/MavenPlugin.html

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Curtis Rueden
Hi,

> if a project forgets to override the property value, it won't get a
> sensible "You didn't define this property" error because it's already
> defined with an empty value in the parent.

The way I solved this problem with my project builds is to create a custom
requireElements enforcer rule, part of the scijava-maven-plugin [1], which
lets you require the existence of particular elements in the POM itself—not
an ancestor. Here is the configuration we use:

https://github.com/scijava/pom-scijava-base/blob/pom-
scijava-base-3.0.0/pom.xml#L610-L628

In this way, I ensure that all projects which extend our parent add all the
useful metadata and properties needed for successful builditude.

We released scijava-maven-plugin 1.0.0 on Maven Central; feel free to use
it if it helps you.

Regards,
Curtis

[1] https://github.com/scijava/scijava-maven-plugin/blob/
scijava-maven-plugin-1.0.0/src/main/java/org/scijava/maven/plugin/enforcer/
RequireElements.java#L55-L61

--
Curtis Rueden
LOCI software architect - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden


On Wed, Mar 1, 2017 at 12:35 PM, <[hidden email]> wrote:

> Hello.
>
> I'm looking to move to an organization-wide parent POM but am not sure
> how to handle the following configuration case.
>
> The japicmp [0] plugin takes a configuration parameter that specifies
> the previous version of a module against which the current version of
> the module will be checked for API compatibility. I believe it can
> sometimes infer the correct version by itself, but for the sake of
> explanation here, let's assume that it can't and that I need to specify
> it myself. This isn't a japicmp plugin issue, it's just a specific
> example of a more general problem regarding the scope and definitions
> of properties.
>
> I have a parent pom:
>
> https://github.com/io7m/maven-parent-properties-20170301/blo
> b/develop/pom.xml
>
> ... which contains a definition like this:
>
> <project>
>   ...
>   <properties>
>     <io7m.previousVersion></io7m.previousVersion>
>   </properties>
>
>   ...
>
>   <build>
>     <pluginManagement>
>       <plugins>
>         <!-- Verify API compatibility -->
>         <plugin>
>           <groupId>com.github.siom79.japicmp</groupId>
>           <artifactId>japicmp-maven-plugin</artifactId>
>           <version>0.9.4</version>
>           <executions>
>             <execution>
>               <phase>verify</phase>
>               <goals>
>                 <goal>cmp</goal>
>               </goals>
>               <configuration>
>                 <oldVersion>
>                   <dependency>
>                     <groupId>${project.groupId}</groupId>
>                     <artifactId>${project.artifactId}</artifactId>
>                     <version>${io7m.previousVersion}</version>
>                     <type>jar</type>
>                   </dependency>
>                 </oldVersion>
>               </configuration>
>             </execution>
>           </executions>
>         </plugin>
>       </plugins>
>     </pluginManagement>
>   </build>
> </project>
>
> I then have an example project that inherits from the parent:
>
> https://github.com/io7m/maven-parent-properties-20170301/blo
> b/develop/mod-a/pom.xml
>
> <project>
>   <parent>
>     <groupId>com.io7m.experimental</groupId>
>     <artifactId>maven-parent-properties-20170301</artifactId>
>     <version>1.0.0</version>
>   </parent>
>
>   <artifactId>mod-a</artifactId>
>   <properties>
>     <io7m.previousVersion>0.9.0</io7m.previousVersion>
>   </properties>
>
>   <build>
>     <plugins>
>       <plugin>
>         <groupId>com.github.siom79.japicmp</groupId>
>         <artifactId>japicmp-maven-plugin</artifactId>
>       </plugin>
>     </plugins>
>   </build>
> </project>
>
> Note that the child project must override the io7m.previousVersion
> property from the parent. Is this the correct way to handle this? The
> downside to this is that if a project forgets to override the property
> value, it won't get a sensible "You didn't define this property" error
> because it's already defined with an empty value in the parent. If I
> don't define the property in the parent, many IDEs get upset at the
> presence of an undefined property in the POM.
>
> Any advice would be appreciated.
>
> M
>
> [0] https://siom79.github.io/japicmp/MavenPlugin.html
>
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Mark Raynsford
On 2017-03-01T12:46:45 -0600
Curtis Rueden <[hidden email]> wrote:
>
> In this way, I ensure that all projects which extend our parent add all the
> useful metadata and properties needed for successful builditude.
>
> We released scijava-maven-plugin 1.0.0 on Maven Central; feel free to use
> it if it helps you.

Hah, well, I'm not sure you could have solved my problem any more
precisely than that! Looks like exactly what I need. Thanks very much!

M

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Mark Raynsford
In reply to this post by Curtis Rueden
On 2017-03-01T12:46:45 -0600
Curtis Rueden <[hidden email]> wrote:
>
> In this way, I ensure that all projects which extend our parent add all the
> useful metadata and properties needed for successful builditude.
>

Hm, slight issue with this.

If you take a look at how my projects are usually designed:

  https://github.com/io7m/jtensors/blob/develop/pom.xml

That's the root pom for the project. It defines all of the project's
information such as plugin versions, dependency versions, metadata such
as the SCM location, site, etc.

Then, each module looks like this:

  https://github.com/io7m/jtensors/blob/develop/io7m-jtensors-core/pom.xml

Note how this is a module of the root project and therefore it'd be
redundant to have to re-specify all of the information such as the
contributors, SCM location [0], etc. I only provide the information
that's specific to that module such as the OSGi manifest, dependencies,
etc.

Using the scijava-maven-plugin RequireElements rule would seem to
require me to specify all of this information again in each module.
Is there a way to avoid this?

M

[0] Although I do actually have to re-specify the SCM location due to
    an utterly ancient bug/design flaw in the site plugin.

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Curtis Rueden
Hi,

> Note how this is a module of the root project and therefore it'd be
> redundant to have to re-specify all of the information such as the
> contributors, SCM location [0], etc. I only provide the information
> that's specific to that module such as the OSGi manifest,
> dependencies, etc.

If what you want is to ensure the property is simply non-empty, or matching
a particular regex, then take a look at the requireProperty enforcer rule
[1].

Or if your goal is to make sure that a property value _differs_ from the
value defined in an ancestor, the requirePropertyDiverges rule [2] might be
for you.

In my case, I really wanted to make sure that all those properties were
(re)defined in the child POM, because otherwise, it was too easy for
downstream developers to accidentally forget to override things propertly.
E.g., the parent POM defines <issueManagement> as the issue tracker for
that parent POM itself—but this should never be inherited by the child;
instead, every child should define its own <issueManagement> for its own
issue tracker. (If you don't have an issue tracker, you can write
<issueManagement><system>None</system></issueManagement> to satisfy the
enforcer.)

Regards,
Curtis

[1] https://maven.apache.org/enforcer/enforcer-rules/requireProperty.html
[2] http://www.mojohaus.org/extra-enforcer-rules/
requirePropertyDiverges.html

--
Curtis Rueden
LOCI software architect - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden
Did you know ImageJ has a forum? http://forum.imagej.net/


On Wed, Mar 1, 2017 at 2:17 PM, <[hidden email]> wrote:

> On 2017-03-01T12:46:45 -0600
> Curtis Rueden <[hidden email]> wrote:
> >
> > In this way, I ensure that all projects which extend our parent add all
> the
> > useful metadata and properties needed for successful builditude.
> >
>
> Hm, slight issue with this.
>
> If you take a look at how my projects are usually designed:
>
>   https://github.com/io7m/jtensors/blob/develop/pom.xml
>
> That's the root pom for the project. It defines all of the project's
> information such as plugin versions, dependency versions, metadata such
> as the SCM location, site, etc.
>
> Then, each module looks like this:
>
>   https://github.com/io7m/jtensors/blob/develop/io7m-jtensors-core/pom.xml
>
> Note how this is a module of the root project and therefore it'd be
> redundant to have to re-specify all of the information such as the
> contributors, SCM location [0], etc. I only provide the information
> that's specific to that module such as the OSGi manifest, dependencies,
> etc.
>
> Using the scijava-maven-plugin RequireElements rule would seem to
> require me to specify all of this information again in each module.
> Is there a way to avoid this?
>
> M
>
> [0] Although I do actually have to re-specify the SCM location due to
>     an utterly ancient bug/design flaw in the site plugin.
>
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Mark Raynsford
Hello!

On 2017-03-01T15:49:10 -0600
Curtis Rueden <[hidden email]> wrote:
>
> If what you want is to ensure the property is simply non-empty, or matching
> a particular regex, then take a look at the requireProperty enforcer rule
> [1].
>
> Or if your goal is to make sure that a property value _differs_ from the
> value defined in an ancestor, the requirePropertyDiverges rule [2] might be
> for you.

I do actually want to enforce this, the issue is that I only want to
enforce it as far as the first ancestor. My current projects look like
this (where indentation indicates inheritance):

  + io7m-jtensors
    + io7m-jtensors-core
    + io7m-jtensors-tests
    + io7m-jtensors-ieee754b16
    + ...
  + io7m-r2
    + io7m-r2-core
    + io7m-r2-shaders
    + ...

I want to move to:

  + io7m-ancestor
    + io7m-jtensors
      + io7m-jtensors-core
      + io7m-jtensors-tests
      + io7m-jtensors-ieee754b16
      + ...
    + io7m-r2
      + io7m-r2-core
      + io7m-r2-shaders
      + ...

So I want to enforce that io7m-jtensors and io7m-r2 override the
required properties (and elements such as issueManagement), but I don't
want to propagate that requirement to the individual submodules of
io7m-jtensors such as io7m-jtensors-core, because this would introduce
pointless redundancy. I have around 50 top-level projects to manage in
this form, so any redundancy that can be eliminated really needs to be!

I'm not sure the enforcer plugin is able to express this "only redefine
once" aspect of the above. Am I wrong?

M

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Curtis Rueden
Hi,

> I do actually want to enforce this, the issue is that I only want to
> enforce it as far as the first ancestor.

Sorry if you stated otherwise in your writeup, but my understanding is that
you want to define some empty properties in your new root POM, and then
ensure they are _not_ empty in the next level down. Right?

If so, then I think the requireProperty rule should be sufficient. You can
write:

  <properties>
    <io7m.previous.version />
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>1.4.1</version>
        <executions>
          <execution>
            <id>enforce-property</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <requireProperty>
                  <property>io7m.previous.version</property>
                  <message>You must define the io7m.previous.version
property!</message>
                  <regex>.+</regex>
                  <regexMessage>You must set the io7m.previous.version
property!</regexMessage>
                </requireProperty>
              </rules>
              <fail>true</fail>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Regards,
Curtis

--
Curtis Rueden
LOCI software architect - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden


On Thu, Mar 2, 2017 at 2:50 AM, <[hidden email]> wrote:

> Hello!
>
> On 2017-03-01T15:49:10 -0600
> Curtis Rueden <[hidden email]> wrote:
> >
> > If what you want is to ensure the property is simply non-empty, or
> matching
> > a particular regex, then take a look at the requireProperty enforcer rule
> > [1].
> >
> > Or if your goal is to make sure that a property value _differs_ from the
> > value defined in an ancestor, the requirePropertyDiverges rule [2] might
> be
> > for you.
>
> I do actually want to enforce this, the issue is that I only want to
> enforce it as far as the first ancestor. My current projects look like
> this (where indentation indicates inheritance):
>
>   + io7m-jtensors
>     + io7m-jtensors-core
>     + io7m-jtensors-tests
>     + io7m-jtensors-ieee754b16
>     + ...
>   + io7m-r2
>     + io7m-r2-core
>     + io7m-r2-shaders
>     + ...
>
> I want to move to:
>
>   + io7m-ancestor
>     + io7m-jtensors
>       + io7m-jtensors-core
>       + io7m-jtensors-tests
>       + io7m-jtensors-ieee754b16
>       + ...
>     + io7m-r2
>       + io7m-r2-core
>       + io7m-r2-shaders
>       + ...
>
> So I want to enforce that io7m-jtensors and io7m-r2 override the
> required properties (and elements such as issueManagement), but I don't
> want to propagate that requirement to the individual submodules of
> io7m-jtensors such as io7m-jtensors-core, because this would introduce
> pointless redundancy. I have around 50 top-level projects to manage in
> this form, so any redundancy that can be eliminated really needs to be!
>
> I'm not sure the enforcer plugin is able to express this "only redefine
> once" aspect of the above. Am I wrong?
>
> M
>
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Mark Raynsford
'Ello.

On 2017-03-02T08:16:43 -0600
Curtis Rueden <[hidden email]> wrote:

> Hi,
>
> > I do actually want to enforce this, the issue is that I only want to
> > enforce it as far as the first ancestor.  
>
> Sorry if you stated otherwise in your writeup, but my understanding is that
> you want to define some empty properties in your new root POM, and then
> ensure they are _not_ empty in the next level down. Right?

Yes, but additionally some XML elements as well.

I'd like to enforce that:

  1. Some properties that are defined as empty in the root POM are
     non-empty in all descendants.

  2. Some XML elements that are defined in the root POM (such as
     issueManagement) are overridden _at least once_ between the root
     and any leaf project.

The requireProperty rule you provided does seem to properly handle point
1, but I think that the options we've discussed are too heavy-handed
for point 2. Unless I've missed something obvious, it seems that I can
only require that the XML elements be overridden in *all* descendant
POMs, and this introduces too much redundancy.

M

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Curtis Rueden
> it seems that I can only require that the XML elements be overridden
> in *all* descendant POMs, and this introduces too much redundancy.

I see.

Would it be sufficient if the requireElements rule had a multiModule flag
which, if set, green-lighted the build when the stated elements are defined
in the local parent POM? This feature would assume you are using the
aggregator==parent scheme, and follow the <relativePath> declared in the
<parent> of each POM. If it finds a POM there, it would parse it and then
check for the required elements in _that_ POM instead of the initial one.
And do this recursively, in case you have a multi-layered multi-module
build.

The downside of this approach: modules of a project would only build if the
parent is available locally. E.g.: if you try to build one module of a
multi-module build which has been physically disconnected from its parent
(e.g., a partial SVN checkout), the enforcer would fail because it would
not find the local parent POM to validate against. One can also imagine
various "aggegator != parent" organizations where the parent is not
available locally, which would also all fail to support this scheme.

Thoughts?

--
Curtis Rueden
LOCI software architect - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden


On Thu, Mar 2, 2017 at 9:13 AM, <[hidden email]> wrote:

> 'Ello.
>
> On 2017-03-02T08:16:43 -0600
> Curtis Rueden <[hidden email]> wrote:
>
> > Hi,
> >
> > > I do actually want to enforce this, the issue is that I only want to
> > > enforce it as far as the first ancestor.
> >
> > Sorry if you stated otherwise in your writeup, but my understanding is
> that
> > you want to define some empty properties in your new root POM, and then
> > ensure they are _not_ empty in the next level down. Right?
>
> Yes, but additionally some XML elements as well.
>
> I'd like to enforce that:
>
>   1. Some properties that are defined as empty in the root POM are
>      non-empty in all descendants.
>
>   2. Some XML elements that are defined in the root POM (such as
>      issueManagement) are overridden _at least once_ between the root
>      and any leaf project.
>
> The requireProperty rule you provided does seem to properly handle point
> 1, but I think that the options we've discussed are too heavy-handed
> for point 2. Unless I've missed something obvious, it seems that I can
> only require that the XML elements be overridden in *all* descendant
> POMs, and this introduces too much redundancy.
>
> M
>
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Mark Raynsford
On 2017-03-02T10:29:30 -0600
Curtis Rueden <[hidden email]> wrote:

> > it seems that I can only require that the XML elements be overridden
> > in *all* descendant POMs, and this introduces too much redundancy.  
>
> I see.
>
> Would it be sufficient if the requireElements rule had a multiModule flag
> which, if set, green-lighted the build when the stated elements are defined
> in the local parent POM? This feature would assume you are using the
> aggregator==parent scheme, and follow the <relativePath> declared in the
> <parent> of each POM. If it finds a POM there, it would parse it and then
> check for the required elements in _that_ POM instead of the initial one.
> And do this recursively, in case you have a multi-layered multi-module
> build.
>
> The downside of this approach: modules of a project would only build if the
> parent is available locally. E.g.: if you try to build one module of a
> multi-module build which has been physically disconnected from its parent
> (e.g., a partial SVN checkout), the enforcer would fail because it would
> not find the local parent POM to validate against. One can also imagine
> various "aggegator != parent" organizations where the parent is not
> available locally, which would also all fail to support this scheme.
>
I'd need to think a bit more about it, but I personally dislike
relativePath and have never used it (across hundreds of projects),
pretty much for the sorts of reasons you've described. Hard-coding
paths that represent links to other modules seems like a horrendously
bad idea.

I've written a few plugins, but I'm not intimately familiar with the
Maven API: Shouldn't it be possible to recursively retrieve the parent
POMs from the reactor (and failing that, the local and remote
repositories) within the plugin? That would remove the need for
<relativePath>.

If that is possible, then I think the pseudocode is:

  let root(p) be the root POM of project p
  let parent(p) be the parent of p
  let definesElements(p) return true if p defines the required elements

  Project q = p
  while (!done) {
    if (q == root(p)) {
      throw RequiredElementsMissing()
    }

    if (definesElements(q)) {
      done = true
    }

    q = parent(p)
  }

This feels like it would achieve what I need with only minimal
assumptions about the hierarchy of projects.

M

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Curtis Rueden
Hi,

> I'd need to think a bit more about it, but I personally dislike
> relativePath and have never used it (across hundreds of projects),
> pretty much for the sorts of reasons you've described. Hard-coding
> paths that represent links to other modules seems like a
> horrendously bad idea.

That is fair. I will point out, though, that if you do not specify the
relativePath, then it is ".." by default. Best practice is to write
"<relativePath />" if you explicitly do _not_ want Maven to check for the
parent in the parent directory. Hence, if we implemented my requireElements
enhancement, the relativePath would be treated as ".." when one is not
explicitly specified.

I will also point out that each "<module>" of a multi-module build is also
a hard-coded link to another module, which according to your reasoning,
makes multi-module projects in general a horrendous idea. (And I am not
being totally facetious here—I personally prefer never to use multi-module
projects at all. Though I would not go so far as to call them
"horrendous"—they definitely have their uses.)

> I've written a few plugins, but I'm not intimately familiar with the
> Maven API: Shouldn't it be possible to recursively retrieve the parent
> POMs from the reactor (and failing that, the local and remote
> repositories) within the plugin? That would remove the need for
> <relativePath>.

Sure. You are absolutely welcome to file a PR against the
scijava-maven-plugin adding this feature. The complication is just that
instead of loading POMs from local files, you now also need to resolve them
from the appropriate remote repositories, for which there is certainly
Maven API, but I am also not familiar enough with it to tell you what it is
off the top of my head. Hopefully someone else here can comment in more
detail, and/or suggest alternative solutions here. In any case, if you
pursue this, it should work to test locally by installing the plugin into
your local repo cache using the "install" phase, and then using
"org.scijava:scijava-maven-plugin:1.0.1-SNAPSHOT" in your test POMs.

Regards,
Curtis

--
Curtis Rueden
LOCI software architect - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden


On Thu, Mar 2, 2017 at 11:02 AM, <[hidden email]> wrote:

> On 2017-03-02T10:29:30 -0600
> Curtis Rueden <[hidden email]> wrote:
>
> > > it seems that I can only require that the XML elements be overridden
> > > in *all* descendant POMs, and this introduces too much redundancy.
> >
> > I see.
> >
> > Would it be sufficient if the requireElements rule had a multiModule flag
> > which, if set, green-lighted the build when the stated elements are
> defined
> > in the local parent POM? This feature would assume you are using the
> > aggregator==parent scheme, and follow the <relativePath> declared in the
> > <parent> of each POM. If it finds a POM there, it would parse it and then
> > check for the required elements in _that_ POM instead of the initial one.
> > And do this recursively, in case you have a multi-layered multi-module
> > build.
> >
> > The downside of this approach: modules of a project would only build if
> the
> > parent is available locally. E.g.: if you try to build one module of a
> > multi-module build which has been physically disconnected from its parent
> > (e.g., a partial SVN checkout), the enforcer would fail because it would
> > not find the local parent POM to validate against. One can also imagine
> > various "aggegator != parent" organizations where the parent is not
> > available locally, which would also all fail to support this scheme.
> >
>
> I'd need to think a bit more about it, but I personally dislike
> relativePath and have never used it (across hundreds of projects),
> pretty much for the sorts of reasons you've described. Hard-coding
> paths that represent links to other modules seems like a horrendously
> bad idea.
>
> I've written a few plugins, but I'm not intimately familiar with the
> Maven API: Shouldn't it be possible to recursively retrieve the parent
> POMs from the reactor (and failing that, the local and remote
> repositories) within the plugin? That would remove the need for
> <relativePath>.
>
> If that is possible, then I think the pseudocode is:
>
>   let root(p) be the root POM of project p
>   let parent(p) be the parent of p
>   let definesElements(p) return true if p defines the required elements
>
>   Project q = p
>   while (!done) {
>     if (q == root(p)) {
>       throw RequiredElementsMissing()
>     }
>
>     if (definesElements(q)) {
>       done = true
>     }
>
>     q = parent(p)
>   }
>
> This feels like it would achieve what I need with only minimal
> assumptions about the hierarchy of projects.
>
> M
>
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Mark Raynsford
On 2017-03-02T11:12:58 -0600
Curtis Rueden <[hidden email]> wrote:

> Hi,
>
> > I'd need to think a bit more about it, but I personally dislike
> > relativePath and have never used it (across hundreds of projects),
> > pretty much for the sorts of reasons you've described. Hard-coding
> > paths that represent links to other modules seems like a
> > horrendously bad idea.  
>
> That is fair. I will point out, though, that if you do not specify the
> relativePath, then it is ".." by default. Best practice is to write
> "<relativePath />" if you explicitly do _not_ want Maven to check for the
> parent in the parent directory. Hence, if we implemented my requireElements
> enhancement, the relativePath would be treated as ".." when one is not
> explicitly specified.
Right.

I get the sense that adding <relativePath /> is something that would
upset IDEs (my experience has been that they cope relatively poorly
with anything uncommon like that).

> I will also point out that each "<module>" of a multi-module build is also
> a hard-coded link to another module, which according to your reasoning,
> makes multi-module projects in general a horrendous idea. (And I am not
> being totally facetious here—I personally prefer never to use multi-module
> projects at all. Though I would not go so far as to call them
> "horrendous"—they definitely have their uses.)

Hehe, I probably overstated it a touch. I tend to think of the <module>
entries slightly differently though: I consider them to be module names
that match the artifact ID of the submodule and also just happen to
correspond to the directory that contains the module's sources. They
don't inspire the same revulsion because they don't exist in my mental
model as filesystem paths. I'm not actually sure they are in Maven's
model either... Can a module name contain slashes?

> > I've written a few plugins, but I'm not intimately familiar with the
> > Maven API: Shouldn't it be possible to recursively retrieve the parent
> > POMs from the reactor (and failing that, the local and remote
> > repositories) within the plugin? That would remove the need for
> > <relativePath>.  
>
> Sure. You are absolutely welcome to file a PR against the
> scijava-maven-plugin adding this feature. The complication is just that
> instead of loading POMs from local files, you now also need to resolve them
> from the appropriate remote repositories, for which there is certainly
> Maven API, but I am also not familiar enough with it to tell you what it is
> off the top of my head. Hopefully someone else here can comment in more
> detail, and/or suggest alternative solutions here. In any case, if you
> pursue this, it should work to test locally by installing the plugin into
> your local repo cache using the "install" phase, and then using
> "org.scijava:scijava-maven-plugin:1.0.1-SNAPSHOT" in your test POMs.
I will give it a go. I've had somewhat poor experiences with the Maven
APIs as they tend not to be documented too well. I may end up living
with just not enforcing these things...

M

attachment0 (871 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Defining a property designed to be overridden?

Curtis Rueden
Hi,

> I get the sense that adding <relativePath /> is something that would
> upset IDEs (my experience has been that they cope relatively poorly
> with anything uncommon like that).

My group uses "<relativePath />" a lot in IDEs including Eclipse, NetBeans
and IDEA, and it works for us. I suggest giving it a try and seeing if it
causes you any problems. Of course, in your case, since you have
multi-module builds, you probably actually _want_ the default behavior of
".." for your submodules, so maybe you don't want to change anything.

> Can a module name contain slashes?

Sure can! It's a relative directory path.

> I will give it a go. I've had somewhat poor experiences with the Maven
> APIs as they tend not to be documented too well.

Yeah, me too. I've found it pretty hard to get into Maven plugin
development, especially since the APIs have gone through a few major
iterations from 2.x to 3.0.x to 3.1.x etc. And in some cases, plugins mix
and match APIs from those different iterations. :-O

That said, this list (and the Maven dev list) is here for you. Others on
this list know a lot more about it, and can help you win awards.

> I may end up living with just not enforcing these things...

Well, since this rule is mostly for you yourself, and not some nebulous
cloud of community developers consuming your stuff, you can probably get
away with a nice shell script that calls grep over your POMs, and barfs
when various things are not found. Easy, right?

Regards,
Curtis

--
Curtis Rueden
LOCI software architect - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden
Did you know ImageJ has a forum? http://forum.imagej.net/


On Thu, Mar 2, 2017 at 1:34 PM, <[hidden email]> wrote:

> On 2017-03-02T11:12:58 -0600
> Curtis Rueden <[hidden email]> wrote:
>
> > Hi,
> >
> > > I'd need to think a bit more about it, but I personally dislike
> > > relativePath and have never used it (across hundreds of projects),
> > > pretty much for the sorts of reasons you've described. Hard-coding
> > > paths that represent links to other modules seems like a
> > > horrendously bad idea.
> >
> > That is fair. I will point out, though, that if you do not specify the
> > relativePath, then it is ".." by default. Best practice is to write
> > "<relativePath />" if you explicitly do _not_ want Maven to check for the
> > parent in the parent directory. Hence, if we implemented my
> requireElements
> > enhancement, the relativePath would be treated as ".." when one is not
> > explicitly specified.
>
> Right.
>
> I get the sense that adding <relativePath /> is something that would
> upset IDEs (my experience has been that they cope relatively poorly
> with anything uncommon like that).
>
> > I will also point out that each "<module>" of a multi-module build is
> also
> > a hard-coded link to another module, which according to your reasoning,
> > makes multi-module projects in general a horrendous idea. (And I am not
> > being totally facetious here—I personally prefer never to use
> multi-module
> > projects at all. Though I would not go so far as to call them
> > "horrendous"—they definitely have their uses.)
>
> Hehe, I probably overstated it a touch. I tend to think of the <module>
> entries slightly differently though: I consider them to be module names
> that match the artifact ID of the submodule and also just happen to
> correspond to the directory that contains the module's sources. They
> don't inspire the same revulsion because they don't exist in my mental
> model as filesystem paths. I'm not actually sure they are in Maven's
> model either... Can a module name contain slashes?
>
> > > I've written a few plugins, but I'm not intimately familiar with the
> > > Maven API: Shouldn't it be possible to recursively retrieve the parent
> > > POMs from the reactor (and failing that, the local and remote
> > > repositories) within the plugin? That would remove the need for
> > > <relativePath>.
> >
> > Sure. You are absolutely welcome to file a PR against the
> > scijava-maven-plugin adding this feature. The complication is just that
> > instead of loading POMs from local files, you now also need to resolve
> them
> > from the appropriate remote repositories, for which there is certainly
> > Maven API, but I am also not familiar enough with it to tell you what it
> is
> > off the top of my head. Hopefully someone else here can comment in more
> > detail, and/or suggest alternative solutions here. In any case, if you
> > pursue this, it should work to test locally by installing the plugin into
> > your local repo cache using the "install" phase, and then using
> > "org.scijava:scijava-maven-plugin:1.0.1-SNAPSHOT" in your test POMs.
>
> I will give it a go. I've had somewhat poor experiences with the Maven
> APIs as they tend not to be documented too well. I may end up living
> with just not enforcing these things...
>
> M
>