Any way to specify a FileSet as command line parameter?
Asked Answered
S

2

10

I'm creating a Mojo which doesn't need a project to run.

I would like to use something similar to org.apache.maven.model.FileSet (providing multiple directories with includes and excludes) as a @parameter but my problem is that I need to be able to set those values using command line.

Any idea how to achieve this?

Silvanasilvano answered 24/7, 2015 at 22:52 Comment(0)
S
6

See:

POM

  <groupId>so</groupId>
  <artifactId>multiple-values-maven-plugin</artifactId>
  <version>1.0</version>
  <packaging>maven-plugin</packaging>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.3.3</version>
    </dependency>

    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.4</version>
      <scope>provided</scope><!-- annotations are needed only to build the plugin -->
    </dependency>
  </dependencies>

  <!-- This latest plugin has to be used if using Java 8 classes. -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-plugin-plugin</artifactId>
        <version>3.4</version>
      </plugin>
    </plugins>
  </build>

Mojo

package so;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.maven.model.FileSet;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

@Mojo( name = "values", requiresProject = false )
public class MultipleValuesMojo extends AbstractMojo
    {
    @Parameter( property = "array", required = true )
    private String[] array;

    @Parameter( property = "list", required = true )
    private List<String> list;

    @Parameter( property = "set", required = true )
    private String[] setElements;
    private Set<String> set;

    @Parameter( property = "map", required = true )
    private String[] mapEntries;
    private Map<String, String> map;

    @Parameter( property = "includes", required = true )
    private List<String> includes;

    @Parameter( property = "excludes", required = true )
    private List<String> excludes;

    @Override
    public void execute() throws MojoExecutionException
        {
        getLog().info( "Array: " + Arrays.toString( array ) );
        getLog().info( " List: " + list.toString() );
        set = Arrays.stream( setElements ).collect( Collectors.toSet() ); // with Java >=8
        addSetElementsToSet(); // with Java <8
        getLog().info( "  Set: " + set.toString() );
        map = Arrays.stream( mapEntries ).collect( Collectors.toMap( s -> s, s -> s ) ); // with Java >=8
        putMapEntriesToMap(); // with Java <8
        getLog().info( "  Map: " + map.toString() );

        getLog().info( "Includes: " + includes.toString() );
        getLog().info( "Excludes: " + excludes.toString() );

        FileSet fileSet = new FileSet();
        fileSet.setIncludes( includes );
        fileSet.setExcludes( excludes );
        getLog().info( " FileSet: " + fileSet.toString() );
        } // execute()

    private void addSetElementsToSet()
        {
        set = new HashSet<String>( setElements.length );
        for ( String entry : setElements )
            {
            set.add( entry );
            }
        } // addSetElementsToSet()

    private void putMapEntriesToMap()
        {
        map = new HashMap<String, String>( mapEntries.length );
        for ( String entry : mapEntries )
            {
            int equalsPosition = entry.indexOf( "=" );
            map.put(
                entry.substring( 0, equalsPosition ),
                entry.substring( equalsPosition + 1 ) );
            }
        } // putMapEntriesToMap()

    } // MultipleValuesMojo

Run

