|
1 | 1 | import fs from 'node:fs' |
2 | | -import os from 'node:os' |
3 | 2 | import path from 'node:path' |
4 | 3 |
|
5 | 4 | import fg from 'fast-glob' |
6 | 5 | import { load as yamlLoad } from 'js-yaml' |
7 | 6 | import micromatch from 'micromatch' |
8 | 7 |
|
9 | | -import { getCustom, getCustomPath, getGitRootDir, getWrapperPreference, invokeCommand } from './tools.js' |
| 8 | +import { getCustom, getCustomPath, invokeCommand } from './tools.js' |
10 | 9 |
|
11 | 10 | /** Default paths skipped during JS workspace discovery (merged with user patterns). */ |
12 | 11 | const DEFAULT_WORKSPACE_DISCOVERY_IGNORE = [ |
13 | 12 | '**/node_modules/**', |
14 | 13 | '**/.git/**', |
15 | | - '**/build/**', |
16 | | - '**/.gradle/**', |
17 | 14 | ] |
18 | 15 |
|
19 | 16 | /** |
@@ -227,159 +224,6 @@ async function discoverFromPackageJsonWorkspaces(root, packageJsonPath, globOpts |
227 | 224 | return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns) |
228 | 225 | } |
229 | 226 |
|
230 | | -/** |
231 | | - * Walk up from `startDir` to `repoRoot` looking for an executable wrapper script. |
232 | | - * |
233 | | - * @param {string} startDir - Absolute directory to start from |
234 | | - * @param {string} wrapperName - Wrapper filename (e.g. `mvnw`) |
235 | | - * @param {string} [repoRoot] - Stop boundary (defaults to git root or filesystem root) |
236 | | - * @returns {string | undefined} |
237 | | - */ |
238 | | -function traverseForWrapper(startDir, wrapperName, repoRoot = undefined) { |
239 | | - const currentDir = path.resolve(startDir) |
240 | | - repoRoot = repoRoot || getGitRootDir(currentDir) || path.parse(currentDir).root |
241 | | - const wrapperPath = path.join(currentDir, wrapperName) |
242 | | - |
243 | | - try { |
244 | | - fs.accessSync(wrapperPath, fs.constants.X_OK) |
245 | | - return wrapperPath |
246 | | - } catch (err) { |
247 | | - if (err.code === 'ENOENT') { |
248 | | - const rootDir = path.parse(currentDir).root |
249 | | - if (currentDir === repoRoot || currentDir === rootDir) { |
250 | | - return undefined |
251 | | - } |
252 | | - const parentDir = path.dirname(currentDir) |
253 | | - if (parentDir === currentDir || parentDir === rootDir) { |
254 | | - return undefined |
255 | | - } |
256 | | - return traverseForWrapper(parentDir, wrapperName, repoRoot) |
257 | | - } |
258 | | - throw new Error(`failure searching for ${wrapperName}`, { cause: err }) |
259 | | - } |
260 | | -} |
261 | | - |
262 | | -/** Gradle init script that emits structured project listing. */ |
263 | | -const GRADLE_INIT_SCRIPT = `allprojects { |
264 | | - task daListProjects { |
265 | | - doLast { |
266 | | - println "::DA_PROJECT::\${project.path}::\${project.projectDir}" |
267 | | - } |
268 | | - } |
269 | | -} |
270 | | -` |
271 | | - |
272 | | -/** |
273 | | - * Resolve the Gradle binary, respecting wrapper preference. |
274 | | - * |
275 | | - * @param {string} startDir - Directory from which to start the wrapper search |
276 | | - * @param {import('./index.js').Options} [opts={}] |
277 | | - * @returns {string} Path to the Gradle binary |
278 | | - */ |
279 | | -function resolveGradleBinary(startDir, opts = {}) { |
280 | | - const localWrapper = 'gradlew' + (process.platform === 'win32' ? '.bat' : '') |
281 | | - const useWrapper = getWrapperPreference('gradle', opts) |
282 | | - if (useWrapper) { |
283 | | - const wrapper = traverseForWrapper(startDir, localWrapper) |
284 | | - if (wrapper !== undefined) { |
285 | | - return wrapper |
286 | | - } |
287 | | - } |
288 | | - return getCustomPath('gradle', opts) |
289 | | -} |
290 | | - |
291 | | -/** |
292 | | - * Discover all build.gradle[.kts] manifest paths in a Gradle multi-project build. |
293 | | - * Uses a custom init script to get structured project listing. |
294 | | - * |
295 | | - * @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain settings.gradle[.kts]) |
296 | | - * @param {import('./index.js').Options} [opts={}] |
297 | | - * @returns {Promise<string[]>} Paths to build.gradle[.kts] files (absolute) |
298 | | - */ |
299 | | -export async function discoverGradleSubprojects(workspaceRoot, opts = {}) { |
300 | | - const root = path.resolve(workspaceRoot) |
301 | | - const hasSettings = fs.existsSync(path.join(root, 'settings.gradle')) |
302 | | - || fs.existsSync(path.join(root, 'settings.gradle.kts')) |
303 | | - |
304 | | - if (!hasSettings) { |
305 | | - return [] |
306 | | - } |
307 | | - |
308 | | - const gradleBin = resolveGradleBinary(root, opts) |
309 | | - const manifestPaths = [] |
310 | | - |
311 | | - const rootBuildKts = path.join(root, 'build.gradle.kts') |
312 | | - const rootBuild = path.join(root, 'build.gradle') |
313 | | - if (fs.existsSync(rootBuildKts)) { |
314 | | - manifestPaths.push(rootBuildKts) |
315 | | - } else if (fs.existsSync(rootBuild)) { |
316 | | - manifestPaths.push(rootBuild) |
317 | | - } |
318 | | - |
319 | | - const initScriptPath = path.join(os.tmpdir(), `da-list-projects-${process.pid}.gradle`) |
320 | | - try { |
321 | | - fs.writeFileSync(initScriptPath, GRADLE_INIT_SCRIPT) |
322 | | - let output |
323 | | - try { |
324 | | - output = invokeCommand(gradleBin, [ |
325 | | - '-q', '--no-daemon', |
326 | | - '--init-script', initScriptPath, |
327 | | - 'daListProjects', |
328 | | - ], { cwd: root }) |
329 | | - } catch { |
330 | | - const ignorePatterns = resolveWorkspaceDiscoveryIgnore(opts) |
331 | | - return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns) |
332 | | - } |
333 | | - |
334 | | - const projects = parseGradleInitScriptOutput(output.toString()) |
335 | | - for (const proj of projects) { |
336 | | - if (proj.path === ':') { |
337 | | - continue |
338 | | - } |
339 | | - const projDir = path.resolve(proj.dir) |
340 | | - const buildKts = path.join(projDir, 'build.gradle.kts') |
341 | | - const buildGroovy = path.join(projDir, 'build.gradle') |
342 | | - if (fs.existsSync(buildKts)) { |
343 | | - manifestPaths.push(buildKts) |
344 | | - } else if (fs.existsSync(buildGroovy)) { |
345 | | - manifestPaths.push(buildGroovy) |
346 | | - } |
347 | | - } |
348 | | - } finally { |
349 | | - try { fs.unlinkSync(initScriptPath) } catch { /* ignore */ } |
350 | | - } |
351 | | - |
352 | | - const ignorePatterns = resolveWorkspaceDiscoveryIgnore(opts) |
353 | | - return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns) |
354 | | -} |
355 | | - |
356 | | -/** |
357 | | - * Parse the structured output from the Gradle init script. |
358 | | - * |
359 | | - * @param {string} raw - Raw stdout from gradle |
360 | | - * @returns {{ path: string, dir: string }[]} |
361 | | - */ |
362 | | -function parseGradleInitScriptOutput(raw) { |
363 | | - const projects = [] |
364 | | - for (const line of raw.split('\n')) { |
365 | | - if (!line.startsWith('::DA_PROJECT::')) { |
366 | | - continue |
367 | | - } |
368 | | - const prefix = '::DA_PROJECT::' |
369 | | - const remainder = line.substring(prefix.length) |
370 | | - const lastSep = remainder.lastIndexOf('::') |
371 | | - if (lastSep < 0) { |
372 | | - continue |
373 | | - } |
374 | | - const projPath = remainder.substring(0, lastSep) |
375 | | - const dir = remainder.substring(lastSep + 2) |
376 | | - if (projPath && dir) { |
377 | | - projects.push({ path: projPath, dir }) |
378 | | - } |
379 | | - } |
380 | | - return projects |
381 | | -} |
382 | | - |
383 | 227 | /** |
384 | 228 | * Discover all Cargo.toml manifest paths in a Cargo workspace. |
385 | 229 | * Uses `cargo metadata` to get workspace members. |
|
0 commit comments