chcp.com 65001 > $null

$script:cache_dir = "D:\wyc\cached_external_library\cef_cache"




# ============================================
# 说明
# 1. 请把本脚本保存为 UTF-8 with BOM
# 2. 不改变现有外部命令的输出方式
# 3. 额外生成两份日志：
#    - transcript：控制台转录，尽量保留原始输出
#    - marker log：北京时间阶段日志
# ============================================

# =========================
# 北京时间日志
# =========================
$script:bj_tz = [System.TimeZoneInfo]::FindSystemTimeZoneById("China Standard Time")
$script:log_dir = $null
$script:marker_log_file = $null
$script:transcript_log_file = $null
$script:transcript_started = $false
$script:build_start_utc = [datetime]::UtcNow

function Get-BJNow {
    return [System.TimeZoneInfo]::ConvertTimeFromUtc([datetime]::UtcNow, $script:bj_tz)
}

function Get-BJTimeString {
    param(
        [switch]$ForFileName
    )

    $dt = Get-BJNow
    if ($ForFileName) {
        return $dt.ToString("yyyyMMdd_HHmmss")
    }
    return $dt.ToString("yyyy-MM-dd HH:mm:ss.fff")
}



function Invoke-CmdLineLogged {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0)]
        [string]$cmdLine
    )

    if ([string]::IsNullOrWhiteSpace($script:NativeCommandLogFile)) {
        throw '$script:NativeCommandLogFile 未设置，无法写日志。'
    }

    function Write-ConsoleAndLog {
        param(
            [Parameter(Mandatory)]
            [string]$Text
        )

        Write-Host $Text
        Add-Content -Path $script:NativeCommandLogFile -Value $Text -Encoding UTF8
    }

    $startTime = Get-Date
    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

    Write-ConsoleAndLog "================================================================"
    Write-ConsoleAndLog ("[开始时间] {0}" -f $startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"))
    Write-ConsoleAndLog ("[执行命令] {0}" -f $cmdLine)
    Write-ConsoleAndLog "----------------------------------------------------------------"

    cmd.exe /d /c $cmdLine 2>&1 |
            Tee-Object -FilePath $script:NativeCommandLogFile -Append |
            Out-Host

    $exitCode = $LASTEXITCODE
    $script:LastNativeExitCode = $exitCode

    $stopwatch.Stop()
    $endTime = Get-Date
    $elapsed = $stopwatch.Elapsed

    Write-ConsoleAndLog "----------------------------------------------------------------"
    Write-ConsoleAndLog ("[结束时间] {0}" -f $endTime.ToString("yyyy-MM-dd HH:mm:ss.fff"))
    Write-ConsoleAndLog ("[耗时] {0:hh\:mm\:ss\.fff}" -f $elapsed)
    Write-ConsoleAndLog ("[退出码] {0}" -f $exitCode)
    Write-ConsoleAndLog "================================================================"

    return $exitCode
}

#function Write-MarkerLog {
#    param(
#        [Parameter(Mandatory = $true)]
#        [string]$Message,
#
#        [ValidateSet("INFO", "STEP", "WARN", "ERROR")]
#        [string]$Level = "INFO"
#    )
#
#    if ([string]::IsNullOrWhiteSpace($script:marker_log_file)) {
#        return
#    }
#
#    $line = "[{0}] [{1}] {2}" -f (Get-BJTimeString), $Level, $Message
#    Add-Content -Path $script:marker_log_file -Value $line -Encoding UTF8
#}
function Write-MarkerLog {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Message,

        [ValidateSet("INFO", "STEP", "WARN", "ERROR")]
        [string]$Level = "INFO"
    )

    $line = "[{0}] [{1}] {2}" -f (Get-BJTimeString), $Level, $Message
    Write-Host $line
}
function Initialize-Logging {
    param(
        [Parameter(Mandatory = $true)]
        [string]$BaseDir
    )

    $script:log_dir = Join-Path $BaseDir "logs"
    if (!(Test-Path $script:log_dir)) {
        New-Item -ItemType Directory -Path $script:log_dir -Force | Out-Null
    }

    $ts = Get-BJTimeString -ForFileName
    $script:marker_log_file = Join-Path $script:log_dir ("cef_build_{0}.bj.log" -f $ts)
    $script:transcript_log_file = Join-Path $script:log_dir ("cef_build_{0}.transcript.log" -f $ts)

    New-Item -ItemType File -Path $script:marker_log_file -Force | Out-Null

    Start-Transcript -Path $script:transcript_log_file -Force | Out-Null
    $script:transcript_started = $true

    Write-MarkerLog "日志初始化完成"
    Write-MarkerLog "marker_log=$script:marker_log_file"
    Write-MarkerLog "transcript_log=$script:transcript_log_file"
}

