
Eliteforge Java Service Generator
- 48 installs
- Updated July 24, 2026
- cloudsen/eliteforge-skills
Generates a Java service layer scaffold following EliteForge conventions.
About
Scaffolds Java service-layer code to the EliteForge structure. A developer uses it to generate a new service in an EliteForge Java project.
- Generates service-layer Java code
- Follows EliteForge Java project conventions
Eliteforge Java Service Generator by the numbers
- 48 all-time installs (skills.sh)
- Ranked #38 of 89 Java & JVM skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cloudsen/eliteforge-skills --skill eliteforge-java-service-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 48 |
|---|---|
| Last updated | July 24, 2026 |
| Repository | cloudsen/eliteforge-skills ↗ |
What it does
Generates a Java service layer scaffold following EliteForge conventions.
Files
EliteForge Java Service Generator (Maven Archetype)
Goal
Create a new EliteForge Java service by running scripts/generate.py, and perform project build/initialization through project-internal make commands.
Preconditions
- Require
python3,make, JDK, and network access (for archetype download).
Build Command Policy (MUST follow)
- In generated project root, use project-internal
maketargets for build/init/verify tasks. - Do not run system Maven commands in generated project (for example:
mvn clean install,mvn test). - If Maven command is explicitly required in generated project, use project wrapper only:
./mvnw .... - Never replace
./mvnwwith systemmvnin command examples or execution steps.
Required Inputs (never infer)
companyNameproductNameserviceName- Validate all three with:
^[a-z0-9]+(-[a-z0-9]+)*$ - If any value is missing or invalid, ask only for missing/invalid fields.
Workflow (every run)
1. Collect and validate required inputs. 2. Build command and run script:
python3 scripts/generate.py --company <companyName> --product <productName> --service <serviceName> [--desc "<projectDescription>"] [--tech "<tech stack text>"] [--enable enableX --enable enableY ...]
3. Map tech stack to enableXXX when user provides stack text:
- Use
references/mapping-rules.md. - Pass explicit user switches through
--enable. - Use
references/enable-flags.mdas canonical flag list. - If uncertain, ask instead of guessing.
4. Verify result:
- Output folder exists:
app-<companyName>-<productName>-<serviceName>/ pom.xmlexists in that folder.
5. Run post-generation consistency checks in project root (<artifactId>/):
- Java package should match expected package prefix (check
src/main/javaandsrc/test/java). - Maven model name should match expected value (check
pom.xml<name>). pom.xmlartifactIdshould equal expectedartifactId.- For any mismatch, report expected vs actual and stop.
6. Initialize project in root directory (<artifactId>/) by running make install and require success (exit code 0):
- Example:
cd app-<companyName>-<productName>-<serviceName> && make install
7. For build/test/verification after generation, continue using project make targets (for example make test, make build) instead of direct Maven commands; if a Maven command is unavoidable, run ./mvnw ... only. 8. On failure, return exact error and full executed command (including the failed make command).
Coordinate Rules (script behavior)
groupId = cn.<companyName(with '-' -> '.')>.<productName(with '-' -> '.')>artifactId = app-<companyName>-<productName>-<serviceName>
Expected Values For Post-check
expectedGroupId = groupIdexpectedArtifactId = artifactIdexpectedJavaPackagePrefix = <expectedGroupId>.<serviceName(with '-' -> '.')>expectedMavenModelName = expectedArtifactId(unless user explicitly requires another naming rule)
Quick Examples
- Minimal:
python3 scripts/generate.py --company cisdigital --product cap --service cache-center --desc "CAP 缓存中心"- Post-generation init (required):
cd app-cisdigital-cap-cache-center && make install- Tech + explicit override:
python3 scripts/generate.py --company cisdigital --product cap --service cache-center --tech "mysql redisson lombok mapstruct" --enable enableJacksonDatatypeJsr310
interface:
display_name: "EliteForge Java 服务生成器"
short_description: "基于 Maven archetype 生成 EliteForge Java 服务工程,并执行初始化校验。"
default_prompt: "使用 $eliteforge-java-service-generator,按 companyName/productName/serviceName 生成服务工程;缺失必填参数先追问,不要推断。"
EliteForge Archetype enableXXX Flags (canonical list)
All flags default to false. Set via: -DenableXxx=true
Biz dependency flags
- enableAutoService: com.google.auto.service:auto-service
- enableDruid: com.alibaba:druid
- enableHikariCP: com.zaxxer:HikariCP
- enablePostgresql: org.postgresql:postgresql
- enableMysqlConnectorJ: com.mysql:mysql-connector-j
- enableOjdbc11: com.oracle.database.jdbc:ojdbc11
- enableOrai18n: com.oracle.database.nls:orai18n
- enableDmJdbcDriver18: com.dameng:DmJdbcDriver18
- enableKingbase8: cn.com.kingbase:kingbase8
- enableUcanaccess: net.sf.ucanaccess:ucanaccess
- enableSqliteJdbc: org.xerial:sqlite-jdbc
- enableMssqlJdbc: com.microsoft.sqlserver:mssql-jdbc
- enableRocketmqClient: org.apache.rocketmq:rocketmq-client
- enableJconn4: jdbc.sybase:jconn4
- enableEasyexcel: com.alibaba:easyexcel
- enableJacksonDatatypeJsr310: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
- enableJacksonDatatypeJdk8: com.fasterxml.jackson.datatype:jackson-datatype-jdk8
- enableLombok: org.projectlombok:lombok (scope=provided)
- enableDynamicDatasourceSpringBoot3Starter: com.baomidou:dynamic-datasource-spring-boot3-starter
- enableCommonsLang3: org.apache.commons:commons-lang3
- enableCommonsText: org.apache.commons:commons-text
- enableCommonsIo: commons-io:commons-io
- enableCommonsFileupload: commons-fileupload:commons-fileupload
- enableCommonsCollections4: org.apache.commons:commons-collections4
- enableCommonsCodec: commons-codec:commons-codec
- enableCommonsPool2: org.apache.commons:commons-pool2
- enableRedissonSpringBootStarter: org.redisson:redisson-spring-boot-starter
- enableMinio: io.minio:minio
- enableOkhttpJvm: com.squareup.okhttp3:okhttp-jvm
- enableGuava: com.google.guava:guava
- enableKafkaClients: org.apache.kafka:kafka-clients
- enableRocketmqTools: org.apache.rocketmq:rocketmq-tools
- enableDb2jcc: com.ibm.db2.jcc:db2jcc
- enableVastbaseJdbc: cn.com.vastdata:vastbase-jdbc
- enableBcprovJdk18on: org.bouncycastle:bcprov-jdk18on
- enableBcpkixJdk18on: org.bouncycastle:bcpkix-jdk18on
- enableNimbusJoseJwt: com.nimbusds:nimbus-jose-jwt
- enableJavaJwt: com.auth0:java-jwt
- enableJacksonModuleAfterburner: com.fasterxml.jackson.module:jackson-module-afterburner
- enableTransmittableThreadLocal: com.alibaba:transmittable-thread-local
- enableReactorKafka: io.projectreactor.kafka:reactor-kafka
- enableCaffeine: com.github.ben-manes.caffeine:caffeine
- enableSapjco3: org.hibersap:com.sap.conn.jco.sapjco3
- enableZookeeper: org.apache.zookeeper:zookeeper
- enableFlinkClients: org.apache.flink:flink-clients
- enableElasticjobLiteCore: org.apache.shardingsphere.elasticjob:elasticjob-lite-core
- enableElasticjobLiteSpringBootStarter: org.apache.shardingsphere.elasticjob:elasticjob-lite-spring-boot-starter
- enableCalciteCore: org.apache.calcite:calcite-core
- enableCalciteServer: org.apache.calcite:calcite-server
- enableCalciteBabel: org.apache.calcite:calcite-babel
- enableMapstruct: org.mapstruct:mapstruct
- enableMapstructProcessor: org.mapstruct:mapstruct-processor
- enableCglib: cglib:cglib
- enableAsm: org.ow2.asm:asm
- enableAwsS3: software.amazon.awssdk:s3
- enableAwsS3TransferManager: software.amazon.awssdk:s3-transfer-manager
- enableEsdkObsJavaBundle: com.huaweicloud:esdk-obs-java-bundle
- enableAviator: com.googlecode.aviator:aviator
- enableWiremock: org.wiremock:wiremock (scope=test)
- enableJsonUnitAssertj: net.javacrumbs.json-unit:json-unit-assertj (scope=test)
- enableLombokMapstructBinding: org.projectlombok:lombok-mapstruct-binding
- enablePf4j: org.pf4j:pf4j
- enablePf4jSpring: org.pf4j:pf4j-spring
- enableJavaUuidGenerator: com.fasterxml.uuid:java-uuid-generator
- enableRedisson: org.redisson:redisson
- enableSmartDoc: com.ly.smart-doc:smart-doc
- enableHippo4jCore: cn.hippo4j:hippo4j-core
- enableDuckdbJdbc: org.duckdb:duckdb_jdbc
- enablePinyin4j: com.belerweb:pinyin4j
- enableFastExcel: cn.idev.excel:fastexcel
- enableOpencc4j: com.github.houbb:opencc4j
- enableQlexpress4: com.alibaba:qlexpress4
- enableDocuments4jApi: com.documents4j:documents4j-api
- enableDocuments4jLocal: com.documents4j:documents4j-local
- enablePdfbox: org.apache.pdfbox:pdfbox
- enableThumbnailator: net.coobird:thumbnailator
- enableDom4j: org.dom4j:dom4j
- enableOpenpdf: com.github.librepdf:openpdf
- enableZxingCore: com.google.zxing:core
- enableZxingJavase: com.google.zxing:javase
- enableCuratorClient: org.apache.curator:curator-client
- enableCuratorRecipes: org.apache.curator:curator-recipes
- enableByteBuddy: net.bytebuddy:byte-buddy
- enableByteBuddyAgent: net.bytebuddy:byte-buddy-agent
- enableJspecify: org.jspecify:jspecify
- enableHypersistenceTsid: io.hypersistence:hypersistence-tsid
- enableEasyRulesCore: org.jeasy:easy-rules-core
- enableJuniversalchardet: com.googlecode.juniversalchardet:juniversalchardet
- enableProtostuffCore: io.protostuff:protostuff-core
- enableProtostuffRuntime: io.protostuff:protostuff-runtime
- enableEtcdJava: com.ibm.etcd:etcd-java
- enableGrpcNetty: io.grpc:grpc-netty
- enableGrpcProtobuf: io.grpc:grpc-protobuf
- enableGrpcStub: io.grpc:grpc-stub
- enableLz4Java: org.lz4:lz4-java
- enableSassEmbeddedHost: de.larsgrefer.sass:sass-embedded-host
- enableApmToolkitTrace: org.apache.skywalking:apm-toolkit-trace
- enableApmToolkitLogback: org.apache.skywalking:apm-toolkit-logback-1.x
- enableOceanbaseClient: com.oceanbase:oceanbase-client
- enableTikaCore: org.apache.tika:tika-core
- enableJavapoet: com.squareup:javapoet
- enableClassgraph: io.github.classgraph:classgraph
- enableSnakeyaml: org.yaml:snakeyaml
- enableCompileTesting: com.google.testing.compile:compile-testing
- enableSpringAiStdioMcpServer: org.springframework.ai:spring-ai-starter-mcp-server
- enableSpringAiSSEMvcMcpServer: org.springframework.ai:spring-ai-starter-mcp-server-webmvc
- enableSpringAiSSEWebFluxMcpServer: org.springframework.ai:spring-ai-starter-mcp-server-webflux
- enableSpringAiMcpClient: org.springframework.ai:spring-ai-starter-mcp-client-webflux
Tech Stack → enableXXX Mapping Rules
Principles
- Conservative enabling: only enable when the keyword is explicit.
- Prefer explicit user switches when provided (e.g., user says "enableMysqlConnectorJ").
- If user says "redis" but doesn't say "redisson", do NOT auto-enable redisson by default.
High-confidence keyword mapping (examples)
DB
- mysql → enableMysqlConnectorJ
- postgresql/postgres → enablePostgresql
- oracle/ojdbc → enableOjdbc11
- sqlite → enableSqliteJdbc
- sql server/mssql → enableMssqlJdbc
- db2 → enableDb2jcc
- kingbase → enableKingbase8
- vastbase → enableVastbaseJdbc
- oceanbase → enableOceanbaseClient
- duckdb → enableDuckdbJdbc
- 达梦/dameng → enableDmJdbcDriver18
- sybase/jconn4 → enableJconn4
- access/ucanaccess → enableUcanaccess
Connection pool
- hikari/hikaricp → enableHikariCP
- druid → enableDruid
Cache
- redisson → enableRedissonSpringBootStarter
- caffeine → enableCaffeine
MQ / Streaming
- kafka → enableKafkaClients
- rocketmq → enableRocketmqClient
JSON / Jackson
- jsr310/java time/localdatetime → enableJacksonDatatypeJsr310
- jdk8 → enableJacksonDatatypeJdk8
- afterburner → enableJacksonModuleAfterburner
Build-time helpers
- lombok → enableLombok
- mapstruct → enableMapstruct + enableMapstructProcessor
- lombok + mapstruct → also enableLombokMapstructBinding
Storage / HTTP
- okhttp → enableOkhttpJvm
- minio → enableMinio
- aws s3 / s3 → enableAwsS3
- transfer manager → enableAwsS3TransferManager
- huawei obs / obs → enableEsdkObsJavaBundle
Utilities
- commons-lang3 → enableCommonsLang3
- commons-io → enableCommonsIo
- guava → enableGuava
Security
- nimbus/jose/jwt → enableNimbusJoseJwt
- auth0/java-jwt → enableJavaJwt
ZK / Curator
- zookeeper → enableZookeeper
- curator → enableCuratorClient + enableCuratorRecipes
Spring AI MCP
- mcp → enableSpringAiStdioMcpServer
- mcp + webmvc → enableSpringAiSSEMvcMcpServer
- mcp + mvc → enableSpringAiSSEMvcMcpServer
- mcp + webflux → enableSpringAiSSEWebFluxMcpServer + enableSpringAiMcpClient
When in doubt
Do not enable. Ask the user to confirm or require explicit --enable flags.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import os
import re
import shlex
import subprocess
import sys
from typing import Dict, List, Set, Tuple
KEBAB_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
DEFAULT_ARCHETYPE = {
"archetypeCatalog": "remote",
"archetypeGroupId": "cn.cisdigital.generator.archtype",
"archetypeArtifactId": "cisdigital-generator-mesh-app-archetype",
"archetypeVersion": "1.2.2",
}
def eprint(*args: object) -> None:
print(*args, file=sys.stderr)
def require_kebab(name: str, value: str) -> None:
if not KEBAB_RE.match(value):
raise ValueError(
f"{name} must be kebab-case (^[a-z0-9]+(-[a-z0-9]+)*$), got: {value}"
)
def normalize_bool_flag(flag: str) -> str:
# allow passing "enableX=true" or "enableX"
flag = flag.strip()
if "=" in flag:
left, right = flag.split("=", 1)
left = left.strip()
right = right.strip().lower()
if right in ("true", "1", "yes", "y", "on"):
return left
# explicit false -> ignore
return ""
return flag
def infer_enable_flags(tech_text: str) -> Set[str]:
"""
Heuristic inference: map tech keywords -> enableXXX flags.
Keep conservative: only enable when confidence is high.
"""
if not tech_text:
return set()
t = tech_text.lower()
flags: Set[str] = set()
# Databases / JDBC
if re.search(r"\bmysql\b", t):
flags.add("enableMysqlConnectorJ")
if re.search(r"\bpostgres\b|\bpostgresql\b", t):
flags.add("enablePostgresql")
if re.search(r"\boracle\b|\bojdbc\b", t):
flags.add("enableOjdbc11")
if re.search(r"\borai18n\b", t):
flags.add("enableOrai18n")
if re.search(r"\bsqlite\b", t):
flags.add("enableSqliteJdbc")
if re.search(r"\bmssql\b|\bsql server\b", t):
flags.add("enableMssqlJdbc")
if re.search(r"\bdb2\b", t):
flags.add("enableDb2jcc")
if re.search(r"\bkingbase\b", t):
flags.add("enableKingbase8")
if re.search(r"\bvastbase\b", t):
flags.add("enableVastbaseJdbc")
if re.search(r"\boceanbase\b", t):
flags.add("enableOceanbaseClient")
if re.search(r"\bduckdb\b", t):
flags.add("enableDuckdbJdbc")
if re.search(r"\bdm\b|\bdameng\b|\b达梦\b", t):
flags.add("enableDmJdbcDriver18")
if re.search(r"\bsybase\b|\bjconn4\b", t):
flags.add("enableJconn4")
if re.search(r"\bucanaccess\b|\baccess\b", t):
flags.add("enableUcanaccess")
# Connection pool
if re.search(r"\bhikaricp\b|\bhikari\b", t):
flags.add("enableHikariCP")
if re.search(r"\bdruid\b", t):
flags.add("enableDruid")
# Cache / Redis
if re.search(r"\bredisson\b", t):
flags.add("enableRedissonSpringBootStarter")
elif re.search(r"\bredis\b", t):
# Redis mentioned but not redisson; keep conservative: don't force redisson
pass
if re.search(r"\bcaffeine\b", t):
flags.add("enableCaffeine")
# MQ / streaming
if re.search(r"\bkafka\b", t):
flags.add("enableKafkaClients")
if re.search(r"\brocketmq\b", t):
flags.add("enableRocketmqClient")
# JSON / Jackson modules
if re.search(r"\bjsr310\b|\bjava time\b|\blocaldatetime\b", t):
flags.add("enableJacksonDatatypeJsr310")
if re.search(r"\bjdk8\b", t):
flags.add("enableJacksonDatatypeJdk8")
if re.search(r"\bafterburner\b", t):
flags.add("enableJacksonModuleAfterburner")
# Lombok / MapStruct
if re.search(r"\blombok\b", t):
flags.add("enableLombok")
if re.search(r"\bmapstruct\b", t):
flags.add("enableMapstruct")
flags.add("enableMapstructProcessor")
# common combo
if "enableLombok" in flags:
flags.add("enableLombokMapstructBinding")
# HTTP client / storage
if re.search(r"\bokhttp\b", t):
flags.add("enableOkhttpJvm")
if re.search(r"\bminio\b", t):
flags.add("enableMinio")
if re.search(r"\baws\s*s3\b|\bs3\b", t):
flags.add("enableAwsS3")
if re.search(r"\btransfer manager\b", t):
flags.add("enableAwsS3TransferManager")
if re.search(r"\bhuawei\b|\bobs\b", t):
flags.add("enableEsdkObsJavaBundle")
# Utils
if re.search(r"\bcommons[- ]lang3\b", t):
flags.add("enableCommonsLang3")
if re.search(r"\bcommons[- ]io\b", t):
flags.add("enableCommonsIo")
if re.search(r"\bguava\b", t):
flags.add("enableGuava")
# Security / JWT
if re.search(r"\bnimbus\b|\bjose\b|\bjwt\b", t):
flags.add("enableNimbusJoseJwt")
if re.search(r"\bauth0\b|\bjava-jwt\b", t):
flags.add("enableJavaJwt")
# ZK / Curator
if re.search(r"\bzookeeper\b", t):
flags.add("enableZookeeper")
if re.search(r"\bcurator\b", t):
flags.add("enableCuratorClient")
flags.add("enableCuratorRecipes")
# Spring AI MCP
if re.search(r"\bmcp\b", t):
# default to stdio server unless explicitly says webmvc/webflux
flags.add("enableSpringAiStdioMcpServer")
if re.search(r"\bwebmvc\b", t):
flags.add("enableSpringAiSSEMvcMcpServer")
if re.search(r"\bwebflux\b", t):
flags.add("enableSpringAiSSEWebFluxMcpServer")
flags.add("enableSpringAiMcpClient")
return flags
def build_mvn_cmd(
group_id: str,
artifact_id: str,
company: str,
product: str,
service: str,
desc: str,
gitignore: str,
enable_flags: Set[str],
archetype: Dict[str, str],
opt_versions: Dict[str, str],
) -> List[str]:
cmd = [
"mvn",
"-B",
"archetype:generate",
f"-DarchetypeCatalog={archetype['archetypeCatalog']}",
f"-DarchetypeGroupId={archetype['archetypeGroupId']}",
f"-DarchetypeArtifactId={archetype['archetypeArtifactId']}",
f"-DarchetypeVersion={archetype['archetypeVersion']}",
f"-DgroupId={group_id}",
f"-DartifactId={artifact_id}",
f"-DproductName={product}",
f"-DserviceName={service}",
f"-DprojectDescription={desc}",
f"-Dgitignore={gitignore}",
f"-DcompanyName={company}",
"-DinteractiveMode=false",
]
# optional unified versions
for k in ("buildParentVersion", "dependenciesParentVersion", "infraVersion"):
v = opt_versions.get(k)
if v:
cmd.append(f"-D{k}={v}")
# enable flags
for flag in sorted(enable_flags):
cmd.append(f"-D{flag}=true")
return cmd
def main() -> int:
p = argparse.ArgumentParser(
description="EliteForge Java service generator (Maven archetype wrapper)."
)
p.add_argument("--company", required=True, help="companyName (kebab-case)")
p.add_argument("--product", required=True, help="productName (kebab-case)")
p.add_argument("--service", required=True, help="serviceName (kebab-case)")
p.add_argument("--desc", default="", help="projectDescription")
p.add_argument("--gitignore", default=".gitignore", help="gitignore template value")
p.add_argument("--tech", default="", help="free text tech stack description")
p.add_argument(
"--enable",
action="append",
default=[],
help="explicit enable flag name, e.g. enableMysqlConnectorJ (repeatable). Also supports enableX=true/false",
)
# archetype overrides
p.add_argument("--archetypeCatalog", default=DEFAULT_ARCHETYPE["archetypeCatalog"])
p.add_argument("--archetypeGroupId", default=DEFAULT_ARCHETYPE["archetypeGroupId"])
p.add_argument(
"--archetypeArtifactId", default=DEFAULT_ARCHETYPE["archetypeArtifactId"]
)
p.add_argument("--archetypeVersion", default=DEFAULT_ARCHETYPE["archetypeVersion"])
# optional versions
p.add_argument("--buildParentVersion", default="")
p.add_argument("--dependenciesParentVersion", default="")
p.add_argument("--infraVersion", default="")
args = p.parse_args()
try:
require_kebab("companyName", args.company)
require_kebab("productName", args.product)
require_kebab("serviceName", args.service)
except ValueError as ex:
eprint(f"[INPUT ERROR] {ex}")
return 2
company = args.company
product = args.product
service = args.service
company_group = company.replace("-", ".")
product_group = product.replace("-", ".")
group_id = f"cn.{company_group}.{product_group}"
artifact_id = f"app-{company}-{product}-{service}"
desc = args.desc.strip() if args.desc.strip() else f"{product} {service}"
# infer + explicit
enable_flags = infer_enable_flags(args.tech)
for raw in args.enable:
flag = normalize_bool_flag(raw)
if not flag:
continue
if not flag.startswith("enable"):
eprint(f"[WARN] Ignoring invalid flag (must start with 'enable'): {raw}")
continue
enable_flags.add(flag)
# guard: do not overwrite
if os.path.exists(artifact_id):
eprint(
f"[ABORT] Target directory already exists: ./{artifact_id}\n"
f"Refusing to overwrite. Please remove it or choose a different serviceName."
)
return 3
archetype = {
"archetypeCatalog": args.archetypeCatalog,
"archetypeGroupId": args.archetypeGroupId,
"archetypeArtifactId": args.archetypeArtifactId,
"archetypeVersion": args.archetypeVersion,
}
opt_versions = {
"buildParentVersion": args.buildParentVersion.strip(),
"dependenciesParentVersion": args.dependenciesParentVersion.strip(),
"infraVersion": args.infraVersion.strip(),
}
cmd = build_mvn_cmd(
group_id=group_id,
artifact_id=artifact_id,
company=company,
product=product,
service=service,
desc=desc,
gitignore=args.gitignore.strip(),
enable_flags=enable_flags,
archetype=archetype,
opt_versions=opt_versions,
)
print("== EliteForge Generation Plan ==")
print(f"companyName: {company}")
print(f"productName: {product}")
print(f"serviceName: {service}")
print(f"groupId : {group_id}")
print(f"artifactId : {artifact_id}")
print(f"desc : {desc}")
print(f"enableFlags: {', '.join(sorted(enable_flags)) if enable_flags else '(none)'}")
print("")
print("== Executing ==")
print(" ".join(shlex.quote(x) for x in cmd))
print("")
try:
completed = subprocess.run(cmd, check=False)
except FileNotFoundError:
eprint("[ERROR] 'mvn' not found. Install Maven and ensure it is on PATH.")
return 127
if completed.returncode != 0:
eprint(f"[FAILED] Maven exited with code: {completed.returncode}")
return completed.returncode
# post-check
pom_path = os.path.join(artifact_id, "pom.xml")
if not os.path.exists(pom_path):
eprint(
f"[WARN] Generation finished but pom.xml not found at {pom_path}. "
"Please check archetype output."
)
return 4
print(f"[OK] Generated project: ./{artifact_id}")
return 0
if __name__ == "__main__":
raise SystemExit(main())