mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-10 22:33:44 +00:00
311 lines
12 KiB
PowerShell
311 lines
12 KiB
PowerShell
# Copy-Recursive.ps1
|
|
# ====================
|
|
# SUPERWEAPON: Recursive dependency-aware file copier.
|
|
#
|
|
# Given one or more Java source files from mc1710, this function:
|
|
# 1. Copies each file to the corresponding location in core/
|
|
# 2. Parses all import statements in the copied file
|
|
# 3. For each import that maps to another project file:
|
|
# - Checks if the file's path starts with an ALLOWED prefix (whitelist)
|
|
# - Checks if it already exists in core/
|
|
# - If allowed AND not in core, copies it
|
|
# - Then recursively processes THAT file's imports (subject to AllowRecursePaths)
|
|
# 4. Skips all Minecraft/Forge/Java stdlib imports
|
|
# 5. Logs every file it copies and every file it skips (with reason)
|
|
#
|
|
# USAGE:
|
|
# . tools/migration/Copy-Recursive.ps1
|
|
#
|
|
# # Copy AnimationController and ALL its allowed deps:
|
|
# Copy-Recursive -Sources @('noppes/npcs/controllers/AnimationController.java') `
|
|
# -AllowPaths @('noppes/npcs/controllers/', 'noppes/npcs/roles/', 'noppes/npcs/quests/', 'noppes/npcs/config/')
|
|
#
|
|
# # Copy with recursion restricted to controllers/ only:
|
|
# Copy-Recursive -Sources @('noppes/npcs/controllers/AnimationController.java') `
|
|
# -AllowPaths @('noppes/npcs/controllers/', 'noppes/npcs/roles/', 'noppes/npcs/quests/') `
|
|
# -AllowRecursePaths @('noppes/npcs/controllers/')
|
|
#
|
|
# PARAMS:
|
|
# -Sources Array of relative paths within McRoot (e.g., 'noppes/npcs/controllers/Foo.java')
|
|
# -AllowPaths WHITELIST: only recursively copy files whose path starts with one of these prefixes.
|
|
# The initial -Sources files are ALWAYS copied regardless of whitelist.
|
|
# If empty/not provided, ALL project files are allowed (no filter).
|
|
# -AllowRecursePaths RECURSION WHITELIST: only follow/scan imports of files whose path starts with
|
|
# one of these prefixes. Files from non-whitelisted paths are still COPIED as
|
|
# dependencies, but their own imports are NOT recursively followed.
|
|
# Initial -Sources files ALWAYS have their imports followed regardless.
|
|
# If empty/not provided, ALL files have their imports followed (current behavior).
|
|
# DIFFERENT from -AllowPaths:
|
|
# -AllowPaths = WHERE files can be copied TO (destination filter)
|
|
# -AllowRecursePaths = WHERE imports can be recursively FOLLOWED FROM (recursion filter)
|
|
# -McRoot Source root directory (default: 'mc1710/src/main/java')
|
|
# -CoreRoot Destination root directory (default: 'core/src/main/java')
|
|
# -ProjectRoot Absolute project root (auto-detected from script location if not provided)
|
|
# -ForbiddenPrefixes Import prefixes that are NEVER followed (external deps).
|
|
# Defaults to java.*, net.minecraft.*, cpw.mods.*, net.minecraftforge.*, etc.
|
|
#
|
|
# OUTPUT:
|
|
# Returns array of all files that were copied (relative paths).
|
|
# Prints detailed log to stdout.
|
|
|
|
function Copy-Recursive {
|
|
param(
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]$Sources,
|
|
|
|
[string[]]$AllowPaths = @(),
|
|
|
|
[string[]]$AllowRecursePaths = @(),
|
|
|
|
[string]$McRoot = 'mc1710/src/main/java',
|
|
[string]$CoreRoot = 'core/src/main/java',
|
|
[string]$ProjectRoot,
|
|
|
|
# Import prefixes that are NEVER followed/copied (external deps)
|
|
[string[]]$ForbiddenPrefixes = @(
|
|
'java.', 'javax.', 'sun.',
|
|
'net.minecraft.', 'cpw.mods.', 'net.minecraftforge.',
|
|
'org.lwjgl.', 'org.apache.', 'com.google.',
|
|
'org.mozilla.', 'io.netty.', 'org.objectweb.',
|
|
'scala.', 'org.spongepowered.'
|
|
)
|
|
)
|
|
|
|
# Auto-detect ProjectRoot from script location if not provided
|
|
if (-not $ProjectRoot) {
|
|
$ProjectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
|
|
}
|
|
|
|
# State
|
|
$script:visited = @{}
|
|
$script:copied = [System.Collections.ArrayList]::new()
|
|
$script:skippedExisting = [System.Collections.ArrayList]::new()
|
|
$script:skippedNotAllowed = [System.Collections.ArrayList]::new()
|
|
$script:skippedRecurse = [System.Collections.ArrayList]::new()
|
|
$script:notFound = [System.Collections.ArrayList]::new()
|
|
$script:initialSourceCount = 0
|
|
$script:nonRecurseImportCount = 0
|
|
$script:depth = 0
|
|
|
|
$hasWhitelist = $AllowPaths.Count -gt 0
|
|
$hasRecurseWhitelist = $AllowRecursePaths.Count -gt 0
|
|
|
|
function Is-Forbidden {
|
|
param([string]$Import)
|
|
foreach ($prefix in $ForbiddenPrefixes) {
|
|
if ($Import.StartsWith($prefix)) { return $true }
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Is-Allowed {
|
|
param([string]$RelativePath)
|
|
if (-not $hasWhitelist) { return $true }
|
|
foreach ($allow in $AllowPaths) {
|
|
if ($RelativePath.StartsWith($allow)) { return $true }
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Is-RecurseAllowed {
|
|
param([string]$RelativePath)
|
|
if (-not $hasRecurseWhitelist) { return $true }
|
|
foreach ($allow in $AllowRecursePaths) {
|
|
if ($RelativePath.StartsWith($allow)) { return $true }
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Process-File {
|
|
param(
|
|
[string]$RelativePath,
|
|
[bool]$IsInitialSource = $false
|
|
)
|
|
|
|
# Normalize separators
|
|
$RelativePath = $RelativePath -replace '\\', '/'
|
|
|
|
# Avoid cycles
|
|
if ($script:visited.ContainsKey($RelativePath)) { return }
|
|
$script:visited[$RelativePath] = $true
|
|
|
|
# Whitelist check (initial sources bypass)
|
|
if (-not $IsInitialSource -and -not (Is-Allowed -RelativePath $RelativePath)) {
|
|
[void]$script:skippedNotAllowed.Add($RelativePath)
|
|
return
|
|
}
|
|
|
|
# Determine if we should recurse into this file's imports
|
|
$shouldRecurse = $IsInitialSource -or (Is-RecurseAllowed -RelativePath $RelativePath)
|
|
|
|
$srcFull = Join-Path $ProjectRoot (Join-Path $McRoot $RelativePath)
|
|
$dstFull = Join-Path $ProjectRoot (Join-Path $CoreRoot $RelativePath)
|
|
|
|
# Skip if already exists in core
|
|
if (Test-Path $dstFull) {
|
|
[void]$script:skippedExisting.Add($RelativePath)
|
|
$indent = ' ' * $script:depth
|
|
if ($shouldRecurse) {
|
|
# STILL parse imports to find transitive deps that may not exist in core yet
|
|
$content = [IO.File]::ReadAllText($dstFull)
|
|
Write-Host "${indent}EXISTS: $RelativePath"
|
|
Parse-And-Follow -Content $content
|
|
} else {
|
|
Write-Host "${indent}EXISTS: $RelativePath (recursion restricted -- not in AllowRecursePaths)"
|
|
[void]$script:skippedRecurse.Add($RelativePath)
|
|
$script:nonRecurseImportCount++
|
|
}
|
|
return
|
|
}
|
|
|
|
# Skip if source doesn't exist in mc1710
|
|
if (!(Test-Path $srcFull)) {
|
|
[void]$script:notFound.Add($RelativePath)
|
|
return
|
|
}
|
|
|
|
# Copy the file
|
|
$dir = Split-Path $dstFull -Parent
|
|
if (!(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
|
Copy-Item $srcFull $dstFull -Force
|
|
|
|
[void]$script:copied.Add($RelativePath)
|
|
$indent = ' ' * $script:depth
|
|
|
|
if ($IsInitialSource) {
|
|
$script:initialSourceCount++
|
|
Write-Host "${indent}COPIED: $RelativePath [initial source]"
|
|
} elseif ($shouldRecurse) {
|
|
Write-Host "${indent}COPIED: $RelativePath"
|
|
} else {
|
|
Write-Host "${indent}COPIED: $RelativePath (non-recurse import -- path not in AllowRecursePaths)"
|
|
$script:nonRecurseImportCount++
|
|
}
|
|
|
|
# Parse imports and recurse (only if allowed)
|
|
if ($shouldRecurse) {
|
|
$content = [IO.File]::ReadAllText($srcFull)
|
|
Parse-And-Follow -Content $content
|
|
} else {
|
|
[void]$script:skippedRecurse.Add($RelativePath)
|
|
}
|
|
}
|
|
|
|
function Parse-And-Follow {
|
|
param([string]$Content)
|
|
|
|
$imports = [regex]::Matches($Content, 'import\s+(?:static\s+)?([^;]+);')
|
|
|
|
$script:depth++
|
|
|
|
foreach ($match in $imports) {
|
|
$imp = $match.Groups[1].Value.Trim()
|
|
|
|
# Skip forbidden (MC, Forge, Java stdlib, etc.)
|
|
if (Is-Forbidden -Import $imp) {
|
|
continue
|
|
}
|
|
|
|
# Handle wildcard imports: import noppes.npcs.controllers.data.*;
|
|
if ($imp -match '\.\*$') {
|
|
$pkgPath = ($imp -replace '\.\*$', '') -replace '\.', '/'
|
|
$pkgDir = Join-Path $ProjectRoot (Join-Path $McRoot $pkgPath)
|
|
if (Test-Path $pkgDir) {
|
|
Get-ChildItem -Path $pkgDir -Filter '*.java' -File | ForEach-Object {
|
|
$relPath = ($pkgPath + '/' + $_.Name) -replace '\\', '/'
|
|
Process-File -RelativePath $relPath
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
|
|
# Convert import to file path and try to find it
|
|
$filePath = ($imp -replace '\.', '/') + '.java'
|
|
$fullCheck = Join-Path $ProjectRoot (Join-Path $McRoot $filePath)
|
|
|
|
if (Test-Path $fullCheck) {
|
|
Process-File -RelativePath $filePath
|
|
} else {
|
|
# Might be inner class or static member -- try removing last segment(s)
|
|
$parts = $imp -split '\.'
|
|
for ($i = $parts.Length - 1; $i -ge 1; $i--) {
|
|
$tryImport = ($parts[0..($i-1)] -join '/') + '.java'
|
|
$tryFull = Join-Path $ProjectRoot (Join-Path $McRoot $tryImport)
|
|
if (Test-Path $tryFull) {
|
|
Process-File -RelativePath $tryImport
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$script:depth--
|
|
}
|
|
|
|
# ===== MAIN EXECUTION =====
|
|
Write-Host ""
|
|
Write-Host "============================================"
|
|
Write-Host " COPY-RECURSIVE -- Dependency-Aware Copier"
|
|
Write-Host "============================================"
|
|
Write-Host "Source root: $McRoot"
|
|
Write-Host "Dest root: $CoreRoot"
|
|
Write-Host "Targets: $($Sources.Count) file(s)"
|
|
if ($hasWhitelist) {
|
|
Write-Host "AllowPaths: $($AllowPaths.Count) path prefix(es) [copy destination whitelist]"
|
|
foreach ($a in $AllowPaths) { Write-Host " >> $a" }
|
|
} else {
|
|
Write-Host "AllowPaths: NONE (all project files allowed)"
|
|
}
|
|
if ($hasRecurseWhitelist) {
|
|
Write-Host "AllowRecursePaths: $($AllowRecursePaths.Count) prefix(es) [recursion source whitelist]"
|
|
foreach ($a in $AllowRecursePaths) { Write-Host " ~> $a" }
|
|
} else {
|
|
Write-Host "AllowRecursePaths: NONE (all discovered files recursed)"
|
|
}
|
|
Write-Host "============================================"
|
|
Write-Host ""
|
|
|
|
foreach ($src in $Sources) {
|
|
$src = $src -replace '\\', '/'
|
|
Process-File -RelativePath $src -IsInitialSource $true
|
|
}
|
|
|
|
# ===== SUMMARY =====
|
|
$recursivelyDiscovered = $script:copied.Count - $script:initialSourceCount
|
|
Write-Host ""
|
|
Write-Host "============================================"
|
|
Write-Host " RECURSIVE COPY SUMMARY"
|
|
Write-Host "============================================"
|
|
Write-Host "Copied: $($script:copied.Count) files ($($script:initialSourceCount) initial sources, $($recursivelyDiscovered) recursively discovered, $($script:nonRecurseImportCount) non-recurse imports)"
|
|
Write-Host ""
|
|
Write-Host "Files COPIED: $($script:copied.Count)"
|
|
foreach ($f in $script:copied) {
|
|
Write-Host " + $f"
|
|
}
|
|
Write-Host ""
|
|
Write-Host "Already in core: $($script:skippedExisting.Count)"
|
|
foreach ($f in $script:skippedExisting) {
|
|
Write-Host " = $f"
|
|
}
|
|
Write-Host ""
|
|
Write-Host "Skipped (not whitelisted): $($script:skippedNotAllowed.Count)"
|
|
foreach ($f in $script:skippedNotAllowed) {
|
|
Write-Host " x $f"
|
|
}
|
|
if ($hasRecurseWhitelist) {
|
|
Write-Host ""
|
|
Write-Host "Recursion restricted: $($script:skippedRecurse.Count) (copied but imports NOT followed)"
|
|
foreach ($f in $script:skippedRecurse) {
|
|
Write-Host " ~ $f -- path not in AllowRecursePaths"
|
|
}
|
|
}
|
|
Write-Host ""
|
|
Write-Host "Not found in mc1710: $($script:notFound.Count)"
|
|
foreach ($f in $script:notFound) {
|
|
Write-Host " ? $f"
|
|
}
|
|
Write-Host "============================================"
|
|
|
|
return $script:copied.ToArray()
|
|
}
|