XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
# Functions shared by the managed/compiler and native/PAL source receipts.
function Get-RuntimeInputHash([string]$Path) {
    (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
function Get-RuntimeRelativeInput([string]$Root,[string]$Path) {
    $absolute=[IO.Path]::GetFullPath($Path)
    $prefix=[IO.Path]::GetFullPath($Root).TrimEnd([char]'\',[char]'/')+[IO.Path]::DirectorySeparatorChar
    if (!$absolute.StartsWith($prefix,[StringComparison]::OrdinalIgnoreCase)) { throw ('Input outside the repository cannot be source-bound: '+$absolute) }
    $absolute.Substring($prefix.Length).Replace('\','/')
}
function Get-RuntimeAbsoluteInput([string]$Directory,[string]$Path) {
    if([IO.Path]::IsPathRooted($Path)) { return [IO.Path]::GetFullPath($Path) }
    return [IO.Path]::GetFullPath((Join-Path $Directory $Path))
}
function Get-RuntimeGlobInputs([string]$Directory,[string]$Pattern) {
    $normalized=$Pattern.Replace('\','/')
    $first=$normalized.IndexOfAny([char[]]'*?')
    if($first -lt 0) { throw ('Not a wildcard input: '+$Pattern) }
    $slash=$normalized.LastIndexOf('/', $first)
    $parent=if($slash -ge 0){$normalized.Substring(0,$slash)}else{'.'}
    $suffix=if($slash -ge 0){$normalized.Substring($slash+1)}else{$normalized}
    # Windows GetFullPath rejects wildcard characters. Resolve only the literal
    # parent, then match file paths ourselves using MSBuild's ** directory rule.
    $absolute=(Get-RuntimeAbsoluteInput $Directory $parent).TrimEnd([char]'\',[char]'/')
    if(!(Test-Path -LiteralPath $absolute -PathType Container)) { throw ('Wildcard parent is unavailable: '+$absolute) }
    $parts=$suffix.Split('/')
    $expression='^'
    for($index=0;$index -lt $parts.Length;$index++) {
        $part=$parts[$index]
        if($part -eq '**') {
            $expression+=if($index -lt $parts.Length-1){'(?:[^/]+/)*'}else{'.*'}
            continue
        }
        if($part -eq '..') { throw ('Parent traversal after a wildcard cannot be source-bound: '+$Pattern) }
        foreach($character in $part.ToCharArray()) {
            if($character -eq '*'){$expression+='[^/]*'}
            elseif($character -eq '?'){$expression+='[^/]'}
            else{$expression+=[regex]::Escape([string]$character)}
        }
        if($index -lt $parts.Length-1){$expression+='/'}
    }
    $expression+='$'
    $matcher=[regex]::new($expression,[Text.RegularExpressions.RegexOptions]::IgnoreCase)
    $found=@(Get-ChildItem -LiteralPath $absolute -Recurse -File | Where-Object {
        $relative=$_.FullName.Substring($absolute.Length+1).Replace('\','/')
        $matcher.IsMatch($relative)
    })
    if(!$found.Count) { throw ('Embedded/input pattern has no files: '+$Pattern) }
    return $found
}
function Add-RuntimeBuildImports([string]$Path,$Files,$Visited) {
    $absolute=[IO.Path]::GetFullPath($Path)
    if(!$Visited.Add($absolute)) { return }
    [void]$Files.Add($absolute)
    [xml]$xml=Get-Content -LiteralPath $absolute -Raw -Encoding UTF8
    $directory=Split-Path -Parent $absolute
    foreach($import in $xml.SelectNodes('//Import[@Project]')) {
        $expression=$import.Project.Replace('$(MSBuildThisFileDirectory)',$directory+[IO.Path]::DirectorySeparatorChar)
        if($expression -match '[$][(]') { throw ('Unevaluated explicit MSBuild import: '+$expression) }
        foreach($include in $expression.Split(';')) {
            if($include -match '[*?]') {
                foreach($file in Get-RuntimeGlobInputs $directory $include) { Add-RuntimeBuildImports $file.FullName $Files $Visited }
            } else {
                $next=Get-RuntimeAbsoluteInput $directory $include
                if(!(Test-Path -LiteralPath $next -PathType Leaf)) { throw ('Explicit MSBuild import is unavailable: '+$next) }
                Add-RuntimeBuildImports $next $Files $Visited
            }
        }
    }
}
function Get-RuntimeProjectInputs([string]$Root,[string]$Project) {
    $files=[Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
    $projects=[Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
    $queue=[Collections.Generic.Queue[string]]::new()
    $queue.Enqueue([IO.Path]::GetFullPath($Project))
    while($queue.Count) {
        $current=$queue.Dequeue()
        if(!$projects.Add($current)) { continue }
        $directory=Split-Path -Parent $current
        [void]$files.Add($current)
        foreach($file in Get-ChildItem -LiteralPath $directory -Recurse -File) {
            if($file.FullName -notmatch '[/\\](bin|obj)[/\\]') { [void]$files.Add($file.FullName) }
        }
        [xml]$xml=Get-Content -LiteralPath $current -Raw -Encoding UTF8
        if($xml.SelectNodes('//PackageReference').Include -match '^Cosmos[.]') { throw ('Cosmos package in native application graph: '+$current) }
        foreach($reference in $xml.SelectNodes('//ProjectReference[@Include]')) {
            foreach($include in $reference.Include.Split(';')) {
                if($include -match '[$][(]|[*?]') { throw ('Unresolved project reference in source receipt: '+$include) }
                $next=Get-RuntimeAbsoluteInput $directory $include
                if(!(Test-Path -LiteralPath $next -PathType Leaf)) { throw ('Referenced project is unavailable: '+$next) }
                $queue.Enqueue($next)
            }
        }
        # Capture linked C# files and exact external embedded assets, including
        # resources outside the project's directory and semicolon/wildcard items.
        foreach($item in $xml.SelectNodes('//Compile[@Include]|//EmbeddedResource[@Include]|//AdditionalFiles[@Include]|//Reference/HintPath|//Import[@Project]')) {
            $expression=if($item.Name -eq 'HintPath'){$item.InnerText}elseif($item.Name -eq 'Import'){$item.Project}else{$item.Include}
            foreach($include in $expression.Split(';')) {
                if(!$include) { continue }
                if($include -match '[$][(]|[%][(]') { throw ('Unevaluated build input in source receipt: '+$include) }
                if($include -match '[*?]') {
                    $found=@(Get-RuntimeGlobInputs $directory $include)
                    foreach($file in $found) { [void]$files.Add($file.FullName) }
                } else {
                    $absolute=Get-RuntimeAbsoluteInput $directory $include
                    if(!(Test-Path -LiteralPath $absolute -PathType Leaf)) { throw ('Explicit build input is unavailable: '+$absolute) }
                    [void]$files.Add($absolute)
                }
            }
        }
    }
    foreach($name in @('Directory.Build.props','Directory.Build.targets','Directory.Packages.props','NuGet.config','nuget.config','global.json')) {
        $path=Join-Path $Root $name
        if(Test-Path -LiteralPath $path -PathType Leaf) { [void]$files.Add([IO.Path]::GetFullPath($path)) }
    }
    $imports=[Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
    foreach($name in @('Directory.Build.props','Directory.Build.targets','Directory.Packages.props')) {
        $path=Join-Path $Root $name
        if(Test-Path -LiteralPath $path -PathType Leaf) { Add-RuntimeBuildImports $path $files $imports }
    }
    # HostJint.targets executes this source tool as part of the real application
    # build. It is an implicit build dependency, not a ProjectReference.
    $jintTool=Join-Path $Root 'Tools/JintCleanupPatch'
    if(Test-Path -LiteralPath $jintTool -PathType Container) {
        foreach($file in Get-ChildItem -LiteralPath $jintTool -Recurse -File) {
            if($file.FullName -notmatch '[/\\](bin|obj)[/\\]') { [void]$files.Add($file.FullName) }
        }
    }
    $hashes=[ordered]@{}
    foreach($path in @($files | Sort-Object)) { $hashes[(Get-RuntimeRelativeInput $Root $path)]=Get-RuntimeInputHash $path }
    return $hashes
}
function Assert-RuntimeSourceInputs([string]$Root,$Hashes) {
    foreach($entry in $Hashes.GetEnumerator()) {
        $path=Join-Path $Root $entry.Key
        if(!(Test-Path -LiteralPath $path -PathType Leaf) -or (Get-RuntimeInputHash $path) -cne $entry.Value) {
            throw ('A source/asset input changed during compilation: '+$entry.Key)
        }
    }
}
function Assert-RuntimeManagedDependencies([string]$ManagedInputPath,[string[]]$References) {
    $manifest=[IO.Path]::ChangeExtension($ManagedInputPath,'.deps.json')
    if(!(Test-Path -LiteralPath $manifest -PathType Leaf)) { throw ('Managed dependency manifest is unavailable: '+$manifest) }
    $dependencies=Get-Content -LiteralPath $manifest -Raw -Encoding UTF8 | ConvertFrom-Json
    $target=$dependencies.targets.PSObject.Properties[$dependencies.runtimeTarget.name]
    if(!$target) { throw ('Managed dependency target is unavailable: '+$dependencies.runtimeTarget.name) }
    $available=[Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
    foreach($path in (@($ManagedInputPath)+@($References))) {
        if(!(Test-Path -LiteralPath $path -PathType Leaf)) { throw ('Managed compiler input is unavailable: '+$path) }
        [void]$available.Add([IO.Path]::GetFileName($path))
    }
    $required=[Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
    foreach($library in $target.Value.PSObject.Properties) {
        foreach($asset in $library.Value.runtime.PSObject.Properties) {
            if(![string]::Equals([IO.Path]::GetExtension($asset.Name),'.dll',[StringComparison]::OrdinalIgnoreCase)) { continue }
            $name=[IO.Path]::GetFileName($asset.Name)
            [void]$required.Add($name)
            if(!$available.Contains($name)) { throw ('Declared managed runtime dependency is absent from ILC inputs: '+$name+' ('+$library.Name+')') }
        }
    }
    if(!$required.Count -or !$required.Contains([IO.Path]::GetFileName($ManagedInputPath))) { throw 'Managed dependency manifest does not identify the entry assembly.' }
    return [pscustomobject]@{Path=$manifest;Sha256=(Get-RuntimeInputHash $manifest);RuntimeTarget=$dependencies.runtimeTarget.name;RuntimeAssemblies=@($required | Sort-Object)}
}
function Assert-RuntimeIlcDiagnostics([string]$LogPath) {
    $diagnostics=Get-Content -LiteralPath $LogPath -Raw -Encoding UTF8
    if($diagnostics -match '(?im)\b(?:AOT analysis|code generation)\s+error\b|\berror\s+IL[0-9]{4}\b') {
        throw ('NativeAOT reported a compilation/analysis error despite its process exit code; see '+$LogPath)
    }
}