Właściwość Maven2, która wskazuje katalog nadrzędny

105

Mam projekt wielomodułowy, taki jak ten:

main-project/
    module1/
    module2/
        sub-module1/
        sub-module2/
        sub-module3/
        ...
    module3/
    module4/
    ...

Muszę zdefiniować zestaw właściwości (które są zależne od środowiska, w którym chcę wydać mój projekt) w Maven2. Nie będę używać, <properties>ponieważ jest wiele właściwości ... Dlatego używam wtyczki Properties Maven2 .

Pliki właściwości znajdują się w main-project/katalogu. Jak mogę ustawić poprawny katalog w głównym pom.xml, aby wskazać każdemu dziecku, gdzie znaleźć plik właściwości?

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <file>???/env_${env}.properties</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

Jeśli <file>env_${env}.properties</file>ustawię tylko , to gdy Maven2 kompiluje pierwszy moduł, nie znajdzie main-project/env_dev.propertiespliku. Jeśli ustawię <file>../env_${env}.properties</file>, błąd zostanie podniesiony na poziomie nadrzędnym lub na dowolnym poziomie podmodułu ...

Romain Linsolas
źródło
1
Po prostu użyj${maven.multiModuleProjectDirectory}
qoomon

Odpowiedzi:

164

Spróbuj ustawić właściwość w każdym pomie, aby znaleźć główny katalog projektu.

U rodzica:

<properties>
    <main.basedir>${project.basedir}</main.basedir>
</properties>

U dzieci:

<properties>
    <main.basedir>${project.parent.basedir}</main.basedir>
</properties>

W wnukach:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>
Glina
źródło
19
Czy te wstępnie ustawione właściwości zostały usunięte? ${parent.basedir}już nie analizuje niczego w 3.0.4 ...
matt5784
7
Tak, to nie działa. $ {project.parent.basedir} zwraca wartość null.
Jared
22
Odniosłem sukces, ${project.basedir}/..ale tak naprawdę działa to tylko w projektach wielomodułowych, które są w ścisłej hierarchii katalogów.
Jonathan
90
Westchnienie. Niewiarygodne, że Maven tak to utrudnia.
Stefan Haberl
5
Podobnie jak Jonathan powyżej, muszę używać ścieżek względnych, ale czuję, że najlepiej jest użyć takiej file.separatorzmiennej<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired
29

Przynajmniej w aktualnej wersji mavena (3.6.0) możesz z niego skorzystać ${maven.multiModuleProjectDirectory}

qoomon
źródło
2
Próbuję znaleźć dokument na ten temat i wydaje się, że jest to przeznaczone do użytku wewnętrznego, może zostać usunięte / zmienione w przyszłości MNG-6589
Greg Domjan
Jak to wykorzystać? -1
hey_you
Jest to własność, z której możesz korzystać tak jak z innymi.
qoomon
nie jestem pewien, czy powinniśmy użyć tej odpowiedzi. Zgodnie z tym biletem jest on wewnętrzny i może przejść w dowolnym momencie. Dlatego też nie jest to nigdzie udokumentowane. Wciąż nie ma czystego rozwiązania
Hilikus
21

Użyj katalogu-maven-plugin z katalogiem celu .

W przeciwieństwie do innych sugestii:

  • To rozwiązanie sprawdza się w projektach wielomodułowych.
  • Działa niezależnie od tego, czy budujesz cały projekt, czy też podmoduł.
  • Działa niezależnie od tego, czy uruchamiasz maven z folderu głównego, czy z modułu podrzędnego.
  • Nie ma potrzeby ustawiania właściwości ścieżki względnej w każdym module podrzędnym!

Wtyczka pozwala ustawić wybraną właściwość na ścieżkę bezwzględną dowolnego modułu projektu. W moim przypadku ustawiłem go na moduł główny ... W moim projekcie root pom:

<plugin>
    <groupId>org.commonjava.maven.plugins</groupId>
    <artifactId>directory-maven-plugin</artifactId>
    <version>0.1</version>
    <executions>
        <execution>
            <id>directories</id>
            <goals>
                <goal>directory-of</goal>
            </goals>
            <phase>initialize</phase>
            <configuration>
                <property>myproject.basedir</property>
                <project>
                    <groupId>com.my.domain</groupId>
                    <artifactId>my-root-artifact</artifactId>
                </project>
            </configuration>
        </execution>
    </executions>
</plugin>

Odtąd $ {myproject.basedir} w każdym podmodułu pom zawsze ma ścieżkę do modułu głównego projektu. Oczywiście możesz ustawić właściwość na dowolny moduł, nie tylko na katalog główny ...

iskrzący
źródło
Nie testuj fazy. Spowodowało mi wiele problemów. Działa świetnie, jak pokazano powyżej.
ElectronicBlacksmith
15

Znalazłem rozwiązanie, aby rozwiązać mój problem: przeszukuję pliki właściwości za pomocą wtyczki Groovy Maven.

Ponieważ mój plik właściwości jest koniecznie w bieżącym katalogu, w ../ lub .. / .., napisałem mały kod Groovy, który sprawdza te trzy foldery.

Oto wyciąg z mojego pom.xml:

<!-- Use Groovy to search the location of the properties file. -->
<plugin>
    <groupId>org.codehaus.groovy.maven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.0-rc-5</version>
    <executions>
        <execution>
            <phase>validate</phase>
            <goals>
                <goal>execute</goal>
            </goals>
            <configuration>
                <source>
                    import java.io.File;
                    String p = project.properties['env-properties-file'];
                    File f = new File(p); 
                    if (!f.exists()) {
                        f = new File("../" + p);
                        if (!f.exists()) {
                            f = new File("../../" + p);
                        }
                    }
                    project.properties['env-properties-file-by-groovy'] = f.getAbsolutePath();
            </source>
            </configuration>
        </execution>
    </executions>
</plugin>
<!-- Now, I can load the properties file using the new 'env-properties-file-by-groovy' property. -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <file>${env-properties-file-by-groovy}</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

To działa, ale nie podoba mi się to.

Więc jeśli masz lepsze rozwiązanie, nie wahaj się pisać!

Romain Linsolas
źródło
12

Tak więc problem, jaki widzę, polega na tym, że nie można uzyskać bezwzględnej ścieżki do katalogu nadrzędnego w maven.

<rant> Słyszałem, że mówiono o tym jako o anty-wzorcu , ale dla każdego anty-wzorca istnieje dla niego prawdziwy, uzasadniony przypadek użycia i mam dość maven, który mówi mi, że mogę podążać tylko za ich wzorcami. </ rant>

Tak więc praca, którą znalazłem, polegała na użyciu antrun. Spróbuj tego w podrzędnym pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.7</version>
    <executions>
        <execution>
            <id>getMainBaseDir</id>
            <phase>validate</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <exportAntProperties>true</exportAntProperties>
                <target>
                    <!--Adjust the location below to your directory structure -->
                    <property name="main.basedir" location="./.." />
                    <echo message="main.basedir=${main.basedir}"/>
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

Jeśli biegniesz mvn verify, powinieneś zobaczyć coś takiego:

main:
     [echo] main.basedir=C:\src\parent.project.dir.name

Możesz następnie użyć ${main.basedir}dowolnej innej wtyczki, itp. Zajęło mi to trochę czasu, zanim to zrozumiałem, więc mam nadzieję, że pomoże to komuś innemu.

Jared
źródło
jak przekazać to do maven-surefire-plugin?
Kalpesh Soni
7

Inna alternatywa:

w pompie rodzicielskim użyj:

<properties>
   <rootDir>${session.executionRootDirectory}</rootDir>
<properties>

W pompkach dziecięcych możesz odwołać się do tej zmiennej.

Główne zastrzeżenie: Zmusza cię do wykonywania polecenia zawsze z głównego katalogu nadrzędnego pom. Następnie, jeśli chcesz uruchamiać polecenia (na przykład test) tylko dla określonego modułu, użyj następującej składni:

test mvn --projects

Konfiguracja surefire do parametryzacji zmiennej „path_to_test_data” może zatem wyglądać następująco:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire.plugin.version}</version>
    <configuration>
        <systemPropertyVariables>
            <path_to_test_data>${rootDir}/../testdata</path_to_test_data>
        </systemPropertyVariables>
    </configuration>
</plugin>
Francois Marot
źródło
5

Poniższy mały profil zadziałał dla mnie. Potrzebowałem takiej konfiguracji dla CheckStyle, którą umieściłem w configkatalogu w katalogu głównym projektu, dzięki czemu mogę go uruchomić z modułu głównego oraz z modułów podrzędnych.

<profile>
    <id>root-dir</id>
    <activation>
        <file>
            <exists>${project.basedir}/../../config/checkstyle.xml</exists>
        </file>
    </activation>
    <properties>
        <project.config.path>${project.basedir}/../config</project.config.path>
    </properties>
</profile>

To nie zadziała dla zagnieżdżonych modułów, ale jestem pewien, że można to zmodyfikować, używając kilku profili z różnymi exists. (Nie mam pojęcia, dlaczego w tagu weryfikacyjnym powinno znajdować się „../ ..”, a po prostu „..” w samej nadpisanej właściwości, ale działa to tylko w ten sposób).

Vic
źródło
Nie wiem, dlaczego to działa (dodatkowe .../), ale wydaje się, że to najczystsze rozwiązanie (ja też miałem problemy z konfiguracją checkstyle.xml)
RockMeetHardplace
5

W moim przypadku działa to tak:

...
<properties>
  <main_dir>${project.parent.relativePath}/..</main_dir>
</properties>
...

<plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0-alpha-1</version>
        <executions>
          <execution>
            <phase>initialize</phase>
            <goals>
              <goal>read-project-properties</goal>
            </goals>
            <configuration>
              <files>
                 <file>${main_dir}/maven_custom.properties</file>
              </files>
            </configuration>
          </execution>
        </executions>
</plugin>
ilya1245
źródło
3

Znalazłem rozwiązanie tego problemu: użyj $ {parent.relativePath}

<parent>
    <artifactId>xxx</artifactId>
    <groupId>xxx</groupId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>..</relativePath>
</parent>
<build>
    <filters>
        <filter>${parent.relativePath}/src/main/filters/filter-${env}.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
Caille
źródło
2
To nie zawsze może być bezpieczne; $ {parent.relativePath} może zawierać nazwę pliku, np. „../pom.xml”
pimlottc
3

Jesteś w projekcie C, projekt C to podmoduł z B, a B to podmoduł z A. Próbujesz dotrzeć do src/test/config/etckatalogu modułu D z projektu C. D jest również podmodułem z A. Poniższe wyrażenie umożliwia uzyskanie ścieżki URI:

-Dparameter=file:/${basedir}/../../D/src/test/config/etc
fatih tekin
źródło
2
<plugins>
  <plugin>
    <groupId>org.codehaus.groovy.maven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.0</version>
    <executions>
      <execution>
        <phase>validate</phase>
        <goals>
          <goal>execute</goal>
        </goals>
        <configuration>
          <source>
            import java.io.File
            project.properties.parentdir = "${pom.basedir}"
            while (new File(new File(project.properties.parentdir).parent, 'pom.xml').exists()) {
                project.properties.parentdir = new File(project.properties.parentdir).parent
            }
          </source>
        </configuration>
      </execution>
    </executions>
  </plugin>
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-2</version>
    <executions>
      <execution>
        <phase>initialize</phase>
        <goals>
          <goal>read-project-properties</goal>
        </goals>
        <configuration>
          <files>
            <file>${parentdir}/build.properties</file>
          </files>
        </configuration>
      </execution>
    </executions>
  </plugin>
  ...

źródło
1