#function Invoke-Step {
#    param(
#        [Parameter(Mandatory = $true)]
#        [string]$Name,
#
#        [Parameter(Mandatory = $true)]
#        [scriptblock]$Action
#    )
#
#    Write-MarkerLog "$Name 开始" "STEP"
#    $sw = [System.Diagnostics.Stopwatch]::StartNew()
#
#    & $Action
#
#    $sw.Stop()
#    Write-MarkerLog ("{0} 完成，耗时={1:n2}s" -f $Name, $sw.Elapsed.TotalSeconds) "STEP"
#}


function Invoke-Step {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [Parameter(Mandatory = $true)]
        [scriptblock]$Action
    )

    Write-MarkerLog "$Name 开始" "STEP"
    $sw = [System.Diagnostics.Stopwatch]::StartNew()

    $oldVerbosePreference = $VerbosePreference
    $oldDebugPreference = $DebugPreference
    $oldInformationPreference = $InformationPreference

    try {
        $VerbosePreference = 'Continue'
        $DebugPreference = 'Continue'
        $InformationPreference = 'Continue'

        if ([string]::IsNullOrWhiteSpace($script:marker_log_file)) {
            & $Action *>&1 | Out-Host
        }
        else {
            & $Action *>&1 |
                    Tee-Object -FilePath $script:marker_log_file -Append |
                    Out-Host
        }

        if ($LASTEXITCODE -ne 0) {
            throw "步骤 '$Name' 执行失败，退出码=$LASTEXITCODE"
        }
    }
    catch {
        Write-MarkerLog ("{0} 失败: {1}" -f $Name, $_.Exception.Message) "ERROR"
        throw
    }
    finally {
        $VerbosePreference = $oldVerbosePreference
        $DebugPreference = $oldDebugPreference
        $InformationPreference = $oldInformationPreference

        $sw.Stop()
        Write-MarkerLog ("{0} 完成，耗时={1:n2}s" -f $Name, $sw.Elapsed.TotalSeconds) "STEP"
    }
}


function Install-VSNativeDesktopComponents {
    param(
        [Parameter(Mandatory = $true)]
        [string]$InstallerPath,

        [switch]$ARM64
    )

    if (!(Test-Path $InstallerPath)) {
        throw "Installer not found: $InstallerPath"
    }

    $args = @(
        "--add", "Microsoft.VisualStudio.Workload.NativeDesktop",
        "--add", "Microsoft.VisualStudio.Component.VC.ATLMFC",
        "--includeRecommended"
    )

    if ($ARM64) {
        $args += @(
            "--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64",
            "--add", "Microsoft.VisualStudio.Component.VC.MFC.ARM64"
        )
    }

    Write-MarkerLog "Install-VSNativeDesktopComponents 开始: $InstallerPath" "STEP"
    Write-Host "Running installer: $InstallerPath"
    Write-Host "Arguments:"
    $args | ForEach-Object { Write-Host "  $_" }

    & $InstallerPath @args
    $exitCode = $LASTEXITCODE
    Write-MarkerLog "VS 安装器退出码: $exitCode"

    if ($exitCode -ne 0) {
        throw "Visual Studio installer failed with exit code: $exitCode"
    }

    Write-Host "Visual Studio components installed successfully."
    Write-MarkerLog "Install-VSNativeDesktopComponents 完成" "STEP"
}



