Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ Version 2.0, at revision 158b854d47ac9af2bbd99c0d7c354a5875cb6f81:
offline.svg platform/icons/src/actions/offlineMode.svg
skipTests.svg platform/icons/src/expui/run/showIgnored.svg

maven-project.svg and maven-project_dark.svg, the icons of the New Project
entries, come from the same repository's Maven plugin resources (plugins/maven
resources, moved from the Java Support plugin), under the Apache License,
Version 2.0. Their exact file paths and revision are not recorded.

Copyright 2000-2024 JetBrains s.r.o. and contributors.

The backend includes the Apache-2.0 licensed official Lithe Java plugin SDK
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@
| 快照 | 项目和依赖保存在工作区状态目录,重新打开项目时直接显示;POM、`.mvn/` 配置、settings.xml、选项或 Maven/Java 变化后才重新运行 Maven,Reload 总是重新运行 |
| 同步 | `pom.xml`、`.mvn/maven.config`、`.mvn/extensions.xml` 变化后重新读取项目 |

## 新建项目

插件在 **New Project** 窗口提供两个条目:

- **Maven**:生成 Maven Java 项目,可选示例代码,可设置 GroupId 和 ArtifactId。
- **Maven Archetype**:用内置原型或自定义原型,由 `mvn` 生成项目。

模板在 `io.github.lithe-idea.maven-build/templates/java/`,从 Java Support 插件移来。
生成的项目需要 Java Support 提供 Java 语言支持。

## 依赖的程序

插件不带 Maven,使用你项目或电脑上的 Maven,按以下顺序查找:
Expand Down Expand Up @@ -92,7 +102,8 @@ Windows 的日志实现仍为 v1,未声明 Windows v2 已完成验收。