W odpowiedzi na inne pytanie pokazałem, jak można rozszerzyć wtyczkę maven-properties-plugin o zewnętrzne deskryptory właściwości zdefiniowane w zależnościach Mavena.

Możesz rozszerzyć ten pomysł, aby mieć wiele plików JAR deskryptorów, każdy z nazwą środowiska jako część artifactId, zawierający $ {env} .properties. Następnie możesz użyć właściwości, aby wybrać odpowiedni jar i plik właściwości, na przykład:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>properties-ext-maven-plugin</artifactId>
  <version>0.0.1</version>
  <executions>
    <execution>
      <id>read-properties</id>
      <phase>initialize</phase>
      <goals>
        <goal>read-project-properties</goal>
      </goals>
    </execution>
  </executions>                              
  <configuration>
    <filePaths>
      <!--assume the descriptor project has a file in the root of the jar -->
      <filePath>${env}.properties</filePath>
    </filePaths>
  </configuration> 
  <dependencies>
    <!-- reference the properties jar for the particular environment-->
    <dependency>
      <groupId>some.descriptor.group</groupId>
      <artifactId>env-${env}-descriptor</artifactId>
      <version>0.0.1</version>
    </dependency>
  </dependencies>
</plugin>
Bogaty sprzedawca
źródło
1

Po prostu ulepszam groovy skrypt z góry, aby zapisać właściwość w głównym pliku właściwości nadrzędnych:

import java.io.*;
String p = project.properties['env-properties-file']
File f = new File(p)
if (f.exists()) {
try{
FileWriter fstream = new FileWriter(f.getAbsolutePath())
BufferedWriter out = new BufferedWriter(fstream)
String propToSet = f.getAbsolutePath().substring(0, f.getAbsolutePath().lastIndexOf(File.separator))
if (File.separator != "/") {
propToSet = propToSet.replace(File.separator,File.separator+File.separator+File.separator)
}
out.write("jacoco.agent = " + propToSet + "/lib/jacocoagent.jar")
out.close()
}catch (Exception e){
}
}
String ret = "../"
while (!f.exists()) {
f = new File(ret + p)
ret+= "../"
}
project.properties['env-properties-file-by-groovy'] = f.getAbsolutePath()
Tcharl
źródło
0

Myślę, że jeśli użyjesz wzorca rozszerzenia użytego w przykładzie dla wtyczki findbugs i multimodułu, możesz być w stanie ustawić globalne właściwości związane ze ścieżkami bezwzględnymi. Używa góry

przykład dla wielu modułów

Pom najwyższego poziomu ma niepowiązany projekt build-config i element nadrzędny aplikacji dla modułów projektu wielomodułowego. Element nadrzędny aplikacji używa rozszerzenia, aby połączyć się z projektem build-config i uzyskać z niego zasoby. Służy do przenoszenia wspólnych plików konfiguracyjnych do modułów. Może to być również kanał dla właściwości. Możesz zapisać główny katalog do pliku właściwości używanego przez build-config. (wydaje się zbyt skomplikowane)

Problem polega na tym, że do projektu wielomodułowego należy dodać nowy najwyższy poziom, aby to zadziałało. Próbowałem przejść na stronę z naprawdę niepowiązanym projektem build-config, ale był niezdarny i wydawał się kruchy.

Peter Kahn
źródło
0

To rozszerza odpowiedź Romaintaza, która jest niesamowita, ponieważ rozwiązuje problem, a także wyraźnie wskazuje na brakującą funkcjonalność Mavena. Wybrałem późniejszą wersję wtyczki i dodałem przypadek, w którym projekt może mieć więcej niż 3 poziomy głębokości.

<pluginManagement>
  <plugins>
    ..
    <plugin>
      <groupId>org.codehaus.gmaven</groupId>
      <artifactId>groovy-maven-plugin</artifactId>
      <version>2.0</version>
    </plugin>
    ..
  </plugins>
</pluginManagement>