function get_cached_file($url, $cache_path, $out_path) {
    $cache_file_path = Join-Path -Path $script:cache_dir -ChildPath $cache_path

    $cache_dir_path = Split-Path -Path $cache_file_path -Parent
    if (!(Test-Path $cache_dir_path)) {
        New-Item -ItemType Directory -Path $cache_dir_path -Force | Out-Null
    }

    Write-MarkerLog "get_cached_file: url=$url"
    Write-MarkerLog "get_cached_file: cache=$cache_file_path"
    Write-MarkerLog "get_cached_file: out=$out_path"

    if (!(Test-Path $cache_file_path)) {
        Write-Host "下载文件: $url"
        Invoke-WebRequest -Uri $url -OutFile $cache_file_path
        Write-MarkerLog "文件下载完成: $cache_file_path"
    }
    else {
        Write-Host "缓存已存在，跳过下载: $cache_file_path"
        Write-MarkerLog "命中缓存: $cache_file_path"
    }

    $out_dir = Split-Path -Path $out_path -Parent
    if ($out_dir -and !(Test-Path $out_dir)) {
        New-Item -ItemType Directory -Path $out_dir -Force | Out-Null
    }

    Copy-Item -Path $cache_file_path -Destination $out_path -Force
    Write-Host "已复制到: $out_path"
    Write-MarkerLog "复制完成: $out_path"
}

function get_cached_zip($url, $cache_path, $out_path) {
    $zip_path = Join-Path -Path $script:cache_dir -ChildPath $cache_path

    $zip_dir = Split-Path -Path $zip_path -Parent
    if (!(Test-Path $zip_dir)) {
        New-Item -ItemType Directory -Path $zip_dir -Force | Out-Null
    }

    Write-MarkerLog "get_cached_zip: url=$url"
    Write-MarkerLog "get_cached_zip: cache=$zip_path"
    Write-MarkerLog "get_cached_zip: out=$out_path"

    if (!(Test-Path $zip_path)) {
        Write-Host "下载压缩包: $url"
        Invoke-WebRequest -Uri $url -OutFile $zip_path
        Write-MarkerLog "压缩包下载完成: $zip_path"
    }
    else {
        Write-Host "缓存已存在，跳过下载: $zip_path"
        Write-MarkerLog "命中缓存: $zip_path"
    }

    if (Test-Path $out_path) {
        Remove-Item -Path $out_path -Recurse -Force
        Write-MarkerLog "删除旧目录: $out_path"
    }
    New-Item -ItemType Directory -Path $out_path -Force | Out-Null

    Write-Host "解压到: $out_path"
    Expand-Archive -Path $zip_path -DestinationPath $out_path -Force
    Write-MarkerLog "解压完成: $out_path"
}

function write_text_file {
    param(
        [string]$file_path,
        [string]$content
    )

    $dir = Split-Path -Path $file_path -Parent
    if ($dir -and !(Test-Path $dir)) {
        New-Item -ItemType Directory -Path $dir -Force | Out-Null
    }

    Set-Content -Path $file_path -Value $content -Encoding UTF8
    Write-MarkerLog "写入文件: $file_path"
}

$work_dir = $null
$automate_dir = $null
$depot_tools_dir = $null
$chromium_git_dir = $null
$create_dir = $null
$automate_py = $null
$python3_bat = $null
$depot_tools_url = $null
$automate_url = $null
$ver = $null
$script:chromium_ref = $null

