#
tokens: 7350/50000 10/10 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .dockerignore
├── .gitignore
├── .mvn
│   └── wrapper
│       ├── .gitignore
│       ├── maven-wrapper.properties
│       └── MavenWrapperDownloader.java
├── mvnw
├── mvnw.cmd
├── pom.xml
├── README.md
└── src
    └── main
        ├── docker
        │   ├── Dockerfile.jvm
        │   ├── Dockerfile.legacy-jar
        │   ├── Dockerfile.native
        │   └── Dockerfile.native-micro
        ├── java
        │   └── org
        │       └── acme
        │           └── Backstage.java
        └── resources
            └── application.properties
```

# Files

--------------------------------------------------------------------------------
/.mvn/wrapper/.gitignore:
--------------------------------------------------------------------------------

```
1 | maven-wrapper.jar
2 | 
```

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
1 | *
2 | !target/*-runner
3 | !target/*-runner.jar
4 | !target/lib/*
5 | !target/quarkus-app/*
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | #Maven
 2 | target/
 3 | pom.xml.tag
 4 | pom.xml.releaseBackup
 5 | pom.xml.versionsBackup
 6 | release.properties
 7 | .flattened-pom.xml
 8 | 
 9 | # Eclipse
10 | .project
11 | .classpath
12 | .settings/
13 | bin/
14 | 
15 | # IntelliJ
16 | .idea
17 | *.ipr
18 | *.iml
19 | *.iws
20 | 
21 | # NetBeans
22 | nb-configuration.xml
23 | 
24 | # Visual Studio Code
25 | .vscode
26 | .factorypath
27 | 
28 | # OSX
29 | .DS_Store
30 | 
31 | # Vim
32 | *.swp
33 | *.swo
34 | 
35 | # patch
36 | *.orig
37 | *.rej
38 | 
39 | # Local environment
40 | .env
41 | 
42 | # Plugin directory
43 | /.quarkus/cli/plugins/
44 | # TLS Certificates
45 | .certs/
46 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Backstage MCP
  2 | 
  3 | This is an example of using [Backstage](https://backstage.io) with [MCP](https://github.com/Backstage/mcp) via [Quarkus Backstage](https://github.com/quarkiverse/quarkus-backstage).
  4 | The server has been tested with [Goose](https://github.com/block/goose). See below for details. 
  5 | 
  6 | ## Features
  7 | 
  8 | - List available Backstage templates
  9 | - Instantiate a template from the command line
 10 | 
 11 | ## Requirements
 12 | A [Backstage](https://backstage.io) installation is required.
 13 | The installation needs to have enabled [Service to Service](https://backstage.io/docs/auth/service-to-service-auth/) communication.
 14 | Users need to have access of the token used for such communication. The `yaml` snippet below shows where and how it's setup.
 15 | 
 16 | ```yaml
 17 | app:
 18 | # ...
 19 | backend:
 20 |   # ... 
 21 |   auth:
 22 |     # ...
 23 |     externalAccess:
 24 |       - type: static
 25 |         options:
 26 |           token: <put your token here>
 27 |           subject: curl-requests
 28 | ```
 29 | 
 30 | ## Anatomy
 31 | 
 32 | ### Dependencies 
 33 | 
 34 | The project is using:
 35 | 
 36 | ```xml
 37 |         <dependency>
 38 |             <groupId>io.quarkiverse.mcp</groupId>
 39 |             <artifactId>quarkus-mcp-server-stdio</artifactId>
 40 |             <version>1.0.0.Alpha5</version>
 41 |         </dependency>
 42 | ```        
 43 | 
 44 | for implementing an mcp server that reads from stdin and writes to stdout.
 45 | 
 46 | It also uses:
 47 | 
 48 | ```xml
 49 |         <dependency>
 50 |             <groupId>io.quarkiverse.backstage</groupId>
 51 |             <artifactId>quarkus-backstage</artifactId>
 52 |             <version>0.4.1</version>
 53 |         </dependency>
 54 | 
 55 | ```
 56 | 
 57 | For talking to the [Backstage](https://backstage.io) API.
 58 | 
 59 | ### The implementation
 60 | 
 61 | The implementation is pretty straight forward, as there is a tiny file needed:
 62 | [[src/main/java/org/acme/Backstage.java]]
 63 | 
 64 | ## Setting up goose
 65 | 
 66 | [Goose](https://github.com/block/goose) is an local AI agent that runs as an interactive shell and is supports plugins (including mcp servers).
 67 | 
 68 | To setup goose so that it uses this mcp server add the followng extension to your config.yaml:
 69 | 
 70 | ```yaml
 71 |   quarkus-backstage-mcp:
 72 |     args:
 73 |     - --quiet
 74 |     - /home/iocanel/demo/backstage-mcp/target/quarkus-app/quarkus-run.jar
 75 |     cmd: jbang
 76 |     enabled: true
 77 |     envs: {}
 78 |     name: quarkus-backstage-mcp
 79 |     type: stdio
 80 | ```
 81 | 
 82 | ### Sample prompts
 83 | 
 84 | #### Listing the templates
 85 | ```bash
 86 | list all the available backstage templates
 87 | ```
 88 | 
 89 | ### Instantiating a template
 90 | 
 91 | To instantiate a template one needs values.yaml file containing the template parameters to use.
 92 | The default values can be extracted from the template using the backstage CLI:
 93 | 
 94 | ```sh
 95 | quarkus backstage template info --show-default-values <template name>
 96 | ```
 97 | 
 98 | The output can be saved to a file, say `values.yaml` and then used to instantiate the template from a goose session:
 99 | 
100 | ```sh
101 | create a new project from template <template name> using values from values.yaml
102 | ```
103 | 
104 | 
```