mvn so:multiple-value-maven-plugin:values
  -Darray=VALUE_1,VALUE_2,VALUE_3
  -Dlist=VALUE_1,VALUE_2,VALUE_3
  -Dset=VALUE_1,VALUE_2,VALUE_3
  -Dmap=KEY_1=VALUE_1,KEY_2=VALUE_2,KEY_3=VALUE_3
  -Dincludes=/,/usr/*
  -Dexcludes=/root,/tmp 

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building multiple-values-maven-plugin 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- multiple-values-maven-plugin:1.0:values (default-cli) @ multiple-values-maven-plugin ---
[INFO] Array: [VALUE_1, VALUE_2, VALUE_3]
[INFO]  List: [VALUE_1, VALUE_2, VALUE_3]
[INFO]   Set: [VALUE_3, VALUE_2, VALUE_1]
[INFO]   Map: {KEY_1=VALUE_1, KEY_3=VALUE_3, KEY_2=VALUE_2}
[INFO] Includes: [/, /usr/*]
[INFO] Excludes: [/root, /tmp]
[INFO]  FileSet: FileSet {directory: null, PatternSet [includes: {/, /usr/*}, excludes: {/root, /tmp}]}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.671 s
[INFO] Finished at: 2015-07-25T21:44:09+02:00
[INFO] Final Memory: 11M/115M
[INFO] ------------------------------------------------------------------------
Son answered 25/7, 2015 at 19:53 Comment(13)
Impressive example of how to pass parameters on the command line, except Fileset isn't one of them.Adnate
That actually doesn't answer the OP's problem even a little bit. Downvoting.Contrition
@kyl191 Is it better now?Son
@Contrition Is it better now?Son
@GeroldBroser it is closer, but you still have to create the FileSet object out of the includes and excludes. I mean, it's not a single parameter where you can define all the properties needed for a FileSet. Maybe the answer is that it's not possible?Favoritism
@MiguelFerreira I think "single parameter" vs. "properties" (in plural) is a contradiction in itself. (Remember, -D stands for define property.) Sure, one could pack multiple properties into a single parameter by using a separator and tokenizing the values inside the program, like -Dproperties=/,/usr/*|/root,/tmp but what's the point of that? It has the disadvantages that 1) it is not clear what is what on the command line at first sight, 2) the order of the values is vital, 3) it complicates the code by having to implement the tokenizing, and maybe even more I'm not thinking of atm.Son
@GeroldBroser This is not a matter of contriving examples and then arguing about their merits. It's a very practical question. For example, the jacoco maven plugin offers a goal named merge that takes a FileSet as a mandatory parameter. If you want to run that goal from the cmd line, you do need to specify 1 single property with the required value to instantiate the FileSet. Do you not? (see eclemma.org/jacoco/trunk/doc/merge-mojo.html#fileSets)Favoritism
@MiguelFerreira Jacoco's merge mojo makes use of Maven's Mapping Complex Objects and Mapping Lists (but requires a project the POM of which requires a fileSet parameter with its according structure). [to be continued]Son
@MiguelFerreira [continued] I'm pretty sure that an object's (hierarchical) member variables structure cannot be represented by one single property value other than by introducing and evaluating an according structure inside this property value yourself – by using JSON or XML, for instance, to extend the simpler example mentioned in my previous comment. So, yes, you're right insofar as it is not possbile easily and directly when passing values of complex objects via command line is desired.Son
@MiguelFerreira The jacoco.fileSets parameter has been removed finally due to "serious doubts that specification of this property via command line ever worked since initial implementation of "merge" mojo, because backing structure is not a plain String, but a complex object".Son
@GeroldBroserreinstatesMonica would you like to update your answer? I would then accept it as the answer to this question.Favoritism
@MiguelFerreira Update with what exactly? The question doesn't mention Jacoco. And how are you going to accept it? It's not your question but Cristiano's. Or ist this you, too?Son
@GeroldBroser yes you are right, it's not my question.Favoritism
S
1

Anyone looking for the solution:

-D<some-property>.fileSet=['path-to-fileset']

did the trick for me. It might require slight modification, depending on a plugin you're configuring, but you get the idea.

Tested on Maven 3.5.0

Steatopygia answered 16/1, 2020 at 10:39 Comment(4)
How do you declare <some-property> in the Mojo? Where did you get this <some-property>.fileSet=['path-to-fileset'] syntax? I couldn't make this work except with a <build>/<plugins>/<plugin>/<configuration>/<fileset>/<directory>${fileSet} and a <properties>/<fileSet>path-to-fileset declaration in the POM which can be overriden on the command line with -DfileSet=other-path-to-fileset. But that's not what the OP wants: "a Mojo which doesn't need a project to run".Son
I did some research to remember why exactly I needed this. This is the source of my answer: github.com/jeremylong/DependencyCheck/issues/…Steatopygia
Thank you for digging this out from 2018. However, after a lot of try & error with my own code here this syntax seems to be just fake. I tried the org.owasp:dependency-check-maven plugin with -DscanSet.fileSet=src/main and got a BUILD SUCCESS, too. Then I tried -DscanSet.fileSet=['src/main'] -X and found in the build log: [DEBUG] (f) scanSet = []. The normal output of the plugin doesn't show any difference with either parameter, so you don't recognize this without -X and searching through almost one thousand debug lines.Son
I created an according issue and it has been changed accordingly.Son

© 2022 - 2024 — McMap. All rights reserved.