Zdecydowałem się nie używać właściwości do definiowania nazwy pliku. Zwróć uwagę, że jeśli plik build.properties nie zostanie znaleziony, będzie się obracał w nieskończoność. Dodałem wykrywanie .git dir, ale nie chciałem zbytnio komplikować odpowiedzi, więc nie jest tutaj pokazany.

  <plugin>
      <groupId>org.codehaus.gmaven</groupId>
      <artifactId>groovy-maven-plugin</artifactId>
      <executions>
          <execution>
              <phase>validate</phase>
              <goals>
                  <goal>execute</goal>
              </goals>
              <configuration>
                 <source>
                    import java.io.File;
                    String p = "build.properties";
                    while(true) {
                      File f = new File(p); 
                      if(f.exists()) {
                        project.properties['project-properties-file'] = f.getAbsolutePath();
                        break;
                      }
                      else {
                        p = "../${p}";
                      }
                    }
                </source>
              </configuration>
          </execution>
      </executions>
  </plugin>
Bruce Edge
źródło
0

Podobny problem musiałem rozwiązać dla lokalnego repozytorium umieszczonego w głównym projekcie projektu wielomodułowego. Zasadniczo prawdziwą ścieżką był ${basedir}/ lib. W końcu zdecydowałem się na to w moim parent.pom:

<repository>
    <id>local-maven-repo</id>
    <url>file:///${basedir}/${project.parent.relativePath}/lib</url>
</repository>

To basedirzawsze pokazuje aktualny moduł lokalny, nie ma sposobu na zdobycie ścieżki do projektu "głównego" (wstyd Mavena). Niektóre z moich modułów podrzędnych są o jeden kierunek głębsze, niektóre o dwa kanały głębsze, ale wszystkie z nich są modułami bezpośrednimi elementu nadrzędnego, który definiuje adres URL repozytorium.

Więc to nie rozwiązuje ogólnie problemu. Zawsze możesz połączyć to z zaakceptowaną odpowiedzią Claya i zdefiniować inną właściwość - działa dobrze i musi zostać ponownie zdefiniowana tylko w przypadkach, gdy wartość z parent.pomnie jest wystarczająco dobra. Lub możesz po prostu zmienić konfigurację wtyczki - co robisz tylko w artefaktach POM (rodzicach innych podmodułów). Wartość wyodrębniona do właściwości jest prawdopodobnie lepsza, jeśli potrzebujesz jej w większej liczbie miejsc, zwłaszcza gdy nic w konfiguracji wtyczki się nie zmienia.

Użycie basedirw wartości było tutaj istotną częścią, ponieważ URLfile://${project.parent.relativePath}/lib nie chciał załatwić sprawy (usunąłem jeden ukośnik, aby uczynić go względnym). Konieczne było użycie własności, która daje mi dobrą ścieżkę absolutną, a następnie przejście względem niej względem niej.

Jeśli ścieżka nie jest adresem URL / URI, prawdopodobnie upuszczenie nie jest takim problemem basedir.

virgo47
źródło
0

Uzyskałem dostęp do powyższego katalogu za pomocą $ {basedir} .. \ src \

Secelean Monica
źródło
1
tak ale nie. W przypadku sub-module1będzie wskazywał katalog module2, a nie plik main-project.
Romain Linsolas
-1

Próbowałeś ../../env_${env}.properties ?

Zwykle wykonujemy następujące czynności, gdy moduł2 znajduje się na tym samym poziomie co podmoduły

<modules>
    <module>../sub-module1</module>
    <module>../sub-module2</module>
    <module>../sub-module3</module>
</modules>

Myślę, że ../ .. pozwoliłby ci podskoczyć o dwa poziomy. Jeśli nie, możesz skontaktować się z autorami wtyczki i sprawdzić, czy jest to znany problem.

sal
źródło
Jeśli wstawię ../../env.props do głównego pom.xml, wtedy pojawi się błąd, gdy Maven2 spróbuje zbudować główny pom i cały modułX. Ta konfiguracja będzie faktycznie
działać