--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------

```
1 | 
```

--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------

```
 1 | # Licensed to the Apache Software Foundation (ASF) under one
 2 | # or more contributor license agreements.  See the NOTICE file
 3 | # distributed with this work for additional information
 4 | # regarding copyright ownership.  The ASF licenses this file
 5 | # to you under the Apache License, Version 2.0 (the
 6 | # "License"); you may not use this file except in compliance
 7 | # with the License.  You may obtain a copy of the License at
 8 | #
 9 | #   http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied.  See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | wrapperVersion=3.3.2
18 | distributionType=source
19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
20 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
```

--------------------------------------------------------------------------------
/src/main/java/org/acme/Backstage.java:
--------------------------------------------------------------------------------

```java
 1 | package org.acme;
 2 | 
 3 | import java.util.List;
 4 | 
 5 | 
 6 | import io.quarkiverse.backstage.client.BackstageClient;
 7 | import io.quarkiverse.backstage.common.utils.Serialization;
 8 | import io.quarkiverse.mcp.server.Tool;
 9 | import io.quarkiverse.mcp.server.ToolArg;
10 | import jakarta.enterprise.context.ApplicationScoped;
11 | import jakarta.inject.Inject;
12 | import java.util.Map;
13 | import java.nio.file.Path;
14 | import com.fasterxml.jackson.core.type.TypeReference;
15 | 
16 | 
17 | @ApplicationScoped
18 | public class Backstage {
19 | 
20 |   @Inject
21 |   BackstageClient client;
22 | 
23 |   @Tool(description = "List backstage templates")
24 |   public List<String> listTemplates() {
25 |     return client.entities().list("kind=template").stream().map(e -> e.getMetadata().getName()).toList();
26 |   }
27 | 
28 |   @Tool(description = "Create a backstage project using a template")
29 |   public String createProject(@ToolArg(description = "Template name") String templateName, 
30 |                               @ToolArg(description = "Path to parameters file") String valuesFile) {
31 | 
32 |         Map<String, Object> values = Serialization.unmarshal(Path.of(valuesFile).toFile(), new TypeReference<Map<String, Object>>() {});
33 |         return client.templates().withName(templateName).instantiate(values);
34 |   }
35 | }
36 | 
37 | 
```

--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------