```text
io.github.lithe-idea.maven-build/plugin.json # 插件描述,目录名必须等于插件 id
io.github.lithe-idea.maven-build/icons/ # 工具窗口和工具栏图标(来源见 NOTICE)
io.github.lithe-idea.maven-build/icons/ # 工具窗口、工具栏和新建项目图标(来源见 NOTICE)
io.github.lithe-idea.maven-build/templates/ # 新建项目的文件模板(Maven 项目),打包时检查路径是否存在
extension/ # Maven 核心扩展,导出模型和依赖树
backend/ # 构建后端(Java 8,Lithe 插件 SDK),快照和 Maven 运行
vendor/ # 官方 Java SDK 生产源码和许可证(不带测试、JAR、target)
Expand Down
4 changes: 4 additions & 0 deletions io.github.lithe-idea.maven-build/icons/maven-project.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions io.github.lithe-idea.maven-build/icons/maven-project_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
206 changes: 204 additions & 2 deletions io.github.lithe-idea.maven-build/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
"displayName": "Maven",
"version": "0.1.2",
"pluginAPIVersion": 3,
"requires": { "buildProviders": 1, "buildSystems": 1, "serverProcess": 1 },
"requires": { "buildProviders": 1, "buildSystems": 1, "projectGenerators": 1, "serverProcess": 1 },
"vendor": {
"id": "io.github.lithe-idea",
"displayName": "Lithe Community",
"signatureRequirement": "none"
},
"permissions": ["languageServer.launch", "process.build"],
"permissions": ["languageServer.launch", "process.build", "project.generate"],
"activationEvents": ["onBuildSystem:maven"],
"languages": [],
"buildSystems": [
Expand Down Expand Up @@ -288,5 +288,207 @@
"options": { "profiles": "profiles", "settingsFile": "settingsFile", "localRepository": "localRepository" }
}
}
],
"projectGenerators": [
{
"id": "maven-java",
"displayName": "Maven",
"description": "A Java project built with Maven.",
"section": "project",
"order": 20,
"icon": { "path": "icons/maven-project.svg", "darkPath": "icons/maven-project_dark.svg", "mode": "original" },
"fields": [
{
"id": "jdk",
"type": "runtime",
"title": "JDK",
"runtime": "java",
"minimumVersion": "11"
},
{
"id": "addSampleCode",
"type": "boolean",
"title": "Add sample code",
"default": true
},
{
"id": "groupId",
"type": "text",
"title": "GroupId",
"description": "Usually the reversed domain name of your organization, such as com.example.",
"advanced": true,
"default": "org.example",
"pattern": "[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*",
"maxLength": 200
},
{
"id": "artifactId",
"type": "text",
"title": "ArtifactId",
"description": "The name of the artifact the build produces.",
"advanced": true,
"default": "${project.name}",
"pattern": "[A-Za-z0-9_][A-Za-z0-9_.-]*",
"maxLength": 200
}
],
"requirements": [
{ "languageID": "java" },
{ "buildSystemID": "maven" }
],
"steps": [
{ "kind": "files", "source": "templates/java/maven" },
{
"kind": "files",
"source": "templates/java/standard-sample",
"when": { "field": "addSampleCode", "equals": true }
},
{
"kind": "files",
"source": "templates/java/standard-sample-main",
"target": "src/main/java/${field.groupId|package|path}",
"when": { "field": "addSampleCode", "equals": true }
},
{
"kind": "files",
"source": "templates/java/standard-empty",
"when": { "field": "addSampleCode", "equals": false }
}
],
"openFiles": [
{
"path": "src/main/java/${field.groupId|package|path}/Main.java",
"when": { "field": "addSampleCode", "equals": true }
}
]
},
{
"id": "maven-archetype",
"displayName": "Maven Archetype",
"description": "A project generated by Maven from an archetype.",
"section": "generator",
"order": 10,
"icon": { "path": "icons/maven-project.svg", "darkPath": "icons/maven-project_dark.svg", "mode": "original" },
"fields": [
{
"id": "jdk",
"type": "runtime",
"title": "JDK",
"description": "Maven runs with this JDK, and the new project uses it.",
"runtime": "java",
"minimumVersion": "11"
},
{
"id": "archetype",
"type": "enum",
"title": "Archetype",
"presentation": "menu",
"default": "maven-archetype-quickstart",
"options": [
{ "value": "maven-archetype-quickstart", "title": "maven-archetype-quickstart" },
{ "value": "maven-archetype-webapp", "title": "maven-archetype-webapp" },
{ "value": "maven-archetype-simple", "title": "maven-archetype-simple" },
{ "value": "maven-archetype-j2ee-simple", "title": "maven-archetype-j2ee-simple" },
{ "value": "maven-archetype-plugin", "title": "maven-archetype-plugin" },
{ "value": "maven-archetype-archetype", "title": "maven-archetype-archetype" },
{ "value": "maven-archetype-site-simple", "title": "maven-archetype-site-simple" },
{ "value": "custom", "title": "Custom archetype…" }
]
},
{
"id": "archetypeGroupId",
"type": "text",
"title": "Archetype GroupId",
"pattern": "[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_-]*)*",
"maxLength": 200,
"placeholder": "org.example.archetypes",
"visibleWhen": { "field": "archetype", "equals": "custom" }
},
{
"id": "archetypeArtifactId",
"type": "text",
"title": "Archetype ArtifactId",
"pattern": "[A-Za-z0-9_][A-Za-z0-9_.-]*",
"maxLength": 200,
"placeholder": "my-archetype",
"visibleWhen": { "field": "archetype", "equals": "custom" }
},
{
"id": "archetypeVersion",
"type": "text",
"title": "Archetype version",
"description": "Leave empty to use the latest version Maven finds in its catalog.",
"optional": true,
"pattern": "[A-Za-z0-9_.-]+",
"maxLength": 64,
"placeholder": "Latest"
},
{
"id": "groupId",
"type": "text",
"title": "GroupId",
"advanced": true,
"default": "org.example",
"pattern": "[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*",
"maxLength": 200
},
{
"id": "artifactId",
"type": "text",
"title": "ArtifactId",
"advanced": true,
"default": "${project.name}",
"pattern": "[A-Za-z0-9_][A-Za-z0-9_.-]*",
"maxLength": 200
},
{
"id": "version",
"type": "text",
"title": "Version",
"advanced": true,
"default": "1.0-SNAPSHOT",
"pattern": "[A-Za-z0-9_.-]+",
"maxLength": 64
},
{
"id": "packageName",
"type": "text",
"title": "Package",
"advanced": true,
"default": "${field.groupId}.${field.artifactId|package}",
"pattern": "[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*",
"maxLength": 200
}
],
"requirements": [
{ "languageID": "java" },
{ "buildSystemID": "maven" }
],
"steps": [
{
"kind": "command",
"command": "mvn",
"arguments": [
"-B",
"org.apache.maven.plugins:maven-archetype-plugin:3.3.1:generate",
"-DinteractiveMode=false",
{ "value": "-DarchetypeGroupId=org.apache.maven.archetypes", "when": { "field": "archetype", "notEquals": "custom" } },
{ "value": "-DarchetypeArtifactId=${field.archetype}", "when": { "field": "archetype", "notEquals": "custom" } },
{ "value": "-DarchetypeGroupId=${field.archetypeGroupId}", "when": { "field": "archetype", "equals": "custom" } },
{ "value": "-DarchetypeArtifactId=${field.archetypeArtifactId}", "when": { "field": "archetype", "equals": "custom" } },
{ "value": "-DarchetypeVersion=${field.archetypeVersion}", "when": { "field": "archetypeVersion", "notEquals": "" } },
"-DgroupId=${field.groupId}",
"-DartifactId=${field.artifactId}",
"-Dversion=${field.version}",
"-Dpackage=${field.packageName}"
],
"environment": { "JAVA_HOME": "${field.jdk}" },
"collect": "${field.artifactId}",
"mayUseNetwork": true,
"timeoutSeconds": 900
}
],
"openFiles": ["pom.xml"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### Lithe ###
.lithe/workspace/

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### macOS ###
.DS_Store
43 changes: 43 additions & 0 deletions io.github.lithe-idea.maven-build/templates/java/maven/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>{{ field.groupId }}</groupId>
<artifactId>{{ field.artifactId }}</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.release>{{ field.jdk.major }}</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.4</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<pluginManagement>
<plugins>
<!-- Maven 3.8 binds Compiler 3.1, which ignores maven.compiler.release, and
Surefire 2.12, which cannot run JUnit Jupiter tests. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package {{ field.groupId | package }};

public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
20 changes: 19 additions & 1 deletion scripts/package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { createReport } from "./report.mjs";
import { verifySdk } from "./sdk/verify-sdk.mjs";
import { createHash } from "node:crypto";
import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync } from "node:fs";
import { join, resolve } from "node:path";
import { isAbsolute, join, resolve } from "node:path";

const PACKAGE_DIR = "io.github.lithe-idea.maven-build";
const ASSET_PREFIX = "maven-build";
Expand Down Expand Up @@ -53,6 +53,24 @@ if (tagFlag >= 0) {
const tag = process.argv[tagFlag + 1];
if (tag !== `v${manifest.version}`) problems.push(`tag ${tag} does not match plugin.json version ${manifest.version} (expected v${manifest.version})`);
}

// New Project reads a generator's icons and file templates from the installed
// package, so a wrong path would otherwise only fail on a user's machine.
const checkGeneratorPath = (generatorID, label, path, isExpected) => {
if (typeof path !== "string" || path === "" || isAbsolute(path) || path.split(/[\\/]/).includes("..")) {
problems.push(`generator ${generatorID}: ${label} ${JSON.stringify(path)} must be a relative path inside the package without ".."`);
return;
}
const target = join(PACKAGE_DIR, path);
if (!existsSync(target) || !isExpected(lstatSync(target))) problems.push(`generator ${generatorID}: missing ${label} ${path}`);
};
for (const generator of manifest.projectGenerators ?? []) {
if (generator.icon?.path !== undefined) checkGeneratorPath(generator.id, "icon file", generator.icon.path, (stat) => stat.isFile());
if (generator.icon?.darkPath !== undefined) checkGeneratorPath(generator.id, "dark icon file", generator.icon.darkPath, (stat) => stat.isFile());
for (const step of generator.steps ?? []) {
if (step.source !== undefined) checkGeneratorPath(generator.id, "template directory", step.source, (stat) => stat.isDirectory());
}
}
if (problems.length > 0) {
for (const problem of problems) console.error(`✗ ${problem}`);
process.exit(1);
Expand Down
Loading