function update_tools() {
    Invoke-Step "update_tools" {
        get_cached_zip  $depot_tools_url "depot_tools_$ver.zip" $depot_tools_dir
        get_cached_file $automate_url    "automate_$ver.py"     $automate_py

        Write-MarkerLog "执行: $(Join-Path $depot_tools_dir 'update_depot_tools.bat')"
        & (Join-Path $depot_tools_dir "update_depot_tools.bat")
        Write-MarkerLog "update_depot_tools.bat 退出码: $LASTEXITCODE"
        if ($LASTEXITCODE -ne 0) {
            throw "update_depot_tools.bat 执行失败: $LASTEXITCODE"
        }

        if (($env:PATH -split ';') -notcontains $depot_tools_dir) {
            $env:PATH = "$depot_tools_dir;$env:PATH"
            Write-MarkerLog "已追加 depot_tools 到 PATH"
        }

        Write-MarkerLog "执行: $python3_bat $automate_py --help"
        & $python3_bat $automate_py --help
        Write-MarkerLog "automate-git.py --help 退出码: $LASTEXITCODE"
        if ($LASTEXITCODE -ne 0) {
            throw "automate-git.py --help 执行失败: $LASTEXITCODE"
        }
    }
}

function prepare_env($work_dir, $ver, $chromium_ref) {
    $script:work_dir="$work_dir"
    $script:ver="$ver"
    $script:chromium_ref = "$chromium_ref"
    $script:automate_dir     = Join-Path $work_dir "automate"
    $script:depot_tools_dir  = Join-Path $work_dir "depot_tools"
    $script:chromium_git_dir = Join-Path $work_dir "chromium_git"
    $script:create_dir       = Join-Path $work_dir "chromium_git/chromium/src/cef"
    $script:automate_py      = Join-Path $automate_dir "automate-git.py"
    $script:python3_bat      = Join-Path $depot_tools_dir "python3.bat"
    $script:depot_tools_url = "https://storage.googleapis.com/chrome-infra/depot_tools.zip"
    $script:automate_url    = "https://raw.githubusercontent.com/chromiumembedded/cef/${ver}/tools/automate/automate-git.py"
}

function generate_update_script(){
    $bat= Join-Path $chromium_git_dir "update.bat"
    write_text_file "$bat" @"
@echo off
chcp 65001 >nul
cd /d "$chromium_git_dir"
set "PATH=$depot_tools_dir;%PATH%"
call "$python3_bat" "$automate_py" ^
  --download-dir="$chromium_git_dir" ^
  --depot-tools-dir="$depot_tools_dir" ^
  --no-chromium-history ^
  --no-distrib ^
  --no-build
"@
    Write-MarkerLog "已生成 update.bat: $bat"
}

function generate_create_script(){
    $bat = Join-Path $create_dir "create.bat"
    echo "bat $bat"
    write_text_file "$bat" @"
chcp 65001 >nul
cd ${create_dir}
set "PATH=$depot_tools_dir;%PATH%"
set "GN_DEFINES=is_component_build=true"
set "GN_ARGUMENTS=--ide=vs2022 --sln=cef --filters=//cef/*"
call cef_create_projects.bat
"@
    Write-MarkerLog "已生成 create.bat: $bat"
}