```java
 1 | /*
 2 |  * Licensed to the Apache Software Foundation (ASF) under one
 3 |  * or more contributor license agreements.  See the NOTICE file
 4 |  * distributed with this work for additional information
 5 |  * regarding copyright ownership.  The ASF licenses this file
 6 |  * to you under the Apache License, Version 2.0 (the
 7 |  * "License"); you may not use this file except in compliance
 8 |  * with the License.  You may obtain a copy of the License at
 9 |  *
10 |  *  http://www.apache.org/licenses/LICENSE-2.0
11 |  *
12 |  * Unless required by applicable law or agreed to in writing,
13 |  * software distributed under the License is distributed on an
14 |  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 |  * KIND, either express or implied.  See the License for the
16 |  * specific language governing permissions and limitations
17 |  * under the License.
18 |  */
19 | 
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.net.Authenticator;
23 | import java.net.PasswordAuthentication;
24 | import java.net.URI;
25 | import java.net.URL;
26 | import java.nio.file.Files;
27 | import java.nio.file.Path;
28 | import java.nio.file.Paths;
29 | import java.nio.file.StandardCopyOption;
30 | import java.util.concurrent.ThreadLocalRandom;
31 | 
32 | public final class MavenWrapperDownloader {
33 |     private static final String WRAPPER_VERSION = "3.3.2";
34 | 
35 |     private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE"));
36 | 
37 |     public static void main(String[] args) {
38 |         log("Apache Maven Wrapper Downloader " + WRAPPER_VERSION);
39 | 
40 |         if (args.length != 2) {
41 |             System.err.println(" - ERROR wrapperUrl or wrapperJarPath parameter missing");
42 |             System.exit(1);
43 |         }
44 | 
45 |         try {
46 |             log(" - Downloader started");
47 |             final URL wrapperUrl = URI.create(args[0]).toURL();
48 |             final String jarPath = args[1].replace("..", ""); // Sanitize path
49 |             final Path wrapperJarPath = Paths.get(jarPath).toAbsolutePath().normalize();
50 |             downloadFileFromURL(wrapperUrl, wrapperJarPath);
51 |             log("Done");
52 |         } catch (IOException e) {
53 |             System.err.println("- Error downloading: " + e.getMessage());
54 |             if (VERBOSE) {
55 |                 e.printStackTrace();
56 |             }
57 |             System.exit(1);
58 |         }
59 |     }
60 | 
61 |     private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJarPath)
62 |             throws IOException {
63 |         log(" - Downloading to: " + wrapperJarPath);
64 |         if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
65 |             final String username = System.getenv("MVNW_USERNAME");
66 |             final char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
67 |             Authenticator.setDefault(new Authenticator() {
68 |                 @Override
69 |                 protected PasswordAuthentication getPasswordAuthentication() {
70 |                     return new PasswordAuthentication(username, password);
71 |                 }
72 |             });
73 |         }
74 |         Path temp = wrapperJarPath
75 |                 .getParent()
76 |                 .resolve(wrapperJarPath.getFileName() + "."
77 |                         + Long.toUnsignedString(ThreadLocalRandom.current().nextLong()) + ".tmp");
78 |         try (InputStream inStream = wrapperUrl.openStream()) {
79 |             Files.copy(inStream, temp, StandardCopyOption.REPLACE_EXISTING);
80 |             Files.move(temp, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING);
81 |         } finally {
82 |             Files.deleteIfExists(temp);
83 |         }
84 |         log(" - Downloader complete");
85 |     }
86 | 
87 |     private static void log(String msg) {
88 |         if (VERBOSE) {
89 |             System.out.println(msg);
90 |         }
91 |     }
92 | 
93 | }
94 | 
```

--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------

