Repository: quarkusio/quarkus
Issue: quarkus-maven-plugin does not obey --file -f command line flag

**Describe the bug**
When --file is specified on command line (e.g. `mvn --file pom2.xml quarkus:dev`) it is ignored. Quarkus plugin either loads pom.xml or complains that there is no pom.xml.

**Expected behavior**
Plugin should use specified file.

**Actual behavior**
Plugin ignores the flag and always uses pom.xml.


**To Reproduce**
Steps to reproduce the behavior:
1. Rename pom.xml to pom2.xml.
2. mvn --file pom2.xml quarkus:dev

[ERROR] The goal you specified requires a project to execute but there is no POM in this directory (D:\\Atron\\repo\\asc\\import-aservice-quarkus). Please verify you invoked Maven from the correct directory. -> [Help 1]

**Configuration**

Not relevant.

```properties
# Add your application.properties here, if applicable.

```

**Screenshots**
(If applicable, add screenshots to help explain your problem.)

**Environment (please complete the following information):**
 - Output of `uname -a` or `ver`: Microsoft Windows [Version 10.0.18362.418]
 - Output of `java -version`: 
      java version "1.8.0_221"
      Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
      Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
 - GraalVM version (if different from Java): 
 - Quarkus version or git rev: 0.26.1

**Additional context**
(Add any other context about the problem here.)


Changed files:
independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java
integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java
independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java
independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java
devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java

diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
index 1374f6fc1f7..9ea99983b50 100644
--- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
+++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
@@ -635,16 +635,16 @@ void prepare(final boolean triggerCompile) throws Exception {
             setKotlinSpecificFlags(devModeContext);
             final LocalProject localProject;
             if (noDeps) {
-                localProject = LocalProject.load(outputDirectory.toPath());
+                localProject = LocalProject.load(project.getModel().getPomFile().toPath());
                 addProject(devModeContext, localProject, true);
-                pomFiles.add(localProject.getDir().resolve("pom.xml"));
+                pomFiles.add(localProject.getRawModel().getPomFile().toPath());
                 devModeContext.getLocalArtifacts()
                         .add(new AppArtifactKey(localProject.getGroupId(), localProject.getArtifactId(), null, "jar"));
             } else {
-                localProject = LocalProject.loadWorkspace(outputDirectory.toPath());
+                localProject = LocalProject.loadWorkspace(project.getModel().getPomFile().toPath());
                 for (LocalProject project : filterExtensionDependencies(localProject)) {
                     addProject(devModeContext, project, project == localProject);
-                    pomFiles.add(project.getDir().resolve("pom.xml"));
+                    pomFiles.add(project.getRawModel().getPomFile().toPath());
                     devModeContext.getLocalArtifacts()
                             .add(new AppArtifactKey(project.getGroupId(), project.getArtifactId(), null, "jar"));
                 }
diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java
index 0c69f49aec1..2593bcea18d 100644
--- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java
+++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java
@@ -208,8 +208,9 @@ private BootstrapMavenContext createBootstrapMavenContext() throws AppModelResol
             config.setOffline(offline);
         }
         // Currently projectRoot may be an app location which is not exactly a Maven project dir
-        if (projectRoot != null && Files.isDirectory(projectRoot) && Files.exists(projectRoot.resolve("pom.xml"))) {
-            config.setCurrentProject(projectRoot.toString());
+        final Path projectPom = config.getPomForDirOrNull(projectRoot);
+        if (projectPom != null) {
+            config.setCurrentProject(projectPom.toString());
         }
         config.setWorkspaceDiscovery(isWorkspaceDiscoveryEnabled());
         return mvnContext = new BootstrapMavenContext(config);
diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java
index 882888bd107..607885d1e13 100644
--- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java
+++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java
@@ -126,7 +126,7 @@ public BootstrapMavenContext(BootstrapMavenContextConfig<?> config)
          * This means the values that are available in the config should be set before
          * the instance method invocations.
          */
-        this.alternatePomName = config.alternativePomName;
+        this.alternatePomName = config.alternatePomName;
         this.artifactTransferLogging = config.artifactTransferLogging;
         this.localRepo = config.localRepo;
         this.offline = config.offline;
@@ -134,6 +134,7 @@ public BootstrapMavenContext(BootstrapMavenContextConfig<?> config)
         this.repoSession = config.repoSession;
         this.remoteRepos = config.remoteRepos;
         this.remoteRepoManager = config.remoteRepoManager;
+        this.cliOptions = config.cliOptions;
         if (config.currentProject != null) {
             this.currentProject = config.currentProject;
             this.currentPom = currentProject.getRawModel().getPomFile().toPath();
@@ -655,32 +656,7 @@ private Path resolveCurrentPom() {
         final String basedirProp = PropertyUtils.getProperty(BASEDIR);
         if (basedirProp != null) {
             // this is the actual current project dir
-            final Path basedir = Paths.get(basedirProp);
-
-            // if the basedir matches the parent of the alternate pom, it's the alternate pom
-            if (alternatePom != null
-                    && alternatePom.isAbsolute()
-                    && alternatePom.getParent().equals(basedir)) {
-                return alternatePom;
-            }
-            // even if the alternate pom has been specified we try the default pom.xml first
-            // since unlike Maven CLI we don't know which project originated the build
-            Path pom = basedir.resolve("pom.xml");
-            if (Files.exists(pom)) {
-                return pom;
-            }
-
-            // if alternate pom path has a single element we can try it
-            // if it has more, it won't match the basedir
-            if (alternatePom != null && !alternatePom.isAbsolute() && alternatePom.getNameCount() == 1) {
-                pom = basedir.resolve(alternatePom);
-                if (Files.exists(pom)) {
-                    return pom;
-                }
-            }
-
-            // give up
-            return null;
+            return getPomForDirOrNull(Paths.get(basedirProp), alternatePom);
         }
 
         // we are not in the context of a Maven build
@@ -697,6 +673,33 @@ private Path resolveCurrentPom() {
         return Files.exists(pom) ? pom : null;
     }
 
+    static Path getPomForDirOrNull(final Path basedir, Path alternatePom) {
+        // if the basedir matches the parent of the alternate pom, it's the alternate pom
+        if (alternatePom != null
+                && alternatePom.isAbsolute()
+                && alternatePom.getParent().equals(basedir)) {
+            return alternatePom;
+        }
+        // even if the alternate pom has been specified we try the default pom.xml first
+        // since unlike Maven CLI we don't know which project originated the build
+        Path pom = basedir.resolve("pom.xml");
+        if (Files.exists(pom)) {
+            return pom;
+        }
+
+        // if alternate pom path has a single element we can try it
+        // if it has more, it won't match the basedir
+        if (alternatePom != null && !alternatePom.isAbsolute() && alternatePom.getNameCount() == 1) {
+            pom = basedir.resolve(alternatePom);
+            if (Files.exists(pom)) {
+                return pom;
+            }
+        }
+
+        // give up
+        return null;
+    }
+
     private static Path pomXmlOrNull(Path path) {
         if (Files.isDirectory(path)) {
             path = path.resolve("pom.xml");
diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java
index 017c20c249d..26bd0cfad2d 100644
--- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java
+++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java
@@ -1,7 +1,11 @@
 package io.quarkus.bootstrap.resolver.maven;
 
+import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions;
 import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject;
 import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.List;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
@@ -18,9 +22,10 @@
     protected RepositorySystemSession repoSession;
     protected List<RemoteRepository> remoteRepos;
     protected RemoteRepositoryManager remoteRepoManager;
-    protected String alternativePomName;
+    protected String alternatePomName;
     protected File userSettings;
     protected boolean artifactTransferLogging = true;
+    protected BootstrapMavenOptions cliOptions;
 
     /**
      * Local repository location
@@ -133,7 +138,7 @@ public T setRemoteRepositoryManager(RemoteRepositoryManager remoteRepoManager) {
      */
     @SuppressWarnings("unchecked")
     public T setCurrentProject(String currentProject) {
-        this.alternativePomName = currentProject;
+        this.alternatePomName = currentProject;
         return (T) this;
     }
 
@@ -161,4 +166,24 @@ public T setArtifactTransferLogging(boolean artifactTransferLogging) {
         this.artifactTransferLogging = artifactTransferLogging;
         return (T) this;
     }
+
+    /**
+     * Resolves a POM file for a basedir.
+     *
+     * @param basedir project's basedir
+     * @return POM file for the basedir or null, if it could not be resolved
+     */
+    public Path getPomForDirOrNull(Path basedir) {
+        if (!Files.isDirectory(basedir)) {
+            return null;
+        }
+        final String altPom = alternatePomName == null
+                ? getInitializedCliOptions().getOptionValue(BootstrapMavenOptions.ALTERNATE_POM_FILE)
+                : alternatePomName;
+        return BootstrapMavenContext.getPomForDirOrNull(basedir, altPom == null ? null : Paths.get(altPom));
+    }
+
+    private BootstrapMavenOptions getInitializedCliOptions() {
+        return cliOptions == null ? cliOptions = BootstrapMavenOptions.newInstance() : cliOptions;
+    }
 }
diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java
index 1c86986a3e3..07b495619ee 100644
--- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java
+++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java
@@ -148,9 +148,9 @@ public File findArtifact(Artifact artifact) {
 
             // otherwise, this project hasn't been built yet
         } else if (type.equals(AppArtifactCoords.TYPE_POM)) {
-            final Path path = lp.getDir().resolve("pom.xml");
-            if (Files.exists(path)) {
-                return path.toFile();
+            final File pom = lp.getRawModel().getPomFile();
+            if (pom.exists()) {
+                return pom;
             }
         }
         return null;
diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
index 93266f33d21..3b739c23abb 100644
--- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
+++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
@@ -166,6 +166,54 @@ public void testThatSourceChangesAreDetectedOnPomChange() throws Exception {
 
     }
 
+    @Test
+    public void testAlternatePom() throws Exception {
+        testDir = initProject("projects/classic", "projects/project-classic-alternate-pom");
+
+        File pom = new File(testDir, "pom.xml");
+        if (!pom.exists()) {
+            throw new IllegalStateException("Failed to locate project's pom.xml at " + pom);
+        }
+        final String alternatePomName = "alternate-pom.xml";
+        File alternatePom = new File(testDir, alternatePomName);
+        if (alternatePom.exists()) {
+            alternatePom.delete();
+        }
+        pom.renameTo(alternatePom);
+        if (pom.exists()) {
+            throw new IllegalStateException(pom + " was expected to be renamed to " + alternatePom);
+        }
+        runAndCheck("-f", alternatePomName);
+
+        // Edit a Java file too
+        final File javaSource = new File(testDir, "src/main/java/org/acme/HelloResource.java");
+        final String uuid = UUID.randomUUID().toString();
+        filter(javaSource, Collections.singletonMap("return \\"hello\\";", "return \\"hello " + uuid + "\\";"));
+
+        // edit the application.properties too
+        final File applicationProps = new File(testDir, "src/main/resources/application.properties");
+        filter(applicationProps, Collections.singletonMap("greeting=bonjour", "greeting=" + uuid + ""));
+
+        // Now edit the pom.xml to trigger the dev mode restart
+        filter(alternatePom, Collections.singletonMap("<!-- insert test dependencies here -->",
+                "        <dependency>\\n" +
+                        "            <groupId>io.quarkus</groupId>\\n" +
+                        "            <artifactId>quarkus-smallrye-openapi</artifactId>\\n" +
+                        "        </dependency>"));
+
+        // Wait until we get the updated responses
+        await()
+                .pollDelay(100, TimeUnit.MILLISECONDS)
+                .atMost(1, TimeUnit.MINUTES)
+                .until(() -> DevModeTestUtils.getHttpResponse("/app/hello").contains("hello " + uuid));
+
+        await()
+                .pollDelay(100, TimeUnit.MILLISECONDS)
+                .atMost(1, TimeUnit.MINUTES)
+                .until(() -> DevModeTestUtils.getHttpResponse("/app/hello/greeting").contains(uuid));
+
+    }
+
     @Test
     public void testThatTheApplicationIsReloadedOnPomChange() throws MavenInvocationException, IOException {
         testDir = initProject("projects/classic", "projects/project-classic-run-pom-change");