if ($true) {
    try {

        #prepare_env "D:\cef_builds\4_4_1436" "7680" "146.0.7680.184"
        #prepare_env "D:\cef_builds\4_4_1913" "6613" "128.0.6613.138"  这个构建不了 不带--no-chromium-history 源码下载不下来
        # prepare_env "D:\cef_builds\4_7_1048" "7204" "138.0.7204.50" 这个构建不了 不带--no-chromium-history 源码下载不下来
        prepare_env "D:\cef_builds\4_7_1129"  "7680" "146.0.7680.184"


        Initialize-Logging -BaseDir $work_dir
        Write-MarkerLog "构建开始" "STEP"
        Write-MarkerLog "work_dir=$work_dir"
        Write-MarkerLog "CEF branch=$ver"
        Write-MarkerLog "chromium_ref=$script:chromium_ref"

        update_tools

        Invoke-Step "generate_update_script" {
            generate_update_script
        }

        Invoke-Step "执行 update.bat" {
            Write-MarkerLog "执行: $chromium_git_dir\update.bat"
            & "$chromium_git_dir\update.bat"
            Write-MarkerLog "update.bat 退出码: $LASTEXITCODE"
            if ($LASTEXITCODE -ne 0) {
                throw "update.bat 执行失败: $LASTEXITCODE"
            }
        }

        Invoke-Step "generate_create_script" {
            generate_create_script
        }

        Invoke-Step "执行 create.bat" {
            Write-MarkerLog "执行: $create_dir\create.bat"
            & "$create_dir\create.bat"
            Write-MarkerLog "create.bat 退出码: $LASTEXITCODE"
            if ($LASTEXITCODE -ne 0) {
                throw "create.bat 执行失败: $LASTEXITCODE"
            }
        }

        $DepotPyDir = "$work_dir\depot_tools\bootstrap-2@3_11_8_chromium_35_bin\python3\bin"
        $env:PATH = "$DepotPyDir;$env:PATH"
        Write-MarkerLog "已追加 DepotPyDir 到 PATH: $DepotPyDir"

        Invoke-Step "where.exe python3" {
            where.exe python3
            Write-MarkerLog "where.exe 退出码: $LASTEXITCODE"
            if ($LASTEXITCODE -ne 0) {
                throw "where.exe python3 执行失败: $LASTEXITCODE"
            }
        }

        Invoke-Step "python3 --version" {
            python3 --version
            Write-MarkerLog "python3 --version 退出码: $LASTEXITCODE"
            if ($LASTEXITCODE -ne 0) {
                throw "python3 --version 执行失败: $LASTEXITCODE"
            }
        }

        if (($env:PATH -split ';') -notcontains $depot_tools_dir) {
            $env:PATH = "$depot_tools_dir;$env:PATH"
            Write-MarkerLog "再次确保 depot_tools 在 PATH 中"
        }

        Set-Location "$work_dir\chromium_git\chromium\src"
        Write-MarkerLog "切换目录到: $(Get-Location)"

        Invoke-Step "ninja cef" {
            & "C:\Program Files\JetBrains\CLion 2026.1\bin\ninja\win\x64\ninja.exe" `
          -C "out\Release_GN_x64" `
          cef

            Write-MarkerLog "ninja 退出码: $LASTEXITCODE"
            if ($LASTEXITCODE -ne 0) {
                throw "ninja cef 执行失败: $LASTEXITCODE"
            }
        }

        #Install-VSNativeDesktopComponents -InstallerPath "D:\wyc\Environment\vs_Enterprise2022.exe"

        #D:\cef_builds\4_4_851\chromium_git\chromium\src\out\Release_GN_x64
        Invoke-Step "运行 ceftests.exe" {
            $exe = Join-Path $work_dir 'chromium_git\chromium\src\out\Release_GN_x64\ceftests.exe'
            $xmlFile = Join-Path $work_dir 'ceftests.xml'
            $script:NativeCommandLogFile = Join-Path $work_dir 'ceftests.log'

            #$cmdLine = "`"$exe`" --gtest_color=yes --proxy-server=`"http://127.0.0.1:7897`" --proxy-bypass-list=`"localhost;127.0.0.1`" --gtest_output=xml:`"$xmlFile`" 2>&1"
            $cmdLine = "`"$exe`" --gtest_color=yes --no-proxy-server --disable-background-networking --gtest_filter=`"OSRTest.*:ViewsButtonTest.*:ViewsTextfieldTest.*:ViewsWindowTest.WindowAccelerator`" --gtest_output=xml:`"$xmlFile`" 2>&1"
            $exitCode = Invoke-CmdLineLogged $cmdLine

            Write-MarkerLog "ceftests.exe 退出码: $exitCode"
            Write-MarkerLog "日志文件: $script:NativeCommandLogFile"
            Write-MarkerLog "XML报告: $xmlFile"

            if ($exitCode -ne 0) {
                throw "ceftests.exe 执行失败: $exitCode，详见: $script:NativeCommandLogFile"
            }
        }

        Invoke-Step "安装动态库" {
            $toolsDir = Join-Path $work_dir 'chromium_git\chromium\src\cef\tools'
            $outputDir = Join-Path $work_dir 'distrib'

            Push-Location $toolsDir
            try {
                $args = @(
                    'make_distrib.py'
                    '--output-dir', $outputDir
                    '--ninja-build'
                    '--x64-build'
                    '--minimal'
                    '--allow-partial'
                    '--no-symbols'
                    '--no-docs'
                    '--no-archive'
                )

                & python @args

                $exitCode = $LASTEXITCODE
                Write-MarkerLog "make_distrib.py 退出码: $exitCode"
                Write-MarkerLog "输出目录: $outputDir"

                if ($exitCode -ne 0) {
                    throw "make_distrib.py 执行失败: $exitCode"
                }
            }
            finally {
                Pop-Location
            }
        }


        Write-MarkerLog "全部流程执行完成" "STEP"
        exit 0
    }
    catch {
        Write-MarkerLog ("执行失败: " + $_.Exception.Message) "ERROR"
        throw
    }
    finally {
        $elapsed = [datetime]::UtcNow - $script:build_start_utc
        Write-MarkerLog ("总耗时: {0:n2} 分钟" -f $elapsed.TotalMinutes)

        if ($script:transcript_started) {
            try {
                Stop-Transcript | Out-Null
            }
            catch {
            }
        }
    }
} else {

    prepare_env "D:\cef_builds\4_4_1436" "7680" "146.0.7680.184"


    #Invoke-Step "运行 ceftests.exe" {
    #    $exe = Join-Path $work_dir 'chromium_git\chromium\src\out\Release_GN_x64\ceftests.exe'
    #    $xmlFile = Join-Path $work_dir 'ceftests.xml'
    #    $script:NativeCommandLogFile = Join-Path $work_dir 'ceftests.log'
    #
    #    #$cmdLine = "`"$exe`" --gtest_color=yes --proxy-server=`"http://127.0.0.1:7897`" --proxy-bypass-list=`"localhost;127.0.0.1`" --gtest_output=xml:`"$xmlFile`" 2>&1"
    #    $cmdLine = "`"$exe`" --gtest_color=yes --no-proxy-server --disable-background-networking --gtest_filter=`"OSRTest.*:ViewsButtonTest.*:ViewsTextfieldTest.*:ViewsWindowTest.WindowAccelerator`" --gtest_output=xml:`"$xmlFile`" 2>&1"
    #    $exitCode = Invoke-CmdLineLogged $cmdLine
    #
    #    Write-MarkerLog "ceftests.exe 退出码: $exitCode"
    #    Write-MarkerLog "日志文件: $script:NativeCommandLogFile"
    #    Write-MarkerLog "XML报告: $xmlFile"
    #
    #    if ($exitCode -ne 0) {
    #        throw "ceftests.exe 执行失败: $exitCode，详见: $script:NativeCommandLogFile"
    #    }
    #}

    Invoke-Step "安装动态库" {
        $toolsDir = Join-Path $work_dir 'chromium_git\chromium\src\cef\tools'
        $outputDir = Join-Path $work_dir 'distrib'

        Push-Location $toolsDir
        try {
            $args = @(
                'make_distrib.py'
                '--output-dir', $outputDir
                '--ninja-build'
                '--x64-build'
                '--minimal'
                '--allow-partial'
                '--no-symbols'
                '--no-docs'
                '--no-archive'
            )

            & python @args

            $exitCode = $LASTEXITCODE
            Write-MarkerLog "make_distrib.py 退出码: $exitCode"
            Write-MarkerLog "输出目录: $outputDir"

            if ($exitCode -ne 0) {
                throw "make_distrib.py 执行失败: $exitCode"
            }
        }
        finally {
            Pop-Location
        }
    }
}