```
  1 | <?xml version="1.0" encoding="UTF-8"?>
  2 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  3 |     <modelVersion>4.0.0</modelVersion>
  4 |     <groupId>org.acme</groupId>
  5 |     <artifactId>backstage-mcp</artifactId>
  6 |     <version>1.0.0-SNAPSHOT</version>
  7 | 
  8 |     <properties>
  9 |         <compiler-plugin.version>3.14.0</compiler-plugin.version>
 10 |         <maven.compiler.release>21</maven.compiler.release>
 11 |         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 12 |         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 13 |         <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
 14 |         <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
 15 |         <quarkus.platform.version>3.19.4</quarkus.platform.version>
 16 |         <skipITs>true</skipITs>
 17 |         <surefire-plugin.version>3.5.2</surefire-plugin.version>
 18 |     </properties>
 19 | 
 20 |     <dependencyManagement>
 21 |         <dependencies>
 22 |             <dependency>
 23 |                 <groupId>${quarkus.platform.group-id}</groupId>
 24 |                 <artifactId>${quarkus.platform.artifact-id}</artifactId>
 25 |                 <version>${quarkus.platform.version}</version>
 26 |                 <type>pom</type>
 27 |                 <scope>import</scope>
 28 |             </dependency>
 29 |         </dependencies>
 30 |     </dependencyManagement>
 31 | 
 32 |     <dependencies>
 33 |         <dependency>
 34 |             <groupId>io.quarkiverse.mcp</groupId>
 35 |             <artifactId>quarkus-mcp-server-stdio</artifactId>
 36 |             <version>1.0.0.Alpha5</version>
 37 |         </dependency>
 38 |         <dependency>
 39 |             <groupId>io.quarkiverse.backstage</groupId>
 40 |             <artifactId>quarkus-backstage</artifactId>
 41 |             <version>0.4.1</version>
 42 |         </dependency>
 43 |         <dependency>
 44 |             <groupId>io.quarkus</groupId>
 45 |             <artifactId>quarkus-arc</artifactId>
 46 |         </dependency>
 47 |         <dependency>
 48 |             <groupId>io.quarkus</groupId>
 49 |             <artifactId>quarkus-junit5</artifactId>
 50 |             <scope>test</scope>
 51 |         </dependency>
 52 |     </dependencies>
 53 | 
 54 |     <build>
 55 |         <plugins>
 56 |             <plugin>
 57 |                 <groupId>${quarkus.platform.group-id}</groupId>
 58 |                 <artifactId>quarkus-maven-plugin</artifactId>
 59 |                 <version>${quarkus.platform.version}</version>
 60 |                 <extensions>true</extensions>
 61 |                 <executions>
 62 |                     <execution>
 63 |                         <goals>
 64 |                             <goal>build</goal>
 65 |                             <goal>generate-code</goal>
 66 |                             <goal>generate-code-tests</goal>
 67 |                             <goal>native-image-agent</goal>
 68 |                         </goals>
 69 |                     </execution>
 70 |                 </executions>
 71 |             </plugin>
 72 |             <plugin>
 73 |                 <artifactId>maven-compiler-plugin</artifactId>
 74 |                 <version>${compiler-plugin.version}</version>
 75 |                 <configuration>
 76 |                     <parameters>true</parameters>
 77 |                 </configuration>
 78 |             </plugin>
 79 |             <plugin>
 80 |                 <artifactId>maven-surefire-plugin</artifactId>
 81 |                 <version>${surefire-plugin.version}</version>
 82 |                 <configuration>
 83 |                     <systemPropertyVariables>
 84 |                         <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
 85 |                         <maven.home>${maven.home}</maven.home>
 86 |                     </systemPropertyVariables>
 87 |                 </configuration>
 88 |             </plugin>
 89 |             <plugin>
 90 |                 <artifactId>maven-failsafe-plugin</artifactId>
 91 |                 <version>${surefire-plugin.version}</version>
 92 |                 <executions>
 93 |                     <execution>
 94 |                         <goals>
 95 |                             <goal>integration-test</goal>
 96 |                             <goal>verify</goal>
 97 |                         </goals>
 98 |                     </execution>
 99 |                 </executions>
100 |                 <configuration>
101 |                     <systemPropertyVariables>
102 |                         <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
103 |                         <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
104 |                         <maven.home>${maven.home}</maven.home>
105 |                     </systemPropertyVariables>
106 |                 </configuration>
107 |             </plugin>
108 |         </plugins>
109 |     </build>
110 | 
111 |     <profiles>
112 |         <profile>
113 |             <id>native</id>
114 |             <activation>
115 |                 <property>
116 |                     <name>native</name>
117 |                 </property>
118 |             </activation>
119 |             <properties>
120 |                 <skipITs>false</skipITs>
121 |                 <quarkus.native.enabled>true</quarkus.native.enabled>
122 |             </properties>
123 |         </profile>
124 |     </profiles>
125 | </project>
126 | 
```

--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------

