дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
fix(gradle): read dependencies from scripts a build applies (#2277)
Dependencies declared in a script pulled in with `apply from:` never reached External Libraries, and `"g🅰️${v}"` versions were dropped because statement splitting at `{` cut them in half. The scan now follows `apply from` recursively (Groovy and Kotlin DSL; `$rootDir`, `$projectDir`, `rootProject.projectDir`; relative paths from the project directory, then beside the applying script; URLs and missing files skipped; cycles and aliases cut by canonical path, bounded at 256 scripts and 32 levels). It fills `ext`/`extra` values (`ext.x`, `ext { }`, `ext["x"]`, `extra["x"]`, `val x by extra(...)`) into `${...}` versions with gradle.properties taking precedence, and counts applied scripts as build inputs, so editing one invalidates the cached model and refreshes the Build tool window and External Libraries. Co-authored-by: zmh69695328 <[email protected]>
Цей коміт міститься в:
1 джерело
e86134ce83
коміт
dfa610beb0
9 files changed
+787
-20
No files matched your search
@@ -6,6 +6,7 @@
|
||||
import { onEditorEvent, registerEditorContribution } from "@/editor/api";
|
||||
import { executeAction, registerActions } from "@/platform/actions";
|
||||
import { setContext } from "@/platform/context";
|
||||
import { isGradleBuildInput } from "@/platform/buildFiles";
|
||||
import { onIdeEvent, type BuildModel, type BuildTool } from "@/platform/ipc";
|
||||
import { useProject } from "@/platform/project";
|
||||
import {
|
||||
@@ -58,8 +59,8 @@ export const MAVEN_WHEN = "projectOpen && build.maven";
|
||||
export const GRADLE_WHEN = "projectOpen && build.gradle";
|
||||
|
||||
/** Build files whose creation / change / removal re-reads the model. */
|
||||
const BUILD_FILE =
|
||||
/(?:^|\/)(?:pom\.xml|(?:build|settings)\.gradle(?:\.kts)?|mvnw(?:\.cmd)?|gradlew(?:\.bat)?|gradle\.properties|gradle-wrapper\.properties|[^/]+\.versions\.toml)$/;
|
||||
const isBuildFile = (path: string) =>
|
||||
isGradleBuildInput(path) || /(?:^|[\\/])(?:pom\.xml|mvnw(?:\.cmd)?|gradlew(?:\.bat)?)$/.test(path);
|
||||
|
||||
function expandAll(tool: BuildTool) {
|
||||
const { model, configs } = useBuild.getState();
|
||||
@@ -234,10 +235,10 @@ export function activate(): () => void {
|
||||
if (s.project) void loadModel();
|
||||
}),
|
||||
onEditorEvent((e) => {
|
||||
if (e.type === "docSaved" && BUILD_FILE.test(e.path)) noteIdeSave(e.path);
|
||||
if (e.type === "docSaved" && isBuildFile(e.path)) noteIdeSave(e.path);
|
||||
}),
|
||||
onIdeEvent("fsChanged", (e) => {
|
||||
const changed = [...e.created, ...e.modified, ...e.removed].filter((p) => BUILD_FILE.test(p));
|
||||
const changed = [...e.created, ...e.modified, ...e.removed].filter(isBuildFile);
|
||||
if (!changed.length) return;
|
||||
// Changes the IDE's own saves didn't make came from outside (a VCS update, another tool),
|
||||
// also for a build file open in a tab.
|
||||
|
||||
@@ -3,6 +3,7 @@ import { act, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { executeAction, registerAction, allActions, isActionEnabled } from "@/platform/actions";
|
||||
import { setContext } from "@/platform/context";
|
||||
import type { BuildModel, GradleModel, ProjectInfo, RunConfig } from "@/platform/ipc";
|
||||
import { emitLocalIdeEvent } from "@/platform/ipc";
|
||||
import { useProject } from "@/platform/project";
|
||||
import { GradleView, MavenView } from "./BuildToolView";
|
||||
import { activate } from "./index";
|
||||
@@ -112,6 +113,22 @@ afterEach(() => {
|
||||
setContext("projectOpen", false);
|
||||
});
|
||||
|
||||
it("re-reads the build model when an applied Groovy or Kotlin script changes", async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
for (const path of ["/p/gradle/dependencies.gradle", "/p/gradle/dependencies.gradle.kts"]) {
|
||||
const calls = mocks.model.mock.calls.length;
|
||||
await act(async () => {
|
||||
emitLocalIdeEvent({ type: "fsChanged", created: [], modified: [path], removed: [] });
|
||||
await vi.advanceTimersByTimeAsync(300);
|
||||
});
|
||||
expect(mocks.model).toHaveBeenCalledTimes(calls + 1);
|
||||
}
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("offers unlink on a root's context menu and persists a confirmed project setting", async () => {
|
||||
render(<MavenView />);
|
||||
fireEvent.contextMenu(screen.getByText("project-a"));
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { Channel } from "@tauri-apps/api/core";
|
||||
import { commands, type LibraryGroup, type RequestId } from "@/bindings";
|
||||
import { mergeLibraryGroups } from "@/platform/libraries";
|
||||
import { isGradleBuildInput } from "@/platform/buildFiles";
|
||||
import { registerActions } from "@/platform/actions";
|
||||
import { setLibraryRoots } from "@/editor/api";
|
||||
import { call, isCancelled, isTauri, nextRequestId, onIdeEvent } from "@/platform/ipc";
|
||||
@@ -73,7 +74,7 @@ export function touchesManifest(paths: readonly string[]): boolean {
|
||||
return paths.some(
|
||||
(p) =>
|
||||
!/[\\/]node_modules[\\/]/.test(p) &&
|
||||
MANIFESTS.has(p.slice(Math.max(p.lastIndexOf("/"), p.lastIndexOf("\\")) + 1)),
|
||||
(isGradleBuildInput(p) || MANIFESTS.has(p.slice(Math.max(p.lastIndexOf("/"), p.lastIndexOf("\\")) + 1))),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,13 @@ describe("External Libraries", () => {
|
||||
expect(touchesManifest(["/p/src/package.json.bak", "/p/README.md"])).toBe(false);
|
||||
});
|
||||
|
||||
it("refreshes when an applied Gradle script or properties file changes", () => {
|
||||
expect(touchesManifest(["/p/gradle/dependencies.gradle"])).toBe(true);
|
||||
expect(touchesManifest(["C:\\p\\gradle\\dependencies.gradle.kts"])).toBe(true);
|
||||
expect(touchesManifest(["/p/gradle.properties"])).toBe(true);
|
||||
expect(touchesManifest(["/p/node_modules/tool/dependencies.gradle"])).toBe(false);
|
||||
});
|
||||
|
||||
it("marks files below library roots for read-only editors", () => {
|
||||
dispose = setLibraryRoots("test", ["/py/lib/python3.12"]);
|
||||
expect(isLibraryPath("/py/lib/python3.12/os.py")).toBe(true);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { expect, it } from "vitest";
|
||||
import { isGradleBuildInput } from "./buildFiles";
|
||||
|
||||
it("recognizes applied scripts and Gradle properties for build and library refresh", () => {
|
||||
for (const path of [
|
||||
"/p/gradle/dependencies.gradle",
|
||||
"/p/gradle/dependencies.gradle.kts",
|
||||
"C:\\p\\gradle\\dependencies.gradle",
|
||||
"/p/gradle.properties",
|
||||
"/p/gradle/wrapper/gradle-wrapper.properties",
|
||||
"/p/gradle/libs.versions.toml",
|
||||
]) {
|
||||
expect(isGradleBuildInput(path), path).toBe(true);
|
||||
}
|
||||
for (const path of ["/p/dependencies.gradle.bak", "/p/src/main.kt", "/p/README.md"]) {
|
||||
expect(isGradleBuildInput(path), path).toBe(false);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
/** Gradle scripts and static inputs whose edits can change the build model or libraries. */
|
||||
export function isGradleBuildInput(path: string): boolean {
|
||||
return /(?:^|[\\/])(?:[^\\/]+\.gradle(?:\.kts)?|gradle\.properties|gradle-wrapper\.properties|[^\\/]+\.versions\.toml)$/.test(
|
||||
path,
|
||||
);
|
||||
}
|
||||
Reference in new issue
Заблокувати користувача