```
  1 | @REM ----------------------------------------------------------------------------
  2 | @REM Licensed to the Apache Software Foundation (ASF) under one
  3 | @REM or more contributor license agreements.  See the NOTICE file
  4 | @REM distributed with this work for additional information
  5 | @REM regarding copyright ownership.  The ASF licenses this file
  6 | @REM to you under the Apache License, Version 2.0 (the
  7 | @REM "License"); you may not use this file except in compliance
  8 | @REM with the License.  You may obtain a copy of the License at
  9 | @REM
 10 | @REM    http://www.apache.org/licenses/LICENSE-2.0
 11 | @REM
 12 | @REM Unless required by applicable law or agreed to in writing,
 13 | @REM software distributed under the License is distributed on an
 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15 | @REM KIND, either express or implied.  See the License for the
 16 | @REM specific language governing permissions and limitations
 17 | @REM under the License.
 18 | @REM ----------------------------------------------------------------------------
 19 | 
 20 | @REM ----------------------------------------------------------------------------
 21 | @REM Apache Maven Wrapper startup batch script, version 3.3.2
 22 | @REM
 23 | @REM Required ENV vars:
 24 | @REM JAVA_HOME - location of a JDK home dir
 25 | @REM
 26 | @REM Optional ENV vars
 27 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
 28 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
 29 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
 30 | @REM     e.g. to debug Maven itself, use
 31 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
 32 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
 33 | @REM ----------------------------------------------------------------------------
 34 | 
 35 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
 36 | @echo off
 37 | @REM set title of command window
 38 | title %0
 39 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
 40 | @if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
 41 | 
 42 | @REM set %HOME% to equivalent of $HOME
 43 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
 44 | 
 45 | @REM Execute a user defined script before this one
 46 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
 47 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
 48 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
 49 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
 50 | :skipRcPre
 51 | 
 52 | @setlocal
 53 | 
 54 | set ERROR_CODE=0
 55 | 
 56 | @REM To isolate internal variables from possible post scripts, we use another setlocal
 57 | @setlocal
 58 | 
 59 | @REM ==== START VALIDATION ====
 60 | if not "%JAVA_HOME%" == "" goto OkJHome
 61 | 
 62 | echo. >&2
 63 | echo Error: JAVA_HOME not found in your environment. >&2
 64 | echo Please set the JAVA_HOME variable in your environment to match the >&2
 65 | echo location of your Java installation. >&2
 66 | echo. >&2
 67 | goto error
 68 | 
 69 | :OkJHome
 70 | if exist "%JAVA_HOME%\bin\java.exe" goto init
 71 | 
 72 | echo. >&2
 73 | echo Error: JAVA_HOME is set to an invalid directory. >&2
 74 | echo JAVA_HOME = "%JAVA_HOME%" >&2
 75 | echo Please set the JAVA_HOME variable in your environment to match the >&2
 76 | echo location of your Java installation. >&2
 77 | echo. >&2
 78 | goto error
 79 | 
 80 | @REM ==== END VALIDATION ====
 81 | 
 82 | :init
 83 | 
 84 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
 85 | @REM Fallback to current working directory if not found.
 86 | 
 87 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
 88 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
 89 | 
 90 | set EXEC_DIR=%CD%
 91 | set WDIR=%EXEC_DIR%
 92 | :findBaseDir
 93 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
 94 | cd ..
 95 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
 96 | set WDIR=%CD%
 97 | goto findBaseDir
 98 | 
 99 | :baseDirFound
100 | set MAVEN_PROJECTBASEDIR=%WDIR%
101 | cd "%EXEC_DIR%"
102 | goto endDetectBaseDir
103 | 
104 | :baseDirNotFound
105 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
106 | cd "%EXEC_DIR%"
107 | 
108 | :endDetectBaseDir
109 | 
110 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
111 | 
112 | @setlocal EnableExtensions EnableDelayedExpansion
113 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
114 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
115 | 
116 | :endReadAdditionalConfig
117 | 
118 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 | 
122 | set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
123 | 
124 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
125 |     IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
126 | )
127 | 
128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130 | if exist %WRAPPER_JAR% (
131 |     if "%MVNW_VERBOSE%" == "true" (
132 |         echo Found %WRAPPER_JAR%
133 |     )
134 | ) else (
135 |     if not "%MVNW_REPOURL%" == "" (
136 |         SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
137 |     )
138 |     if "%MVNW_VERBOSE%" == "true" (
139 |         echo Couldn't find %WRAPPER_JAR%, downloading it ...
140 |         echo Downloading from: %WRAPPER_URL%
141 |     )
142 | 
143 |     powershell -Command "&{"^
144 | 		"$webclient = new-object System.Net.WebClient;"^
145 | 		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
146 | 		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
147 | 		"}"^
148 | 		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
149 | 		"}"
150 |     if "%MVNW_VERBOSE%" == "true" (
151 |         echo Finished downloading %WRAPPER_JAR%
152 |     )
153 | )
154 | @REM End of extension
155 | 
156 | @REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
157 | SET WRAPPER_SHA_256_SUM=""
158 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
159 |     IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
160 | )
161 | IF NOT %WRAPPER_SHA_256_SUM%=="" (
162 |     powershell -Command "&{"^
163 |        "Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
164 |        "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
165 |        "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
166 |        "  Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
167 |        "  Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
168 |        "  Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
169 |        "  exit 1;"^
170 |        "}"^
171 |        "}"
172 |     if ERRORLEVEL 1 goto error
173 | )
174 | 
175 | @REM Provide a "standardized" way to retrieve the CLI args that will
176 | @REM work with both Windows and non-Windows executions.
177 | set MAVEN_CMD_LINE_ARGS=%*
178 | 
179 | %MAVEN_JAVA_EXE% ^
180 |   %JVM_CONFIG_MAVEN_PROPS% ^
181 |   %MAVEN_OPTS% ^
182 |   %MAVEN_DEBUG_OPTS% ^
183 |   -classpath %WRAPPER_JAR% ^
184 |   "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
185 |   %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
186 | if ERRORLEVEL 1 goto error
187 | goto end
188 | 
189 | :error
190 | set ERROR_CODE=1
191 | 
192 | :end
193 | @endlocal & set ERROR_CODE=%ERROR_CODE%
194 | 
195 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
196 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
197 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
198 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
199 | :skipRcPost
200 | 
201 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
202 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
203 | 
204 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
205 | 
206 | cmd /C exit /B %ERROR_CODE%
207 | 
```