diff --git a/.github/agents/agentic-workflows.agent.md b/.github/agents/agentic-workflows.agent.md index cd376c5b1b30..f7e5eb4f1cd1 100644 --- a/.github/agents/agentic-workflows.agent.md +++ b/.github/agents/agentic-workflows.agent.md @@ -19,7 +19,13 @@ This is a **dispatcher agent** that routes your request to the appropriate speci - **Creating shared components**: Routes to `create-shared-agentic-workflow` prompt - **Fixing Dependabot PRs**: Routes to `dependabot` prompt — use this when Dependabot opens PRs that modify generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`). Never merge those PRs directly; instead update the source `.md` files and rerun `gh aw compile --dependabot` to bundle all fixes - **Analyzing test coverage**: Routes to `test-coverage` prompt — consult this whenever the workflow reads, analyzes, or reports on test coverage data from PRs or CI runs +- **Rendering ASCII charts in markdown**: Routes to `asciicharts` guide — consult this whenever the workflow needs compact charts that render reliably in GitHub issues, comments, or discussions - **CLI commands and triggering workflows**: Routes to `cli-commands` guide — consult this whenever the user asks how to run, compile, debug, or manage workflows from the command line, or when they need the MCP tool equivalent of a `gh aw` command +- **Reducing token consumption / cost optimization**: Routes to `token-optimization` guide — consult this whenever the user asks how to reduce token usage, lower costs, speed up workflows, or measure the impact of prompt changes with experiments +- **Choosing workflow architectures and design patterns**: Routes to `patterns` guide — consult this whenever the user asks for strategy, architecture, operating models, or pattern selection for agentic workflows + +> [!IMPORTANT] +> For architecture/pattern-selection requests, load `https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/patterns.md` first. Workflows may optionally include: @@ -31,7 +37,7 @@ Workflows may optionally include: - Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` - Workflow lock files: `.github/workflows/*.lock.yml` - Shared components: `.github/workflows/shared/*.md` -- Configuration: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/github-agentic-workflows.md +- Configuration: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/github-agentic-workflows.md ## Problems This Solves @@ -53,7 +59,7 @@ When you interact with this agent, it will: ### Create New Workflow **Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/create-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/create-agentic-workflow.md **Use cases**: - "Create a workflow that triages issues" @@ -63,7 +69,7 @@ When you interact with this agent, it will: ### Update Existing Workflow **Load when**: User wants to modify, improve, or refactor an existing workflow -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/update-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/update-agentic-workflow.md **Use cases**: - "Add web-fetch tool to the issue-classifier workflow" @@ -73,7 +79,7 @@ When you interact with this agent, it will: ### Debug Workflow **Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/debug-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/debug-agentic-workflow.md **Use cases**: - "Why is this workflow failing?" @@ -83,7 +89,7 @@ When you interact with this agent, it will: ### Upgrade Agentic Workflows **Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/upgrade-agentic-workflows.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/upgrade-agentic-workflows.md **Use cases**: - "Upgrade all workflows to the latest version" @@ -93,7 +99,7 @@ When you interact with this agent, it will: ### Create a Report-Generating Workflow **Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/report.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/report.md **Use cases**: - "Create a weekly CI health report" @@ -103,7 +109,7 @@ When you interact with this agent, it will: ### Create Shared Agentic Workflow **Load when**: User wants to create a reusable workflow component or wrap an MCP server -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/create-shared-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/create-shared-agentic-workflow.md **Use cases**: - "Create a shared component for Notion integration" @@ -113,7 +119,7 @@ When you interact with this agent, it will: ### Fix Dependabot PRs **Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/dependabot.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/dependabot.md **Use cases**: - "Fix the open Dependabot PRs for npm dependencies" @@ -123,17 +129,27 @@ When you interact with this agent, it will: ### Analyze Test Coverage **Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/test-coverage.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/test-coverage.md **Use cases**: - "Create a workflow that comments coverage on PRs" - "Analyze coverage trends over time" - "Add a coverage gate that blocks PRs below a threshold" +### Render ASCII Charts in Markdown +**Load when**: The workflow needs in-markdown charts (sparklines, bars, table+trend views) that must align cleanly and render reliably across GitHub surfaces, including mobile. + +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/asciicharts.md + +**Use cases**: +- "Show a compact trend chart in an issue comment" +- "Render a dashboard table with sparkline trends" +- "Generate aligned ASCII bars for service metrics" + ### CLI Commands Reference **Load when**: The user asks how to run, compile, debug, or manage workflows from the command line; needs the MCP tool equivalent of a `gh aw` command; or is in a restricted environment (e.g., Copilot Cloud) without direct CLI access. -**Reference file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/cli-commands.md +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/cli-commands.md **Use cases**: - "How do I trigger workflow X on the main branch?" @@ -141,6 +157,30 @@ When you interact with this agent, it will: - "I'm in Copilot Cloud — how do I compile a workflow?" - "Show me all available gh aw commands" +### Token Consumption Optimization +**Load when**: The user asks how to reduce token usage, lower workflow costs, make a workflow faster or cheaper, or measure the impact of prompt or configuration changes. + +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/token-optimization.md + +**Use cases**: +- "How do I reduce the token cost of this workflow?" +- "My workflow is too expensive — how do I optimize it?" +- "How do I compare token usage between two runs?" +- "Should I use gh-proxy or the MCP server?" +- "How do I use sub-agents to reduce costs?" +- "How do I measure the impact of a prompt change?" + +### Workflow Pattern Selection +**Load when**: The user asks for architecture, strategy, operating model selection, or pattern recommendations for building agentic workflows. + +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/patterns.md + +**Use cases**: +- "Which pattern should I use for multi-repo rollout?" +- "How should I structure this workflow architecture?" +- "What pattern fits slash-command triage?" +- "Should this be DispatchOps or DailyOps?" + ## Instructions When a user interacts with you: @@ -185,12 +225,12 @@ gh aw compile --validate ## Important Notes -- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/github-agentic-workflows.md for complete documentation +- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/github-agentic-workflows.md for complete documentation - Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud - Workflows must be compiled to `.lock.yml` files before running in GitHub Actions - **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF - Follow security best practices: minimal permissions, explicit network access, no template injection -- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. - **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. - **Triggering runs**: Always use `gh aw run ` to trigger a workflow on demand — not `gh workflow run .lock.yml`. `gh aw run` handles workflow resolution by short name, input parsing and validation, and correct run-tracking for agentic workflows. Use `--ref ` to run on a specific branch. -- **CLI commands reference**: For a complete guide on all `gh aw` commands and their MCP tool equivalents (for restricted environments), see https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/cli-commands.md +- **CLI commands reference**: For a complete guide on all `gh aw` commands and their MCP tool equivalents (for restricted environments), see https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/cli-commands.md diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 4b30f2d3389b..0edb6d2e41ac 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -25,10 +25,10 @@ "version": "v7.0.1", "sha": "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" }, - "github/gh-aw-actions/setup@v0.72.1": { + "github/gh-aw-actions/setup@v0.77.5": { "repo": "github/gh-aw-actions/setup", - "version": "v0.72.1", - "sha": "bc56a0cad2f450c562810785ef38649c04db812a" + "version": "v0.77.5", + "sha": "3ea13c02d765410340d533515cb31a7eef2baaf0" } }, "containers": { diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 11176de6fa6a..6239217c4e1a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -131,6 +131,11 @@ interface SomeClass { ## MSBuild Integration +### FileWrites + +If a target or task creates a file, that file must be added to the `FileWrites` item group. This ensures MSBuild's incremental clean can delete generated files. Additionally, if a target produces multiple output files, all of them should be listed in the target's `Outputs` attribute for correct incremental build behavior. + + ### Custom MSBuild Tasks Located in `msbuild/` directory: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6cc00712d1c7..13434fb1a2d8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,10 @@ -version: 2 updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 7 +- cooldown: + default-days: 7 + directory: / + ignore: + - dependency-name: "github/gh-aw-actions/**" # Managed by gh aw compile. Version-locked to the gh-aw compiler; do not bump. + package-ecosystem: github-actions + schedule: + interval: weekly +version: 2 diff --git a/.github/skills/update-expected-app-size/SKILL.md b/.github/skills/update-expected-app-size/SKILL.md new file mode 100644 index 000000000000..1537c6cc59b2 --- /dev/null +++ b/.github/skills/update-expected-app-size/SKILL.md @@ -0,0 +1,126 @@ +--- +name: update-expected-app-size +description: >- + Download updated expected app size files from Azure DevOps CI artifacts for + the current branch. Use when app size tests fail in CI and the user wants to + update the expected files locally. Trigger on "update app size", "download + expected files", "fix app size test", or "update expected app size files". +--- + +# Update Expected App Size Files + +Download updated expected app size files from Azure DevOps artifacts for the current branch's PR build, and apply them to the repository. + +## When to Use + +- App size tests failed in CI and the user wants to update the expected files +- User asks to "update app size", "download expected files", or "fix app size test failures" +- User wants to pull the updated expected files from a recent CI build + +## Background + +The app size tests (`tests/dotnet/UnitTests/AppSizeTest.cs`) compare the built app's size and preserved APIs against expected files stored in `tests/dotnet/UnitTests/expected/`. When the test detects a difference and `WRITE_KNOWN_FAILURES` is not set, it writes the updated expected file to `$(Build.ArtifactStagingDirectory)/updated-expected-sizes/`, and a pipeline step publishes this directory as a build artifact. + +The artifact name follows the pattern `{uploadPrefix}updated-expected-sizes-{testPrefix}-{attempt}` (e.g., `updated-expected-sizes-dotnettests_ios-1`). Inside the artifact, files are named after the test variant: +- `{Platform}-{Variant}-size.txt` — e.g., `iOS-MonoVM-size.txt`, `iOS-MonoVM-interpreter-size.txt`, `iOS-NativeAOT-TrimmableStatic-size.txt`, `MacOSX-CoreCLR-Interpreter-size.txt` +- `{Platform}-{Variant}-preservedapis.txt` — e.g., `iOS-MonoVM-preservedapis.txt`, `MacCatalyst-MonoVM-interpreter-preservedapis.txt` + +The expected files on disk are at: +- `tests/dotnet/UnitTests/expected/{Platform}-{Variant}-size.txt` +- `tests/dotnet/UnitTests/expected/{Platform}-{Variant}-preservedapis.txt` + +## Workflow + +### 1. Determine the current branch and PR + +```bash +BRANCH=$(git branch --show-current) +# Find the PR number for this branch +gh pr list --head "$BRANCH" --repo dotnet/macios --json number,url --jq '.[0]' +``` + +If no PR is found, inform the user that this skill requires a PR to exist for the current branch (so that CI has run). + +### 2. Find the Azure DevOps build + +The CI builds for PRs in dotnet/macios run in the `devdiv` Azure DevOps organization, project `DevDiv`. + +Use the GitHub PR checks to find the Azure DevOps build URL: + +```bash +gh pr checks --repo dotnet/macios +``` + +Look for a check that links to Azure DevOps. The build URL will look like: +``` +https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=XXXXXXX +``` + +Extract the `buildId` from the URL. + +### 3. Download the artifacts + +Use the Azure DevOps REST API to list and download artifacts: + +```bash +# List artifacts for the build +TOKEN=$(az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv) +curl -s "https://devdiv.visualstudio.com/DevDiv/_apis/build/builds/{buildId}/artifacts?api-version=7.0" \ + -H "Authorization: Bearer $TOKEN" +``` + +Look for artifacts whose names contain `updated-expected-sizes` (e.g., `updated-expected-sizes-dotnettests_ios-1`). Get the artifact's `downloadUrl` and download it: + +```bash +# Get the download URL for a specific artifact +ARTIFACT_INFO=$(curl -s "https://devdiv.visualstudio.com/DevDiv/_apis/build/builds/{buildId}/artifacts?artifactName={artifactName}&api-version=7.0" \ + -H "Authorization: Bearer $TOKEN") +DOWNLOAD_URL=$(echo "$ARTIFACT_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['resource']['downloadUrl'])") + +# Download the artifact zip +curl -sL "$DOWNLOAD_URL" -H "Authorization: Bearer $TOKEN" -o artifact.zip +``` + +If `az` is not available or not authenticated, direct the user to download manually from the Azure DevOps build artifacts page. + +### 4. Place the files + +Extract the downloaded artifact zip and place the files in the expected directory: + +```bash +EXPECTED_DIR="tests/dotnet/UnitTests/expected" +unzip -o artifact.zip -d /tmp/updated-sizes/ +cp /tmp/updated-sizes/*/*.txt "$EXPECTED_DIR/" +``` + +The files inside the zip already have the correct names (e.g., `iOS-MonoVM-size.txt`) and can be copied directly. + +### 5. Verify and commit + +After placing the files: +1. Run `git diff` to show what changed +2. Ask the user if the changes look correct +3. If confirmed, commit the changes: + ```bash + git add tests/dotnet/UnitTests/expected/ + git commit -m "[tests] Update expected app size files" + ``` + +## Fallback: Manual Download + +If automated download fails (auth issues, etc.), provide the user with: +1. The Azure DevOps build URL +2. Instructions to navigate to the build → Summary → Artifacts section +3. Look for individual artifacts whose names contain `updated-expected-sizes` +4. Download the artifact zip, extract it, and copy the `.txt` files (e.g., `iOS-MonoVM-interpreter-size.txt`) into `tests/dotnet/UnitTests/expected/` + +## Fallback: Run Locally + +If the user can build locally, they can update the expected files directly: + +```bash +WRITE_KNOWN_FAILURES=1 tests-dotnet AppSizeTest +``` + +This runs the tests, updates the expected files in place, and marks the tests as passed. + diff --git a/.github/workflows/autoformat-v2.yml b/.github/workflows/autoformat-v2.yml new file mode 100644 index 000000000000..e1e32292ad03 --- /dev/null +++ b/.github/workflows/autoformat-v2.yml @@ -0,0 +1,97 @@ +name: Autoformat code v2 +on: pull_request + +permissions: {} + +jobs: + # Job for same-repo PRs: format and push directly + autoformat-push: + name: Autoformat and push + runs-on: ubuntu-latest + if: github.event.pull_request.head.repo.full_name == github.repository + permissions: + contents: write + + steps: + - name: 'Checkout' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + ref: ${{ github.head_ref }} + fetch-depth: 1 + persist-credentials: false + + - name: 'Install .NET' + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 + with: + global-json-file: ./global.json + + - name: 'Autoformat' + run: ./tools/autoformat.sh + + - name: 'Check for changes' + id: check + run: | + if git diff --quiet; then + echo "changes=false" >> "$GITHUB_OUTPUT" + else + echo "changes=true" >> "$GITHUB_OUTPUT" + fi + + - name: 'Commit and push' + if: steps.check.outputs.changes == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + git config user.email 'github-actions-autoformatter@xamarin.com' + git config user.name 'GitHub Actions Autoformatter' + git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}" + git add -A + git commit -m 'Auto-format source code' + git push + + # Job for fork PRs: format and upload patch as artifact + autoformat-artifact: + name: Autoformat and upload patch + runs-on: ubuntu-latest + if: github.event.pull_request.head.repo.full_name != github.repository + permissions: + contents: read + + steps: + - name: 'Checkout' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + fetch-depth: 1 + + - name: 'Install .NET' + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 + with: + global-json-file: ./global.json + + - name: 'Autoformat' + run: ./tools/autoformat.sh + + - name: 'Create patch' + id: patch + run: | + if git diff --quiet; then + echo "changes=false" >> "$GITHUB_OUTPUT" + else + echo "changes=true" >> "$GITHUB_OUTPUT" + git config user.email 'github-actions-autoformatter@xamarin.com' + git config user.name 'GitHub Actions Autoformatter' + git add -A + git commit -m 'Auto-format source code' + mkdir -p autoformat-output + git format-patch HEAD~1 --stdout > autoformat-output/autoformat.patch + fi + + - name: 'Upload patch' + if: steps.patch.outputs.changes == 'true' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: autoformat + path: autoformat-output/ diff --git a/.github/workflows/autoformat.yml b/.github/workflows/autoformat.yml deleted file mode 100644 index f20d04015aad..000000000000 --- a/.github/workflows/autoformat.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Autoformat code -on: pull_request - -# This action only need a single permission in order to autoformat the code. -permissions: - contents: read - -jobs: - autoformat-code: - name: Autoformat code - runs-on: ubuntu-latest - - steps: - - name: 'Checkout' - uses: actions/checkout@v6 - with: - fetch-depth: 0 - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.sha }} - - name: 'Install .NET' - uses: actions/setup-dotnet@v5 - with: - global-json-file: ./global.json - - name: 'Autoformat' - uses: rolfbjarne/autoformat@v0.6 - with: - script: ./tools/autoformat.sh - git_user_email: 'github-actions-autoformatter@xamarin.com' - git_user_name: 'GitHub Actions Autoformatter' - checkoutSource: false diff --git a/.github/workflows/autoformat2.yml b/.github/workflows/autoformat2.yml deleted file mode 100644 index bc382aaf8c2e..000000000000 --- a/.github/workflows/autoformat2.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Autoformat code - push results -on: - workflow_run: - workflows: ["Autoformat code"] - types: - - completed - -# This action needs the following permissions in order to push the results back to the original branch. -permissions: - pull-requests: write - contents: write - -jobs: - push-and-notify: - name: Push autoformatted code and notify user - runs-on: ubuntu-latest - if: > - github.event.workflow_run.event == 'pull_request' && - github.event.workflow_run.conclusion == 'success' - steps: - - name: 'Push autoformatted patch' - uses: rolfbjarne/autoformat-push@v0.3 - with: - githubToken: ${{ secrets.GITHUB_TOKEN }} - git_user_email: 'github-actions-autoformatter@xamarin.com' - git_user_name: 'GitHub Actions Autoformatter' - commentOnPullRequest: false diff --git a/.github/workflows/ci-postmortem.lock.yml b/.github/workflows/ci-postmortem.lock.yml index 9d6b4a9a0a6e..61755f20a0a7 100644 --- a/.github/workflows/ci-postmortem.lock.yml +++ b/.github/workflows/ci-postmortem.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"15354af11629eb0049ecb70f03b13ed2df90af330f1d6a40d7ce9a202538bb0b","compiler_version":"v0.71.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"239aec45b78c8799417efdd5bc6d8cc036629ec1","version":"v0.71.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.28","digest":"sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28","digest":"sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.28","digest":"sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.0","digest":"sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.0@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d"},{"image":"ghcr.io/github/github-mcp-server:v1.0.2","digest":"sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.2@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"e7f2b78dc23c58554e0403a91ececfda7a6869936e0f622236e8b581313a38a7","body_hash":"ad13b1075fd08c989fe77b74abdce355d88ab2ebeea692809a67d8b68cd7559b","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.71.1). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -32,29 +32,26 @@ # Custom actions used: # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 -# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 +# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 +# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb -# - ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474 -# - ghcr.io/github/gh-aw-mcpg:v0.3.0@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d -# - ghcr.io/github/github-mcp-server:v1.0.2@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba -# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f +# - ghcr.io/github/gh-aw-firewall/agent:0.25.58 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.58 +# - ghcr.io/github/gh-aw-mcpg:v0.3.22 +# - ghcr.io/github/github-mcp-server:v1.1.0 +# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14 name: "CI Post-Mortem Analysis" -"on": - schedule: - - cron: "45 11 * * 0" - # Friendly format: weekly on sunday (scattered) +on: workflow_dispatch: inputs: aw_context: default: "" - description: Agent caller context (used internally by Agentic Workflows). + description: "Agent caller context (used internally by Agentic Workflows)." required: false type: string @@ -78,35 +75,43 @@ jobs: lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "claude-sonnet-4.5" - GH_AW_INFO_VERSION: "1.0.35" - GH_AW_INFO_AGENT_VERSION: "1.0.35" - GH_AW_INFO_CLI_VERSION: "v0.71.1" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AGENT_VERSION: "1.0.55" + GH_AW_INFO_CLI_VERSION: "v0.77.5" GH_AW_INFO_WORKFLOW_NAME: "CI Post-Mortem Analysis" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","github","aka.ms","dev.azure.com","devdiv.visualstudio.com","microsoft.com","vsassets.io"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.28" + GH_AW_INFO_AWF_VERSION: "v0.25.58" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -125,22 +130,24 @@ jobs: sparse-checkout: | .github .agents + .antigravity .claude .codex .crush .gemini .opencode + .pi sparse-checkout-cone-mode: true fetch-depth: 1 - name: Save agent config folders for base branch restoration env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" # poutine:ignore untrusted_checkout_exec run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" - name: Check workflow lock file id: check-lock-file - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_WORKFLOW_FILE: "ci-postmortem.lock.yml" GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}" @@ -151,9 +158,9 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); - name: Check compile-agentic version - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.71.1" + GH_AW_COMPILED_VERSION: "v0.77.5" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -164,11 +171,11 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -176,56 +183,60 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_956c986f1e45d6a0_EOF' + cat << 'GH_AW_PROMPT_452cd77d855884c0_EOF' - GH_AW_PROMPT_956c986f1e45d6a0_EOF + GH_AW_PROMPT_452cd77d855884c0_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_956c986f1e45d6a0_EOF' + cat << 'GH_AW_PROMPT_452cd77d855884c0_EOF' Tools: add_comment(max:20), create_issue(max:20), update_issue(max:20), missing_tool, missing_data, noop + GH_AW_PROMPT_452cd77d855884c0_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" + cat << 'GH_AW_PROMPT_452cd77d855884c0_EOF' The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} + {{#if github.actor}} - **actor**: __GH_AW_GITHUB_ACTOR__ {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} + {{#if github.repository}} - **repository**: __GH_AW_GITHUB_REPOSITORY__ {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} + {{#if github.workspace}} - **workspace**: __GH_AW_GITHUB_WORKSPACE__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} + - **issue-number**: #__GH_AW_EXPR_802A9F6A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} + - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} + - **pull-request-number**: #__GH_AW_EXPR_463A214A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{#if github.event.comment.id || github.aw.context.comment_id}} + - **comment-id**: __GH_AW_EXPR_FF1D34CE__ {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} + {{#if github.run_id}} - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} - GH_AW_PROMPT_956c986f1e45d6a0_EOF + GH_AW_PROMPT_452cd77d855884c0_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_956c986f1e45d6a0_EOF' + cat << 'GH_AW_PROMPT_452cd77d855884c0_EOF' {{#runtime-import .github/workflows/ci-postmortem.md}} - GH_AW_PROMPT_956c986f1e45d6a0_EOF + GH_AW_PROMPT_452cd77d855884c0_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_ENGINE_ID: "copilot" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -233,17 +244,18 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); await main(); - name: Substitute placeholders - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -255,14 +267,15 @@ jobs: return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, substitutions: { + GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, + GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, + GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, + GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, - GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, + GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST } }); - name: Validate prompt placeholders @@ -280,11 +293,17 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: activation + include-hidden-files: true path: | /tmp/gh-aw/aw_info.json + /tmp/gh-aw/model_multipliers.json /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/aw-prompts/prompt-template.txt + /tmp/gh-aw/aw-prompts/prompt-import-tree.json /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/base + /tmp/gh-aw/.github/agents + /tmp/gh-aw/.github/skills if-no-files-found: ignore retention-days: 1 @@ -294,8 +313,6 @@ jobs: permissions: contents: read issues: read - concurrency: - group: "gh-aw-copilot-${{ github.workflow }}" env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} GH_AW_ASSETS_ALLOWED_EXTS: "" @@ -304,25 +321,35 @@ jobs: GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs GH_AW_WORKFLOW_ID_SANITIZED: cipostmortem outputs: - agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} + agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} + effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} - inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} - mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} + inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} + mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} model: ${{ needs.activation.outputs.model }} - model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} + model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths run: | @@ -358,7 +385,7 @@ jobs: id: checkout-pr if: | github.event.pull_request || github.event.issue.pull_request - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} with: @@ -369,11 +396,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.35 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.28 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -389,20 +416,29 @@ jobs: - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" + - name: Restore inline sub-agents from activation artifact + env: + GH_AW_SUB_AGENT_DIR: ".github/agents" + GH_AW_SUB_AGENT_EXT: ".agent.md" + run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" + - name: Restore inline skills from activation artifact + env: + GH_AW_SKILL_DIR: ".github/skills" + run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474 ghcr.io/github/gh-aw-mcpg:v0.3.0@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d ghcr.io/github/github-mcp-server:v1.0.2@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f - - name: Write Safe Outputs Config + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14 + - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_c2d474e65378a915_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_418d6ffb54599ea1_EOF' {"add_comment":{"max":20},"create_issue":{"max":20},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":20}} - GH_AW_SAFE_OUTPUTS_CONFIG_c2d474e65378a915_EOF - - name: Write Safe Outputs Tools + GH_AW_SAFE_OUTPUTS_CONFIG_418d6ffb54599ea1_EOF + - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { @@ -447,6 +483,9 @@ jobs: "sanitize": true, "maxLength": 65000 }, + "fields": { + "type": "array" + }, "labels": { "type": "array", "itemType": "string", @@ -599,7 +638,7 @@ jobs: "customValidation": "requiresOneOf:status,title,body" } } - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -660,6 +699,7 @@ jobs: # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_HOST_DOMAIN="localhost" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') echo "::add-mask::${MCP_GATEWAY_API_KEY}" export MCP_GATEWAY_API_KEY @@ -671,17 +711,22 @@ jobs: export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.0' + case "${DOCKER_HOST:-}" in + unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; + /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; + * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; + esac + DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22' mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_7bd5cd6513b45b21_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_f57e5774da7cad26_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.0.2", + "container": "ghcr.io/github/github-mcp-server:v1.1.0", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -720,33 +765,70 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_7bd5cd6513b45b21_EOF - - name: Clean git credentials + GH_AW_MCP_CONFIG_f57e5774da7cad26_EOF + - name: Mount MCP servers as CLIs + id: mount-mcp-clis + continue-on-error: true + env: + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }} + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/mount_mcp_as_cli.cjs'); + await main(); + - name: Clean credentials continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh" + - name: Audit pre-agent workspace + id: pre_agent_audit + continue-on-error: true + run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","*.vsblob.vsassets.io","aka.ms","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.nuget.org","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","azuresearch-usnc.nuget.org","azuresearch-ussc.nuget.org","builds.dotnet.microsoft.com","ci.dot.net","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","dc.services.visualstudio.com","dev.azure.com","devdiv.visualstudio.com","dist.nuget.org","docs.github.com","dot.net","dotnet.microsoft.com","dotnetcli.blob.core.windows.net","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","microsoft.com","nuget.org","nuget.pkg.github.com","nugetregistryv2prod.blob.core.windows.net","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","oneocsp.microsoft.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","pkgs.dev.azure.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","vsassets.io","www.googleapis.com","www.microsoft.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + elif [ -d "/home/runner/work/_tool" ]; then + GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" + fi # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --image-tag 0.25.28,squid=sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474,agent=sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a,api-proxy=sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb,cli-proxy=sha256:fdf310e4678ce58d248c466b89399e9680a3003038fd19322c388559016aaac7 --skip-pull --enable-api-proxy \ - -- /bin/bash -c 'GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: + AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.71.1 + GH_AW_VERSION: v0.77.5 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -760,12 +842,13 @@ jobs: GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] + RUNNER_TEMP: ${{ runner.temp }} XDG_CONFIG_HOME: /home/runner - - name: Detect Copilot errors - id: detect-copilot-errors + - name: Detect agent errors if: always() + id: detect-agent-errors continue-on-error: true - run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs" + run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs" - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -794,7 +877,7 @@ jobs: bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID" - name: Redact secrets in logs if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -820,10 +903,10 @@ jobs: - name: Ingest agent output id: collect_output if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -834,7 +917,7 @@ jobs: await main(); - name: Parse agent logs for step summary if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ with: @@ -846,7 +929,7 @@ jobs: - name: Parse MCP Gateway logs for step summary if: always() id: parse-mcp-gateway - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -861,7 +944,7 @@ jobs: run: | # Fix permissions on firewall logs/audit dirs so they can be uploaded as artifacts # AWF runs with sudo, creating files owned by root - sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall 2>/dev/null || true + sudo chmod -R a+rX /tmp/gh-aw/sandbox/firewall 2>/dev/null || true # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) if command -v awf &> /dev/null; then awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" @@ -871,13 +954,23 @@ jobs: - name: Parse token usage for step summary if: always() continue-on-error: true - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); await main(); + - name: Print AWF reflect summary + if: always() + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/awf_reflect_summary.cjs'); + await main(); - name: Write agent output placeholder if missing if: always() run: | @@ -899,14 +992,17 @@ jobs: !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/pre-agent-audit.txt /tmp/gh-aw/agent/ /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/safeoutputs.jsonl /tmp/gh-aw/agent_output.json /tmp/gh-aw/aw-*.patch /tmp/gh-aw/aw-*.bundle + /tmp/gh-aw/awf-config.json /tmp/gh-aw/sandbox/firewall/logs/ /tmp/gh-aw/sandbox/firewall/audit/ + /tmp/gh-aw/sandbox/firewall/awf-reflect.json if-no-files-found: ignore conclusion: @@ -927,6 +1023,7 @@ jobs: concurrency: group: "gh-aw-conclusion-ci-postmortem" cancel-in-progress: false + queue: max outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -935,11 +1032,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -956,11 +1060,12 @@ jobs: echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" - name: Process no-op messages id: noop - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/ci-postmortem.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_NOOP_REPORT_AS_ISSUE: "true" @@ -973,10 +1078,11 @@ jobs: await main(); - name: Log detection run id: detection_runs - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/ci-postmortem.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} @@ -989,11 +1095,12 @@ jobs: await main(); - name: Record missing tool id: missing_tool - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/ci-postmortem.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1003,11 +1110,12 @@ jobs: await main(); - name: Record incomplete id: report_incomplete - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/ci-postmortem.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1018,10 +1126,11 @@ jobs: - name: Handle agent failure id: handle_agent_failure if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/ci-postmortem.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "ci-postmortem" @@ -1029,15 +1138,21 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} + GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} + GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com" GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" + GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "20" + GH_AW_MAX_EFFECTIVE_TOKENS: "25000000" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1062,11 +1177,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1092,7 +1214,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 - name: Check if detection needed id: detection_guard if: always() @@ -1107,7 +1229,7 @@ jobs: echo "run_detection=false" >> "$GITHUB_OUTPUT" echo "Detection skipped: no agent outputs or patches to analyze" fi - - name: Clear MCP configuration for detection + - name: Clear MCP Config for detection if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | rm -f "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json" @@ -1118,6 +1240,9 @@ jobs: run: | mkdir -p /tmp/gh-aw/threat-detection/aw-prompts cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then + echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context." + fi cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true for f in /tmp/gh-aw/aw-*.patch; do [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true @@ -1129,7 +1254,7 @@ jobs: ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true - name: Setup threat detection if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: WORKFLOW_NAME: "CI Post-Mortem Analysis" WORKFLOW_DESCRIPTION: "No description provided" @@ -1151,33 +1276,53 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.35 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.28 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' + continue-on-error: true id: detection_agentic_execution # Copilot CLI tool arguments (sorted): timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + elif [ -d "/home/runner/work/_tool" ]; then + GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" + fi # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --image-tag 0.25.28,squid=sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474,agent=sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a,api-proxy=sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb,cli-proxy=sha256:fdf310e4678ce58d248c466b89399e9680a3003038fd19322c388559016aaac7 --skip-pull --enable-api-proxy \ - -- /bin/bash -c 'GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: + AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.71.1 + GH_AW_VERSION: v0.77.5 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1190,6 +1335,7 @@ jobs: GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] + RUNNER_TEMP: ${{ runner.temp }} XDG_CONFIG_HOME: /home/runner - name: Upload threat detection log if: always() && steps.detection_guard.outputs.run_detection == 'true' @@ -1201,16 +1347,35 @@ jobs: - name: Parse and conclude threat detection id: detection_conclusion if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); + try { + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + } catch (loadErr) { + const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; + const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; + const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); + core.error(msg); + core.setOutput('reason', 'parse_error'); + if (continueOnError && !detectionExecutionFailed) { + core.warning('\u26A0\uFE0F ' + msg); + core.setOutput('conclusion', 'warning'); + core.setOutput('success', 'false'); + } else { + core.setOutput('conclusion', 'failure'); + core.setOutput('success', 'false'); + core.setFailed(msg); + } + } safe_outputs: needs: @@ -1232,9 +1397,10 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "claude-sonnet-4.5" - GH_AW_ENGINE_VERSION: "1.0.35" + GH_AW_ENGINE_VERSION: "1.0.55" GH_AW_WORKFLOW_ID: "ci-postmortem" GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/ci-postmortem.md" outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} @@ -1249,11 +1415,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1279,10 +1452,11 @@ jobs: echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - name: Process Safe Outputs id: process_safe_outputs - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":20},\"create_issue\":{\"max\":20},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":20}}" diff --git a/.github/workflows/ci-postmortem.md b/.github/workflows/ci-postmortem.md index 64065525ca6e..ae2eda3ac76c 100644 --- a/.github/workflows/ci-postmortem.md +++ b/.github/workflows/ci-postmortem.md @@ -1,7 +1,5 @@ --- on: - schedule: - - cron: "weekly on sunday" workflow_dispatch: permissions: contents: read diff --git a/.github/workflows/code-radiator.lock.yml b/.github/workflows/code-radiator.lock.yml index 8c0f8d46a7c0..2f6344841183 100644 --- a/.github/workflows/code-radiator.lock.yml +++ b/.github/workflows/code-radiator.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a665debda1a902047622496aa625b015b0b9f053d3892454a63ac7b73cc61808","compiler_version":"v0.72.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"bc56a0cad2f450c562810785ef38649c04db812a","version":"v0.72.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41","digest":"sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41","digest":"sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41","digest":"sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.6","digest":"sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"3f1a9ee34482a7876690cddd0a715bb51cd8db1f78e741ef5d16c383db9b0508","body_hash":"b966744ea05e67fd471e10231f2cce01d0525af33bc90ff317655344e889cc92","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.72.1). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -36,18 +36,18 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 +# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 -# - ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 -# - ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c -# - ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 -# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f +# - ghcr.io/github/gh-aw-firewall/agent:0.25.58 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.58 +# - ghcr.io/github/gh-aw-mcpg:v0.3.22 +# - ghcr.io/github/github-mcp-server:v1.1.0 +# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14 name: "Code Radiator" -"on": +on: # roles: # Roles processed as role check in pre-activation job # - admin # Roles processed as role check in pre-activation job # - maintain # Roles processed as role check in pre-activation job @@ -59,7 +59,7 @@ name: "Code Radiator" inputs: aw_context: default: "" - description: Agent caller context (used internally by Agentic Workflows). + description: "Agent caller context (used internally by Agentic Workflows)." required: false type: string @@ -84,35 +84,39 @@ jobs: lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "claude-sonnet-4.5" - GH_AW_INFO_VERSION: "1.0.40" - GH_AW_INFO_AGENT_VERSION: "1.0.40" - GH_AW_INFO_CLI_VERSION: "v0.72.1" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AGENT_VERSION: "1.0.55" + GH_AW_INFO_CLI_VERSION: "v0.77.5" GH_AW_INFO_WORKFLOW_NAME: "Code Radiator" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.41" + GH_AW_INFO_AWF_VERSION: "v0.25.58" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -135,6 +139,7 @@ jobs: sparse-checkout: | .github .agents + .antigravity .claude .codex .crush @@ -145,8 +150,8 @@ jobs: fetch-depth: 1 - name: Save agent config folders for base branch restoration env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" # poutine:ignore untrusted_checkout_exec run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" - name: Check workflow lock file @@ -164,7 +169,7 @@ jobs: - name: Check compile-agentic version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.72.1" + GH_AW_COMPILED_VERSION: "v0.77.5" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -175,11 +180,11 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -187,61 +192,61 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_0170a78c8d56645a_EOF' + cat << 'GH_AW_PROMPT_78cbc6c89dc649e4_EOF' - GH_AW_PROMPT_0170a78c8d56645a_EOF + GH_AW_PROMPT_78cbc6c89dc649e4_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_0170a78c8d56645a_EOF' + cat << 'GH_AW_PROMPT_78cbc6c89dc649e4_EOF' Tools: add_comment(max:10), create_pull_request(max:10), update_pull_request(max:10), add_labels(max:10), push_to_pull_request_branch(max:10), missing_tool, missing_data, noop - GH_AW_PROMPT_0170a78c8d56645a_EOF + GH_AW_PROMPT_78cbc6c89dc649e4_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_0170a78c8d56645a_EOF' + cat << 'GH_AW_PROMPT_78cbc6c89dc649e4_EOF' - GH_AW_PROMPT_0170a78c8d56645a_EOF + GH_AW_PROMPT_78cbc6c89dc649e4_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_0170a78c8d56645a_EOF' + cat << 'GH_AW_PROMPT_78cbc6c89dc649e4_EOF' The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} + {{#if github.actor}} - **actor**: __GH_AW_GITHUB_ACTOR__ {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} + {{#if github.repository}} - **repository**: __GH_AW_GITHUB_REPOSITORY__ {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} + {{#if github.workspace}} - **workspace**: __GH_AW_GITHUB_WORKSPACE__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} + - **issue-number**: #__GH_AW_EXPR_802A9F6A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} + - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} + - **pull-request-number**: #__GH_AW_EXPR_463A214A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{#if github.event.comment.id || github.aw.context.comment_id}} + - **comment-id**: __GH_AW_EXPR_FF1D34CE__ {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} + {{#if github.run_id}} - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} - **checkouts**: The following repositories have been checked out and are available in the workspace: - - `$GITHUB_WORKSPACE` → `__GH_AW_GITHUB_REPOSITORY__` (cwd) [full history, all branches available as remote-tracking refs] [additional refs fetched: *] + - repo `__GH_AW_GITHUB_REPOSITORY__` → `$GITHUB_WORKSPACE` (cwd) [full history, all branches available as remote-tracking refs] [additional refs fetched: *] - **Note**: If a branch you need is not in the list above and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it without proper authentication. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: ["refs/pulls/open/*"]` for all open PR refs, or `fetch: ["main", "feature/my-branch"]` for specific branches). - GH_AW_PROMPT_0170a78c8d56645a_EOF + GH_AW_PROMPT_78cbc6c89dc649e4_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_0170a78c8d56645a_EOF' + cat << 'GH_AW_PROMPT_78cbc6c89dc649e4_EOF' {{#runtime-import .github/workflows/code-radiator.md}} - GH_AW_PROMPT_0170a78c8d56645a_EOF + GH_AW_PROMPT_78cbc6c89dc649e4_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -258,11 +263,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -278,11 +283,11 @@ jobs: return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, substitutions: { + GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, + GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, + GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, + GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, @@ -307,12 +312,14 @@ jobs: include-hidden-files: true path: | /tmp/gh-aw/aw_info.json + /tmp/gh-aw/model_multipliers.json /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/aw-prompts/prompt-template.txt /tmp/gh-aw/aw-prompts/prompt-import-tree.json /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/base /tmp/gh-aw/.github/agents + /tmp/gh-aw/.github/skills if-no-files-found: ignore retention-days: 1 @@ -324,6 +331,7 @@ jobs: pull-requests: read concurrency: group: "gh-aw-copilot-${{ github.workflow }}" + queue: max env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} GH_AW_ASSETS_ALLOWED_EXTS: "" @@ -332,29 +340,35 @@ jobs: GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs GH_AW_WORKFLOW_ID_SANITIZED: coderadiator outputs: - agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} + agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} + effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} - inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} - mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} + inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} + mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} model: ${{ needs.activation.outputs.model }} - model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} + model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths run: | @@ -408,11 +422,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -428,24 +442,28 @@ jobs: - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" - name: Restore inline sub-agents from activation artifact env: GH_AW_SUB_AGENT_DIR: ".github/agents" GH_AW_SUB_AGENT_EXT: ".agent.md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" + - name: Restore inline skills from activation artifact + env: + GH_AW_SKILL_DIR: ".github/skills" + run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14 - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_1344cecc882c8d36_EOF' - {"add_comment":{"max":10,"target":"*"},"add_labels":{"max":10,"target":"*"},"create_pull_request":{"allowed_base_branches":["net[0-9]*.0","xcode[0-9]*","xcode[0-9]*.[0-9]*"],"max":10,"max_patch_files":100,"max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"]},"create_report_incomplete_issue":{},"merge_pull_request":{"max":10},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"if_no_changes":"warn","max":10,"max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"target":"*","title_prefix":"🤖 Merge 'main' =\u003e '"},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":true,"max":10,"update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_1344cecc882c8d36_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_1667342258ba4bbd_EOF' + {"add_comment":{"max":10,"target":"*"},"add_labels":{"max":10,"target":"*"},"create_pull_request":{"allowed_base_branches":["net*.0","xcode*","xcode*.*"],"max":10,"max_patch_files":1000,"max_patch_size":10240,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","signed_commits":false},"create_report_incomplete_issue":{},"merge_pull_request":{"max":10},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"if_no_changes":"warn","max":10,"max_patch_size":10240,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"signed_commits":false,"target":"*","title_prefix":"🤖 Merge 'main' =\u003e '"},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":true,"max":10,"update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_1667342258ba4bbd_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -778,17 +796,22 @@ jobs: export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.6' + case "${DOCKER_HOST:-}" in + unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; + /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; + * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; + esac + DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22' mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_2bd87db1366a659d_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_b4c6a644a0b8a10f_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.0.3", + "container": "ghcr.io/github/github-mcp-server:v1.1.0", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -827,7 +850,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_2bd87db1366a659d_EOF + GH_AW_MCP_CONFIG_b4c6a644a0b8a10f_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -855,25 +878,42 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"models":{"auto":["large"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"]}},"container":{"imageTag":"0.25.41,squid=sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4,agent=sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770,api-proxy=sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + elif [ -d "/home/runner/work/_tool" ]; then + GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.77.5 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -887,12 +927,13 @@ jobs: GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] + RUNNER_TEMP: ${{ runner.temp }} XDG_CONFIG_HOME: /home/runner - - name: Detect Copilot errors - id: detect-copilot-errors + - name: Detect agent errors if: always() + id: detect-agent-errors continue-on-error: true - run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs" + run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs" - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -950,7 +991,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -1067,6 +1108,7 @@ jobs: concurrency: group: "gh-aw-conclusion-code-radiator" cancel-in-progress: false + queue: max outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1075,15 +1117,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1105,6 +1150,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: "Code Radiator" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/code-radiator.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_NOOP_REPORT_AS_ISSUE: "true" @@ -1121,6 +1167,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Code Radiator" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/code-radiator.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} @@ -1138,6 +1185,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "Code Radiator" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/code-radiator.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1152,6 +1200,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "Code Radiator" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/code-radiator.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1166,6 +1215,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Code Radiator" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/code-radiator.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "code-radiator" @@ -1173,6 +1223,8 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} + GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} @@ -1187,6 +1239,7 @@ jobs: GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "20" + GH_AW_MAX_EFFECTIVE_TOKENS: "25000000" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1211,15 +1264,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1245,7 +1301,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 - name: Check if detection needed id: detection_guard if: always() @@ -1271,6 +1327,9 @@ jobs: run: | mkdir -p /tmp/gh-aw/threat-detection/aw-prompts cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then + echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context." + fi cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true for f in /tmp/gh-aw/aw-*.patch; do [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true @@ -1304,11 +1363,11 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true @@ -1317,23 +1376,40 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.41"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + elif [ -d "/home/runner/work/_tool" ]; then + GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.77.5 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1346,6 +1422,7 @@ jobs: GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] + RUNNER_TEMP: ${{ runner.temp }} XDG_CONFIG_HOME: /home/runner - name: Upload threat detection log if: always() && steps.detection_guard.outputs.run_detection == 'true' @@ -1361,6 +1438,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: script: | @@ -1371,10 +1449,11 @@ jobs: await main(); } catch (loadErr) { const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; + const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); core.error(msg); core.setOutput('reason', 'parse_error'); - if (continueOnError) { + if (continueOnError && !detectionExecutionFailed) { core.warning('\u26A0\uFE0F ' + msg); core.setOutput('conclusion', 'warning'); core.setOutput('success', 'false'); @@ -1405,9 +1484,10 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "claude-sonnet-4.5" - GH_AW_ENGINE_VERSION: "1.0.40" + GH_AW_ENGINE_VERSION: "1.0.55" GH_AW_WORKFLOW_ID: "code-radiator" GH_AW_WORKFLOW_NAME: "Code Radiator" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/code-radiator.md" outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} @@ -1424,15 +1504,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1456,34 +1539,29 @@ jobs: - name: Extract base branch from agent output id: extract-base-branch if: steps.download-agent-output.outcome == 'success' - shell: bash - run: | - if [ -f "/tmp/gh-aw/agent_output.json" ]; then - GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - BASE_BRANCH=$("$GH_AW_NODE" -e " - try { - const data = JSON.parse(require('fs').readFileSync('/tmp/gh-aw/agent_output.json', 'utf8')); - const item = (data.items || []).find(i => - (i.type === 'create_pull_request' || i.type === 'push_to_pull_request_branch') && - i.base_branch - ); - if (item) process.stdout.write(item.base_branch); - } catch(e) {} - " 2>/dev/null || true) - # Validate: only allow safe git branch name characters - if [[ "$BASE_BRANCH" =~ ^[a-zA-Z0-9/_.-]+$ ]] && [ ${#BASE_BRANCH} -le 255 ]; then - printf 'base-branch=%s\n' "$BASE_BRANCH" >> "$GITHUB_OUTPUT" - echo "Extracted base branch from safe output: $BASE_BRANCH" - fi - fi + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/extract_base_branch_from_agent_output.cjs'); + await main(); + - name: Checkout repository (trusted default branch for comment events) + if: ((!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) && (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.event.repository.default_branch }} + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + persist-credentials: false + fetch-depth: 0 - name: Checkout repository - if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + if: ((!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) && github.event_name != 'issue_comment' && github.event_name != 'pull_request_review_comment' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ steps.extract-base-branch.outputs.base-branch || github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }} token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} persist-credentials: false - fetch-depth: 1 + fetch-depth: 0 - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: @@ -1512,10 +1590,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"add_labels\":{\"max\":10,\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net[0-9]*.0\",\"xcode[0-9]*\",\"xcode[0-9]*.[0-9]*\"],\"max\":10,\"max_patch_files\":100,\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"]},\"create_report_incomplete_issue\":{},\"merge_pull_request\":{\"max\":10},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":10,\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"target\":\"*\",\"title_prefix\":\"🤖 Merge 'main' =\\u003e '\"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":true,\"max\":10,\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"add_labels\":{\"max\":10,\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net*.0\",\"xcode*\",\"xcode*.*\"],\"max\":10,\"max_patch_files\":1000,\"max_patch_size\":10240,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"signed_commits\":false},\"create_report_incomplete_issue\":{},\"merge_pull_request\":{\"max\":10},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":10,\"max_patch_size\":10240,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"signed_commits\":false,\"target\":\"*\",\"title_prefix\":\"🤖 Merge 'main' =\\u003e '\"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":true,\"max\":10,\"update_branch\":false}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/code-radiator.md b/.github/workflows/code-radiator.md index 9fec3bff181d..89fd81f9bdef 100644 --- a/.github/workflows/code-radiator.md +++ b/.github/workflows/code-radiator.md @@ -25,12 +25,15 @@ checkout: fetch: ["*"] fetch-depth: 0 safe-outputs: + max-patch-files: 1000 + max-patch-size: 10240 create-pull-request: max: 10 + signed-commits: false allowed-base-branches: - - "net[0-9]*.0" - - "xcode[0-9]*" - - "xcode[0-9]*.[0-9]*" + - "net*.0" + - "xcode*" + - "xcode*.*" add-comment: max: 10 target: "*" @@ -41,8 +44,9 @@ safe-outputs: max: 10 push-to-pull-request-branch: max: 10 + signed-commits: false target: "*" - title-prefix: "🤖 Merge 'main' => '" + required-title-prefix: "🤖 Merge 'main' => '" update-pull-request: max: 10 --- @@ -54,9 +58,9 @@ Merge code from `main` into active target branches, creating pull requests for e ## Target Branch Patterns Only consider remote branches matching these patterns: -- `net[0-9]*.0` (e.g., `net11.0`, `net10.0`) -- `xcode[0-9]*` (e.g., `xcode26`) -- `xcode[0-9]*.[0-9]*` (e.g., `xcode26.4`) +- `net*.0` (e.g., `net11.0`, `net10.0`) +- `xcode*` (e.g., `xcode26`) +- `xcode*.*` (e.g., `xcode26.4`) Only process branches that have had commits in the last 30 days. @@ -137,19 +141,19 @@ If there are merge conflicts: - Add the `do-not-merge` label. - Add a comment requesting human review of the conflict resolution, listing which files were manually resolved. -#### e. Push and create/update the PR +#### e. Create or update the PR -```bash -git push origin "" -``` +Do **NOT** run `git push` manually. The safeoutputs tool handles pushing. + +Use the `create_pull_request` safeoutput tool to push the branch and create/update the PR: +- `branch`: `` (e.g., `merge/main-to-net11.0-20260527`) +- `base`: `` (e.g., `net11.0`) — **always provide this field** +- `title`: `🤖 Merge 'main' => ''` +- `body`: `Automated merge of \`main\` into \`\`.\n\nCreated by the code-radiator workflow.` + +> **Important**: Do NOT unset the upstream tracking branch. After `git checkout -B "" "origin/"`, the upstream is set to `origin/`. Keep it set — the safeoutputs tool relies on this to detect the commits to push. -- If updating an existing PR: the push is sufficient (the PR updates automatically). -- If creating a new PR: - - Title: `🤖 Merge 'main' => ''` - - Body: `Automated merge of \`main\` into \`\`.\n\nCreated by the code-radiator workflow.` - - Base: the target branch - - Head: the local branch - - Enable automerge (merge strategy) on the new PR. +After creating the PR, enable automerge (merge strategy) using the GitHub MCP `enable_auto_merge` tool or `gh pr merge --auto --merge`. ### 3. Summary @@ -178,7 +182,10 @@ Split version strings on `.`, `-`, and `+`. Compare each segment numerically. Ex ## Important Notes -- Never force push. Always use regular `git push`. +- Never force push. +- Do NOT run `git push` manually — the safeoutputs `create_pull_request` tool handles pushing. +- Do NOT unset the upstream tracking branch after creating the local branch. The safeoutputs tool uses `@{upstream}` to detect commits that need to be pushed. Unsetting the upstream causes the tool to report "No changes to commit - no commits found" even when commits exist. +- Always provide the `base` branch when calling `safeoutputs create_pull_request` (e.g., `base: "net11.0"`). - The workflow operates on the current repository checkout. - Run `git fetch origin` before starting to ensure up-to-date remote refs. -- Use `gh` CLI for PR operations (create, comment, list, merge --auto). +- Use the GitHub MCP tools or `gh` CLI for non-push PR operations (comment, list, merge --auto, enable automerge). diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 0ae42f6f5c4b..451d17b79bd5 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,8 +19,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Install gh-aw extension - uses: github/gh-aw-actions/setup-cli@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup-cli@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: - version: v0.72.1 + version: v0.74.8 diff --git a/.github/workflows/inter-branch-merge-flow.yml b/.github/workflows/inter-branch-merge-flow.yml index b6b979ddad46..b456685eebb4 100644 --- a/.github/workflows/inter-branch-merge-flow.yml +++ b/.github/workflows/inter-branch-merge-flow.yml @@ -30,4 +30,4 @@ permissions: jobs: Merge: - uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@main + uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@b6ed8ef7f3251d0b67ac2428c06253d0ba328e97 # main diff --git a/.github/workflows/macios-reviewer.lock.yml b/.github/workflows/macios-reviewer.lock.yml index 616d54825de5..582956c5136e 100644 --- a/.github/workflows/macios-reviewer.lock.yml +++ b/.github/workflows/macios-reviewer.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a0f64139dbc6fe8697f9fd99f5489155b561c37ec0b13d7eaf30bda56d034e7f","compiler_version":"v0.72.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"bc56a0cad2f450c562810785ef38649c04db812a","version":"v0.72.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41","digest":"sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41","digest":"sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41","digest":"sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.6","digest":"sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"a0f64139dbc6fe8697f9fd99f5489155b561c37ec0b13d7eaf30bda56d034e7f","body_hash":"62e09281b84230e857c88588f55f5794cfba9d3e9ff9021d9528645b9b3c2965","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.72.1). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -35,18 +35,18 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 +# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 -# - ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 -# - ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c -# - ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 -# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f +# - ghcr.io/github/gh-aw-firewall/agent:0.25.58 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.58 +# - ghcr.io/github/gh-aw-mcpg:v0.3.22 +# - ghcr.io/github/github-mcp-server:v1.1.0 +# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14 name: ".NET for Apple Platforms PR Reviewer" -"on": +on: issue_comment: types: - created @@ -83,6 +83,8 @@ jobs: lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} slash_command: ${{ needs.pre_activation.outputs.matched_command }} stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} @@ -91,31 +93,34 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "claude-sonnet-4.5" - GH_AW_INFO_VERSION: "1.0.40" - GH_AW_INFO_AGENT_VERSION: "1.0.40" - GH_AW_INFO_CLI_VERSION: "v0.72.1" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AGENT_VERSION: "1.0.55" + GH_AW_INFO_CLI_VERSION: "v0.77.5" GH_AW_INFO_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","github","aka.ms","dev.azure.com","microsoft.com","vsassets.io"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.41" + GH_AW_INFO_AWF_VERSION: "v0.25.58" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -128,7 +133,7 @@ jobs: await main(core, context); - name: Add eyes reaction for immediate feedback id: react - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id || github.event_name == 'pull_request_review' && github.event.pull_request.head.repo.id == github.repository_id + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_REACTION: "eyes" @@ -151,6 +156,7 @@ jobs: sparse-checkout: | .github .agents + .antigravity .claude .codex .crush @@ -161,8 +167,8 @@ jobs: fetch-depth: 1 - name: Save agent config folders for base branch restoration env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" # poutine:ignore untrusted_checkout_exec run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" - name: Check workflow lock file @@ -180,7 +186,7 @@ jobs: - name: Check compile-agentic version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.72.1" + GH_AW_COMPILED_VERSION: "v0.77.5" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -191,7 +197,7 @@ jobs: id: sanitized uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -200,7 +206,7 @@ jobs: await main(); - name: Add comment with workflow run link id: add-comment - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id || github.event_name == 'pull_request_review' && github.event.pull_request.head.repo.id == github.repository_id + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" @@ -214,11 +220,11 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -243,28 +249,28 @@ jobs: cat << 'GH_AW_PROMPT_33adc77fba6f068a_EOF' The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} + {{#if github.actor}} - **actor**: __GH_AW_GITHUB_ACTOR__ {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} + {{#if github.repository}} - **repository**: __GH_AW_GITHUB_REPOSITORY__ {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} + {{#if github.workspace}} - **workspace**: __GH_AW_GITHUB_WORKSPACE__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} + - **issue-number**: #__GH_AW_EXPR_802A9F6A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} + - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} + - **pull-request-number**: #__GH_AW_EXPR_463A214A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{#if github.event.comment.id || github.aw.context.comment_id}} + - **comment-id**: __GH_AW_EXPR_FF1D34CE__ {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} + {{#if github.run_id}} - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} @@ -294,11 +300,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -317,11 +323,11 @@ jobs: return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, substitutions: { + GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, + GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, + GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, + GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, @@ -349,12 +355,14 @@ jobs: include-hidden-files: true path: | /tmp/gh-aw/aw_info.json + /tmp/gh-aw/model_multipliers.json /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/aw-prompts/prompt-template.txt /tmp/gh-aw/aw-prompts/prompt-import-tree.json /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/base /tmp/gh-aw/.github/agents + /tmp/gh-aw/.github/skills if-no-files-found: ignore retention-days: 1 @@ -372,29 +380,35 @@ jobs: GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs GH_AW_WORKFLOW_ID_SANITIZED: maciosreviewer outputs: - agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} + agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} + effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} - inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} - mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} + inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} + mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} model: ${{ needs.activation.outputs.model }} - model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} + model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths run: | @@ -441,11 +455,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -461,16 +475,20 @@ jobs: - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" - name: Restore inline sub-agents from activation artifact env: GH_AW_SUB_AGENT_DIR: ".github/agents" GH_AW_SUB_AGENT_EXT: ".agent.md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" + - name: Restore inline skills from activation artifact + env: + GH_AW_SKILL_DIR: ".github/skills" + run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14 - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -694,8 +712,13 @@ jobs: export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.6' + case "${DOCKER_HOST:-}" in + unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; + /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; + * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; + esac + DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22' mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) @@ -704,7 +727,7 @@ jobs: "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.0.3", + "container": "ghcr.io/github/github-mcp-server:v1.1.0", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -771,25 +794,42 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","*.vsblob.vsassets.io","aka.ms","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.nuget.org","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","azuresearch-usnc.nuget.org","azuresearch-ussc.nuget.org","builds.dotnet.microsoft.com","ci.dot.net","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","dc.services.visualstudio.com","dev.azure.com","dist.nuget.org","docs.github.com","dot.net","dotnet.microsoft.com","dotnetcli.blob.core.windows.net","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","microsoft.com","nuget.org","nuget.pkg.github.com","nugetregistryv2prod.blob.core.windows.net","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","oneocsp.microsoft.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","pkgs.dev.azure.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","vsassets.io","www.googleapis.com","www.microsoft.com"]},"apiProxy":{"enabled":true,"models":{"auto":["large"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"]}},"container":{"imageTag":"0.25.41,squid=sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4,agent=sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770,api-proxy=sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","*.vsblob.vsassets.io","aka.ms","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.nuget.org","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","azuresearch-usnc.nuget.org","azuresearch-ussc.nuget.org","builds.dotnet.microsoft.com","ci.dot.net","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","dc.services.visualstudio.com","dev.azure.com","dist.nuget.org","docs.github.com","dot.net","dotnet.microsoft.com","dotnetcli.blob.core.windows.net","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","microsoft.com","nuget.org","nuget.pkg.github.com","nugetregistryv2prod.blob.core.windows.net","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","oneocsp.microsoft.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","pkgs.dev.azure.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","vsassets.io","www.googleapis.com","www.microsoft.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + elif [ -d "/home/runner/work/_tool" ]; then + GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.77.5 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -803,12 +843,13 @@ jobs: GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] + RUNNER_TEMP: ${{ runner.temp }} XDG_CONFIG_HOME: /home/runner - - name: Detect Copilot errors - id: detect-copilot-errors + - name: Detect agent errors if: always() + id: detect-agent-errors continue-on-error: true - run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs" + run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs" - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -866,10 +907,10 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_COMMAND: review + GH_AW_COMMANDS: "[\"review\"]" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -982,6 +1023,7 @@ jobs: concurrency: group: "gh-aw-conclusion-macios-reviewer" cancel-in-progress: false + queue: max outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -990,15 +1032,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1020,6 +1065,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/macios-reviewer.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_NOOP_REPORT_AS_ISSUE: "true" @@ -1036,6 +1082,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/macios-reviewer.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} @@ -1053,6 +1100,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/macios-reviewer.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1067,6 +1115,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/macios-reviewer.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1081,6 +1130,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/macios-reviewer.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "macios-reviewer" @@ -1088,6 +1138,8 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} + GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} @@ -1100,6 +1152,7 @@ jobs: GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "20" + GH_AW_MAX_EFFECTIVE_TOKENS: "25000000" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1144,15 +1197,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1178,7 +1234,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 - name: Check if detection needed id: detection_guard if: always() @@ -1204,6 +1260,9 @@ jobs: run: | mkdir -p /tmp/gh-aw/threat-detection/aw-prompts cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then + echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context." + fi cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true for f in /tmp/gh-aw/aw-*.patch; do [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true @@ -1237,11 +1296,11 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true @@ -1250,23 +1309,40 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.41"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + elif [ -d "/home/runner/work/_tool" ]; then + GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.77.5 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1279,6 +1355,7 @@ jobs: GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] + RUNNER_TEMP: ${{ runner.temp }} XDG_CONFIG_HOME: /home/runner - name: Upload threat detection log if: always() && steps.detection_guard.outputs.run_detection == 'true' @@ -1294,6 +1371,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: script: | @@ -1304,10 +1382,11 @@ jobs: await main(); } catch (loadErr) { const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; + const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); core.error(msg); core.setOutput('reason', 'parse_error'); - if (continueOnError) { + if (continueOnError && !detectionExecutionFailed) { core.warning('\u26A0\uFE0F ' + msg); core.setOutput('conclusion', 'warning'); core.setOutput('success', 'false'); @@ -1324,18 +1403,22 @@ jobs: outputs: activated: ${{ steps.check_membership.outputs.is_team_member == 'true' && steps.check_command_position.outputs.command_position_ok == 'true' }} matched_command: ${{ steps.check_command_position.outputs.matched_command }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for command workflow id: check_membership uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1373,14 +1456,16 @@ jobs: timeout-minutes: 15 env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/macios-reviewer" + GH_AW_COMMANDS: "[\"review\"]" GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "claude-sonnet-4.5" - GH_AW_ENGINE_VERSION: "1.0.40" + GH_AW_ENGINE_VERSION: "1.0.55" GH_AW_WORKFLOW_ID: "macios-reviewer" GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/macios-reviewer.md" outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} @@ -1391,15 +1476,18 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.55" + GH_AW_INFO_AWF_VERSION: "v0.25.58" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1428,7 +1516,8 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request_review_comment\":{\"max\":50,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"submit_pull_request_review\":{\"allowed_events\":[\"COMMENT\",\"REQUEST_CHANGES\"],\"max\":1,\"supersede_older_reviews\":true}}" diff --git a/.github/workflows/maestro-changelog.yml b/.github/workflows/maestro-changelog.yml index e390cd2d872c..ab0ebf924389 100644 --- a/.github/workflows/maestro-changelog.yml +++ b/.github/workflows/maestro-changelog.yml @@ -17,7 +17,7 @@ jobs: if: github.event.pull_request.user.login == 'dotnet-maestro[bot]' steps: - - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5 + - uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 with: dotnet-version: '9' diff --git a/.github/workflows/update-single-platform-branches.yml b/.github/workflows/update-single-platform-branches.yml index 0944fe689a68..bb0e62bcf29d 100644 --- a/.github/workflows/update-single-platform-branches.yml +++ b/.github/workflows/update-single-platform-branches.yml @@ -19,9 +19,10 @@ jobs: steps: - name: Checkout repo - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 + persist-credentials: true # need to push changes - name: 'Update branches' run: | diff --git a/.github/workflows/yamllint.yml b/.github/workflows/yamllint.yml index d2fa268c38a3..ccef5822206a 100644 --- a/.github/workflows/yamllint.yml +++ b/.github/workflows/yamllint.yml @@ -13,10 +13,11 @@ jobs: steps: - name: 'Checkout' - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 + persist-credentials: false - name: Install yamllint run: pip install yamllint diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 000000000000..a27c501d6710 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,34 @@ +name: zizmor 🌈 + +on: + push: + branches: ["main"] + pull_request: + branches: ["**"] + +permissions: {} + +jobs: + zizmor: + name: zizmor 🌈 + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Find workflow files + id: find-files + run: | + files=$(find .github/workflows -name '*.yml' ! -name '*.lock.yml' | sort | tr '\n' ' ') + echo "files=$files" >> "$GITHUB_OUTPUT" + + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + with: + inputs: ${{ steps.find-files.outputs.files }} diff --git a/Directory.Build.props b/Directory.Build.props index d2990a2b1d1d..a5be85f32d94 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ $(MicrosoftBuildPackageVersion) $(MicrosoftBuildPackageVersion) 3.22.0 - 3.1.15 + 8.0.0 4.7.2 @@ -19,9 +19,11 @@ 21.1.8 18.0.1 0.11.6 - 6.1.0 - 4.7.0 - 4.4.0 + 6.2.0 + 4.13.0 + 4.6.1 + $(NUnitPackageVersion) + 3.8.0 latest diff --git a/Make.config b/Make.config index ccc667f39b6f..c03107f58990 100644 --- a/Make.config +++ b/Make.config @@ -206,11 +206,13 @@ MACCATALYST_NUGET_VERSION_PATCH=$(word 3, $(subst ., ,$(MACCATALYST_NUGET_VERSIO MACCATALYST_NUGET_VERSION_NO_METADATA=$(MACCATALYST_NUGET_VERSION)$(NUGET_PRERELEASE_IDENTIFIER) MACCATALYST_NUGET_VERSION_FULL=$(MACCATALYST_NUGET_VERSION_NO_METADATA)$(NUGET_BUILD_METADATA) +-include $(TOP)/configure.inc + # Xcode version should have both a major and a minor version (even if the minor version is 0) XCODE_VERSION=26.5 XCODE_URL=https://bosstoragemirror.blob.core.windows.net/internal-files/xcodes/Xcode_26.5.xip ifndef NO_XCODE -XCODE_DEVELOPER_ROOT=/Applications/Xcode_26.5.0.app/Contents/Developer +XCODE_DEVELOPER_ROOT?=/Applications/Xcode_26.5.0.app/Contents/Developer ifneq (OK,$(shell test -d $(abspath $(XCODE_DEVELOPER_ROOT)) && echo OK)) NO_XCODE=1 $(warning The required Xcode ($(XCODE_VERSION)) is not installed in $(XCODE_DEVELOPER_ROOT) - this directory does not exist. Any parts of the build that require Xcode will be disabled.) @@ -239,7 +241,6 @@ endif # Tell both Xcode and our build logic which Xcode we're using. export DEVELOPER_DIR=$(XCODE_DEVELOPER_ROOT) -export MD_APPLE_SDK_ROOT=$(abspath $(XCODE_DEVELOPER_ROOT)/../..) else # Without Xcode, set placeholder Xcode values but honor XCODE_CHANNEL so we configure bots correctly ifeq ($(XCODE_CHANNEL),Beta) diff --git a/NuGet.config b/NuGet.config index de071dd918b2..84a934c55c08 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,26 +1,25 @@ - + - + - - + + - - - - - - - - - - + + + + + + + + + + @@ -31,16 +30,32 @@ - + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + \ No newline at end of file diff --git a/configure b/configure index a040e46460bb..bf82ee1b84aa 100755 --- a/configure +++ b/configure @@ -29,6 +29,11 @@ Usage: configure [options] --custom-dotnet=[dotnet/runtime] Use a locally built version of dotnet/runtime. Pass the path to an already build checkout of dotnet/runtime. See docs/CORECLR.md for detailed instructions about how to build dotnet/runtime from source. + --xcode=[path] Select the Xcode app or developer root to use for the build. + --xcode-root=[path] Select the Xcode app to use for the build. + --xcode-developer-root=[path] + Select the Xcode developer root to use for the build. + --ignore-unknown-params alters the default behavior to not return an non-zero exit code when an unknown parameter is provided. --no-xcode Only do things that don't require Xcode. This won't produce anything useful, but might come in handy once in a blue moon when testing something that doesn't require Xcode somewhere Xcode can't be installed (Linux, older macOS devices, etc.) @@ -39,6 +44,39 @@ cd "$(dirname "${BASH_SOURCE[0]}")" CONFIGURED_FILE=configure.inc IGNORE_UNKNOWN_PARAMS=false UNKNOWN_PARAMETERS= +NO_XCODE_FLAG= +XCODE_ARG= + +function fail_configure () { + echo "configure: $1" >&2 + rm -f "$CONFIGURED_FILE" + exit 1 +} + +function set_xcode_arg () { + local value="$1" + local option="$2" + + while [[ "$value" == */ ]]; do + value="${value%/}" + done + + if [[ -z "$value" ]]; then + fail_configure "$option requires a non-empty path" + fi + + if [[ ! "$value" =~ ^/[A-Za-z0-9._+/-]+$ ]]; then + fail_configure "$option path contains unsupported characters: '$value'" + fi + + if [[ "$value" == *.app ]]; then + value="$value/Contents/Developer" + elif [[ "$value" != */Contents/Developer ]]; then + fail_configure "$option must point to an Xcode .app bundle or Contents/Developer directory" + fi + + XCODE_ARG="$value" +} rm -f $CONFIGURED_FILE @@ -130,6 +168,17 @@ while test "x$1" != x; do echo "DOTNET_RUNTIME_PATH=$2" >> "$CONFIGURED_FILE" shift 2 ;; + --xcode=*|--xcode-root=*|--xcode-developer-root=*) + set_xcode_arg "${1#*=}" "${1%%=*}" + shift + ;; + --xcode|--xcode-root|--xcode-developer-root) + if [[ $# -lt 2 ]] || [[ "$2" == --* ]]; then + fail_configure "$1 requires a value" + fi + set_xcode_arg "$2" "$1" + shift 2 + ;; --disable-device) echo "INCLUDE_DEVICE=" >> "$CONFIGURED_FILE" shift @@ -153,6 +202,7 @@ while test "x$1" != x; do ;; --no-xcode) echo "Ignoring Xcode requirement" + NO_XCODE_FLAG=1 echo "NO_XCODE=1" >> "$CONFIGURED_FILE" shift ;; @@ -168,6 +218,10 @@ while test "x$1" != x; do esac done +if [[ -n "$NO_XCODE_FLAG" && -n "$XCODE_ARG" ]]; then + fail_configure "--no-xcode cannot be combined with --xcode, --xcode-root, or --xcode-developer-root" +fi + if [[ "$IGNORE_UNKNOWN_PARAMS" = false ]] && [[ -n "$UNKNOWN_PARAMETERS" ]]; then exit 1 fi @@ -176,4 +230,9 @@ if [[ "$IGNORE_UNKNOWN_PARAMS" = true ]] && [[ -n "$UNKNOWN_PARAMETERS" ]]; then echo "The following parameters were ignored: $UNKNOWN_PARAMETERS" fi +if [[ -n "$XCODE_ARG" ]]; then + echo "XCODE_DEVELOPER_ROOT=$XCODE_ARG" >> "$CONFIGURED_FILE" + echo "Xcode developer root set to $XCODE_ARG" +fi + exit 0 diff --git a/docs/building-apps/build-items.md b/docs/building-apps/build-items.md index ff18c071b9e6..2fd81202cf18 100644 --- a/docs/building-apps/build-items.md +++ b/docs/building-apps/build-items.md @@ -186,7 +186,8 @@ Only applicable to iOS and tvOS projects. ## ImageAsset -An item group that contains image assets. +An item group that contains image assets, including files inside asset catalogs +(\*.xcassets) and Icon Composer directories (\*.icon). ## InterfaceDefinition diff --git a/docs/building-apps/build-properties.md b/docs/building-apps/build-properties.md index 45929fa49458..54ad732fbba4 100644 --- a/docs/building-apps/build-properties.md +++ b/docs/building-apps/build-properties.md @@ -580,6 +580,42 @@ See also: * The [AlternateAppIcon](build-items.md#alternateappicon) item group. * The [AppIcon](#appicon) property. +## InlineClassGetHandle + +Controls whether the build system replaces runtime calls to `Class.GetHandle` / +`Class.GetHandleIntrinsic` with direct native references to Objective-C classes +at build time. + +See [docs/code/class-handles.md](../code/class-handles.md) for an overview. + +The valid options are: + +* `compatibility`: Inlines `Class.GetHandle` calls only for types whose declaring + type matches the requested Objective-C class name. +* `strict`: Inlines all `Class.GetHandle` calls unconditionally. Requires using + the static registrar (not the dynamic registrar). +* (empty): Disables inlining of `Class.GetHandle` calls. + +Default value: +* .NET 11+: `strict` when using NativeAOT (`PublishAot=true`), `compatibility` otherwise. +* .NET 10 and earlier: not set (disabled). + +Example: + +```xml + + compatibility + +``` + +Custom behavior for specific Objective-C classes can be set using the [ReferenceNativeSymbol](build-items.md#referencenativesymbol) item group: + +```xml + + + +``` + ## InlineDlfcnMethods Controls whether the build system replaces runtime calls to `ObjCRuntime.Dlfcn` methods with direct native symbol lookups at build time, eliminating the overhead of `dlsym` at runtime. @@ -602,7 +638,7 @@ Example: ``` -Custom behavior for specific symbols can be set using the [ReferenceNativeSymbol](build-items.md#referencenativesymbols) item group: +Custom behavior for specific symbols can be set using the [ReferenceNativeSymbol](build-items.md#referencenativesymbol) item group: ```xml @@ -1532,6 +1568,21 @@ Consider using the unified [AppBundleResourcePrefix](#appbundleresourceprefix) p See also [IPhoneResourcePrefix](#iphoneresourceprefix) and [MonoMacResourcePrefix](#monomacresourceprefix). +## XcodeLocation + +Specifies the location of Xcode. + +When the build searches for Xcode, it's done in this order: + +1. If the `XcodeLocation` property is set, use that. Note that since all environment variables are automatically MSBuild properties as well, it's also possible to set the `XcodeLocation` environment variable for the same effect. +2. If the `MD_APPLE_SDK_ROOT` environment variable is set, use that. +3. If either of the files `~/Library/Preferences/maui/Settings.plist` or `~/Library/Preferences/Xamarin/Settings.plist` exist, and has the property list value `AppleSdkRoot`, use that. +4. Use the system version of Xcode (as determined by executing `xcode-select --print-path`). + +> [!WARNING] +> Support for the `MD_APPLE_SDK_ROOT` environment variable, and the `~/Library/Preferences/maui/Settings.plist` and `~/Library/Preferences/Xamarin/Settings.plist` files, is deprecated and will be removed in the future. +> Going forward, choose which Xcode to use by either making it the system's version of Xcode (either using `xcode-select --switch ...` on the command line, or in Xcode's settings), or by setting the `XcodeLocation` MSBuild property / environment variable. + ## ZipPath The full path to the `zip` command-line tool. diff --git a/docs/code/class-handles.md b/docs/code/class-handles.md new file mode 100644 index 000000000000..48255fb5aa6a --- /dev/null +++ b/docs/code/class-handles.md @@ -0,0 +1,57 @@ +# Objective-C classes + +Objective-C classes can be referenced from managed code in several ways: + +* Calls to Class.GetHandle / GetHandleIntrinsic + +It's highly desirable to use a direct native reference to Objective-C classes when building a mobile app, for a few reasons: + +* It's faster at runtime, and the app is smaller. +* If the referenced Objective-C class comes from a third-party static library, the + native linker can remove it if it's configured to remove unused code + (because the native linker can't see that the class is in fact used + at runtime) unless there's a direct native reference to the class. + +On the other hand there's one scenario when a direct native reference is not desirable: when the native Objective-C class does not exist. + +In order to create a direct native reference to Objective-C classes, we need to know the names of those Objective-C classes. + +## The `InlineClassGetHandle` property + +This behavior is controlled by the `InlineClassGetHandle` MSBuild property, which +can either be enabled or disabled. + +See the [build properties documentation](../building-apps/build-properties.md) for default values. + +## How it works + +During the build we try to collect the following: + +* Any calls to `Class.GetHandle[Intrinsic]` APIs: we try to collect the class name (this might not always succeed, if the class name is not a constant). + +This is further complicated by the fact that we only want to create native +references for managed references that survive trimming. + +So we do the following: + +1. During trimming, two custom linker steps execute: + + * `InlineClassGetHandleStep`: for every call `Class.GetHandle` we've + collected, this step creates a P/Invoke to a native method that will + return the Objective-C class for that symbol (using a direct native + reference), and modifies the code that fetches that symbol to call said + P/Invoke. + +2. After trimming, we figure out which of those symbols survived: + + * For ILTrim: the `_CollectPostILTrimInformation` MSBuild target inspects + the trimmed assemblies and collects all the inlined P/Invokes that + survived. Per-assembly results are cached to speed up incremental builds. + * For NativeAOT: the `_CollectPostNativeAOTTrimInformation` MSBuild target + inspects the native object file (or static library) produced by NativeAOT, + collects all unresolved native references, and filters them against the + Objective-C classes to determine which survived. + +3. The `_PostTrimmingProcessing` MSBuild target takes the surviving symbols + from either path, generates the corresponding native Objective-C code, and + adds it to the list of files to compile and link into the final executable. diff --git a/docs/guides/HowToBranch.md b/docs/guides/HowToBranch.md index ec95a74c03aa..46048712427c 100644 --- a/docs/guides/HowToBranch.md +++ b/docs/guides/HowToBranch.md @@ -20,8 +20,8 @@ sequence of events would be: 3. `dotnet/macios` branches `release/10.0.1xx-preview42` from `net10.0`: ```shell - $ dotnet checkout net10.0 - $ dotnet checkout -b release/10.0.1xx-preview42 + $ git checkout net10.0 + $ git checkout -b release/10.0.1xx-preview42 ``` Note that release candidates will use values such as `rc.1`, `rc.2`, etc. diff --git a/docs/os-onboarding.md b/docs/os-onboarding.md index db4f7364a34f..6bb151226afc 100644 --- a/docs/os-onboarding.md +++ b/docs/os-onboarding.md @@ -20,7 +20,7 @@ This involves: ### Bind new APIs -This is technically optional, because we can release support for a new OS version even if we bind any of the new APIs. +This is technically optional, because we can release support for a new OS version even if we don't bind any of the new APIs. Yet we try to bind most of new APIs, because it's hard to predict what users will need. diff --git a/docs/update-api-docs.md b/docs/update-api-docs.md index 58903732193a..ddb1e000babc 100644 --- a/docs/update-api-docs.md +++ b/docs/update-api-docs.md @@ -24,7 +24,7 @@ The steps are: * Copy our platform assemblies and their xml files into their corresponding directory. * Create a new commit and push it to origin. -4. Go here: [Continuous Integration](https://ops.microsoft.com/#/repos/85f784f4-01e7-ffb8-ed06-a012f7d649c0?tabName=ci) (might need VPN enabled, otherwise sometimes you'll get a 403 error page) and then: +4. Go here: [OPS dotnet/macios-api-docs / Continuous Integration](https://ops.microsoft.com/#/repos/85f784f4-01e7-ffb8-ed06-a012f7d649c0?tabName=ci) (if you have to go through the authentication workflow you'll end up on the OPS homepage, in which case just click the link again) and then: * Expand the '.NET macios API docs' job, and then: * Change `Target Repo` -> `Target Branch` to `netX.Y-xcodeZ.W` (same branch as created above). diff --git a/docs/website/binding_types_reference_guide.md b/docs/website/binding_types_reference_guide.md index 78b90f26cbca..ace56aab5bc3 100644 --- a/docs/website/binding_types_reference_guide.md +++ b/docs/website/binding_types_reference_guide.md @@ -1306,28 +1306,9 @@ This should map to Objective-C/clang use of `__attribute__((objc_designated_init ### DisableZeroCopyAttribute -This attribute is applied to string parameters or string properties and -instructs the code generator to not use the zero-copy string marshaling for -this parameter, and instead create a new NSString instance from the C# string. -This attribute is only required on strings if you instruct the generator to use -zero-copy string marshaling using either the `--zero-copy` command -line option or setting the assembly-level attribute `ZeroCopyStringsAttribute`. - -This is necessary in cases where the property is declared in Objective-C to -be a `retain` or `assign` property instead of a `copy` property. These typically -happen in third-party libraries that have been wrongly "optimized" by -developers. In general, `retain` or `assign` `NSString` properties are incorrect -since `NSMutableString` or user-derived classes of `NSString` might alter the -contents of the strings without the knowledge of the library code, subtly -breaking the application. Typically this happens due to premature -optimization. - -The following shows two such properties in Objective-C: - -```csharp -@property(nonatomic,retain) NSString *name; -@property(nonatomic,assign) NSString *name2; -``` +> **Note:** This attribute is obsolete and has no effect. Zero-copy string +> marshaling is no longer supported. The attribute is preserved for source +> compatibility but can be safely removed from binding definitions. @@ -2435,47 +2416,10 @@ This corresponds to `clang` [`__attribute__((objc_requires_super))`](https://cla ### ZeroCopyStringsAttribute -Only available in Xamarin.iOS 5.4 and newer. - -This attribute instructs the generator that the binding for this specific -library (if applied with `[assembly:]`) or type should use the fast -zero-copy string marshaling. This attribute is equivalent to passing the -command line option `--zero-copy` to the generator. - -When using zero-copy for strings, the generator effectively uses the same C# -string as the string that Objective-C consumes without incurring the creation of -a new `NSString` object and avoiding copying the data from the C# strings to the -Objective-C string. The only drawback of using Zero Copy strings is that you -must ensure that any string property that you wrap that happens to be flagged as -`retain` or `copy` has the `[DisableZeroCopy]` attribute set. This is -require because the handle for zero-copy strings is allocated on the stack and -is invalid upon the function return. - -Example: - -```csharp -[ZeroCopyStrings] -[BaseType (typeof (NSObject))] -interface MyBinding { - [Export ("name")] - string Name { get; set; } - - [Export ("domain"), NullAllowed] - string Domain { get; set; } - - [DisablZeroCopy] - [Export ("someRetainedNSString")] - string RetainedProperty { get; set; } -} - -``` - -You can also apply the attribute at the assembly level, and it will apply to -all the types of the assembly: - -```csharp -[assembly:ZeroCopyStrings] -``` +> **Note:** This attribute is obsolete and has no effect. Zero-copy string +> marshaling is no longer supported. The `--use-zero-copy` command line option +> is also no longer supported. The attribute is preserved for source +> compatibility but can be safely removed from binding definitions. ## Strongly-typed dictionaries diff --git a/docs/website/generator-errors.md b/docs/website/generator-errors.md index 1d135ecb476f..365a8964309d 100644 --- a/docs/website/generator-errors.md +++ b/docs/website/generator-errors.md @@ -128,7 +128,7 @@ Please go to [[FieldAttribute]](https://developer.xamarin.com/guides/cross-platf ### BI1026: `*`: Enums attributed with [\*] must have an underlying type of `long` or `ulong` -### BI1027: Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. +### BI1027: Support for ZeroCopy strings is not implemented. The --use-zero-copy option is not supported and will be ignored. ### BI1028: Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/dotnet/DefaultCompilationIncludes.md b/dotnet/DefaultCompilationIncludes.md index 3dec5cdb0a5f..9f14799e6634 100644 --- a/dotnet/DefaultCompilationIncludes.md +++ b/dotnet/DefaultCompilationIncludes.md @@ -33,6 +33,13 @@ All \*.pdf, \*.jpg, \*.png and \*.json files inside asset catalogs (\*.xcassets) in the project directory or any subdirectory are included by default (as `ImageAsset` items). +## Icon Composer files + +All files inside Icon Composer directories (\*.icon) in the project directory +or any subdirectory are included by default (as `ImageAsset` items). Icon +Composer files are created by Xcode's Icon Composer tool (Xcode 26+) and +contain layered app icons with `icon.json` metadata. + ## Atlas Textures All \*.png files inside \*.atlas directories in the project directory or any @@ -52,7 +59,7 @@ included by default (as `Metal` items). All files in the Resources/ subdirectory, except any items in the `Compile` or `EmbeddedResource` item groups, and except the ones mentioned above -(\*.scnassets, \*.storyboard, \*.xib, \*.xcassets, \*.atlas, \*.mlmodel, +(\*.scnassets, \*.storyboard, \*.xib, \*.xcassets, \*.icon, \*.atlas, \*.mlmodel, \*.metal) are included by default (as `BundleResource` items). [1]: https://docs.microsoft.com/en-us/dotnet/core/tools/csproj#default-compilation-includes-in-net-core-projects diff --git a/dotnet/targets/Microsoft.Sdk.DefaultItems.template.props b/dotnet/targets/Microsoft.Sdk.DefaultItems.template.props index d705ae3f56c2..afc08fe18531 100644 --- a/dotnet/targets/Microsoft.Sdk.DefaultItems.template.props +++ b/dotnet/targets/Microsoft.Sdk.DefaultItems.template.props @@ -24,7 +24,7 @@ - + $([MSBuild]::MakeRelative ('$(MSBuildProjectDirectory)', '%(FullPath)')) false true @@ -65,6 +65,7 @@ $(DefaultItemExcludes); $(DefaultExcludesInProjectFolder); $(_ResourcePrefix)\**\*.xcassets\**\*.*; + $(_ResourcePrefix)\**\*.icon\**\*.*; $(_ResourcePrefix)\**\*.storyboard;**\*.xib; $(_ResourcePrefix)\**\*.atlas\*.png; $(_ResourcePrefix)\**\*.mlmodel; diff --git a/dotnet/targets/Xamarin.Shared.Sdk.props b/dotnet/targets/Xamarin.Shared.Sdk.props index fc6465f4c1c0..0fde6897fdae 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.props +++ b/dotnet/targets/Xamarin.Shared.Sdk.props @@ -106,6 +106,12 @@ compatibility + + + strict + compatibility + + diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 592fafb84321..5c65259da13d 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -682,6 +682,7 @@ @(_BundlerEnvironmentVariables -> 'EnvironmentVariable=Overwrite=%(Overwrite)|%(Identity)=%(Value)') @(_XamarinFrameworkAssemblies -> 'FrameworkAssembly=%(Filename)') Interpreter=$(MtouchInterpreter) + InlineClassGetHandle=$(InlineClassGetHandle) InlineDlfcnMethods=$(InlineDlfcnMethods) IntermediateLinkDir=$(IntermediateLinkDir) IntermediateOutputPath=$(DeviceSpecificIntermediateOutputPath) @@ -716,6 +717,7 @@ TargetArchitectures=$(TargetArchitectures) TargetFramework=$(_ComputedTargetFrameworkMoniker) TypeMapAssemblyName=$(_TypeMapAssemblyName) + TypeMapFilePath=$(_TypeMapFilePath) TypeMapOutputDirectory=$(_TypeMapOutputDirectory) UseLlvm=$(MtouchUseLlvm) Verbosity=$(_BundlerVerbosity) @@ -840,6 +842,7 @@ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(Registrar)' == 'trimmable-static'" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.InlineClassGetHandleStep" Condition="'$(InlineClassGetHandle)' != '' And '$(InlineClassGetHandle)' != 'disabled'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.PreOutputDispatcher" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ClassHandleRewriterStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ClassHandleRewriterStep" Condition="'$(InlineClassGetHandle)' == '' Or '$(InlineClassGetHandle)' == 'disabled'" /> + <_TypeMapFilePath Condition="'$(_TypeMapFilePath)' == ''">$(DeviceSpecificIntermediateOutputPath)type-map.txt @@ -1728,20 +1734,22 @@ <_ILTrimSurvivingNativeSymbolsFile>$(DeviceSpecificIntermediateOutputPath)inlined-dlfcn\iltrim-surviving-native-symbols.txt - <_NativeAOTUnresolvedSymbolsFile>$(DeviceSpecificIntermediateOutputPath)nativeaot-unresolved-symbols.txt <_NativeAOTSurvivingNativeSymbolsFile>$(DeviceSpecificIntermediateOutputPath)nativeaot-surviving-native-symbols.txt + <_ILTrimSurvivingClassesFile>$(DeviceSpecificIntermediateOutputPath)inlined-class-gethandle\iltrim-classes.txt + <_NativeAOTSurvivingClassesFile>$(DeviceSpecificIntermediateOutputPath)inlined-class-gethandle\nativeaot-classes.txt @@ -1750,6 +1758,7 @@ + @@ -1760,12 +1769,17 @@ <_SurvivingNativeSymbolsFile Include="$(_ILTrimSurvivingNativeSymbolsFile)" Condition="Exists('$(_ILTrimSurvivingNativeSymbolsFile)')" /> <_SurvivingNativeSymbolsFile Include="$(_NativeAOTSurvivingNativeSymbolsFile)" Condition="Exists('$(_NativeAOTSurvivingNativeSymbolsFile)')" /> + + <_SurvivingClassesFiles Include="$(_ILTrimSurvivingClassesFile)" Condition="Exists('$(_ILTrimSurvivingClassesFile)')" /> + <_SurvivingClassesFiles Include="$(_NativeAOTSurvivingClassesFile)" Condition="Exists('$(_NativeAOTSurvivingClassesFile)')" /> @@ -1775,8 +1789,15 @@ <_PostTrimmingSourceFiles> $(DeviceSpecificIntermediateOutputPath)posttrim-info-compiled/%(Arch)/%(Filename).o + <_NativeExecutableObjectFiles Include="@(_PostTrimmingSourceFiles -> '%(OutputFile)')" /> + + - <_CompiledPostTrimmingFiles Include="@(_PostTrimmingSourceFiles -> '%(OutputFile)')" /> - <_NativeExecutableObjectFiles Include="@(_CompiledPostTrimmingFiles)" /> - + @@ -1854,7 +1873,7 @@ _ReadAppManifest; _WriteAppManifest; _CompileNativeExecutable; - _PostTrimmingProcessing; + _CompilePostTrimmingFiles; _ReidentifyDynamicLibraries; _AddSwiftLinkerFlags; _ComputeLinkerProperties; @@ -1868,8 +1887,11 @@ Condition="'$(_UseNativeAot)' == 'true'" DependsOnTargets="_ComputePostTrimmingPaths;_CompileNativeExecutable" Inputs="$(NativeObject)" - Outputs="$(_NativeAOTSurvivingNativeSymbolsFile)" + Outputs="$(_NativeAOTSurvivingNativeSymbolsFile);$(_NativeAOTSurvivingClassesFile)" > + + <_NativeAOTUnresolvedSymbolsFile>$(DeviceSpecificIntermediateOutputPath)nativeaot-unresolved-symbols.txt + + + + + diff --git a/eng/Version.Details.props b/eng/Version.Details.props index ab48f5c8515f..0c00841cb406 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -1,11 +1,7 @@ - + - + 11.0.0-beta.26256.105 11.0.0-beta.26256.105 0.11.5-preview.26256.105 @@ -16,7 +12,7 @@ This file should be imported by eng/Versions.props 11.0.100-preview.5.26256.105 11.0.0-preview.5.26256.105 11.0.100-preview.5.26256.105 - + 26.0.11017 26.5.10289 26.0.11017 @@ -25,12 +21,12 @@ This file should be imported by eng/Versions.props 26.5.10289 26.0.11017 26.5.10289 - + 11.0.0-prerelease.26217.1 - + - + $(MicrosoftDotNetArcadeSdkPackageVersion) $(MicrosoftDotNetBuildTasksFeedPackageVersion) $(MicrosoftDotNetCecilPackageVersion) @@ -41,7 +37,7 @@ This file should be imported by eng/Versions.props $(MicrosoftNETSdkPackageVersion) $(MicrosoftNETCoreAppRefPackageVersion) $(MicrosoftTemplateEngineAuthoringTasksPackageVersion) - + $(MicrosoftiOSSdknet100_260PackageVersion) $(MicrosoftiOSSdknet100_265PackageVersion) $(MicrosoftMacCatalystSdknet100_260PackageVersion) @@ -50,7 +46,7 @@ This file should be imported by eng/Versions.props $(MicrosoftmacOSSdknet100_265PackageVersion) $(MicrosofttvOSSdknet100_260PackageVersion) $(MicrosofttvOSSdknet100_265PackageVersion) - + $(MicrosoftDotNetXHarnessiOSSharedPackageVersion) - + \ No newline at end of file diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 92ff89e19131..d738060f278a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,3 +1,4 @@ + @@ -16,7 +17,7 @@ https://github.com/dotnet/dotnet d64191f29ec9042e2696d8b7d8326c4bd10ba268 - + https://github.com/dotnet/dotnet d64191f29ec9042e2696d8b7d8326c4bd10ba268 @@ -25,7 +26,7 @@ https://github.com/dotnet/dotnet d64191f29ec9042e2696d8b7d8326c4bd10ba268 - + https://github.com/dotnet/macios 23eb1c2c9465fe76c810c8a69982c1254161f4b0 @@ -42,7 +43,7 @@ https://github.com/dotnet/macios 23eb1c2c9465fe76c810c8a69982c1254161f4b0 - + https://github.com/dotnet/macios 6efb055f2806fbb89e4b201dca9e985ce7399db1 @@ -83,4 +84,4 @@ - + \ No newline at end of file diff --git a/macios/Localize/loc/cs/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/cs/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index 620e5dd4fb7f..e7c0532070d5 100644 --- a/macios/Localize/loc/cs/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/cs/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -2734,6 +2734,24 @@ + + + Components).]]> + + Komponenty).]]> + + + + + + + Components).]]> + + Komponenty).]]> + + + + @@ -3625,6 +3643,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/cs/macios/src/Resources.resx.lcl b/macios/Localize/loc/cs/macios/src/Resources.resx.lcl index 9549f1d38696..8e1699b9acaf 100644 --- a/macios/Localize/loc/cs/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/cs/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/cs/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/cs/macios/tools/mtouch/Errors.resx.lcl index 029bc250773a..e737c9d8e469 100644 --- a/macios/Localize/loc/cs/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/cs/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/de/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/de/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index b2fc70394ad2..10b33895439f 100644 --- a/macios/Localize/loc/de/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/de/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -2734,6 +2734,24 @@ + + + Components).]]> + + Komponenten) ausführen.]]> + + + + + + + Components).]]> + + Komponenten) ausführen.]]> + + + + @@ -3625,6 +3643,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/de/macios/src/Resources.resx.lcl b/macios/Localize/loc/de/macios/src/Resources.resx.lcl index 364c5c515e6e..1c29fc1ad7ee 100644 --- a/macios/Localize/loc/de/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/de/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/de/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/de/macios/tools/mtouch/Errors.resx.lcl index 272d0fd57cab..a92aca87125c 100644 --- a/macios/Localize/loc/de/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/de/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/es/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/es/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index f20f4cb2c0c9..32a33885ce1a 100644 --- a/macios/Localize/loc/es/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/es/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -2734,6 +2734,24 @@ + + + Components).]]> + + Componentes).]]> + + + + + + + Components).]]> + + Componentes).]]> + + + + @@ -3625,6 +3643,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/es/macios/src/Resources.resx.lcl b/macios/Localize/loc/es/macios/src/Resources.resx.lcl index 85246e0ce950..b097266a8d41 100644 --- a/macios/Localize/loc/es/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/es/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/es/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/es/macios/tools/mtouch/Errors.resx.lcl index 6ae060269c6e..3040949dddb1 100644 --- a/macios/Localize/loc/es/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/es/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/fr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/fr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index fada47500cc4..e47ef87b934e 100644 --- a/macios/Localize/loc/fr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/fr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/fr/macios/src/Resources.resx.lcl b/macios/Localize/loc/fr/macios/src/Resources.resx.lcl index 6175b9d20601..d8878181007a 100644 --- a/macios/Localize/loc/fr/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/fr/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/fr/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/fr/macios/tools/mtouch/Errors.resx.lcl index c46996116ac1..57d5b027ef04 100644 --- a/macios/Localize/loc/fr/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/fr/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/it/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/it/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index f1a86dc8993b..c67c30add6ac 100644 --- a/macios/Localize/loc/it/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/it/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/it/macios/src/Resources.resx.lcl b/macios/Localize/loc/it/macios/src/Resources.resx.lcl index 8b231c676455..c6f87770593a 100644 --- a/macios/Localize/loc/it/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/it/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/it/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/it/macios/tools/mtouch/Errors.resx.lcl index 5a5bbaefc1ae..70d4408c9f26 100644 --- a/macios/Localize/loc/it/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/it/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index f71a2b3a978f..429efcd0d6a5 100644 --- a/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/ja/macios/src/Resources.resx.lcl b/macios/Localize/loc/ja/macios/src/Resources.resx.lcl index b042a0a70bac..4ec32400c436 100644 --- a/macios/Localize/loc/ja/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/ja/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/ja/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/ja/macios/tools/mtouch/Errors.resx.lcl index 0326c3f3dc31..0a5c0969fde0 100644 --- a/macios/Localize/loc/ja/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/ja/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/ko/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/ko/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index 638a95bf9892..68a284939316 100644 --- a/macios/Localize/loc/ko/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/ko/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -2734,6 +2734,24 @@ + + + Components).]]> + + 구성 요소)에서 'xcodebuild -downloadPlatform {0}'을 실행하여 설치합니다.]]> + + + + + + + Components).]]> + + 구성 요소)에서 'xcodebuild -downloadPlatform {0}'을 실행하여 시뮬레이터 런타임을 업데이트합니다.]]> + + + + @@ -3625,6 +3643,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/ko/macios/src/Resources.resx.lcl b/macios/Localize/loc/ko/macios/src/Resources.resx.lcl index 2a6ec47780f7..b6f9d3f7c969 100644 --- a/macios/Localize/loc/ko/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/ko/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/ko/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/ko/macios/tools/mtouch/Errors.resx.lcl index 36785bba0430..073974f830fe 100644 --- a/macios/Localize/loc/ko/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/ko/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/pl/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/pl/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index aff2c57e5e45..10afa0d41504 100644 --- a/macios/Localize/loc/pl/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/pl/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/pl/macios/src/Resources.resx.lcl b/macios/Localize/loc/pl/macios/src/Resources.resx.lcl index 535e5be2e3df..40459f23f097 100644 --- a/macios/Localize/loc/pl/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/pl/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/pl/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/pl/macios/tools/mtouch/Errors.resx.lcl index 8e3eafdf8f62..d81fe2182e28 100644 --- a/macios/Localize/loc/pl/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/pl/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/pt-BR/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/pt-BR/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index e9b8116173e4..503593408653 100644 --- a/macios/Localize/loc/pt-BR/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/pt-BR/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -2734,6 +2734,24 @@ + + + Components).]]> + + Componentes).]]> + + + + + + + Components).]]> + + Componentes).]]> + + + + @@ -3625,6 +3643,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/pt-BR/macios/src/Resources.resx.lcl b/macios/Localize/loc/pt-BR/macios/src/Resources.resx.lcl index d12b83b1ff3e..b7ce10acb40c 100644 --- a/macios/Localize/loc/pt-BR/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/pt-BR/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/pt-BR/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/pt-BR/macios/tools/mtouch/Errors.resx.lcl index cb12d7bf13cc..7e153e535bc9 100644 --- a/macios/Localize/loc/pt-BR/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/pt-BR/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index 80fd78c3f715..ff190b437318 100644 --- a/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/ru/macios/src/Resources.resx.lcl b/macios/Localize/loc/ru/macios/src/Resources.resx.lcl index 7bc3cfac722a..095e1f672a82 100644 --- a/macios/Localize/loc/ru/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/ru/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/ru/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/ru/macios/tools/mtouch/Errors.resx.lcl index 720865503b6d..a0a2d50d4c8a 100644 --- a/macios/Localize/loc/ru/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/ru/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index 94ffb3bad606..3251464cd07f 100644 --- a/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/tr/macios/src/Resources.resx.lcl b/macios/Localize/loc/tr/macios/src/Resources.resx.lcl index 87909f7e2e5e..4cf6e27fa0dc 100644 --- a/macios/Localize/loc/tr/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/tr/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/tr/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/tr/macios/tools/mtouch/Errors.resx.lcl index 69c6f943eadf..2aedad71123b 100644 --- a/macios/Localize/loc/tr/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/tr/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index 00517d08e59d..2e41c4b28761 100644 --- a/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -3625,6 +3625,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/zh-Hans/macios/src/Resources.resx.lcl b/macios/Localize/loc/zh-Hans/macios/src/Resources.resx.lcl index 2d4649df1b79..f5da49efa398 100644 --- a/macios/Localize/loc/zh-Hans/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/zh-Hans/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/zh-Hans/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/zh-Hans/macios/tools/mtouch/Errors.resx.lcl index c37d02e4d78a..af179127e37e 100644 --- a/macios/Localize/loc/zh-Hans/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/zh-Hans/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/Localize/loc/zh-Hant/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/zh-Hant/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl index b8f65ed4218a..0f9913fdbb09 100644 --- a/macios/Localize/loc/zh-Hant/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl +++ b/macios/Localize/loc/zh-Hant/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl @@ -2734,6 +2734,24 @@ + + + Components).]]> + + 元件]來安裝。]]> + + + + + + + Components).]]> + + 元件]來更新模擬器執行階段。]]> + + + + @@ -3625,6 +3643,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macios/Localize/loc/zh-Hant/macios/src/Resources.resx.lcl b/macios/Localize/loc/zh-Hant/macios/src/Resources.resx.lcl index 21c2a5d3082f..0074c1598564 100644 --- a/macios/Localize/loc/zh-Hant/macios/src/Resources.resx.lcl +++ b/macios/Localize/loc/zh-Hant/macios/src/Resources.resx.lcl @@ -381,10 +381,13 @@ - + - + + + + diff --git a/macios/Localize/loc/zh-Hant/macios/tools/mtouch/Errors.resx.lcl b/macios/Localize/loc/zh-Hant/macios/tools/mtouch/Errors.resx.lcl index f987a2aa5168..69beebeb0b2d 100644 --- a/macios/Localize/loc/zh-Hant/macios/tools/mtouch/Errors.resx.lcl +++ b/macios/Localize/loc/zh-Hant/macios/tools/mtouch/Errors.resx.lcl @@ -4573,6 +4573,15 @@ + + + + + + + + + diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx index 0714444b8e01..9f4afd35224d 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx @@ -1284,4 +1284,31 @@ The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + \ No newline at end of file diff --git a/macios/src/TranslatedAssemblies/Resources.cs.resx b/macios/src/TranslatedAssemblies/Resources.cs.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.cs.resx +++ b/macios/src/TranslatedAssemblies/Resources.cs.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.de.resx b/macios/src/TranslatedAssemblies/Resources.de.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.de.resx +++ b/macios/src/TranslatedAssemblies/Resources.de.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.es.resx b/macios/src/TranslatedAssemblies/Resources.es.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.es.resx +++ b/macios/src/TranslatedAssemblies/Resources.es.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.fr.resx b/macios/src/TranslatedAssemblies/Resources.fr.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.fr.resx +++ b/macios/src/TranslatedAssemblies/Resources.fr.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.it.resx b/macios/src/TranslatedAssemblies/Resources.it.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.it.resx +++ b/macios/src/TranslatedAssemblies/Resources.it.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.ja.resx b/macios/src/TranslatedAssemblies/Resources.ja.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.ja.resx +++ b/macios/src/TranslatedAssemblies/Resources.ja.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.ko.resx b/macios/src/TranslatedAssemblies/Resources.ko.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.ko.resx +++ b/macios/src/TranslatedAssemblies/Resources.ko.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.pl.resx b/macios/src/TranslatedAssemblies/Resources.pl.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.pl.resx +++ b/macios/src/TranslatedAssemblies/Resources.pl.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.pt-BR.resx b/macios/src/TranslatedAssemblies/Resources.pt-BR.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.pt-BR.resx +++ b/macios/src/TranslatedAssemblies/Resources.pt-BR.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.ru.resx b/macios/src/TranslatedAssemblies/Resources.ru.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.ru.resx +++ b/macios/src/TranslatedAssemblies/Resources.ru.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.tr.resx b/macios/src/TranslatedAssemblies/Resources.tr.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.tr.resx +++ b/macios/src/TranslatedAssemblies/Resources.tr.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.zh-Hans.resx b/macios/src/TranslatedAssemblies/Resources.zh-Hans.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.zh-Hans.resx +++ b/macios/src/TranslatedAssemblies/Resources.zh-Hans.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/src/TranslatedAssemblies/Resources.zh-Hant.resx b/macios/src/TranslatedAssemblies/Resources.zh-Hant.resx index f4c1d83d2521..7b439f46e642 100644 --- a/macios/src/TranslatedAssemblies/Resources.zh-Hant.resx +++ b/macios/src/TranslatedAssemblies/Resources.zh-Hant.resx @@ -250,7 +250,7 @@ `{0}`: Enums attributed with [{1}] must have an underlying type of `long` or `ulong` - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. Internal sanity check failed, please file a bug report (https://github.com/dotnet/macios/issues/new) with a test case. diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx index 3cbbaf109f2a..ce4b85b8b369 100644 --- a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx +++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx @@ -857,6 +857,9 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + The linker step '{0}' failed during processing: {1} diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx index e799cff2ca7f..2e906561c910 100644 --- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx +++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx @@ -1624,14 +1624,6 @@ The task '{0}' is trying to call an external process, but a path to Xcode has not been provided. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. - - Invalid DotNetRuntime value: '{0}' - - - - Unexpected RuntimeLibLinkMode value for 'NativeAOT': '{0}' - - The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. @@ -1639,4 +1631,38 @@ Invalid RuntimeLibLinkMode value: '{0}' + + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The {0} simulator runtime is not installed. This is required by Apple's development tools (even when building for physical devices). Install it by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the required simulator runtime is not installed. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + + Unable to determine if the {0} simulator runtime is installed. If the build fails or hangs, install the {0} simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line. + Shown when we're unable to check for simulator runtime availability. +{0} - The platform name (e.g. "iOS" or "tvOS"). + + + + The installed {0} simulator runtime is not compatible with the current Xcode version. Update the simulator runtime by running 'xcodebuild -downloadPlatform {0}' from the command line, or from Xcode (Settings > Components). + Shown when the tool reports a simulator runtime version mismatch. +{0} - The platform name (e.g. "iOS" or "tvOS"). + diff --git a/msbuild/Xamarin.MacDev.Tasks/Decompress.cs b/msbuild/Xamarin.MacDev.Tasks/Decompress.cs index 2d4f755378de..234eb49cd852 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Decompress.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Decompress.cs @@ -108,7 +108,7 @@ public static bool TryDecompress (XamarinTask task, string zip, string resource, var stampFile = decompressedResource.TrimEnd ('\\', '/') + ".stamp"; - if (FileCopier.IsUptodate (zip, stampFile, XamarinTask.GetFileCopierReportErrorCallback (log), XamarinTask.GetFileCopierLogCallback (log), check_stamp: false)) + if (FileCopier.IsUptodate (task, zip, stampFile, check_stamp: false)) return true; // We use 'unzip' to extract on !Windows, and System.IO.Compression to extract on Windows. diff --git a/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs b/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs index 9827fc45e2bd..8bda5c48e690 100644 --- a/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs +++ b/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs @@ -10,10 +10,9 @@ namespace Xamarin.Bundler { public static partial class ErrorHelper { public static ApplePlatform Platform; - internal static string Prefix { - get { - return Xamarin.MacDev.Tasks.LoggingExtensions.ErrorPrefix; - } + internal static string GetPrefix (IToolLog? log) + { + return Xamarin.MacDev.Tasks.LoggingExtensions.ErrorPrefix; } public enum WarningLevel { @@ -24,7 +23,7 @@ public enum WarningLevel { static Dictionary? warning_levels; - public static WarningLevel GetWarningLevel (int code) + public static WarningLevel GetWarningLevel (IToolLog log, int code) { WarningLevel level; diff --git a/msbuild/Xamarin.MacDev.Tasks/Sdks.cs b/msbuild/Xamarin.MacDev.Tasks/Sdks.cs deleted file mode 100644 index ca04c9c665f1..000000000000 --- a/msbuild/Xamarin.MacDev.Tasks/Sdks.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; - -using Xamarin.Localization.MSBuild; -using Xamarin.Utils; -using Xamarin.MacDev.Tasks; - -#nullable enable - -namespace Xamarin.MacDev { - public static class Sdks { - public static AppleIPhoneSdk IOS { get; private set; } - public static MacOSXSdk MacOS { get; private set; } - public static AppleTVOSSdk TVOS { get; private set; } - - static Sdks () - { - IOS = new AppleIPhoneSdk (AppleSdkSettings.DeveloperRoot, AppleSdkSettings.DeveloperRootVersionPlist); - TVOS = new AppleTVOSSdk (AppleSdkSettings.DeveloperRoot, AppleSdkSettings.DeveloperRootVersionPlist); - MacOS = new MacOSXSdk (AppleSdkSettings.DeveloperRoot, AppleSdkSettings.DeveloperRootVersionPlist); - } - - public static AppleSdk GetSdk (ApplePlatform framework) - { - switch (framework) { - case ApplePlatform.iOS: - return IOS; - case ApplePlatform.TVOS: - return TVOS; - default: - throw new InvalidOperationException (string.Format (MSBStrings.InvalidFramework, framework)); - } - } - - public static AppleSdk GetSdk (string targetFrameworkMoniker) - { - return GetSdk (PlatformFrameworkHelper.GetFramework (targetFrameworkMoniker)); - } - - public static IAppleSdk GetAppleSdk (ApplePlatform framework) - { - switch (framework) { - case ApplePlatform.iOS: - return IOS; - case ApplePlatform.TVOS: - return TVOS; - case ApplePlatform.MacCatalyst: - case ApplePlatform.MacOSX: - return MacOS; - default: - throw new InvalidOperationException (string.Format (MSBStrings.InvalidFramework, framework)); - } - } - - public static IAppleSdk GetAppleSdk (string targetFrameworkMoniker) - { - return GetAppleSdk (PlatformFrameworkHelper.GetFramework (targetFrameworkMoniker)); - } - - } -} diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ACTool.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ACTool.cs index fbdd82f46eb6..829b904260e9 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ACTool.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ACTool.cs @@ -248,12 +248,12 @@ IEnumerable GetCompiledBundleResources (PDictionary output, string in yield break; } - void FindXCAssetsDirectory (string main, string secondary, out string mainResult, out string secondaryResult) + void FindAssetCatalogDirectory (string main, string secondary, out string mainResult, out string secondaryResult) { mainResult = main; secondaryResult = secondary; - while (!string.IsNullOrEmpty (mainResult) && !mainResult.EndsWith (".xcassets", StringComparison.OrdinalIgnoreCase)) { + while (!string.IsNullOrEmpty (mainResult) && !mainResult.EndsWith (".xcassets", StringComparison.OrdinalIgnoreCase) && !mainResult.EndsWith (".icon", StringComparison.OrdinalIgnoreCase)) { mainResult = Path.GetDirectoryName (mainResult)!; if (!string.IsNullOrEmpty (secondaryResult)) secondaryResult = Path.GetDirectoryName (secondaryResult)!; @@ -292,14 +292,14 @@ public override bool Execute () var vpath = BundleResource.GetVirtualProjectPath (this, imageAsset); var catalogFullPath = imageAsset.GetMetadata ("FullPath"); - // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc) + // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, .icon, etc) var catalog = Path.GetDirectoryName (vpath)!; catalogFullPath = Path.GetDirectoryName (catalogFullPath)!; var assetType = Path.GetExtension (catalog).TrimStart ('.'); - // keep walking up the directory structure until we get to the .xcassets directory - FindXCAssetsDirectory (catalog, catalogFullPath, out var catalog2, out var catalogFullPath2); + // keep walking up the directory structure until we get to the .xcassets or .icon directory + FindAssetCatalogDirectory (catalog, catalogFullPath, out var catalog2, out var catalogFullPath2); catalog = catalog2; catalogFullPath = catalogFullPath2; @@ -325,11 +325,11 @@ public override bool Execute () continue; } - // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these - if (Path.GetFileName (vpath) != "Contents.json") - continue; - - items.Add (asset); + // Handle both Contents.json (for .xcassets) and icon.json (for .icon folders) + var fileName = Path.GetFileName (vpath); + if (fileName == "Contents.json" || fileName == "icon.json") { + items.Add (asset); + } } // clone any *.xcassets dirs that need cloning @@ -370,18 +370,20 @@ public override bool Execute () File.Copy (src, dest, true); - // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these - if (Path.GetFileName (vpath) != "Contents.json") + // Handle both Contents.json (for .xcassets) and icon.json (for .icon folders) + var fileName = Path.GetFileName (vpath); + if (fileName != "Contents.json" && fileName != "icon.json") continue; item = new TaskItem (dest); assetItem.CopyMetadataTo (item); item.SetMetadata ("Link", vpath); - FindXCAssetsDirectory (Path.GetFullPath (dest), "", out var catalogFullPath, out var _); + FindAssetCatalogDirectory (Path.GetFullPath (dest), "", out var catalogFullPath, out var _); items.Add (new AssetInfo (item, vpath, asset.Catalog, catalogFullPath, asset.AssetType)); } else { - // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these - if (Path.GetFileName (vpath) != "Contents.json") + // Handle both Contents.json (for .xcassets) and icon.json (for .icon folders) + var fileName = Path.GetFileName (vpath); + if (fileName != "Contents.json" && fileName != "icon.json") continue; items.Add (asset); @@ -389,7 +391,7 @@ public override bool Execute () } } - // Note: `items` contains only the Contents.json files at this point + // Note: `items` contains only the Contents.json and icon.json files at this point for (int i = 0; i < items.Count; i++) { var asset = items [i]; var assetItem = asset.Item; @@ -397,16 +399,19 @@ public override bool Execute () var catalog = asset.Catalog; var path = assetItem.GetMetadata ("FullPath"); var assetType = asset.AssetType; + var vpathDirNameWithoutExtension = Path.GetFileNameWithoutExtension (Path.GetDirectoryName (vpath)!); if (Platform == ApplePlatform.TVOS) { - if (assetType.Equals ("imagestack", StringComparison.OrdinalIgnoreCase)) { - imageStacksInAssets.Add (Path.GetFileNameWithoutExtension (Path.GetDirectoryName (vpath)!)); - } else if (assetType.Equals ("brandassets", StringComparison.OrdinalIgnoreCase)) { - brandAssetsInAssets.Add (Path.GetFileNameWithoutExtension (Path.GetDirectoryName (vpath)!)); + if (assetType.Equals ("imagestack", StringComparison.OrdinalIgnoreCase) || assetType.Equals ("icon", StringComparison.OrdinalIgnoreCase)) { + imageStacksInAssets.Add (vpathDirNameWithoutExtension); + } + if (assetType.Equals ("brandassets", StringComparison.OrdinalIgnoreCase) || assetType.Equals ("icon", StringComparison.OrdinalIgnoreCase)) { + brandAssetsInAssets.Add (vpathDirNameWithoutExtension); } } else { - if (assetType.Equals ("appiconset", StringComparison.OrdinalIgnoreCase)) - appIconsInAssets.Add (Path.GetFileNameWithoutExtension (Path.GetDirectoryName (vpath)!)); + if (assetType.Equals ("appiconset", StringComparison.OrdinalIgnoreCase) || assetType.Equals ("icon", StringComparison.OrdinalIgnoreCase)) { + appIconsInAssets.Add (vpathDirNameWithoutExtension); + } } if (unique.Add (catalog)) { @@ -416,7 +421,8 @@ public override bool Execute () catalogs.Add (item); } - if (SdkPlatform != "WatchSimulator") { + // Only process Contents.json files for on-demand resources (not icon.json files) + if (SdkPlatform != "WatchSimulator" && Path.GetFileName (vpath) == "Contents.json") { var text = File.ReadAllText (assetItem.ItemSpec); if (string.IsNullOrEmpty (text)) diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs index 1dce72ab1386..cfa8c01e85cf 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs @@ -55,8 +55,6 @@ public class BGen : XamarinTask, ICancelableTask { public string ExtraArgs { get; set; } = string.Empty; - public int Verbosity { get; set; } - public string GeneratedSourcesDir { get; set; } = string.Empty; public string GeneratedSourcesFileList { get; set; } = string.Empty; @@ -229,7 +227,7 @@ public virtual List GenerateCommandLineArguments () } } - cmd.AddRange (VerbosityUtils.Merge (ExtraArgs, (LoggerVerbosity) Verbosity)); + VerbosityUtils.RenderVerbosity (cmd, Verbosity); return CommandLineArgumentBuilder.CreateResponseFile (this, ResponseFilePath, cmd, null); } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs index 116ce430cb49..7f2baaad79e3 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs @@ -9,12 +9,15 @@ using Mono.Cecil; +using Xamarin.Bundler; +using Xamarin.Utils; + #nullable enable namespace Xamarin.MacDev.Tasks { /// /// Scans trimmed assemblies to collect information that survived trimming. - /// See docs/code/native-symbols.md for an overview of native symbol handling. + /// See docs/code/native-symbols.md and docs/code/class-handles.md for an overview of native symbol handling. /// public class CollectPostILTrimInformation : XamarinTask { [Required] @@ -26,6 +29,12 @@ public class CollectPostILTrimInformation : XamarinTask { [Required] public string SurvivingNativeSymbolsFile { get; set; } = ""; + /// + /// Output file listing the Class.GetHandle calls that survived trimming. + /// + [Required] + public string SurvivingClassesFile { get; set; } = ""; + /// /// Directory for per-assembly cache files, to avoid re-scanning unchanged assemblies. /// @@ -51,17 +60,17 @@ void CollectSurvivingNativeSymbols () continue; var assemblyName = Path.GetFileNameWithoutExtension (assemblyPath); - var cacheFile = Path.Combine (CacheDirectory, assemblyName + ".dlfcn-symbols.cache"); + var cacheFile = Path.Combine (CacheDirectory, assemblyName + ".internal-symbols.cache"); string []? cachedSymbols = null; if (File.Exists (cacheFile) && File.GetLastWriteTimeUtc (cacheFile) >= File.GetLastWriteTimeUtc (assemblyPath)) { cachedSymbols = File.ReadAllLines (cacheFile); - Log.LogMessage (MessageImportance.Low, "Using cached dlfcn symbols for {0}", assemblyName); + Log.LogMessage (MessageImportance.Low, "Using cached internal symbols for {0}", assemblyName); survivingSymbols.UnionWith (cachedSymbols); } else { var assemblySymbols = new HashSet (); - CollectDlfcnSymbolsFromAssembly (assemblyPath, assemblySymbols); + CollectInternalSymbolsFromAssembly (assemblyPath, assemblySymbols); // Write per-assembly cache (sorted for stability). var sortedAssemblySymbols = assemblySymbols.OrderBy (s => s).ToArray (); @@ -71,29 +80,53 @@ void CollectSurvivingNativeSymbols () } } + WriteSymbolsToFile (this, SurvivingNativeSymbolsFile, FilterToDlfcnSymbols (survivingSymbols)); + WriteSymbolsToFile (this, SurvivingClassesFile, FilterToClassSymbols (survivingSymbols)); + } + + public static void WriteSymbolsToFile (XamarinTask task, string file, IEnumerable unsortedSymbols) + { // Write the combined results only if contents changed (sorted for stability). - var sorted = survivingSymbols.OrderBy (s => s).ToArray (); + var sorted = unsortedSymbols.OrderBy (s => s).ToArray (); - if (File.Exists (SurvivingNativeSymbolsFile)) { - var existing = File.ReadAllLines (SurvivingNativeSymbolsFile); - if (existing.SequenceEqual (sorted)) + if (File.Exists (file)) { + var existing = File.ReadAllLines (file); + if (existing.SequenceEqual (sorted)) { + task.Log.LogMessage (MessageImportance.Low, "The file {0} is already up-to-date with {1} symbols", file, sorted.Length); return; + } } - var dir = Path.GetDirectoryName (SurvivingNativeSymbolsFile); - if (!string.IsNullOrEmpty (dir)) - Directory.CreateDirectory (dir); - File.WriteAllLines (SurvivingNativeSymbolsFile, sorted); - Log.LogMessage (MessageImportance.Low, "Found {0} surviving inlined dlfcn symbols", survivingSymbols.Count); + PathUtils.CreateDirectoryForFile (file); + File.WriteAllLines (file, sorted); + task.Log.LogMessage (MessageImportance.Low, "Wrote {0} symbols to {1}", sorted.Length, file); } - static void CollectDlfcnSymbolsFromAssembly (string assemblyPath, HashSet survivingSymbols) + public static IEnumerable FilterToDlfcnSymbols (IEnumerable symbols) { - const string prefix = "xamarin_Dlfcn_"; - const string suffix = "_Native"; + return FilterTo (symbols, "_xamarin_Dlfcn_", "_Native"); + } + public static IEnumerable FilterToClassSymbols (IEnumerable symbols) + { + return FilterTo (symbols, "_xamarin_Class_GetHandle_", "_Native"); + } + + static IEnumerable FilterTo (IEnumerable symbols, string prefix, string suffix) + { + return symbols + .Where (symbol => symbol.StartsWith (prefix, StringComparison.Ordinal) && symbol.EndsWith (suffix, StringComparison.Ordinal)) + .Select (symbol => symbol.Substring (prefix.Length, symbol.Length - prefix.Length - suffix.Length)); + } + + static void CollectInternalSymbolsFromAssembly (string assemblyPath, HashSet survivingSymbols) + { using var assembly = AssemblyDefinition.ReadAssembly (assemblyPath, new ReaderParameters { ReadSymbols = false }); foreach (var module in assembly.Modules) { + if (!module.HasModuleReferences) + continue; + if (!module.ModuleReferences.Any (mr => mr.Name == "__Internal")) + continue; foreach (var type in module.Types) { if (!type.HasMethods) continue; @@ -102,14 +135,7 @@ static void CollectDlfcnSymbolsFromAssembly (string assemblyPath, HashSet v))); return false; } @@ -252,7 +252,7 @@ bool SetMinimumOSVersion (PDictionary plist) var minimumiOSVersionInManifest = plist.Get (ManifestKeys.MinimumOSVersion)?.Value; if (!string.IsNullOrEmpty (minimumiOSVersionInManifest)) { // Convert to the macOS version - if (!MacCatalystSupport.TryGetMacOSVersion (Sdks.GetAppleSdk (Platform).GetSdkPath (SdkVersion), minimumiOSVersionInManifest!, out var convertedVersion, out var knowniOSVersions)) { + if (!MacCatalystSupport.TryGetMacOSVersion (CurrentSdk.GetSdkPath (SdkVersion), minimumiOSVersionInManifest!, out var convertedVersion, out var knowniOSVersions)) { Log.LogError (MSBStrings.E0188, minimumiOSVersionInManifest, string.Join (", ", knowniOSVersions.OrderBy (v => v))); return false; } @@ -311,14 +311,12 @@ bool Compile (PDictionary plist) return false; } - var currentSDK = Sdks.GetAppleSdk (Platform); - sdkVersion = AppleSdkVersion.Parse (DefaultSdkVersion); - if (!currentSDK.SdkIsInstalled (sdkVersion, SdkIsSimulator)) { + if (!CurrentSdk.SdkIsInstalled (sdkVersion, SdkIsSimulator)) { Log.LogError (null, null, null, null, 0, 0, 0, 0, MSBStrings.E0013, Platform, sdkVersion); return false; } - SetXcodeValues (plist, currentSDK); + SetXcodeValues (plist, CurrentSdk); } switch (Platform) { @@ -426,7 +424,7 @@ void Validation (PDictionary plist) GetMinimumOSVersion (plist, out var minimumOSVersion); if (minimumOSVersion < new Version (11, 0)) { string miniOSVersion = "?"; - if (MacCatalystSupport.TryGetiOSVersion (Sdks.GetAppleSdk (Platform).GetSdkPath (SdkVersion), minimumOSVersion, out var iOSVersion, out var _)) + if (MacCatalystSupport.TryGetiOSVersion (CurrentSdk.GetSdkPath (SdkVersion), minimumOSVersion, out var iOSVersion, out var _)) miniOSVersion = iOSVersion?.ToString () ?? "?"; LogAppManifestError (MSBStrings.E7099 /* The UIDeviceFamily value '6' requires macOS 11.0. Please set the 'SupportedOSPlatformVersion' in the project file to at least 14.0 (the Mac Catalyst version equivalent of macOS 11.0). The current value is {0} (equivalent to macOS {1}). */, miniOSVersion, minimumOSVersion); } @@ -512,7 +510,7 @@ void SetXcodeValues (PDictionary plist, IAppleSdk currentSDK) SetValueIfNotNull (plist, "DTPlatformName", PlatformUtils.GetTargetPlatform (SdkPlatform, false)); SetValueIfNotNull (plist, "DTPlatformVersion", dtSettings.DTPlatformVersion); SetValueIfNotNull (plist, "DTSDKName", sdkSettings.CanonicalName); - SetValueIfNotNull (plist, "DTXcode", AppleSdkSettings.DTXcode); + SetValueIfNotNull (plist, "DTXcode", GetXcodeLocator ().DTXcode); SetValueIfNotNull (plist, "DTXcodeBuild", dtSettings.DTXcodeBuild); } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs index 3f5ac630ef5c..3e2e85074957 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs @@ -117,7 +117,7 @@ string DefaultEntitlementsPath { return "Entitlements.plist"; } - return Path.Combine (Sdks.GetAppleSdk (TargetFrameworkMoniker).GetSdkPath (SdkVersion, false), "Entitlements.plist"); + return Path.Combine (CurrentSdk.GetSdkPath (SdkVersion, false), "Entitlements.plist"); } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs index 67eda6ed7ec0..136e6c321b8f 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs @@ -14,7 +14,7 @@ namespace Xamarin.MacDev.Tasks { /// Takes the list of unresolved native symbols from a NativeAOT static library and computes /// which inlined dlfcn native symbols survived trimming. The output file has the same format /// as CollectPostILTrimInformation's surviving symbols file. - /// See docs/code/native-symbols.md for an overview of native symbol handling. + /// See docs/code/native-symbols.md and docs/code/class-handles.md for an overview of native symbol handling. /// public class ComputeNativeAOTSurvivingNativeSymbols : XamarinTask { /// @@ -29,39 +29,17 @@ public class ComputeNativeAOTSurvivingNativeSymbols : XamarinTask { [Required] public string SurvivingNativeSymbolsFile { get; set; } = ""; + /// + /// Output file listing the Class.GetHandle calls that survived trimming. + /// + [Required] + public string SurvivingClassesFile { get; set; } = ""; + public override bool Execute () { - if (!File.Exists (UnresolvedSymbolsFile)) - return !Log.HasLoggedErrors; - - const string prefix = "_xamarin_Dlfcn_"; - const string suffix = "_Native"; - var survivingSymbols = new HashSet (); - - foreach (var sym in File.ReadAllLines (UnresolvedSymbolsFile)) { - if (!sym.StartsWith (prefix) || !sym.EndsWith (suffix)) - continue; - var symbolLength = sym.Length - prefix.Length - suffix.Length; - if (symbolLength <= 0) - continue; - var symbolName = sym.Substring (prefix.Length, symbolLength); - survivingSymbols.Add (symbolName); - } - - var sorted = survivingSymbols.OrderBy (s => s).ToArray (); - - if (File.Exists (SurvivingNativeSymbolsFile)) { - var existing = File.ReadAllLines (SurvivingNativeSymbolsFile); - if (existing.SequenceEqual (sorted)) - return !Log.HasLoggedErrors; - } - - var dir = Path.GetDirectoryName (SurvivingNativeSymbolsFile); - if (!string.IsNullOrEmpty (dir)) - Directory.CreateDirectory (dir); - File.WriteAllLines (SurvivingNativeSymbolsFile, sorted); - Log.LogMessage (MessageImportance.Low, "Found {0} surviving native symbols from NativeAOT", survivingSymbols.Count); - + var unresolvedSymbols = File.Exists (UnresolvedSymbolsFile) ? File.ReadAllLines (UnresolvedSymbolsFile) : []; + CollectPostILTrimInformation.WriteSymbolsToFile (this, SurvivingNativeSymbolsFile, CollectPostILTrimInformation.FilterToDlfcnSymbols (unresolvedSymbols)); + CollectPostILTrimInformation.WriteSymbolsToFile (this, SurvivingClassesFile, CollectPostILTrimInformation.FilterToClassSymbols (unresolvedSymbols)); return !Log.HasLoggedErrors; } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs index 17d859c5ae4d..722104a9e119 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs @@ -107,7 +107,7 @@ public override bool Execute () Log.LogMessage (MSBStrings.M0121, bindingResourcePath); Directory.CreateDirectory (bindingResourcePath); foreach (var nativeRef in NativeReferences) { - Xamarin.Bundler.FileCopier.UpdateDirectory (nativeRef.ItemSpec, bindingResourcePath, FileCopierReportErrorCallback, FileCopierLogCallback); + Xamarin.Bundler.FileCopier.UpdateDirectory (this, nativeRef.ItemSpec, bindingResourcePath); var bindingOutputPath = Path.Combine (bindingResourcePath, Path.GetFileName (nativeRef.ItemSpec)); if (Directory.Exists (bindingOutputPath)) { diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs index 1f393504e6a8..f06f132d6a7b 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs @@ -29,6 +29,7 @@ public string SdkRoot { get; set; } = ""; + // this is input too (the variable 'XcodeLocation') [Output] public new string SdkDevPath { get => base.SdkDevPath; @@ -59,12 +60,6 @@ public string XcodeVersion { #endregion Outputs - protected IAppleSdk CurrentSdk { - get { - return Sdks.GetAppleSdk (Platform); - } - } - IAppleSdkVersion GetDefaultSdkVersion () { switch (Platform) { @@ -145,33 +140,40 @@ bool ExecuteImpl () return ExecuteRemotely (); } - AppleSdkSettings.Init (); - - if (EnsureAppleSdkRoot ()) - EnsureSdkPath (); - EnsureXamarinSdkRoot (); + var isNet11OrNewer = TargetFramework.Version.Major >= 11; + var appleSdkSettings = GetXcodeLocator (initialDiscovery: true, (locator) => { + locator.SupportEnvironmentVariableLookup = !isNet11OrNewer; + locator.SupportSettingsFileLookup = !isNet11OrNewer; + }); + SetXcodeLocator (appleSdkSettings); + SdkDevPath = appleSdkSettings.DeveloperRoot; + XcodeVersion = appleSdkSettings.XcodeVersion.ToString (); + + if (appleSdkSettings.SystemHasEnvironmentVariable) { + if (isNet11OrNewer) { + Log.LogWarning (MSBStrings.W7172 /* The environment variable '{0}' is deprecated, and will be ignored. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, XcodeLocator.EnvironmentVariableName); + } else { + Log.LogWarning (MSBStrings.W7171 /* The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, XcodeLocator.EnvironmentVariableName); + } + } + foreach (var file in appleSdkSettings.SystemExistingSettingsFiles) { + if (isNet11OrNewer) { + Log.LogWarning (MSBStrings.W7174 /* The settings file '{0}' is deprecated, and will be ignored. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, file); + } else { + Log.LogWarning (MSBStrings.W7173 /* The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, file); + } + } - XcodeVersion = AppleSdkSettings.XcodeVersion.ToString (); + if (Log.HasLoggedErrors) + return false; - return !Log.HasLoggedErrors; - } + Log.LogMessage (MessageImportance.Low, "DeveloperRoot: {0}", CurrentSdk.DeveloperRoot); + Log.LogMessage (MessageImportance.Low, "GetPlatformPath: {0}", CurrentSdk.GetPlatformPath (SdkIsSimulator)); - protected bool EnsureAppleSdkRoot () - { - var currentSdk = CurrentSdk; - if (!currentSdk.IsInstalled) { - Log.LogError (MSBStrings.E0044v2 /* Could not find a valid Xcode app bundle at '{0}'. Please verify that 'xcode-select -p' points to your Xcode installation. For more information see https://aka.ms/macios-missing-xcode. */, AppleSdkSettings.InvalidDeveloperRoot); - return false; - } - Log.LogMessage (MessageImportance.Low, "DeveloperRoot: {0}", currentSdk.DeveloperRoot); - Log.LogMessage (MessageImportance.Low, "GetPlatformPath: {0}", currentSdk.GetPlatformPath (SdkIsSimulator)); + EnsureSdkPath (); + EnsureXamarinSdkRoot (); - SdkDevPath = currentSdk.DeveloperRoot; - if (string.IsNullOrEmpty (SdkDevPath)) { - Log.LogError (MSBStrings.E0086 /* Could not find a valid Xcode developer path */); - return false; - } - return true; + return !Log.HasLoggedErrors; } protected string? DirExists (string checkingFor, params string [] paths) diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs index 224c8e37edc4..8718934d6918 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs @@ -29,12 +29,6 @@ public class DetectSigningIdentity : XamarinTask, ITaskCallback, ICancelableTask static readonly string [] macDirectDistributionPrefixes = { "Developer ID Application" }; static readonly string [] macDevelopmentPrefixes = { "Mac Developer", "Apple Development" }; - protected string DeveloperRoot { - get { - return Sdks.GetAppleSdk (TargetFrameworkMoniker).DeveloperRoot; - } - } - protected string [] DevelopmentPrefixes { get { switch (Platform) { @@ -583,7 +577,7 @@ bool ExecuteImpl () else if (ProvisioningProfile == AutomaticAdHocProvision) type = MobileProvisionDistributionType.AdHoc; - DetectedCodesignAllocate = Path.Combine (DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); + DetectedCodesignAllocate = Path.Combine (CurrentSdk.DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); DetectedDistributionType = type.ToString (); identity.BundleId = BundleIdentifier; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/GetAvailableDevices.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/GetAvailableDevices.cs index 8046bf247001..3a21eb4081d6 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/GetAvailableDevices.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/GetAvailableDevices.cs @@ -100,8 +100,13 @@ public override bool Execute () continue; } // if we have multiple runtime identifiers, we're running in the simulator, and one is x64 and the other is arm64. + // if 'RuntimeIdentifier' is set on the task, set that value, otherwise // if we can run on arm64, then pick the arm64 simulator, otherwise pick the x64 simulator - d.Item.SetMetadata ("RuntimeIdentifier", d.RuntimeIdentifiers.Single (v => v.Contains ("arm64") == CanRunArm64)); + if (!string.IsNullOrEmpty (RuntimeIdentifier)) { + d.Item.SetMetadata ("RuntimeIdentifier", RuntimeIdentifier); + } else { + d.Item.SetMetadata ("RuntimeIdentifier", d.RuntimeIdentifiers.Single (v => v.Contains ("arm64") == CanRunArm64)); + } } DiscardedDevices = devices.Where (d => d.Discarded).Select (v => { diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/MergeAppBundles.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/MergeAppBundles.cs index 08a9770c4bed..41107d796ae9 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/MergeAppBundles.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/MergeAppBundles.cs @@ -212,7 +212,7 @@ public void CopyTo (string outputDirectory, string? subDirectory = null, Entry? } } else { Directory.CreateDirectory (Path.GetDirectoryName (outputFile)!); - if (!FileCopier.IsUptodate (FullPath, outputFile, Task.FileCopierReportErrorCallback, Task.FileCopierLogCallback)) + if (!FileCopier.IsUptodate (Task, FullPath, outputFile)) File.Copy (FullPath, outputFile, true); } @@ -243,7 +243,7 @@ public override bool Execute () sourceDirectory += Path.DirectorySeparatorChar; Log.LogMessage (MessageImportance.Low, $"Copying the single input directory {sourceDirectory} to {targetDirectory}"); - FileCopier.UpdateDirectory (sourceDirectory, targetDirectory, FileCopierReportErrorCallback, FileCopierLogCallback); + FileCopier.UpdateDirectory (this, sourceDirectory, targetDirectory); return !Log.HasLoggedErrors; } @@ -425,7 +425,7 @@ void MergeMachOFiles (string output, IList input) var sourceFiles = input.Select (v => v.FullPath).ToArray (); - if (FileCopier.IsUptodate (sourceFiles, new string [] { output }, FileCopierReportErrorCallback, FileCopierLogCallback)) + if (FileCopier.IsUptodate (this, sourceFiles, new string [] { output })) return; Log.LogMessage (MessageImportance.Low, $"Lipoing '{input [0].RelativePath}' for the merged app bundle from the following sources:\n\t{string.Join ("\n\t", input.Select (v => v.FullPath))}"); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ParseBundlerArguments.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ParseBundlerArguments.cs index 3da5e058b86a..3f2ba75108b7 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ParseBundlerArguments.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ParseBundlerArguments.cs @@ -64,7 +64,7 @@ public class ParseBundlerArguments : XamarinTask { public string? SkipMarkingNSObjectsInUserAssemblies { get; set; } [Output] - public string? Verbosity { get; set; } + public string? BundlerVerbosity { get; set; } [Output] public string? Warn { get; set; } @@ -307,7 +307,7 @@ public override bool Execute () } if (verbosity.HasValue) - Verbosity = verbosity.Value.ToString (); + BundlerVerbosity = verbosity.Value.ToString (); } return !Log.HasLoggedErrors; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs index 77705a8dd1d7..bb65800df942 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs @@ -9,13 +9,14 @@ using Microsoft.Build.Framework; using Xamarin.Bundler; +using Xamarin.Utils; #nullable enable namespace Xamarin.MacDev.Tasks { /// /// Performs post-trimming processing, generating native code only for symbols that survived trimming. - /// See docs/code/native-symbols.md for an overview of native symbol handling. + /// See docs/code/native-symbols.md and docs/code/class-handles.md for an overview of native symbol handling. /// public class PostTrimmingProcessing : XamarinTask { [Required] @@ -26,6 +27,13 @@ public class PostTrimmingProcessing : XamarinTask { public ITaskItem [] ReferenceNativeSymbol { get; set; } = []; + /// + /// Files listing calls to Class.GetHandle that survived trimming. Each file contains one symbol name per line. + /// These can come from either ILTrim (CollectPostILTrimInformation) or NativeAOT + /// (ComputeNativeAOTSurvivingNativeSymbols). + /// + public ITaskItem [] SurvivingClassesFiles { get; set; } = []; + /// /// Files listing native symbols that survived trimming. Each file contains one symbol name per line. /// These can come from either ILTrim (CollectPostILTrimInformation) or NativeAOT @@ -33,6 +41,9 @@ public class PostTrimmingProcessing : XamarinTask { /// public ITaskItem [] SurvivingNativeSymbolsFiles { get; set; } = []; + // Type map + public string TypeMapFilePath { get; set; } = ""; + /// /// Output native source files to be compiled and linked. /// @@ -71,41 +82,166 @@ HashSet IgnoredSymbols { public override bool Execute () { - var items = new List (); + var nativeSourceFiles = new List (); + + Directory.CreateDirectory (OutputDirectory); + GenerateInlinedDlfcnNativeCode (nativeSourceFiles); + GenerateInlinedClassGetHandleNativeCode (nativeSourceFiles); - GenerateInlinedDlfcnNativeCode (items); + NativeSourceFiles = nativeSourceFiles.Select (path => { + var item = new Microsoft.Build.Utilities.TaskItem (path); + item.SetMetadata ("Arch", Architecture.ToLowerInvariant ()); + return item; + }).ToArray (); - NativeSourceFiles = items.ToArray (); return !Log.HasLoggedErrors; } - void GenerateInlinedDlfcnNativeCode (List items) + static HashSet ReadUniqueLinesFromFiles (IEnumerable files) { - // Collect all surviving symbols from all input files. - var survivingSymbols = new HashSet (); - foreach (var file in SurvivingNativeSymbolsFiles) { + var lines = new HashSet (); + foreach (var file in files) { var path = file.ItemSpec; if (!File.Exists (path)) continue; - survivingSymbols.UnionWith (File.ReadAllLines (path)); + lines.UnionWith (File.ReadAllLines (path)); + } + return lines; + } + + List FilterOutIgnoredSymbols (HashSet survivingSymbols, bool filterObjectiveCClasses) + { + var rv = new HashSet (survivingSymbols); + + foreach (var rns in ReferenceNativeSymbol) { + var nativeSymbol = rns.ItemSpec; + var symbolMode = rns.GetMetadata ("SymbolMode"); + if (!string.Equals (symbolMode, "Ignore", StringComparison.OrdinalIgnoreCase)) + continue; + + var symbolType = rns.GetMetadata ("SymbolType").ToLowerInvariant (); + switch (symbolType) { + case "objectivecclass": + if (filterObjectiveCClasses && rv.Remove (nativeSymbol)) { + Log.LogMessage (MessageImportance.Low, "Ignoring Objective-C class '{0}'", nativeSymbol); + } + break; + case "function": + case "field": + if (!filterObjectiveCClasses && rv.Remove (nativeSymbol)) { + Log.LogMessage (MessageImportance.Low, "Ignoring native symbol '{0}'", nativeSymbol); + } + break; + default: + Log.LogMessage (MessageImportance.Low, "Ignoring symbol '{0}' with unknown SymbolType '{1}'", nativeSymbol, symbolType); + continue; + } + } + + rv.Remove (""); // no empty symbols + + return rv.OrderBy (v => v).ToList (); + } + + void GenerateInlinedClassGetHandleNativeCode (List items) + { + // Collect all surviving symbols from all input files. + var classes = FilterOutIgnoredSymbols (ReadUniqueLinesFromFiles (SurvivingClassesFiles), filterObjectiveCClasses: true); + + if (classes.Count == 0) { + Log.LogMessage (MessageImportance.Low, "There were no surviving Objective-C classes that require inlined Class.GetHandle native code."); + return; + } + + if (string.IsNullOrEmpty (TypeMapFilePath) || !File.Exists (TypeMapFilePath)) { + Log.LogError ("The type map file '{0}' does not exist. This file is generated by the linker's CoreTypeMapStep. Ensure that trimming ran successfully.", TypeMapFilePath ?? ""); + return; + } + + var typeMapEntries = File.ReadAllLines (TypeMapFilePath) + .Select (line => { + var parts = line.Split ('|'); + string className = ""; + string framework = ""; + string introduced = ""; + bool iswrapper = false; + bool isstubclass = false; + foreach (var part in parts) { + var kvp = part.Split (new char [] { '=' }, 2); + if (kvp.Length != 2) + continue; + var key = kvp [0].Trim (); + var value = kvp [1].Trim (); + switch (key) { + case "Class": + className = value; + break; + case "Framework": + framework = value; + break; + case "Introduced": + introduced = value; + break; + case "IsWrapper": + iswrapper = string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); + break; + case "IsStubClass": + isstubclass = string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); + break; + } + } + return (Class: className, Framework: framework, Introduced: introduced, IsWrapper: iswrapper, IsStubClass: isstubclass); + }) + .ToArray (); + + var typeMap = new Dictionary (); + foreach (var entry in typeMapEntries) { + if (string.IsNullOrEmpty (entry.Class)) + continue; + if (typeMap.ContainsKey (entry.Class)) { + Log.LogError ("Duplicate class '{0}' found in the type map file '{1}'.", entry.Class, TypeMapFilePath); + return; + } + typeMap [entry.Class] = entry; } - var survivingButIgnoredSymbols = survivingSymbols.Intersect (IgnoredSymbols).ToList (); - if (survivingButIgnoredSymbols.Count > 0) { - Log.LogMessage (MessageImportance.Low, "The following symbols survived trimming but are marked as ignored:"); - foreach (var symbol in survivingButIgnoredSymbols) - Log.LogMessage (MessageImportance.Low, " {0}", symbol); - survivingSymbols.ExceptWith (survivingButIgnoredSymbols); + var sb = new StringBuilder (); + sb.AppendLine ($"#include "); + sb.AppendLine ($"#include "); + foreach (var objectiveCClassName in classes) { + // We don't want to import every header under the sun to find the @interface definitions for each class, so we generate + // a forward declaration for each class. To avoid potential issues with missing classes at runtime, we mark each declaration with __attribute__((weak_import)). + // The only exception is that we need to #include Foundation, which means we can't create declarations for Foundation classes. + if (!typeMap.TryGetValue (objectiveCClassName, out var info)) { + sb.AppendLine ($"__attribute__((weak_import)) @interface {objectiveCClassName} : NSObject @end // no objc type found"); + } else if (info.IsWrapper && info.Framework == "Foundation") { + // This is a special case for wrapper classes in the Foundation framework. Since we need to #include Foundation, we can't create a forward declaration for these classes. However, since they are wrappers, we know they won't be missing at runtime, so we don't need to mark them with __attribute__((weak_import)). + sb.AppendLine ($"// The class '{objectiveCClassName}' comes from the Foundation framework, so no generated @interface declaration."); + } else { + if (info.IsStubClass) + sb.AppendLine ("__attribute__((objc_class_stub)) __attribute__((objc_subclassing_restricted))"); + sb.AppendLine ($"__attribute__((weak_import)) @interface {objectiveCClassName} : NSObject @end // is stub: {info.IsStubClass}"); + } + sb.AppendLine ($"Class xamarin_Class_GetHandle_{objectiveCClassName}_Native ();"); + sb.AppendLine ($"Class xamarin_Class_GetHandle_{objectiveCClassName}_Native () {{ return [{objectiveCClassName} class]; }}"); + sb.AppendLine (); } + var outputPath = Path.Combine (OutputDirectory, "inlined-class-gethandle.m"); + FileUtils.WriteIfDifferent (outputPath, sb.ToString (), (msg) => Log.LogMessage (MessageImportance.Low, msg)); + + items.Add (outputPath); + } + + void GenerateInlinedDlfcnNativeCode (List items) + { + var survivingSymbols = FilterOutIgnoredSymbols (ReadUniqueLinesFromFiles (SurvivingNativeSymbolsFiles), filterObjectiveCClasses: false); + if (survivingSymbols.Count == 0) { Log.LogMessage (MessageImportance.Low, "There were no surviving symbols that require inlined dlfcn native code."); return; } - Directory.CreateDirectory (OutputDirectory); - var outputPath = Path.Combine (OutputDirectory, "inlined-dlfcn.c"); - var sb = new StringBuilder (); // The generated C code uses 'extern void*' declarations and returns the address of the symbol. // This is intentional: it allows the native linker to resolve the symbol at link time, which @@ -118,17 +254,10 @@ void GenerateInlinedDlfcnNativeCode (List items) sb.AppendLine (); } - var content = sb.ToString (); - if (File.Exists (outputPath) && File.ReadAllText (outputPath) == content) { - Log.LogMessage (MessageImportance.Low, "Inlined dlfcn native code is up to date"); - } else { - File.WriteAllText (outputPath, content); - Log.LogMessage (MessageImportance.Low, "Generated inlined dlfcn native code with {0} symbols", survivingSymbols.Count); - } + var outputPath = Path.Combine (OutputDirectory, "inlined-dlfcn.c"); + FileUtils.WriteIfDifferent (outputPath, sb.ToString (), (msg) => Log.LogMessage (MessageImportance.Low, msg)); - var item = new Microsoft.Build.Utilities.TaskItem (outputPath); - item.SetMetadata ("Arch", Architecture.ToLowerInvariant ()); - items.Add (item); + items.Add (outputPath); } } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs index ed31af9848f6..6e70959e2d15 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs @@ -73,7 +73,7 @@ public override bool Execute () if (Platform == ApplePlatform.MacCatalyst) { // The minimum version in the Info.plist is the macOS version. However, the rest of our tooling // expects the iOS version, so expose that. - if (!MacCatalystSupport.TryGetiOSVersion (Sdks.GetAppleSdk (Platform).GetSdkPath (), MinimumOSVersion!, out var convertedVersion, out var knownMacOSVersions)) + if (!MacCatalystSupport.TryGetiOSVersion (CurrentSdk.GetSdkPath (), MinimumOSVersion!, out var convertedVersion, out var knownMacOSVersions)) Log.LogError (MSBStrings.E0187, MinimumOSVersion, string.Join (", ", knownMacOSVersions.OrderBy (v => v))); MinimumOSVersion = convertedVersion; } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs index 1313a4d5e902..3cd5a9386821 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs @@ -9,6 +9,7 @@ using Microsoft.Build.Tasks; using Microsoft.Build.Utilities; +using Xamarin.Bundler; using Xamarin.Localization.MSBuild; using Xamarin.Messaging.Build.Client; using Xamarin.Utils; @@ -17,7 +18,7 @@ #nullable enable namespace Xamarin.MacDev.Tasks { - public abstract class XamarinTask : Task, IHasSessionId, ICustomLogger { + public abstract class XamarinTask : Task, IHasSessionId, ICustomLogger, IToolLog { public string SessionId { get; set; } = string.Empty; @@ -25,6 +26,16 @@ public abstract class XamarinTask : Task, IHasSessionId, ICustomLogger { public string SdkDevPath { get; set; } = string.Empty; + int? verbosity; + public int Verbosity { + get { + if (!verbosity.HasValue) + verbosity = VerbosityUtils.GetVerbosityLevel (Environment.CommandLine); + return verbosity.Value; + } + set => verbosity = value; + } + public string GetSdkDevPath () { if (string.IsNullOrEmpty (SdkDevPath)) { @@ -35,6 +46,52 @@ public string GetSdkDevPath () return SdkDevPath; } + XcodeLocator? xcodeLocator = null; + public XcodeLocator GetXcodeLocator (bool initialDiscovery = false, Action? preprocess = null) + { + if (xcodeLocator is null) { + if (!initialDiscovery && string.IsNullOrEmpty (SdkDevPath)) { + Log.LogError (MSBStrings.E7169, /* The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. */ GetType ().Name, "SdkDevPath"); + } + + var xcodeLocator = new XcodeLocator (this); + preprocess?.Invoke (xcodeLocator); + if (!xcodeLocator.TryLocatingXcode (SdkDevPath)) + Log.LogError (MSBStrings.E0086 /* Could not find a valid Xcode developer path */); + this.xcodeLocator = xcodeLocator; + } + return xcodeLocator; + } + + protected void SetXcodeLocator (XcodeLocator xcodeLocator) + { + this.xcodeLocator = xcodeLocator; + } + + IAppleSdk? currentSdk; + public IAppleSdk CurrentSdk { + get { + if (currentSdk is null) { + var xcodeLocator = GetXcodeLocator (); + switch (Platform) { + case ApplePlatform.iOS: + currentSdk = new AppleIPhoneSdk (xcodeLocator.DeveloperRoot, xcodeLocator.DeveloperRootVersionPlist); + break; + case ApplePlatform.TVOS: + currentSdk = new AppleTVOSSdk (xcodeLocator.DeveloperRoot, xcodeLocator.DeveloperRootVersionPlist); + break; + case ApplePlatform.MacCatalyst: + case ApplePlatform.MacOSX: + currentSdk = new MacOSXSdk (xcodeLocator.DeveloperRoot, xcodeLocator.DeveloperRootVersionPlist); + break; + default: + throw new InvalidOperationException (string.Format (MSBStrings.InvalidPlatform, Platform)); + } + } + return currentSdk; + } + } + void VerifyTargetFrameworkMoniker () { if (!string.IsNullOrEmpty (TargetFrameworkMoniker)) @@ -232,48 +289,6 @@ internal static bool CopyInputsToRemoteServerAsync (T task) where T : Task, I } } - internal protected static ReportErrorCallback GetFileCopierReportErrorCallback (TaskLoggingHelper log) - { - return new ReportErrorCallback ((int code, string format, object? [] arguments) => { - FileCopierReportErrorCallback (log, code, format, arguments); - }); - } - - internal protected static void FileCopierReportErrorCallback (TaskLoggingHelper log, int code, string format, params object? [] arguments) - { - log.LogError (format, arguments); - } - - protected void FileCopierReportErrorCallback (int code, string format, params object? [] arguments) - { - FileCopierReportErrorCallback (Log, code, format, arguments); - } - - internal protected static LogCallback GetFileCopierLogCallback (TaskLoggingHelper log) - { - return new LogCallback ((int min_verbosity, string format, object? [] arguments) => { - FileCopierLogCallback (log, min_verbosity, format, arguments); - }); - } - - protected static void FileCopierLogCallback (TaskLoggingHelper log, int min_verbosity, string format, params object? [] arguments) - { - MessageImportance importance; - if (min_verbosity <= 0) { - importance = MessageImportance.High; - } else if (min_verbosity <= 1) { - importance = MessageImportance.Normal; - } else { - importance = MessageImportance.Low; - } - log.LogMessage (importance, format, arguments); - } - - protected void FileCopierLogCallback (int min_verbosity, string format, params object? [] arguments) - { - FileCopierLogCallback (Log, min_verbosity, format, arguments); - } - protected string GetNonEmptyStringOrFallback (ITaskItem item, string metadataName, string fallbackValue, string? fallbackName = null, bool required = false) { return GetNonEmptyStringOrFallback (item, metadataName, out var _, fallbackValue, fallbackName, required); @@ -354,7 +369,8 @@ protected static string GetExecutable (List arguments, string toolName, #region Xamarin.MacDev.ICustomLogger void ICustomLogger.LogError (string message, Exception? ex) { - Log.LogError (message); + if (!string.IsNullOrEmpty (message)) + Log.LogError (message); if (ex is not null) Log.LogErrorFromException (ex); } @@ -374,5 +390,27 @@ void ICustomLogger.LogDebug (string messageFormat, params object? [] args) Log.LogMessage (MessageImportance.Low, messageFormat, args); } #endregion + + #region Xamarin.Bundler.IToolLog + void IToolLog.Log (string message) + { + ((ICustomLogger) this).LogInfo (message); + } + + void IToolLog.LogError (string message) + { + ((ICustomLogger) this).LogError (message, null); + } + + void IToolLog.LogException (Exception exception) + { + ((ICustomLogger) this).LogError ("", exception); + } + + void IToolLog.LogError (Exception exception) + { + ((ICustomLogger) this).LogError ("", exception); + } + #endregion } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs index 419963539f9b..c189dde986e5 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Text; @@ -13,6 +14,7 @@ using Xamarin.Localization.MSBuild; using Xamarin.MacDev; +using Xamarin.MacDev.Models; using Xamarin.Messaging.Build.Client; using Xamarin.Utils; @@ -154,6 +156,92 @@ static bool IsTranslated () return translated.Value; } + // Cache simulator runtime check results to avoid running simctl multiple times. + // Key includes SdkDevPath because different Xcode installations may have different runtimes. + static ConcurrentDictionary simulatorRuntimeCache = new (); + + /// + /// Returns the platform name used by simctl for the current build platform, or null if no simulator is needed. + /// + string? GetSimulatorPlatformName () + { + switch (Platform) { + case ApplePlatform.iOS: + case ApplePlatform.MacCatalyst: + // Mac Catalyst uses the iOS-based toolchain, so it also needs the iOS simulator runtime. + return "iOS"; + case ApplePlatform.TVOS: + return "tvOS"; + case ApplePlatform.MacOSX: + default: + return null; + } + } + + /// + /// Checks if the required simulator runtime is installed and emits a diagnostic if not. + /// Apple's Xcode tools (actool, ibtool, etc.) require the simulator runtime to function, + /// even when building for physical devices. Call this after a tool failure to provide + /// actionable guidance to the user. + /// + void CheckSimulatorRuntimeAvailable () + { + var simPlatform = GetSimulatorPlatformName (); + if (simPlatform is null) + return; + + var cacheKey = $"{simPlatform}:{SdkDevPath}"; + if (simulatorRuntimeCache.TryGetValue (cacheKey, out var cachedResult)) { + if (!cachedResult) + Log.LogError (MSBStrings.E7175, simPlatform); + return; + } + + var jsonOutputFile = Path.GetTempFileName (); + try { + using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource (cancellationTokenSource.Token); + timeoutCts.CancelAfter (TimeSpan.FromMinutes (1)); + var args = new List { + "simctl", + "list", + "runtimes", + "-j", + "--json-output=" + jsonOutputFile + }; + var rv = ExecuteAsync ("xcrun", args, showErrorIfFailure: false, cancellationToken: timeoutCts.Token).Result; + + if (rv.ExitCode != 0) { + Log.LogWarning (MSBStrings.W7176, simPlatform); + return; + } + + var json = File.ReadAllText (jsonOutputFile); + var runtimes = SimctlOutputParser.ParseRuntimes (json); + + var hasRuntime = runtimes.Any (r => + string.Equals (r.Platform, simPlatform, StringComparison.OrdinalIgnoreCase) && r.IsAvailable); + + simulatorRuntimeCache [cacheKey] = hasRuntime; + if (!hasRuntime) + Log.LogError (MSBStrings.E7175, simPlatform); + } catch (OperationCanceledException) when (cancellationTokenSource.IsCancellationRequested) { + // User cancelled - don't emit diagnostics + } catch (AggregateException ae) when (ae.InnerException is OperationCanceledException && cancellationTokenSource.IsCancellationRequested) { + // User cancelled - don't emit diagnostics + } catch (OperationCanceledException) { + // Timeout + Log.LogWarning (MSBStrings.W7176, simPlatform); + } catch (AggregateException ae) when (ae.InnerException is OperationCanceledException) { + // Timeout + Log.LogWarning (MSBStrings.W7176, simPlatform); + } catch (Exception ex) { + Log.LogWarning (MSBStrings.W7176, simPlatform); + Log.LogMessage (MessageImportance.Low, "Exception while checking simulator runtime: {0}", ex.Message); + } finally { + File.Delete (jsonOutputFile); + } + } + protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) { var environment = new Dictionary (); @@ -193,7 +281,7 @@ protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) if (Log.HasLoggedErrors) return 1; - var rv = ExecuteAsync (executable, args, environment: environment, cancellationToken: cancellationTokenSource.Token).Result; + var rv = ExecuteAsync (executable, args, showErrorIfFailure: true, environment: environment, cancellationToken: cancellationTokenSource.Token).Result; var exitCode = rv.ExitCode; var messages = rv.Output.StandardOutput; File.WriteAllText (manifest.ItemSpec, messages); @@ -206,8 +294,6 @@ protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) if (errors.Length > 0) Log.LogError (null, null, null, items [0].ItemSpec, 0, 0, 0, 0, "{0}", errors); - Log.LogError (MSBStrings.E0117, ToolName, exitCode); - // Note: If the log file exists and is parseable, log those warnings/errors as well... if (File.Exists (manifest.ItemSpec)) { try { @@ -220,6 +306,9 @@ protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) File.Delete (manifest.ItemSpec); } + + // Check if the failure might be caused by a missing simulator runtime. + CheckSimulatorRuntimeAvailable (); } return exitCode; @@ -285,8 +374,14 @@ protected void LogWarningsAndErrors (PDictionary plist, ITaskItem file) if (plist.TryGetValue (string.Format ("com.apple.{0}.errors", ToolName), out array)) { foreach (var item in array.OfType ()) { - if (item.TryGetValue ("description", out message)) + if (item.TryGetValue ("description", out message)) { Log.LogError (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value); + if (IsSimulatorRuntimeVersionError (message.Value)) { + var simPlatform = GetSimulatorPlatformName (); + if (simPlatform is not null) + Log.LogError (MSBStrings.E7177, simPlatform); + } + } } } @@ -298,6 +393,15 @@ protected void LogWarningsAndErrors (PDictionary plist, ITaskItem file) } } + /// + /// Detects error messages like "No simulator runtime version from [...] available to use with ... SDK version ..." + /// which indicate an incompatible or missing simulator runtime version. + /// + static bool IsSimulatorRuntimeVersionError (string message) + { + return message.IndexOf ("simulator runtime", StringComparison.OrdinalIgnoreCase) >= 0; + } + public void Cancel () { if (ShouldExecuteRemotely ()) { diff --git a/msbuild/Xamarin.MacDev.Tasks/VerbosityUtils.cs b/msbuild/Xamarin.MacDev.Tasks/VerbosityUtils.cs index f0797ef078fd..02211f93bcc3 100644 --- a/msbuild/Xamarin.MacDev.Tasks/VerbosityUtils.cs +++ b/msbuild/Xamarin.MacDev.Tasks/VerbosityUtils.cs @@ -10,39 +10,28 @@ namespace Xamarin.MacDev.Tasks { // needs to be verbosity-aware public static class VerbosityUtils { - // verbosity can be set in multiple ways - // this makes it a consistent interpretation of them - static public string [] Merge (string extraArguments, LoggerVerbosity taskVerbosity) + public static void RenderVerbosity (IList arguments, int taskVerbosity) { - string [] result = Array.Empty (); - var empty_extra = String.IsNullOrEmpty (extraArguments); - // We give the priority to the extra arguments given to the tools - if (empty_extra || (!empty_extra && !extraArguments.Contains ("-q") && !extraArguments.Contains ("-v"))) { - // if nothing is specified fall back to msbuild settings - // first check if some were supplied on the command-line - result = GetVerbosityLevel (Environment.CommandLine); - // if not then use the default from the msbuild config files, which Visual Studio for Mac can override (to match the IDE setting for msbuild) - if (result.Length == 0) - result = GetVerbosityLevel (taskVerbosity); - } - return result; + if (taskVerbosity == 0) + return; + + for (var i = 0; i < Math.Abs (taskVerbosity); i++) + arguments.Add (taskVerbosity < 0 ? "-q" : "-v"); } // // This is an hack, since there can be multiple loggers. - // However it's the most common use case and `mtouch` logs - // are often the most important to gather and developers expect - // a single change (in verbosity) to do the job and be consistent in CI. + // However it should cover most use cases. // // msbuild argument format // -verbosity: Display this amount of information in the event log. // The available verbosity levels are: q[uiet], m[inimal], // n[ormal], d[etailed], and diag[nostic]. (Short form: -v) // - static public string [] GetVerbosityLevel (string commandLine) + public static int GetVerbosityLevel (string commandLine) { if (!StringUtils.TryParseArguments (commandLine, out var args, out _)) - return GetVerbosityLevel (LoggerVerbosity.Normal); + return 0; var hasBinaryLog = false; foreach (var arg in args) { @@ -99,20 +88,20 @@ static public string [] GetVerbosityLevel (string commandLine) // The values here come from: https://github.com/mono/monodevelop/blob/143f9b6617123a0841a5cc5a2a4e13b309535792/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/RemoteBuildEngineMessages.cs#L186 // Assume 'Normal (2)' is the default verbosity (no change), and the other values follow from there. - static public string [] GetVerbosityLevel (LoggerVerbosity v) + public static int GetVerbosityLevel (LoggerVerbosity v) { switch ((LoggerVerbosity) v) { case LoggerVerbosity.Quiet: - return new [] { "-q", "-q", "-q", "-q" }; + return -4; case LoggerVerbosity.Minimal: - return new [] { "-q", "-q" }; + return -2; case LoggerVerbosity.Normal: default: - return Array.Empty (); + return 0; case LoggerVerbosity.Detailed: - return new [] { "-v", "-v" }; + return 2; case LoggerVerbosity.Diagnostic: - return new [] { "-v", "-v", "-v", "-v" }; + return 4; } } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj b/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj index 8f4555f6dfd4..713db306ebef 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj +++ b/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj @@ -75,6 +75,9 @@ JsonExtensions.cs + + IToolLog.cs + StringUtils.cs diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 2324108e27c5..c26dc90f564a 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -482,10 +482,18 @@ Copyright (C) 2018 Microsoft. All rights reserved. - + - - + + %(BundleResource.Link) + + + %(Content.Link) + @@ -685,6 +693,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(_ResourcePrefix)" ResourceRules="$(_PreparedResourceRules)" + SdkDevPath="$(_SdkDevPath)" SdkIsSimulator="$(_SdkIsSimulator)" SdkVersion="$(_SdkVersion)" SupportedOSPlatformVersion="$(SupportedOSPlatformVersion)" @@ -711,6 +720,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. Condition="'$(IsMacEnabled)' == 'true' And '$(_BundleOriginalResources)' != 'true'" SessionId="$(BuildSessionId)" AppManifest="$(_TemporaryAppManifest)" + SdkDevPath="$(_SdkDevPath)" TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" > @@ -798,6 +808,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. Entitlements="$(CodesignEntitlements)" CompiledEntitlements="$(_CompiledEntitlementsPath)" ProvisioningProfile="$(_ProvisioningProfile)" + SdkDevPath="$(_SdkDevPath)" SdkIsSimulator="$(_SdkIsSimulator)" SdkPlatform="$(_SdkPlatform)" SdkVersion="$(_SdkVersion)" @@ -2070,6 +2081,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. SdkIsSimulator="$(_SdkIsSimulator)" SdkPlatform="$(_SdkPlatform)" ProvisioningProfile="$(CodesignProvision)" + SdkDevPath="$(_SdkDevPath)" SigningKey="$(_SpecifiedCodesignKey)" DetectedCodeSigningKey="$(_CodeSigningKey)" TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" @@ -2092,6 +2104,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. @@ -2303,7 +2316,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. - + diff --git a/runtime/xamarin/runtime.h b/runtime/xamarin/runtime.h index fd5c697efff5..d9a8961a4598 100644 --- a/runtime/xamarin/runtime.h +++ b/runtime/xamarin/runtime.h @@ -367,10 +367,9 @@ extern xamarin_register_assemblies_callback xamarin_register_assemblies; // This has a managed equivalent in NSObject.cs struct NSObjectData { id handle; - struct objc_super* super; uint32_t /* NSObjectFlags */ flags; // if this structure ever changes, the encoding for this method will likely have to be updated in Registrar.RegistrarTypeUnsafe, currently it's: - // Signature = "^{NSObjectData=@^{objc_super}I}:", + // Signature = "^{NSObjectData=@I}:", }; #ifdef __cplusplus diff --git a/src/AppKit/NSPrintPreviewGraphicsContext.cs b/src/AppKit/NSPrintPreviewGraphicsContext.cs new file mode 100644 index 000000000000..ccc191f682c9 --- /dev/null +++ b/src/AppKit/NSPrintPreviewGraphicsContext.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; + +#if __MACOS__ && !XAMCORE_5_0 + +namespace AppKit { + [UnsupportedOSPlatform ("maccatalyst")] + [UnsupportedOSPlatform ("macos")] + [Obsolete ("This class does not form part of the public API in macOS, and will be removed in the future.")] + [EditorBrowsable (EditorBrowsableState.Never)] + public partial class NSPrintPreviewGraphicsContext : NSGraphicsContext { + + [EditorBrowsable (EditorBrowsableState.Never)] + public override NativeHandle ClassHandle { get { return default; } } + + [EditorBrowsable (EditorBrowsableState.Never)] + protected NSPrintPreviewGraphicsContext (NSObjectFlag t) : base (t) + { + } + + [EditorBrowsable (EditorBrowsableState.Never)] + protected internal NSPrintPreviewGraphicsContext (NativeHandle handle) : base (handle) + { + } + } /* class NSPrintPreviewGraphicsContext */ +} + +#endif // __MACOS__ && !XAMCORE_5_0 diff --git a/src/CoreImage/CIFilterGenerator.cs b/src/CoreImage/CIFilterGenerator.cs new file mode 100644 index 000000000000..cdcd4d1d2646 --- /dev/null +++ b/src/CoreImage/CIFilterGenerator.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if !XAMCORE_5_0 && (__IOS__ || __MACCATALYST__) + +using System.ComponentModel; + +namespace CoreImage; + +[Register ("CIFilterGenerator", true)] +[UnsupportedOSPlatform ("ios")] +[UnsupportedOSPlatform ("maccatalyst")] +[UnsupportedOSPlatform ("tvos")] +[SupportedOSPlatform ("macos")] +[Obsolete (Constants.TypeUnavailable, false)] +[EditorBrowsable (EditorBrowsableState.Never)] +public class CIFilterGenerator : NSObject, ICIFilterConstructor, INSCoding, INSCopying, INSSecureCoding { + [EditorBrowsable (EditorBrowsableState.Never)] + public override NativeHandle ClassHandle { get => throw new PlatformNotSupportedException (Constants.TypeUnavailable); } + + [EditorBrowsable (EditorBrowsableState.Never)] + public CIFilterGenerator (NSCoder coder) : base (NSObjectFlag.Empty) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + protected CIFilterGenerator (NSObjectFlag t) : base (t) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + protected internal CIFilterGenerator (NativeHandle handle) : base (handle) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public CIFilterGenerator (NSUrl aURL) + : base (NSObjectFlag.Empty) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ConnectObject (NSObject sourceObject, string? withSourceKey, NSObject targetObject, string targetKey) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual NSObject Copy (NSZone? zone) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public static CIFilterGenerator Create () + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual CIFilter CreateFilter () + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void DisconnectObject (NSObject sourceObject, string sourceKey, NSObject targetObject, string targetKey) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void EncodeTo (NSCoder encoder) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ExportKey (string key, NSObject targetObject, string? exportedKeyName) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual CIFilter? FilterWithName (string name) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public static CIFilterGenerator? FromUrl (NSUrl aURL) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void RegisterFilterName (string name) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void RemoveExportedKey (string exportedKeyName) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual bool Save (NSUrl toUrl, bool atomically) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void SetAttributesforExportedKey (NSDictionary attributes, NSString exportedKey) + { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual NSDictionary ClassAttributes { + [Export ("classAttributes")] + get { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + [Export ("setClassAttributes:")] + set { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual NSDictionary ExportedKeys { + [Export ("exportedKeys")] + get { + throw new PlatformNotSupportedException (Constants.TypeUnavailable); + } + } +} /* class CIFilterGenerator */ + +#endif // !XAMCORE_5_0 && (__IOS__ || __MACCATALYST__) diff --git a/src/Foundation/NSObject2.cs b/src/Foundation/NSObject2.cs index 7f1a5adb7e8e..22498aeed364 100644 --- a/src/Foundation/NSObject2.cs +++ b/src/Foundation/NSObject2.cs @@ -119,12 +119,9 @@ internal interface INSObjectFactory { #if !COREBUILD // Allocated in native memory, so that it can be accessed from native code without having to deal with the GC. - // Also put objc_super here, because it simplifies code. // This is mirrored in runtime.h and the definition needs to be in sync. - struct NSObjectData { - // the layout here is important, the two first fields have to match the objc_super struct. + internal struct NSObjectData { public NativeHandle handle; - public NativeHandle classHandle; public NSObject.Flags flags; } @@ -137,34 +134,42 @@ struct NSObjectData { // * https://github.com/AustinWise/runtime/blob/2bd10ad43df967950657ae0ade1f899dc1b18a41/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveCMarshal.NativeAot.cs#L15 // * https://github.com/AustinWise/runtime/blob/2bd10ad43df967950657ae0ade1f899dc1b18a41/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveCMarshal.NativeAot.cs#L59-L71 // * https://github.com/AustinWise/runtime/blob/2bd10ad43df967950657ae0ade1f899dc1b18a41/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveCMarshal.NativeAot.cs#L181-L185 - unsafe class NSObjectDataHandle { - NSObjectData* data; + unsafe class NSObjectDataHandle : TrackedMemory { + public NSObjectData* Data { get => (NSObjectData*) Value; } + + public NSObjectDataHandle () : base ((nuint) sizeof (NSObjectData)) + { + } + } + + class TrackedMemory { GCHandle handle; - public NSObjectData* Data { get => data; } + public IntPtr Value { get; private set; } - public NSObjectDataHandle () + public unsafe TrackedMemory (nuint size) { - data = Runtime.AllocZeroed (); + Value = (IntPtr) NativeMemory.AllocZeroed (size); } - public void CreateHandle (NSObject obj) + public unsafe void CreateHandle (NSObject trackedObject) { - handle = GCHandle.Alloc (obj, GCHandleType.WeakTrackResurrection); + handle = GCHandle.Alloc (trackedObject, GCHandleType.WeakTrackResurrection); } - ~NSObjectDataHandle () + ~TrackedMemory () { var handleAllocated = handle.IsAllocated; - if (handleAllocated && handle.Target is not null) { // The NSObject instance isn't gone yet, we have to try again later. GC.ReRegisterForFinalize (this); return; } - NativeMemory.Free (data); - data = null; + unsafe { + NativeMemory.Free ((void*) Value); + } + Value = IntPtr.Zero; if (handleAllocated) handle.Free (); @@ -208,6 +213,10 @@ public partial class NSObject : INativeObject // having to attach those threads to to the managed runtime. IntPtr /* unsafe NSObjectData* */ __data; // Read directly from several places in the runtime +#pragma warning disable CS8618 // "Non-nullable field '...' must contain a non-null value when exiting constructor.": this field is always non-null, because NSObject.Initialize is called before anything else is done. + static ConditionalWeakTable super_map; +#pragma warning restore CS8618 + unsafe NativeHandle handle { get => GetData ()->handle; set => GetData ()->handle = value; @@ -219,18 +228,24 @@ unsafe NativeHandle handle { if (data != IntPtr.Zero) return (NSObjectData*) data; - var data_handle = new NSObjectDataHandle (); - var existing_data = Interlocked.CompareExchange (ref __data, (IntPtr) data_handle.Data, IntPtr.Zero); - if (existing_data != IntPtr.Zero) { - // return the existing data, the GC will collect the other one we just created - return (NSObjectData*) existing_data; + if (Runtime.IsCoreCLR) { + data = (IntPtr) Runtime.GetTaggedMemory (this); + __data = data; // Runtime.GetTaggedMemory will always return the same pointer for the same object, so no synchronization is needed here (redundant writes are benign). + return (NSObjectData*) data; + } else { + var data_handle = new NSObjectDataHandle (); + var existing_data = Interlocked.CompareExchange (ref __data, (IntPtr) data_handle.Data, IntPtr.Zero); + if (existing_data != IntPtr.Zero) { + // return the existing data, the GC will collect the other one we just created + return (NSObjectData*) existing_data; + } + // tell the data handle we just created to track us + data_handle.CreateHandle (this); + // make sure the data isn't freed before this NSObject is collected, but also + // that it is freed after this NSObject is collected. + data_table.Add (this, data_handle); + return data_handle.Data; } - // tell the data handle we just created to track us - data_handle.CreateHandle (this); - // make sure the data isn't freed before this NSObject is collected, but also - // that it is freed after this NSObject is collected. - data_table.Add (this, data_handle); - return data_handle.Data; } unsafe Flags flags { @@ -388,17 +403,29 @@ internal static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, Flag } } +#if !XAMCORE_5_0 unsafe NativeHandle GetSuper () { - var data = GetData (); - if (data->classHandle == NativeHandle.Zero) - data->classHandle = ClassHandle; - return (IntPtr) (&data->handle); + var memory = super_map.GetValue (this, (obj) => { + unsafe { + var memory = new TrackedMemory ((nuint) sizeof (objc_super)); + memory.CreateHandle (obj); + return memory; + } + }); + objc_super* sup = (objc_super*) memory.Value; + if (sup->ClassHandle == NativeHandle.Zero) + sup->ClassHandle = ClassHandle; + sup->Handle = handle; + return memory.Value; } +#endif // !XAMCORE_5_0 internal static NativeHandle Initialize () { - data_table = new ConditionalWeakTable (); + if (!Runtime.IsCoreCLR) + data_table = new ConditionalWeakTable (); + super_map = new ConditionalWeakTable (); return class_ptr; } @@ -722,16 +749,35 @@ public NSObject DangerousAutorelease () return this; } +#if !XAMCORE_5_0 /// Handle used to represent the methods in the base class for this . /// An opaque pointer, represents an Objective-C objc_super object pointing to our base class. /// - /// This property is used to access members of a base class. - /// This is typically used when you call any of the Messaging - /// methods to invoke methods that were implemented in your base - /// class, instead of invoking the implementation in the current - /// class. + /// + /// This property is used to access members of a base class. + /// This is typically used when you call any of the Messaging + /// methods to invoke methods that were implemented in your base + /// class, instead of invoking the implementation in the current + /// class. + /// + /// + /// This property is obsolete; use the struct instead: + /// + /// + /// + /// /// [EditorBrowsable (EditorBrowsableState.Never)] +#if NET11_0_OR_GREATER + [Obsolete ("Use 'ObjCSuper' instead.")] +#endif public NativeHandle SuperHandle { get { if (handle == IntPtr.Zero) @@ -740,6 +786,7 @@ public NativeHandle SuperHandle { return GetSuper (); } } +#endif // !XAMCORE_5_0 /// Handle (pointer) to the unmanaged object representation. /// A pointer. diff --git a/src/Foundation/NSUrlSessionHandler.cs b/src/Foundation/NSUrlSessionHandler.cs index 2c0af8202220..e34081682faa 100644 --- a/src/Foundation/NSUrlSessionHandler.cs +++ b/src/Foundation/NSUrlSessionHandler.cs @@ -134,6 +134,15 @@ static NSUrlSessionConfiguration CreateConfig () // Double.MaxValue does not work, so default to 24 hours config.TimeoutIntervalForRequest = 24 * 60 * 60; config.TimeoutIntervalForResource = 24 * 60 * 60; + + // Disable shared credential storage so credentials we pass with UseCredential in DidReceiveChallenge dont get saved in + // the SharedCredentialStorage so (native) NSUrlSession can't try to authenticate later requests by itself using old credentials + // incluiding redirects, and then our managed DidReceiveChallenge delegate may not get called at all. We already manage + // the credential flow in DidReceiveChallenge and the Credentials property. The switch is just a compat in case we + // someone needs to go back to the old behaviour. + var useSharedCredentialStorage = AppContext.TryGetSwitch ("Foundation.NSUrlSessionHandler.UseSharedCredentialStorage", out var useSharedStorage) && useSharedStorage; + if (!useSharedCredentialStorage) + config.URLCredentialStorage = null; return config; } @@ -1029,7 +1038,30 @@ void WillCacheResponseImpl (NSUrlSession session, NSUrlSessionDataTask dataTask, [Preserve (Conditional = true)] public override void WillPerformHttpRedirection (NSUrlSession session, NSUrlSessionTask task, NSHttpUrlResponse response, NSUrlRequest newRequest, Action completionHandler) { - completionHandler (sessionHandler.AllowAutoRedirect ? newRequest : null!); + if (!sessionHandler.AllowAutoRedirect) { + completionHandler (null!); + return; + } + + var inflight = GetInflightData (task); + + if (inflight is null) { + completionHandler (null!); + return; + } + + inflight.HasRedirected = true; + + if (newRequest.Url?.AbsoluteString is string redirectUrl) { + inflight.CurrentRequestUrl = redirectUrl; + + if (Uri.TryCreate (redirectUrl, UriKind.Absolute, out var redirectUri)) + inflight.HasCrossOriginRedirect |= IsCrossOriginRedirect (inflight.RequestUrl, redirectUri); + else + inflight.HasCrossOriginRedirect = true; + } + + completionHandler (newRequest); } [Preserve (Conditional = true)] @@ -1127,6 +1159,22 @@ void DidReceiveChallengeImpl (NSUrlSession session, NSUrlSessionTask task, NSUrl } } + // Detect redirect from the task as a fallback in case + // WillPerformHttpRedirection has not updated infligth state yet + if (!inflight.HasRedirected) { + var originalUrl = task.OriginalRequest?.Url?.AbsoluteString; + var currentUrl = task.CurrentRequest?.Url?.AbsoluteString; + if (originalUrl is not null && currentUrl is not null + && !string.Equals (originalUrl, currentUrl, StringComparison.Ordinal)) { + inflight.HasRedirected = true; + inflight.CurrentRequestUrl = currentUrl; + if (Uri.TryCreate (currentUrl, UriKind.Absolute, out var redirectUri)) + inflight.HasCrossOriginRedirect |= IsCrossOriginRedirect (inflight.RequestUrl, redirectUri); + else + inflight.HasCrossOriginRedirect = true; + } + } + if (sessionHandler.Credentials is not null && TryGetAuthenticationType (challenge.ProtectionSpace, out var authType)) { NetworkCredential? credentialsToUse = null; if (authType != RejectProtectionSpaceAuthType) { @@ -1147,8 +1195,9 @@ void DidReceiveChallengeImpl (NSUrlSession session, NSUrlSessionTask task, NSUrl var nsurlRespose = challenge.FailureResponse as NSHttpUrlResponse; var responseIsUnauthorized = (nsurlRespose is null) ? false : nsurlRespose.StatusCode == (int) HttpStatusCode.Unauthorized && challenge.PreviousFailureCount > 0; if (!responseIsUnauthorized) { - var uri = inflight.Request.RequestUri!; - credentialsToUse = sessionHandler.Credentials.GetCredential (uri, authType); + var uri = GetCredentialLookupUri (task, inflight); + if (ShouldLookupCredentials (sessionHandler.Credentials, inflight)) + credentialsToUse = sessionHandler.Credentials.GetCredential (uri, authType); } } @@ -1165,6 +1214,45 @@ void DidReceiveChallengeImpl (NSUrlSession session, NSUrlSessionTask task, NSUrl } } + static Uri GetCredentialLookupUri (NSUrlSessionTask task, InflightData inflight) + { + var currentRequestUrl = task.CurrentRequest?.Url?.AbsoluteString; + if (currentRequestUrl is not null && Uri.TryCreate (currentRequestUrl, UriKind.Absolute, out var currentRequestUri)) + return currentRequestUri; + + if (Uri.TryCreate (inflight.CurrentRequestUrl, UriKind.Absolute, out var inflightCurrentRequestUri)) + return inflightCurrentRequestUri; + + return inflight.Request.RequestUri!; + } + + static bool ShouldLookupCredentials (ICredentials credentials, InflightData inflight) + { + if (credentials is CredentialCache) + return true; + + if (!inflight.HasRedirected) + return true; + + // We are now matching .NET handlers (SocketsHttpHandler and WinHttpHandler) redirect behavior by dropping non CredentialCache credentials after a redirect + // Ref: + // https://github.com/dotnet/runtime/blob/eb5503a1f0dc40ee7b73eb79a039eb143ee25038/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs#L541-L547 + // https://github.com/dotnet/runtime/blob/eb5503a1f0dc40ee7b73eb79a039eb143ee25038/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs#L52-L87 + // Provide a way for customers to opt into the old behavior for same origin redirects. + var allowSameOriginRedirectCredentials = AppContext.TryGetSwitch ("Foundation.NSUrlSessionHandler.AllowSameOriginRedirectCredentials", out var allowRedirectCred) && allowRedirectCred; + return allowSameOriginRedirectCredentials && !inflight.HasCrossOriginRedirect; + } + + static bool IsCrossOriginRedirect (string originalRequestUrl, Uri currentRequestUri) + { + if (!Uri.TryCreate (originalRequestUrl, UriKind.Absolute, out var originalRequestUri)) + return true; + + return !string.Equals (originalRequestUri.Scheme, currentRequestUri.Scheme, StringComparison.OrdinalIgnoreCase) + || !string.Equals (originalRequestUri.IdnHost, currentRequestUri.IdnHost, StringComparison.OrdinalIgnoreCase) + || originalRequestUri.Port != currentRequestUri.Port; + } + static readonly string RejectProtectionSpaceAuthType = "reject"; static bool TryGetAuthenticationType (NSUrlProtectionSpace protectionSpace, [NotNullWhen (true)] out string? authenticationType) @@ -1175,15 +1263,19 @@ static bool TryGetAuthenticationType (NSUrlProtectionSpace protectionSpace, [Not authenticationType = "basic"; } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTTPDigest) { authenticationType = "digest"; - } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodNegotiate || - protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTMLForm) { - // Want to reject this authentication type to allow the next authentication method in the request to - // be used. - authenticationType = RejectProtectionSpaceAuthType; - } else { - // ServerTrust, ClientCertificate or Default. + } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodServerTrust || + protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodClientCertificate) { + // ServerTrust and ClientCertificate are handled earlier in DidReceiveChallengeImpl, + // so we should not reach here for these types. Return false just in case. authenticationType = null; return false; + } else { + // For any other authentication method (Negotiate, HTMLForm, Bearer, etc.), + // reject this protection space to allow the next authentication method in the + // request to be tried. This is important when the server advertises multiple + // WWW-Authenticate challenges (e.g. Bearer before Basic) - rejecting unsupported + // methods allows fallback to one we can handle. + authenticationType = RejectProtectionSpaceAuthType; } return true; } @@ -1192,6 +1284,9 @@ static bool TryGetAuthenticationType (NSUrlProtectionSpace protectionSpace, [Not class InflightData { public readonly object Lock = new object (); public string RequestUrl { get; set; } + public string CurrentRequestUrl { get; set; } + public bool HasRedirected { get; set; } + public bool HasCrossOriginRedirect { get; set; } public TaskCompletionSource CompletionSource { get; } = new TaskCompletionSource (TaskCreationOptions.RunContinuationsAsynchronously); public CancellationToken CancellationToken { get; set; } @@ -1210,6 +1305,7 @@ class InflightData { public InflightData (string requestUrl, CancellationToken cancellationToken, HttpRequestMessage request) { RequestUrl = requestUrl; + CurrentRequestUrl = requestUrl; CancellationToken = cancellationToken; Request = request; } diff --git a/src/Makefile b/src/Makefile index 703dc110204c..0fb0bcadc9d8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -67,6 +67,8 @@ endif DOTNET_GENERATOR_FLAGS=$(GENERATOR_FLAGS) --lib=$(DOTNET_BCL_DIR) -attributelib:$(DOTNET_BINDING_ATTRIBUTES) $(DOTNET_REFERENCES) DOTNET_GENERATOR=$(DOTNET_BUILD_DIR)/bgen/bgen DOTNET_BINDING_ATTRIBUTES=$(DOTNET_BUILD_DIR)/Xamarin.Apple.BindingAttributes.dll +APPLE_DOC_READER=$(TOP)/packages/appledocreader.$(ADR_RUNTIME_IDENTIFIER)/$(ADR_NUGET_VERSION)/tools/any/$(ADR_RUNTIME_IDENTIFIER)/AppleDocReader +APPLE_DOC_READER_LOCK=$(BUILD_DIR)/.appledocreader.lock # # Specific warnings that we want reported as errors by generator @@ -347,8 +349,9 @@ $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM)/Microsoft.$(1).xml: $ $$(Q) $(CP) $$< $$@ ifndef NO_XCODE +# AppleDocReader backs up a shared Xcode SQLite database, so serialize invocations. $($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll build/.build-adr-stamp | $($(2)_DOTNET_BUILD_DIR)/doc - $$(Q_GEN) $(TOP)/packages/appledocreader.$(ADR_RUNTIME_IDENTIFIER)/$(ADR_NUGET_VERSION)/tools/any/$(ADR_RUNTIME_IDENTIFIER)/AppleDocReader inject docs --assembly="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll)" --input="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml)" --output="$(abspath $$@)" --xcode="$(DEVELOPER_DIR)/../.." --runtimeDll="$(DOTNET_BCL_DIR)/System.Runtime.dll" -f + $$(Q_GEN) /usr/bin/lockf "$(APPLE_DOC_READER_LOCK)" "$(APPLE_DOC_READER)" inject docs --assembly="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll)" --input="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml)" --output="$(abspath $$@)" --xcode="$(DEVELOPER_DIR)/../.." --runtimeDll="$(DOTNET_BCL_DIR)/System.Runtime.dll" -f else # Without Xcode, skip AppleDocReader and just copy the XML $($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml | $($(2)_DOTNET_BUILD_DIR)/doc @@ -435,6 +438,15 @@ $($(2)_DOTNET_BUILD_DIR)/Microsoft.$(1).rsp: Makefile frameworks.sources $(RSP_D $($(2)_DOTNET_BUILD_DIR)/$(4)/Microsoft.$(1)%dll $($(2)_DOTNET_BUILD_DIR)/$(4)/Microsoft.$(1)%pdb $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1)%dll $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1)%xml: $$($(2)_DOTNET_PLATFORM_ASSEMBLY_DEPENDENCIES) $$(ROSLYN_GENERATOR) $$(ROSLYN_ANALYZER) | $$($(2)_DOTNET_PLATFORM_ASSEMBLY_DIR_DEPENDENCIES) $$(call Q_PROF_CSC,dotnet) $(DOTNET_CSC) @$($(2)_DOTNET_BUILD_DIR)/Microsoft.$(1).rsp +ifdef SERIALIZE_CSC +# This is to serialize the csc commands for the platform assembly. The platform assembly takes a while to compile (maxing out the CPU), and csc is already multi-threaded, which +# means that if we're running multiple long csc tasks simultaneously, the CPU of the machine will get absolutely thrashed. csc (aka Roslyn) isn't exactly a cheapskate with memory either... +# It looks a bit weird, but the idea is that in this template, every platform assembly depends on the assembly from the previous template expansion. +# It's opt-in, because it slows down the build a bit. +$($(2)_DOTNET_BUILD_DIR)/$(4)/Microsoft.$(1).dll: $(LAST_DLL) +LAST_DLL=$($(2)_DOTNET_BUILD_DIR)/$(4)/Microsoft.$(1).dll +endif + dotnet-$(3):: $($(2)_DOTNET_BUILD_DIR)/$(4)/Microsoft.$(1).dll DOTNET_TARGETS_$(3) += \ diff --git a/src/ObjCBindings/ExportTag.cs b/src/ObjCBindings/ExportTag.cs index 7172cc573a55..ca3d9b7d0b13 100644 --- a/src/ObjCBindings/ExportTag.cs +++ b/src/ObjCBindings/ExportTag.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; #nullable enable @@ -169,18 +170,10 @@ public enum Property : Int64 { CustomMarshalDirective = 1 << 5, /// - /// Apply to strings parameters that are merely retained or assigned, - /// not copied this is an exception as it is advised in the coding - /// standard for Objective-C to avoid this, but a few properties do use - /// this. Use this falg for properties flagged with `retain' or - /// `assign', which look like this: - /// - /// @property (retain) NSString foo; - /// @property (assign) NSString assigned; - /// - /// This forced the generator to create an NSString before calling the - /// API instead of using the fast string marshalling code. + /// This flag is obsolete and has no effect. Zero-copy string marshaling is no longer supported. /// + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Zero-copy string marshaling is no longer supported. This flag has no effect.")] DisableZeroCopy = 1 << 6, /// diff --git a/src/ObjCRuntime/DynamicRegistrar.cs b/src/ObjCRuntime/DynamicRegistrar.cs index 93dc571ced6b..0c27e3d8130f 100644 --- a/src/ObjCRuntime/DynamicRegistrar.cs +++ b/src/ObjCRuntime/DynamicRegistrar.cs @@ -806,7 +806,7 @@ protected override bool TryGetAttribute (Type type, string attributeNamespace, s return attribute is not null; } - protected override void ReportError (int code, string message, params object [] args) + protected override void ReportError (int code, string message, params object? [] args) { Runtime.NSLog (String.Format (message, args)); } diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs index 173bf5645c4d..d33f63746e84 100644 --- a/src/ObjCRuntime/Registrar.cs +++ b/src/ObjCRuntime/Registrar.cs @@ -1119,7 +1119,7 @@ protected virtual void OnRegisterCategory (ObjCType type, [NotNullIfNotNull (nam protected abstract ConnectAttribute? GetConnectAttribute (TProperty property); // Return null if no attribute is found. Do not consider inherited properties. public abstract ProtocolAttribute? GetProtocolAttribute (TType type); // Return null if no attribute is found. Do not consider base types. protected abstract IEnumerable GetProtocolMemberAttributes (TType type); // Return null if no attributes found. Do not consider base types. - protected virtual Version? GetSdkIntroducedVersion (TType obj, out string? message) { message = null; return null; } // returns the sdk version when the type was introduced for the current platform (null if all supported versions) + public virtual Version? GetSdkIntroducedVersion (TType obj, out string? message) { message = null; return null; } // returns the sdk version when the type was introduced for the current platform (null if all supported versions) protected abstract Version GetSDKVersion (); protected abstract TType? GetProtocolAttributeWrapperType (TType type); // Return null if no attribute is found. Do not consider base types. public abstract BindAsAttribute? GetBindAsAttribute (TMethod method, int parameter_index); // If parameter_index = -1 then get the attribute for the return type. Return null if no attribute is found. Must consider base method. @@ -2125,7 +2125,7 @@ void FlattenInterfaces (TType? [] ifaces) objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "xamarinGetNSObjectData", Trampoline = Trampoline.GetNSObjectData, - Signature = "^{NSObjectData=@^{objc_super}I}:", + Signature = "^{NSObjectData=@I}:", IsStatic = false, }, ref exceptions); } @@ -2639,6 +2639,26 @@ protected string ToSignature (TType type, ObjCMember member, bool forProperty = throw ErrorHelper.CreateError (4101, Errors.MT4101, GetTypeFullName (type)); } + // Gets the Objective-C name for the given type. + // Returns false if the type in question isn't exported to Objective-C, and thus doesn't have an Objective-C name. + public bool TryGetExportedTypeName (TType type, [NotNullWhen (true)] out string? name) + { + name = null; + + var registerAttribute = GetRegisterAttribute (type); + if (registerAttribute is null) + return false; + + if (!registerAttribute.IsWrapper) + return false; + + if (HasProtocolAttribute (type)) + return false; + + name = GetExportedTypeName (type, registerAttribute); + return true; + } + public string GetExportedTypeName (TType type, RegisterAttribute? register_attribute) { string? name = null; @@ -2721,8 +2741,9 @@ protected string ToSignature (TType type, ObjCMember? member, ref bool success, return "#"; if (IsINativeObject (type)) { - if (!IsGenericType (type) && !IsInterface (type) && !IsNSObject (type) && IsAbstract (type)) - ErrorHelper.Show (CreateWarning (4179, member, Errors.MT4179, type.FullName, member?.FullName)); + if (!IsGenericType (type) && !IsInterface (type) && !IsNSObject (type) && IsAbstract (type)) { + ReportWarning (4179, Errors.MT4179, type.FullName, member?.FullName); + } if (IsNSObject (type) && forProperty) { return "@\"" + GetExportedTypeName (type) + "\""; } else { @@ -2791,7 +2812,7 @@ internal static void NSLog (string format, params object [] args) } #endif - protected virtual void ReportError (int code, string message, params object [] args) + protected virtual void ReportError (int code, string message, params object? [] args) { // Using Console.WriteLine here is error prone, since if we get an early error // we'll end up crashing/infinite recursion since Console.WriteLine is redirected @@ -2800,7 +2821,7 @@ protected virtual void ReportError (int code, string message, params object [] a R.NSLog (String.Format (message, args)); } - protected virtual void ReportWarning (int code, string message, params object [] args) + protected virtual void ReportWarning (int code, string message, params object? [] args) { // Using Console.WriteLine here is error prone, since if we get an early error // we'll end up crashing/infinite recursion since Console.WriteLine is redirected diff --git a/src/ObjCRuntime/Runtime.CoreCLR.cs b/src/ObjCRuntime/Runtime.CoreCLR.cs index fff4e97daf4f..c4cf3636de4b 100644 --- a/src/ObjCRuntime/Runtime.CoreCLR.cs +++ b/src/ObjCRuntime/Runtime.CoreCLR.cs @@ -205,28 +205,35 @@ static void RaiseAppDomainUnhandledExceptionEvent (IntPtr gchandle) ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent (exception); } - // Size: 2 pointers - internal struct TrackedObjectInfo { - public unsafe NSObjectData* Data; - } - [SupportedOSPlatform ("macos")] internal static GCHandle CreateTrackingGCHandle (NSObject obj, IntPtr handle) { var gchandle = ObjectiveCMarshal.CreateReferenceTrackingHandle (obj, out var info); unsafe { - TrackedObjectInfo* tracked_info; fixed (void* ptr = info) - tracked_info = (TrackedObjectInfo*) ptr; - tracked_info->Data = obj.GetData (); - - log_coreclr ($"GetOrCreateTrackingGCHandle ({obj.GetType ().FullName}, 0x{handle.ToString ("x")}) => Info=0x{((IntPtr) tracked_info).ToString ("x")} Data=0x{(IntPtr) tracked_info->Data:x} Created new"); + log_coreclr ($"GetOrCreateTrackingGCHandle ({obj.GetType ().FullName}, 0x{handle.ToString ("x")}) => 0x{((IntPtr) ptr).ToString ("x")} Created new"); } return gchandle; } + internal unsafe static void* GetTaggedMemory (NSObject obj) + { + // If https://github.com/dotnet/runtime/issues/128476 is accepted and implemented, + // can just call that new API instead of calling ObjectiveCMarshal.CreateReferenceTrackingHandle and + // freeing the returned handle. + + var gchandle = ObjectiveCMarshal.CreateReferenceTrackingHandle (obj, out var info); + // We only care about the tagged memory ('info'), so just free the GCHandle. + // We might want to request an API to just get the tagged memory at some point. + gchandle.Free (); + // The tagged memory pointer is guaranteed to be the same for every call to ObjectiveCMarshal.CreateReferenceTrackingHandle, + // and it will automatically be freed once the 'obj' is freed by the GC (in particular _once the instance is freed_, + // not _once the instance is collectible_, which is a very important distinction for us). + return Unsafe.AsPointer (ref info.GetPinnableReference ()); + } + // See "Toggle-ref support for CoreCLR" in coreclr-bridge.m for more information. internal static void RegisterToggleReferenceCoreCLR (NSObject obj, IntPtr handle, bool isCustomType) { diff --git a/src/Resources.Designer.cs b/src/Resources.Designer.cs index 5cd19312d3ee..db627089d6d1 100644 --- a/src/Resources.Designer.cs +++ b/src/Resources.Designer.cs @@ -440,7 +440,7 @@ internal static string BI1026 { } /// - /// Looks up a localized string similar to Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings.. + /// Looks up a localized string similar to The --use-zero-copy option is not supported and will be ignored.. /// internal static string BI1027 { get { diff --git a/src/Resources.resx b/src/Resources.resx index acd9d535c624..3e6aace23529 100644 --- a/src/Resources.resx +++ b/src/Resources.resx @@ -294,7 +294,7 @@ - Support for ZeroCopy strings is not implemented. Strings will be marshalled as NSStrings. + The --use-zero-copy option is not supported and will be ignored. diff --git a/src/appkit.cs b/src/appkit.cs index 4ed3bacd8db8..f3fa730c79dd 100644 --- a/src/appkit.cs +++ b/src/appkit.cs @@ -32,6 +32,7 @@ #nullable enable using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics; using System.ComponentModel; using CoreGraphics; @@ -8678,7 +8679,11 @@ interface NSGraphicsContext { NSGraphicsContext FromGraphicsPort (IntPtr graphicsPort, bool initialFlippedState); [Static, Export ("currentContext"), NullAllowed] - NSGraphicsContext CurrentContext { get; set; } + NSGraphicsContext CurrentContext { + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors, "Foundation.NSProxy", "Microsoft.macOS")] // https://github.com/xamarin/bugzilla-archives/blob/main/16/16505/bug.html + get; + set; + } [Static, Export ("currentContextDrawingToScreen")] bool IsCurrentContextDrawingToScreen { get; } @@ -8941,12 +8946,6 @@ interface NSGridCell : NSCoding { NSLayoutConstraint [] CustomPlacementConstraints { get; set; } } - [NoMacCatalyst] - [BaseType (typeof (NSGraphicsContext))] - [DisableDefaultCtor] - interface NSPrintPreviewGraphicsContext { - } - [NoMacCatalyst] [BaseType (typeof (NSImageRep))] [DisableDefaultCtor] // An uncaught exception was raised: -[NSEPSImageRep init]: unrecognized selector sent to instance 0x1db2d90 diff --git a/src/bgen/AttributeManager.cs b/src/bgen/AttributeManager.cs index 3ceccdd0c76e..4e3b3acbb927 100644 --- a/src/bgen/AttributeManager.cs +++ b/src/bgen/AttributeManager.cs @@ -15,8 +15,12 @@ public class AttributeManager { "System.Runtime.CompilerServices.NullableAttribute", "System.Runtime.CompilerServices.NullableContextAttribute", "System.Runtime.CompilerServices.NativeIntegerAttribute", + "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute", }; + // Cache raw GetCustomAttributesData() results per provider to avoid repeated reflection allocations. + readonly Dictionary> rawAttributeCache = new (); + TypeCache TypeCache { get; } public AttributeManager (TypeCache typeCache) @@ -500,9 +504,15 @@ public virtual T [] GetCustomAttributes (ICustomAttributeProvider? provider) } [return: NotNullIfNotNull (nameof (provider))] - static IList? GetAttributes (ICustomAttributeProvider? provider) - => provider switch { - null => null, + IList? GetAttributes (ICustomAttributeProvider? provider) + { + if (provider is null) + return null; + + if (rawAttributeCache.TryGetValue (provider, out var cached)) + return cached; + + IList result = provider switch { MemberInfo member => member.GetCustomAttributesData (), Assembly assembly => assembly.GetCustomAttributesData (), ParameterInfo pinfo => pinfo.GetCustomAttributesData (), @@ -510,7 +520,11 @@ public virtual T [] GetCustomAttributes (ICustomAttributeProvider? provider) _ => throw new BindingException (1051, true, provider.GetType ().FullName) }; - public static bool HasAttribute (ICustomAttributeProvider provider, string type_name) + rawAttributeCache [provider] = result; + return result; + } + + public bool HasAttribute (ICustomAttributeProvider provider, string type_name) { var attribs = GetAttributes (provider); for (int i = 0; i < attribs.Count; i++) diff --git a/src/bgen/Attributes.cs b/src/bgen/Attributes.cs index a55108690d3c..8e47763419eb 100644 --- a/src/bgen/Attributes.cs +++ b/src/bgen/Attributes.cs @@ -517,20 +517,14 @@ public class NoDefaultValueAttribute : Attribute { public class IgnoredInDelegateAttribute : Attribute { } -// Apply to strings parameters that are merely retained or assigned, -// not copied this is an exception as it is advised in the coding -// standard for Objective-C to avoid this, but a few properties do use -// this. Use this attribtue for properties flagged with `retain' or -// `assign', which look like this: -// -// @property (retain) NSString foo; -// @property (assign) NSString assigned; -// -// This forced the generator to create an NSString before calling the -// API instead of using the fast string marshalling code. +#if !XAMCORE_5_0 +// This attribute is obsolete and has no effect. Zero-copy string marshaling is no longer supported. +[Obsolete ("Zero-copy string marshaling is no longer supported. This attribute has no effect.")] +[AttributeUsage (AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = true)] public class DisableZeroCopyAttribute : Attribute { public DisableZeroCopyAttribute () { } } +#endif // Apply this attribute to methods that need a custom binding method. // @@ -561,29 +555,13 @@ public class MarshalDirectiveAttribute : Attribute { public string? Library { get; set; } } -// -// By default, the generator will not do Zero Copying of strings, as most -// third party libraries do not follow Apple's design guidelines of making -// string properties and parameters copy parameters, instead many libraries -// "retain" as a broken optimization [1]. -// -// The consumer of the generator can force this by passing -// --use-zero-copy or setting the [assembly:ZeroCopyStrings] attribute. -// When these are set, the generator assumes the library perform -// copies over any NSStrings it keeps instead of retains/assigns and -// that any property that happens to be a retain/assign has the -// [DisableZeroCopyAttribute] attribute applied. -// -// [1] It is broken because consumer code can pass an NSMutableString, the -// library retains the value, but does not have a way of noticing changes -// that might happen to the mutable string behind its back. -// -// In the ZeroCopy case it is a problem because we pass handles to stack-allocated -// strings that stop existing after the invocation is over. -// +#if !XAMCORE_5_0 +// This attribute is obsolete and has no effect. Zero-copy string marshaling is no longer supported. +[Obsolete ("Zero-copy string marshaling is no longer supported. This attribute has no effect.")] [AttributeUsage (AttributeTargets.Assembly | AttributeTargets.Method | AttributeTargets.Interface, AllowMultiple = true)] public class ZeroCopyStringsAttribute : Attribute { } +#endif [AttributeUsage (AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class SnippetAttribute : Attribute { diff --git a/src/bgen/BindingTouch.cs b/src/bgen/BindingTouch.cs index 2766217756fa..7b9e2d32dadb 100644 --- a/src/bgen/BindingTouch.cs +++ b/src/bgen/BindingTouch.cs @@ -42,10 +42,11 @@ using System.Threading; #endif -public class BindingTouch : IDisposable { +public class BindingTouch : IDisposable, IToolLog { public static ApplePlatform [] AllPlatforms = new ApplePlatform [] { ApplePlatform.iOS, ApplePlatform.MacOSX, ApplePlatform.TVOS, ApplePlatform.MacCatalyst }; public static PlatformName [] AllPlatformNames = new PlatformName [] { PlatformName.iOS, PlatformName.MacOSX, PlatformName.TvOS, PlatformName.MacCatalyst }; public PlatformName CurrentPlatform; + public ApplePlatform Platform { get => CurrentPlatform.AsApplePlatform (); } public bool BindThirdPartyLibrary = true; public string? outfile; @@ -156,14 +157,16 @@ public bool TryCreateOptionSet (BindingTouchConfig config, string [] args) { "d=", "Defines a symbol", v => config.Defines.Add (v) }, { "api=", "Adds a API definition source file", v => config.ApiSources.Add (v) }, { "s=", "Adds a source file required to build the API", v => config.CoreSources.Add (v) }, - { "q", "Quiet", v => ErrorHelper.Verbosity-- }, - { "v", "Sets verbose mode", v => ErrorHelper.Verbosity++ }, + { "q", "Quiet", v => Verbosity-- }, + { "v", "Sets verbose mode", v => Verbosity++ }, { "x=", "Adds the specified file to the build, used after the core files are compiled", v => config.ExtraSources.Add (v) }, { "e", "Generates smaller classes that can not be subclassed (previously called 'external mode')", v => config.IsExternal = true }, { "p", "Sets private mode", v => config.IsPublicMode = false }, { "baselib=", "Sets the base library", v => config.Baselibdll = v }, { "attributelib=", "Sets the attribute library", v => config.Attributedll = v }, - { "use-zero-copy", v=> config.UseZeroCopy = true }, +#if !XAMCORE_5_0 + { "use-zero-copy", v=> ErrorHelper.Warning (1027) }, +#endif { "nostdlib", "Does not reference mscorlib.dll library", l => config.OmitStandardLibrary = true }, #if !XAMCORE_5_0 { "no-mono-path", "Launches compiler with empty MONO_PATH", l => { }, true }, @@ -364,7 +367,6 @@ bool TryGenerate (BindingTouchConfig config, Api api) try { var g = new Generator (this, api, config.IsPublicMode, config.IsExternal, config.IsDebug) { BaseDir = config.BindingFilesOutputDirectory ?? config.TemporaryFileDirectory!, - ZeroCopyStrings = config.UseZeroCopy, InlineSelectors = config.InlineSelectors ?? (CurrentPlatform != PlatformName.MacOSX), }; @@ -521,7 +523,7 @@ void Compile (List arguments, int errorCode, string? tmpdir) arguments.Insert (i - 1, compile_command [i]); } - if (Driver.RunCommand (compile_command [0], arguments, null, out var compile_output, true, Driver.Verbosity) != 0) + if (Driver.RunCommand (this, compile_command [0], arguments, null, out var compile_output, true, Verbosity) != 0) throw ErrorHelper.CreateError (errorCode, $"{compiler} {StringUtils.FormatArguments (arguments)}\n{compile_output}".Replace ("\n", "\n\t")); var output = string.Join (Environment.NewLine, compile_output.ToString ().Split (new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries)); if (!string.IsNullOrEmpty (output)) @@ -536,10 +538,10 @@ bool TryLoadApi (string? name, [NotNullWhen (true)] out Assembly? assembly) try { assembly = universe?.LoadFromAssemblyPath (name); } catch (Exception e) { - if (Driver.Verbosity > 0) - Console.WriteLine (e); + if (Verbosity > 0) + Log (e.ToString ()); - Console.Error.WriteLine ("Error loading {0}", name); + LogError ($"Error loading {name}"); } return assembly is not null; @@ -574,4 +576,36 @@ public void Dispose () Dispose (disposing: true); GC.SuppressFinalize (this); } + + public void Log (string message) + { + Console.WriteLine (message); + } + + public void LogError (string message) + { + Console.Error.WriteLine (message); + } + + public void LogError (Exception exception) + { + ErrorHelper.Show (exception); + } + + public void LogException (Exception exception) + { + ErrorHelper.Show (exception); + } + + int verbosity = 0; + public int Verbosity { + get => verbosity; + set => verbosity = value; + } +} + +namespace Xamarin.Bundler { + public partial class Driver { + public static int GetDefaultVerbosity () => 0; + } } diff --git a/src/bgen/DocumentationManager.cs b/src/bgen/DocumentationManager.cs index 8b8a29851b37..bd9f3e8c18e2 100644 --- a/src/bgen/DocumentationManager.cs +++ b/src/bgen/DocumentationManager.cs @@ -10,14 +10,25 @@ public class DocumentationManager { string xml; - XmlDocument? doc; + Dictionary? memberLookup; public DocumentationManager (string assembly) { this.xml = Path.ChangeExtension (assembly, ".xml"); if (File.Exists (xml)) { - doc = new XmlDocument (); + var doc = new XmlDocument (); doc.LoadWithoutNetworkAccess (xml); + // Pre-build a dictionary for O(1) member lookups instead of + // O(n) XPath queries on every TryGetDocumentation call. + var members = doc.SelectNodes ("/doc/members/member[@name]"); + if (members is not null) { + memberLookup = new Dictionary (members.Count); + foreach (XmlNode member in members) { + var name = member.Attributes? ["name"]?.Value; + if (name is not null) + memberLookup [name] = member; + } + } } } @@ -38,14 +49,13 @@ public bool TryGetDocumentation (MemberInfo member, [NotNullWhen (true)] out str { documentation = null; - if (doc is null) + if (memberLookup is null) return false; if (!TryGetId (member, out var id)) return false; - var node = doc.SelectSingleNode ($"/doc/members/member[@name='{id}']"); - if (node is null) + if (!memberLookup.TryGetValue (id, out var node)) return false; if (transformNode is not null) diff --git a/src/bgen/Generator.cs b/src/bgen/Generator.cs index cf581d75be9b..f1221a33dafb 100644 --- a/src/bgen/Generator.cs +++ b/src/bgen/Generator.cs @@ -109,9 +109,6 @@ Nomenclator Nomenclator { string? is_direct_binding_value; // An expression that calculates the IsDirectBinding value. Might not be a constant expression. This will be added to every constructor for a type. bool? is_direct_binding; // If a constant value for IsDirectBinding is known, it's stored here. Will be null if no constant value is known. - // Whether to use ZeroCopy for strings, defaults to false - public bool ZeroCopyStrings; - public bool BindThirdPartyLibrary { get { return BindingTouch.BindThirdPartyLibrary; } } public bool InlineSelectors; public string BaseDir { get { return basedir; } set { basedir = value; } } @@ -124,11 +121,6 @@ Nomenclator Nomenclator { // bool type_needs_thread_checks; - // - // If set, the members of this type will get zero copy - // - internal bool type_wants_zero_copy; - // // Used by the public binding generator to populate the // class with types that do not exist @@ -843,16 +835,7 @@ public TrampolineInfo MakeTrampoline (Type t) if (mai.PlainString) return safe_name; else { - bool allow_null = null_allowed_override || AttributeManager.IsNullable (pi); - - if (mai.ZeroCopyStringMarshal) { - if (allow_null) - return String.Format ("{0} is null ? IntPtr.Zero : (IntPtr)(&_s{0})", pi.Name); - else - return String.Format ("(IntPtr)(&_s{0})", pi.Name); - } else { - return "ns" + pi.Name; - } + return "ns" + pi.Name; } } @@ -2805,7 +2788,7 @@ public string MakeSignature (MemberInformation minfo, bool is_async, ParameterIn string name = GetMethodName (minfo, is_async); // Some codepaths already write preservation info - PrintAttributes (minfo.mi, preserve: !alreadyPreserved, advice: true, bindAs: true, requiresSuper: true); + PrintAttributes (minfo.mi, preserve: !alreadyPreserved, advice: true, bindAs: true, requiresSuper: true, dynamicDependency: true); if (minfo.is_ctor && minfo.is_protocol_member) { sb.Append ("T? "); @@ -3097,13 +3080,8 @@ void GenerateInvoke (bool stret, bool supercall, MethodInfo mi, MemberInformatio if (mai.PlainString) ErrorHelper.Warning (1101); - if (mai.ZeroCopyStringMarshal) { - target_name = "(IntPtr)(&_s" + pi.Name + ")"; - handle = ""; - } else { - target_name = "ns" + pi.Name; - handle = ""; - } + target_name = "ns" + pi.Name; + handle = ""; } else target_name = pi.Name.GetSafeParamName (); break; @@ -3248,48 +3226,16 @@ bool IsOptimizable (MemberInfo method) // @probe_null: determines whether null is allowed, and // whether we need to generate code to handle this // - // @must_copy: determines whether to create a new NSString, necessary - // for NSString properties that are flagged with "retain" instead of "copy" - // - // @prefix: prefix to prepend on each line - // // @property: the name of the property // - public string GenerateMarshalString (bool probe_null, bool must_copy) + public string GenerateMarshalString (bool probe_null) { - if (must_copy) { - return "var ns{0} = CFString.CreateNative ({1});\n"; - } - return - "ObjCRuntime.NSStringStruct _s{0}; Console.WriteLine (\"" + CurrentMethod + ": Marshalling: {{1}}\", {1}); \n" + - "_s{0}.ClassPtr = ObjCRuntime.NSStringStruct.ReferencePtr;\n" + - "_s{0}.Flags = 0x010007d1; // RefCount=1, Unicode, InlineContents = 0, DontFreeContents\n" + - "_s{0}.UnicodePtr = _p{0};\n" + - "_s{0}.Length = " + (probe_null ? "{1} is null ? 0 : {1}.Length;" : "{1}.Length;\n"); + return "var ns{0} = CFString.CreateNative ({1});\n"; } - public string GenerateDisposeString (bool probe_null, bool must_copy) + public string GenerateDisposeString (bool probe_null) { - if (must_copy) { - return "CFString.ReleaseNative (ns{0});\n"; - } else - return "if (_s{0}.Flags != 0x010007d1) throw new Exception (\"String was retained, not copied\");"; - } - - List? CollectFastStringMarshalParameters (MethodInfo mi) - { - List? stringParameters = null; - - foreach (var pi in mi.GetParameters ()) { - var mai = new MarshalInfo (this, mi, pi); - - if (mai.ZeroCopyStringMarshal) { - if (stringParameters is null) - stringParameters = new List (); - stringParameters.Add (pi.Name.GetSafeParamName () ?? ""); - } - } - return stringParameters; + return "CFString.ReleaseNative (ns{0});\n"; } AvailabilityBaseAttribute? GetIntroduced (Type? type, string methodName) @@ -3371,8 +3317,8 @@ void GenerateTypeLowering (MethodInfo mi, bool null_allowed_override, out String if (mai.Type == TypeCache.System_String && !mai.PlainString) { bool probe_null = null_allowed_override || AttributeManager.IsNullable (pi); - convs.AppendFormat (GenerateMarshalString (probe_null, !mai.ZeroCopyStringMarshal), pi.Name, pi.Name.GetSafeParamName ()); - disposes.AppendFormat (GenerateDisposeString (probe_null, !mai.ZeroCopyStringMarshal), pi.Name); + convs.AppendFormat (GenerateMarshalString (probe_null), pi.Name, pi.Name.GetSafeParamName ()); + disposes.AppendFormat (GenerateDisposeString (probe_null), pi.Name); } else if (mai.Type.TryIsArray (out var etype)) { if (HasBindAsAttribute (pi)) { convs.AppendFormat ("using var nsb_{0} = {1}\n", pi.Name, GetToBindAsWrapper (mi, null, pi)); @@ -3615,9 +3561,6 @@ public void GenerateMethodBody (MemberInformation minfo, MethodInfo mi, string? GenerateArgumentChecks (mi, false, propInfo, out bool needsGCKeepAlives); - // Collect all strings that can be fast-marshalled - var stringParameters = CollectFastStringMarshalParameters (mi); - GenerateTypeLowering (mi, null_allowed_override, out var args, out var convs, out var disposes, out var by_ref_processing, out var by_ref_init, out var post_return, propInfo); if (minfo.is_protocol_member && minfo.is_static) { @@ -3629,12 +3572,6 @@ public void GenerateMethodBody (MemberInformation minfo, MethodInfo mi, string? if (by_ref_init.Length > 0) print (by_ref_init.ToString ()); - if (stringParameters is not null) { - print ("fixed (char * {0}){{", - stringParameters.Select (name => "_p" + name + " = " + name).Aggregate ((first, second) => first + ", " + second)); - indent++; - } - if (propInfo is not null && IsSetter (mi) && HasBindAsAttribute (propInfo)) { convs.AppendFormat ("using var nsb_{0} = {1}\n", propInfo.Name, GetToBindAsWrapper (mi, minfo, null)); } @@ -3834,10 +3771,6 @@ public void GenerateMethodBody (MemberInformation minfo, MethodInfo mi, string? WriteMarkDirtyIfDerived (sw, mi.DeclaringType!); if (post_return?.Length > 0) print (post_return.ToString ()); - if (stringParameters is not null) { - indent--; - print ("}"); - } indent--; } @@ -4104,7 +4037,7 @@ void GenerateProperty (Type type, PropertyInfo pi, List? instance_fields pi.Name.GetSafeParamName ()); indent++; if (generate_getter) { - PrintAttributes (pi.GetGetMethod ()!, platform: true, preserve: true, advice: true); + PrintAttributes (pi.GetGetMethod ()!, platform: true, preserve: true, advice: true, dynamicDependency: true); print ("get {"); indent++; @@ -4123,7 +4056,7 @@ void GenerateProperty (Type type, PropertyInfo pi, List? instance_fields print ("}"); } if (generate_setter) { - PrintAttributes (pi.GetSetMethod ()!, platform: true, preserve: true, advice: true); + PrintAttributes (pi.GetSetMethod ()!, platform: true, preserve: true, advice: true, dynamicDependency: true); print ("set {"); indent++; @@ -4197,7 +4130,7 @@ void GenerateProperty (Type type, PropertyInfo pi, List? instance_fields // If property getter or setter has its own WrapAttribute we let the user do whatever their heart desires if (generate_getter) { PrintAttributes (pi, platform: true); - PrintAttributes (pi.GetGetMethod (), platform: true, preserve: true, advice: true); + PrintAttributes (pi.GetGetMethod (), platform: true, preserve: true, advice: true, dynamicDependency: true); print ("get {"); indent++; @@ -4237,7 +4170,7 @@ void GenerateProperty (Type type, PropertyInfo pi, List? instance_fields PrintExport (minfo, sel, export!.ArgumentSemantic); } - PrintAttributes (pi.GetGetMethod (), platform: true, preserve: true, advice: true, notImplemented: true, inlinedType: inlinedType); + PrintAttributes (pi.GetGetMethod (), platform: true, preserve: true, advice: true, notImplemented: true, inlinedType: inlinedType, dynamicDependency: true); if (minfo.is_protocol_member && !minfo.is_static) { print ("get {"); print ($"\treturn _Get{pi.Name.GetSafeParamName ()} (this);"); @@ -4293,7 +4226,7 @@ void GenerateProperty (Type type, PropertyInfo pi, List? instance_fields if (not_implemented_attr is null && (!minfo.is_sealed || !minfo.is_wrapper)) PrintExport (minfo, sel, export!.ArgumentSemantic); - PrintAttributes (pi.GetSetMethod (), platform: true, preserve: true, advice: true, notImplemented: true, inlinedType: inlinedType); + PrintAttributes (pi.GetSetMethod (), platform: true, preserve: true, advice: true, notImplemented: true, inlinedType: inlinedType, dynamicDependency: true); if (minfo.is_protocol_member && !minfo.is_static) { print ("set {"); print ($"\t_Set{pi.Name.GetSafeParamName ()} (this, value);"); @@ -5576,7 +5509,7 @@ public void PrintBindAsAttribute (ICustomAttributeProvider? mi, StringBuilder? s // Not adding the experimental attribute is bad (it would mean that an API // we meant to be experimental ended up being released as stable), so it's // opt-out instead of opt-in. - public void PrintAttributes (ICustomAttributeProvider? mi, bool platform = false, bool preserve = false, bool advice = false, bool notImplemented = false, bool bindAs = false, bool requiresSuper = false, Type? inlinedType = null, bool experimental = true, bool obsolete = false, bool objectiveCFramework = false, bool simulatorAvailability = true) + public void PrintAttributes (ICustomAttributeProvider? mi, bool platform = false, bool preserve = false, bool advice = false, bool notImplemented = false, bool bindAs = false, bool requiresSuper = false, Type? inlinedType = null, bool experimental = true, bool obsolete = false, bool objectiveCFramework = false, bool simulatorAvailability = true, bool dynamicDependency = false) { if (platform) PrintPlatformAttributes (mi as MemberInfo, inlinedType); @@ -5598,6 +5531,70 @@ public void PrintAttributes (ICustomAttributeProvider? mi, bool platform = false PrintObjectiveCFrameworkAttribute (mi); if (simulatorAvailability) PrintSimulatorAvailabilityAttributes (mi); + if (dynamicDependency) + PrintDynamicDependencyAttributes (mi); + } + + public void PrintDynamicDependencyAttributes (ICustomAttributeProvider? mi) + { + if (mi is not MemberInfo memberInfo) + return; + + var allAttribs = memberInfo.GetCustomAttributesData (); + foreach (var attrib in allAttribs) { + if (attrib.GetAttributeType ().FullName != "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute") + continue; + var args = attrib.ConstructorArguments; + var parts = new List (); + foreach (var arg in args) { + if (arg.Value is string stringValue) { + parts.Add ($"\"{stringValue}\""); + } else if (arg.Value is int intValue) { + parts.Add (FormatDynamicallyAccessedMemberTypes (intValue)); + } else if (arg.Value is Type typeValue) { + parts.Add ($"typeof ({typeValue})"); + } else { + exceptions.Add (ErrorHelper.CreateError (99, $"Unexpected attribute argument value for DynamicDependency attribute: {arg.ArgumentType.FullName} => {arg.Value}")); + } + } + print ($"[DynamicDependency ({string.Join (", ", parts)})]"); + } + } + + static string FormatDynamicallyAccessedMemberTypes (int memberTypes) + { + if (memberTypes == -1) // All + return "DynamicallyAccessedMemberTypes.All"; + if (memberTypes == 0) // None + return "DynamicallyAccessedMemberTypes.None"; + + // Use the composite values first to match the original source + var flagValues = new (int value, string name) [] { + (3, "PublicConstructors"), // 3 includes PublicParameterlessConstructor + (1, "PublicParameterlessConstructor"), + (4, "NonPublicConstructors"), + (8, "PublicMethods"), + (16, "NonPublicMethods"), + (32, "PublicFields"), + (64, "NonPublicFields"), + (128, "PublicNestedTypes"), + (256, "NonPublicNestedTypes"), + (512, "PublicProperties"), + (1024, "NonPublicProperties"), + (2048, "PublicEvents"), + (4096, "NonPublicEvents"), + (8192, "Interfaces"), + }; + + var parts = new List (); + var remaining = memberTypes; + foreach (var (value, name) in flagValues) { + if (value != 0 && (remaining & value) == value) { + parts.Add ($"DynamicallyAccessedMemberTypes.{name}"); + remaining &= ~value; + } + } + return string.Join (" | ", parts); } public void PrintExperimentalAttribute (ICustomAttributeProvider? mi) @@ -5769,12 +5766,6 @@ public void Generate (Type type) if (is_rgen_type) return; - if (ZeroCopyStrings) { - ErrorHelper.Warning (1027); - ZeroCopyStrings = false; - } - - type_wants_zero_copy = AttributeManager.HasAttribute (type) || ZeroCopyStrings; var tsa = AttributeManager.GetCustomAttribute (type); // if we're inside a special namespace then default is non-thread safe, otherwise default is thread safe if (NamespaceCache.UINamespaces.Contains (type.Namespace!)) { diff --git a/src/bgen/Models/BindingTouchConfig.cs b/src/bgen/Models/BindingTouchConfig.cs index 0aa0d50b614f..4cad9cbbba2f 100644 --- a/src/bgen/Models/BindingTouchConfig.cs +++ b/src/bgen/Models/BindingTouchConfig.cs @@ -5,7 +5,6 @@ public class BindingTouchConfig { public bool ShowHelp = false; - public bool UseZeroCopy = false; public string? BindingFilesOutputDirectory = null; public string? TemporaryFileDirectory = null; public string? HelperClassNamespace = null; diff --git a/src/bgen/Models/MarshalInfo.cs b/src/bgen/Models/MarshalInfo.cs index 27c4a52c6fea..091b1dc32ffd 100644 --- a/src/bgen/Models/MarshalInfo.cs +++ b/src/bgen/Models/MarshalInfo.cs @@ -13,10 +13,6 @@ public class MarshalInfo { public Type Type { get; } public bool IsOut { get; } - // This is set on a string parameter if the argument parameters are set to - // Copy. This means that we can do fast string passing. - public bool ZeroCopyStringMarshal { get; set; } - public bool IsAligned; // Used for parameters @@ -25,9 +21,6 @@ public MarshalInfo (Generator generator, MethodInfo mi, ParameterInfo pi) this.Generator = generator; PlainString = Generator.AttributeManager.HasAttribute (pi); Type = pi.ParameterType; - ZeroCopyStringMarshal = (Type == Generator.TypeCache.System_String) && PlainString == false && !Generator.AttributeManager.HasAttribute (pi) && generator.type_wants_zero_copy; - if (ZeroCopyStringMarshal && Generator.AttributeManager.HasAttribute (mi)) - ZeroCopyStringMarshal = false; IsOut = pi.IsOut; } diff --git a/src/bgen/bgen.csproj b/src/bgen/bgen.csproj index 8e7a65e7d227..fa063bd5b43a 100644 --- a/src/bgen/bgen.csproj +++ b/src/bgen/bgen.csproj @@ -36,6 +36,7 @@ + diff --git a/src/corebluetooth.cs b/src/corebluetooth.cs index 796bdfcbb890..56ee620ce7a4 100644 --- a/src/corebluetooth.cs +++ b/src/corebluetooth.cs @@ -789,7 +789,6 @@ interface CBPeripheral : NSCopying { /// To be added. /// To be added. [Export ("name", ArgumentSemantic.Retain)] - [DisableZeroCopy] [NullAllowed] string Name { get; } diff --git a/src/coreimage.cs b/src/coreimage.cs index ed0494ca9dc2..18060e955e99 100644 --- a/src/coreimage.cs +++ b/src/coreimage.cs @@ -2623,17 +2623,8 @@ interface CIFilterApply { NSString OptionColorSpace { get; } } -#if XAMCORE_5_0 [NoiOS] [NoMacCatalyst] -#else -#if __IOS__ || __MACCATALYST__ - [EditorBrowsable (EditorBrowsableState.Never)] - [Obsolete ("Do not use; this type does not exist on this platform.")] -#endif - [iOS (17, 0)] - [MacCatalyst (17, 0)] -#endif [NoTV] [BaseType (typeof (NSObject))] [DisableDefaultCtor] @@ -2734,21 +2725,18 @@ interface CIFilterGenerator : CIFilterConstructor, NSSecureCoding, NSCopying { /// To be added. /// To be added. /// To be added. - [NoiOS, NoMacCatalyst] [Field ("kCIFilterGeneratorExportedKey", "+CoreImage")] NSString ExportedKey { get; } /// To be added. /// To be added. /// To be added. - [NoiOS, NoMacCatalyst] [Field ("kCIFilterGeneratorExportedKeyTargetObject", "+CoreImage")] NSString ExportedKeyTargetObject { get; } /// To be added. /// To be added. /// To be added. - [NoiOS, NoMacCatalyst] [Field ("kCIFilterGeneratorExportedKeyName", "+CoreImage")] NSString ExportedKeyName { get; } } diff --git a/src/coreml.cs b/src/coreml.cs index d22ce5c74d6b..3e643e9dc127 100644 --- a/src/coreml.cs +++ b/src/coreml.cs @@ -1543,9 +1543,9 @@ interface MLWritable { } #if !XAMCORE_5_0 - [Deprecated (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] [iOS (14, 0)] [MacCatalyst (14, 0)] [NoTV] @@ -1575,9 +1575,9 @@ interface MLModelCollection { #endif // !XAMCORE_5_0 #if !XAMCORE_5_0 - [Deprecated (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] [iOS (14, 0)] [MacCatalyst (14, 0)] [NoTV] diff --git a/src/foundation.cs b/src/foundation.cs index 83e5cd5bfc65..eb9795f2e0cf 100644 --- a/src/foundation.cs +++ b/src/foundation.cs @@ -13011,6 +13011,7 @@ interface NSObject2 : NSObjectProtocol { [NoTV] [NoiOS] [NoMacCatalyst] + [ObjectiveCFramework ("AppKit")] interface NSBindingSelectionMarker : NSCopying { /// To be added. /// To be added. diff --git a/src/frameworks.sources b/src/frameworks.sources index accf45f75e36..0b7237d278a2 100644 --- a/src/frameworks.sources +++ b/src/frameworks.sources @@ -130,6 +130,7 @@ APPKIT_SOURCES = \ AppKit/NSPopUpButtonCell.cs \ AppKit/NSPredicateEditorRowTemplate.cs \ AppKit/NSPrintInfo.cs \ + AppKit/NSPrintPreviewGraphicsContext.cs \ AppKit/NSScreen.cs \ AppKit/NSSegmentedControl.cs \ AppKit/NSSharingService.cs \ @@ -573,6 +574,7 @@ COREIMAGE_SOURCES = \ CoreImage/CIDetector.cs \ CoreImage/CIDetectorOptions.cs \ CoreImage/CIFilter.cs \ + CoreImage/CIFilterGenerator.cs \ CoreImage/CIImage.cs \ CoreImage/CISampler.cs \ CoreImage/CISystemToneMap.cs \ diff --git a/src/glkit.cs b/src/glkit.cs index 9d70fa9313a6..609394d61ab9 100644 --- a/src/glkit.cs +++ b/src/glkit.cs @@ -171,7 +171,6 @@ interface GLKBaseEffect : GLKNamedEffect { /// /// To be added. [Export ("label", ArgumentSemantic.Copy)] - [DisableZeroCopy] [NullAllowed] // default is null on iOS 5.1.1 string Label { get; set; } @@ -583,7 +582,6 @@ interface GLKSkyboxEffect : GLKNamedEffect { /// To be added. [NullAllowed] // by default this property is null [Export ("label", ArgumentSemantic.Copy)] - [DisableZeroCopy] string Label { get; set; } /// To be added. diff --git a/src/mapkit.cs b/src/mapkit.cs index 993faa6fd4c0..829a1f8e63c1 100644 --- a/src/mapkit.cs +++ b/src/mapkit.cs @@ -2055,6 +2055,7 @@ partial interface MKRouteStep { [BaseType (typeof (NSFormatter))] [MacCatalyst (13, 1)] + [ThreadSafe] partial interface MKDistanceFormatter { [Export ("stringFromDistance:")] diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/FieldValidator.cs b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/FieldValidator.cs index 6bc47067a431..3bffa00f9f39 100644 --- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/FieldValidator.cs +++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/FieldValidator.cs @@ -76,6 +76,7 @@ internal static bool FlagsAreValid (Property property, RootContext context, // there are a number of flags that have no effect in a field property, we are not raise a warning for each // of them since they are ignored by rgen. The user that has warnings as errors will have to deal with them. +#pragma warning disable CS0618 // DisableZeroCopy is obsolete var ignoredFlags = new [] { PropertyFlag.IsThreadStatic, PropertyFlag.MarshalNativeExceptions, @@ -93,6 +94,7 @@ internal static bool FlagsAreValid (Property property, RootContext context, PropertyFlag.Optional, PropertyFlag.CreateEvents, }; +#pragma warning restore CS0618 var builder = ImmutableArray.CreateBuilder (); foreach (var flag in ignoredFlags) { diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs index 5c1dc20fae17..623bca12c849 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs @@ -99,10 +99,12 @@ public bool MarshalNativeExceptions public bool IsTransient => IsProperty && ExportPropertyData.Flags.HasFlag (ObjCBindings.Property.Transient); /// - /// True if the property was marked to DisableZeroCopy. + /// True if the property was marked to DisableZeroCopy. This flag is obsolete and has no effect. /// +#pragma warning disable CS0618 // Type or member is obsolete public bool DisableZeroCopy => IsProperty && ExportPropertyData.Flags.HasFlag (ObjCBindings.Property.DisableZeroCopy); +#pragma warning restore CS0618 /// /// True if the generator should not use a NSString for marshalling. diff --git a/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs b/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs index e09a98b9115f..5d35b03547f6 100644 --- a/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs +++ b/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs @@ -90,8 +90,7 @@ static class AttributesNames { public const string DisableDefaultCtorAttribute = "DisableDefaultCtorAttribute"; /// - /// This attribute is applied to string parameters or string properties and instructs the code generator to not - /// use the zero-copy string marshaling for this parameter, and instead create a new NSString instance from the C# string + /// This attribute is obsolete and has no effect. Zero-copy string marshaling is no longer supported. /// [BindingFlag (AttributeTargets.Parameter | AttributeTargets.Property)] public const string DisableZeroCopyAttribute = "DisableZeroCopyAttribute"; diff --git a/system-dependencies.sh b/system-dependencies.sh index c5cc85e0ad29..9393d788eec7 100755 --- a/system-dependencies.sh +++ b/system-dependencies.sh @@ -43,6 +43,25 @@ if test -f configure.inc; then fi fi +function get_xcode_developer_root () +{ + local suffix="${1:-}" + + if test -z "$suffix"; then + if test -n "${XCODE_DEVELOPER_ROOT:-}"; then + echo "$XCODE_DEVELOPER_ROOT" + return + fi + + if XCODE_DEVELOPER_ROOT_ASSIGNMENT=$(grep "^XCODE_DEVELOPER_ROOT=" configure.inc 2>/dev/null); then + echo "${XCODE_DEVELOPER_ROOT_ASSIGNMENT#*=}" + return + fi + fi + + grep "^XCODE${suffix}_DEVELOPER_ROOT[?:]*=" Make.config | sed 's/^[^=]*=//' +} + # parse command-line arguments while ! test -z $1; do case $1 in @@ -219,6 +238,12 @@ while ! test -z $1; do esac done +if test -z "${NO_XCODE:-}"; then + XCODE_DEVELOPER_ROOT=$(get_xcode_developer_root) + export XCODE_DEVELOPER_ROOT + export DEVELOPER_DIR="$XCODE_DEVELOPER_ROOT" +fi + # reporting functions COLOR_RED=$(tput setaf 1 2>/dev/null || true) COLOR_ORANGE=$(tput setaf 3 2>/dev/null || true) @@ -340,6 +365,20 @@ function get_non_universal_simulator_runtimes () rm -f "$TMPFILE" } +function print_non_universal_simulator_runtimes () +{ + local TMPFILE + TMPFILE=$(mktemp) + + xcrun simctl runtime list -j --json-output="$TMPFILE" + + # this json query filters the json to simulator runtimes where iOS/tvOS >= 26.0 and where x64 is *not* supported (which we need to run x64 apps in the simulator on arm64) + JQ_QUERY='map({platformIdentifier: .platformIdentifier, identifier: .identifier, version: .version, state: .state, supportedArchitectures: .supportedArchitectures | join("|"), majorVersion: .version | split(".")[0] | tonumber }) | map(select(.majorVersion>=26) ) | map(select(.supportedArchitectures | contains("x86_64") | not))' + jq "$JQ_QUERY" -r "$TMPFILE" + + rm -f "$TMPFILE" +} + function xcodebuild_download_selected_platforms () { local XCODE_DEVELOPER_ROOT @@ -351,7 +390,7 @@ function xcodebuild_download_selected_platforms () local TVOS_NUGET_OS_VERSION local TVOS_BUILD_VERSION - XCODE_DEVELOPER_ROOT=$(grep XCODE_DEVELOPER_ROOT= Make.config | sed 's/.*=//') + XCODE_DEVELOPER_ROOT=$(get_xcode_developer_root) XCODE_NAME=$(basename "$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")")") # we use the same logic here as in Make.config to determine whether we're using a stable version of Xcode or not (search for XCODE_IS_STABLE/XCODE_IS_PREVIEW) XCODE_IS_STABLE=$(echo "$XCODE_NAME" | sed -e 's@^Xcode[_0-9.]*[.]app$@YES@') @@ -397,8 +436,10 @@ function xcodebuild_download_selected_platforms () log "Looking for iOS/tvOS 26+ simulator runtimes that don't support x64..." get_non_universal_simulator_runtimes - if [[ "$SIMULATORS_WITHOUT_X64_COUNT" -gt 0 ]]; then - log "Found ${SIMULATORS_WITHOUT_X64_COUNT} simulator runtimes that don't support x64, which will now be deleted: ${SIMULATORS_WITHOUT_X64[@]}" + if [[ "$SIMULATORS_WITHOUT_X64_COUNT" -gt 0 && "$ACES" == "1" ]]; then + log "Found ${SIMULATORS_WITHOUT_X64_COUNT} simulator runtimes that don't support x64, but we're running on ACES, so we can't do anything about that." + elif [[ "$SIMULATORS_WITHOUT_X64_COUNT" -gt 0 ]]; then + log "Found ${SIMULATORS_WITHOUT_X64_COUNT} simulator runtimes that don't support x64, which will now be deleted: ${SIMULATORS_WITHOUT_X64[*]}" for sim in "${SIMULATORS_WITHOUT_X64[@]}"; do log "Executing 'xcrun simctl runtime delete $sim'" xcrun simctl runtime delete "$sim" @@ -406,17 +447,24 @@ function xcodebuild_download_selected_platforms () # sadly simulator deletion is done asynchronously, so we have to wait until they're all gone log "Waiting for the simulators to be deleted..." printf " " - for i in $(seq 1 60); do + for i in $(seq 1 300); do sleep 1 get_non_universal_simulator_runtimes if [[ "$SIMULATORS_WITHOUT_X64_COUNT" == "0" ]]; then break fi + # every 60 seconds print the simulators left to delete + if [[ $(( i % 60)) == 0 ]]; then + printf "\n" + printf " Simulators left to delete:\n" + print_non_universal_simulator_runtimes | sed 's/^/ /' + printf " " + fi printf "$SIMULATORS_WITHOUT_X64_COUNT" done printf "\n" if [[ "$SIMULATORS_WITHOUT_X64_COUNT" != "0" ]]; then - warn "Waited for 60 seconds, but there are still $SIMULATORS_WITHOUT_X64_COUNT simulators waiting to deleted." + warn "Waited for 5 minutes, but there are still $SIMULATORS_WITHOUT_X64_COUNT simulators waiting to deleted." fi else log "All installed iOS/tvOS 26+ simulators support x64" @@ -592,7 +640,7 @@ function install_coresimulator () local TARGET_CORESIMULATOR_VERSION local CURRENT_CORESIMULATOR_VERSION - XCODE_DEVELOPER_ROOT=$(grep XCODE_DEVELOPER_ROOT= Make.config | sed 's/.*=//') + XCODE_DEVELOPER_ROOT=$(get_xcode_developer_root) XCODE_ROOT=$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")") CORESIMULATOR_PKG=$XCODE_ROOT/Contents/Resources/Packages/XcodeSystemResources.pkg @@ -658,9 +706,13 @@ function install_coresimulator () } function check_specific_xcode () { - local XCODE_DEVELOPER_ROOT=`grep XCODE$1_DEVELOPER_ROOT= Make.config | sed 's/.*=//'` - local XCODE_VERSION=`grep XCODE$1_VERSION= Make.config | sed 's/.*=//'` - local XCODE_ROOT=$(dirname `dirname $XCODE_DEVELOPER_ROOT`) + local XCODE_DEVELOPER_ROOT + local XCODE_VERSION + local XCODE_ROOT + + XCODE_DEVELOPER_ROOT=$(get_xcode_developer_root "$1") + XCODE_VERSION=$(grep "XCODE$1_VERSION=" Make.config | sed 's/.*=//') + XCODE_ROOT=$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")") if ! test -d $XCODE_DEVELOPER_ROOT; then if ! test -z $PROVISION_XCODE; then @@ -698,11 +750,13 @@ function check_xcode () { if ! test -z $IGNORE_XCODE; then return; fi # must have latest Xcode in /Applications/Xcode.app - check_specific_xcode + check_specific_xcode "" install_coresimulator local IOS_SDK_VERSION MACOS_SDK_VERSION TVOS_SDK_VERSION - local XCODE_DEVELOPER_ROOT=`grep ^XCODE_DEVELOPER_ROOT= Make.config | sed 's/.*=//'` + local XCODE_DEVELOPER_ROOT + + XCODE_DEVELOPER_ROOT=$(get_xcode_developer_root) IOS_SDK_VERSION=$(grep ^IOS_NUGET_OS_VERSION= Make.versions | sed -e 's/.*=//') MACOS_SDK_VERSION=$(grep ^MACOS_NUGET_OS_VERSION= Make.versions | sed -e 's/.*=//') TVOS_SDK_VERSION=$(grep ^TVOS_NUGET_OS_VERSION= Make.versions | sed -e 's/.*=//') @@ -928,7 +982,7 @@ function check_old_simulators () local XCODE local XCODE_DEVELOPER_ROOT - XCODE_DEVELOPER_ROOT=$(grep XCODE$1_DEVELOPER_ROOT= Make.config | sed 's/.*=//') + XCODE_DEVELOPER_ROOT=$(get_xcode_developer_root "$1") IFS=' ' read -r -a EXTRA_SIMULATORS <<< "$(grep ^EXTRA_SIMULATORS= Make.config | sed 's/.*=//')" XCODE=$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")") @@ -1006,4 +1060,3 @@ else echo "System check failed" exit 1 fi - diff --git a/tests/BundledResources/ResourcesTest.cs b/tests/BundledResources/ResourcesTest.cs index e22cdc7ec85e..573102ee7133 100644 --- a/tests/BundledResources/ResourcesTest.cs +++ b/tests/BundledResources/ResourcesTest.cs @@ -22,9 +22,9 @@ public void Bundled () // files are extracted (by MonoDevelop) so we can see them in the file system // that's true for simulator or devices and whatever the linker settings are var dir = NSBundle.MainBundle.ResourcePath!; - Assert.True (File.Exists (Path.Combine (dir, "basn3p08.png")), "file-basn3p08.png"); - Assert.True (File.Exists (Path.Combine (dir, "basn3p08_with_loc.png")), "file-basn3p08_with_loc.png"); - Assert.True (File.Exists (Path.Combine (dir, "xamvideotest.mp4")), "xamvideotest.mp4"); + Assert.That (File.Exists (Path.Combine (dir, "basn3p08.png")), Is.True, "file-basn3p08.png"); + Assert.That (File.Exists (Path.Combine (dir, "basn3p08_with_loc.png")), Is.True, "file-basn3p08_with_loc.png"); + Assert.That (File.Exists (Path.Combine (dir, "xamvideotest.mp4")), Is.True, "xamvideotest.mp4"); // resources are removed by the linker or an extra step (e.g. "link sdk" or "don't link") but that // extra step is done only on device (to keep the simulator builds as fast as possible) diff --git a/tests/EmbeddedResources/ResourcesTest.cs b/tests/EmbeddedResources/ResourcesTest.cs index 04f35a6856e8..e8c83f5d9b08 100644 --- a/tests/EmbeddedResources/ResourcesTest.cs +++ b/tests/EmbeddedResources/ResourcesTest.cs @@ -23,13 +23,13 @@ public class ResourcesTest { public void Embedded () { var manager = new ResourceManager ("EmbeddedResources.Welcome", typeof (ResourcesTest).Assembly); - Assert.AreEqual ("Welcome", manager.GetString ("String1", new CultureInfo ("en")), "en"); - Assert.AreEqual ("G'day", manager.GetString ("String1", new CultureInfo ("en-AU")), "en-AU"); - Assert.AreEqual ("Willkommen", manager.GetString ("String1", new CultureInfo ("de")), "de"); - Assert.AreEqual ("Willkommen", manager.GetString ("String1", new CultureInfo ("de-DE")), "de-DE"); - Assert.AreEqual ("Bienvenido", manager.GetString ("String1", new CultureInfo ("es")), "es"); - Assert.AreEqual ("Bienvenido", manager.GetString ("String1", new CultureInfo ("es-AR")), "es-AR"); - Assert.AreEqual ("Bienvenido", manager.GetString ("String1", new CultureInfo ("es-ES")), "es-ES"); + Assert.That (manager.GetString ("String1", new CultureInfo ("en")), Is.EqualTo ("Welcome"), "en"); + Assert.That (manager.GetString ("String1", new CultureInfo ("en-AU")), Is.EqualTo ("G'day"), "en-AU"); + Assert.That (manager.GetString ("String1", new CultureInfo ("de")), Is.EqualTo ("Willkommen"), "de"); + Assert.That (manager.GetString ("String1", new CultureInfo ("de-DE")), Is.EqualTo ("Willkommen"), "de-DE"); + Assert.That (manager.GetString ("String1", new CultureInfo ("es")), Is.EqualTo ("Bienvenido"), "es"); + Assert.That (manager.GetString ("String1", new CultureInfo ("es-AR")), Is.EqualTo ("Bienvenido"), "es-AR"); + Assert.That (manager.GetString ("String1", new CultureInfo ("es-ES")), Is.EqualTo ("Bienvenido"), "es-ES"); } } } diff --git a/tests/bgen/BGenTests.cs b/tests/bgen/BGenTests.cs index 1a8dd308e6d2..3d20efe5ba53 100644 --- a/tests/bgen/BGenTests.cs +++ b/tests/bgen/BGenTests.cs @@ -1155,6 +1155,64 @@ public void GeneratedAttributeOnPropertyAccessors2 () Assert.That (RenderSupportedOSPlatformAttributes (setter), Is.EqualTo (expectedSetterAttributes), "Setter Attributes"); } + [Test] + public void DynamicDependencyAttribute () + { + var bgen = BuildFile (Profile.macOSMobile, "dynamic-dependency-attribute.cs"); + + var type = bgen.ApiAssembly.MainModule.Types.First (v => v.Name == "MyClass"); + var getter = type.Methods.First (v => v.Name == "get_CurrentContext"); + var setter = type.Methods.First (v => v.Name == "set_CurrentContext"); + var doSomething = type.Methods.First (v => v.Name == "DoSomething"); + var doSomethingElse = type.Methods.First (v => v.Name == "DoSomethingElse"); + var doAnother = type.Methods.First (v => v.Name == "DoAnother"); + var doYetAnother = type.Methods.First (v => v.Name == "DoYetAnother"); + var doAll = type.Methods.First (v => v.Name == "DoAll"); + + // (DynamicallyAccessedMemberTypes, string, string) on property getter + var getterDDA = getter.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (getterDDA.Length, Is.EqualTo (1), "Getter DynamicDependency count"); + Assert.That ((int) getterDDA [0].ConstructorArguments [0].Value, Is.EqualTo (7), "Getter DynamicDependency MemberTypes (PublicConstructors | NonPublicConstructors)"); + Assert.That (getterDDA [0].ConstructorArguments [1].Value, Is.EqualTo ("Foundation.NSProxy"), "Getter DynamicDependency TypeName"); + Assert.That (getterDDA [0].ConstructorArguments [2].Value, Is.EqualTo ("Microsoft.macOS"), "Getter DynamicDependency AssemblyName"); + + // Setter should not have it + var setterDDA = setter.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (setterDDA.Length, Is.EqualTo (0), "Setter DynamicDependency count"); + + // (string, string, string) on method + var methodDDA = doSomething.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (methodDDA.Length, Is.EqualTo (1), "DoSomething DynamicDependency count"); + Assert.That (methodDDA [0].ConstructorArguments [0].Value, Is.EqualTo ("Create"), "DoSomething DynamicDependency MemberSignature"); + Assert.That (methodDDA [0].ConstructorArguments [1].Value, Is.EqualTo ("NS.MyClass"), "DoSomething DynamicDependency TypeName"); + Assert.That (methodDDA [0].ConstructorArguments [2].Value, Is.EqualTo ("api0"), "DoSomething DynamicDependency AssemblyName"); + + // (string) - single member signature + var elseDDA = doSomethingElse.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (elseDDA.Length, Is.EqualTo (1), "DoSomethingElse DynamicDependency count"); + Assert.That (elseDDA [0].ConstructorArguments.Count, Is.EqualTo (1), "DoSomethingElse DynamicDependency arg count"); + Assert.That (elseDDA [0].ConstructorArguments [0].Value, Is.EqualTo ("Activate"), "DoSomethingElse DynamicDependency MemberSignature"); + + // (DynamicallyAccessedMemberTypes, Type) + var anotherDDA = doAnother.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (anotherDDA.Length, Is.EqualTo (1), "DoAnother DynamicDependency count"); + Assert.That ((int) anotherDDA [0].ConstructorArguments [0].Value, Is.EqualTo (8 | 512), "DoAnother DynamicDependency MemberTypes (PublicMethods | PublicProperties)"); + Assert.That (((Mono.Cecil.TypeReference) anotherDDA [0].ConstructorArguments [1].Value).Name, Is.EqualTo ("NSObject"), "DoAnother DynamicDependency Type"); + + // (string, Type) + var yetAnotherDDA = doYetAnother.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (yetAnotherDDA.Length, Is.EqualTo (1), "DoYetAnother DynamicDependency count"); + Assert.That (yetAnotherDDA [0].ConstructorArguments [0].Value, Is.EqualTo ("Create"), "DoYetAnother DynamicDependency MemberSignature"); + Assert.That (((Mono.Cecil.TypeReference) yetAnotherDDA [0].ConstructorArguments [1].Value).Name, Is.EqualTo ("NSObject"), "DoYetAnother DynamicDependency Type"); + + // (DynamicallyAccessedMemberTypes.All, string, string) + var allDDA = doAll.CustomAttributes.Where (ca => ca.AttributeType.Name == "DynamicDependencyAttribute").ToArray (); + Assert.That (allDDA.Length, Is.EqualTo (1), "DoAll DynamicDependency count"); + Assert.That ((int) allDDA [0].ConstructorArguments [0].Value, Is.EqualTo (-1), "DoAll DynamicDependency MemberTypes (All)"); + Assert.That (allDDA [0].ConstructorArguments [1].Value, Is.EqualTo ("NS.MyClass"), "DoAll DynamicDependency TypeName"); + Assert.That (allDDA [0].ConstructorArguments [2].Value, Is.EqualTo ("api0"), "DoAll DynamicDependency AssemblyName"); + } + [Test] [TestCase (Profile.iOS)] public void NewerAvailabilityInInlinedProtocol (Profile profile) diff --git a/tests/bgen/tests/dynamic-dependency-attribute.cs b/tests/bgen/tests/dynamic-dependency-attribute.cs new file mode 100644 index 000000000000..5ffbc3ac5d1e --- /dev/null +++ b/tests/bgen/tests/dynamic-dependency-attribute.cs @@ -0,0 +1,42 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Foundation; +using ObjCRuntime; + +namespace NS { + [BaseType (typeof (NSObject))] + interface MyClass { + [Static, Export ("currentContext"), NullAllowed] + NSObject CurrentContext { + // (DynamicallyAccessedMemberTypes, string, string) + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors, "Foundation.NSProxy", "Microsoft.macOS")] + get; + set; + } + + // (string, string, string) + [Export ("doSomething")] + [DynamicDependency ("Create", "NS.MyClass", "api0")] + void DoSomething (); + + // (string) - single member signature + [Export ("doSomethingElse")] + [DynamicDependency ("Activate")] + void DoSomethingElse (); + + // (DynamicallyAccessedMemberTypes, Type) + [Export ("doAnother")] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties, typeof (NSObject))] + void DoAnother (); + + // (string, Type) + [Export ("doYetAnother")] + [DynamicDependency ("Create", typeof (NSObject))] + void DoYetAnother (); + + // (DynamicallyAccessedMemberTypes.All, string, string) + [Export ("doAll")] + [DynamicDependency (DynamicallyAccessedMemberTypes.All, "NS.MyClass", "api0")] + void DoAll (); + } +} diff --git a/tests/bindings-test/ProtocolTest.cs b/tests/bindings-test/ProtocolTest.cs index b9d2ae0495e9..f94355ccc85f 100644 --- a/tests/bindings-test/ProtocolTest.cs +++ b/tests/bindings-test/ProtocolTest.cs @@ -46,23 +46,23 @@ public void Constructors () using var dateNow = (NSDate) DateTime.Now; using (var obj = IConstructorProtocol.CreateInstance ("Hello world")!) { - Assert.AreEqual ("Hello world", obj.StringValue, "A StringValue"); - Assert.IsNull (obj.DateValue, "A DateValue"); + Assert.That (obj.StringValue, Is.EqualTo ("Hello world"), "A StringValue"); + Assert.That (obj.DateValue, Is.Null, "A DateValue"); } using (var obj = IConstructorProtocol.CreateInstance (dateNow)!) { - Assert.IsNull (obj.StringValue, "B StringValue"); - Assert.AreEqual (dateNow, obj.DateValue, "B DateValue"); + Assert.That (obj.StringValue, Is.Null, "B StringValue"); + Assert.That (obj.DateValue, Is.EqualTo (dateNow), "B DateValue"); } using (var obj = IConstructorProtocol.CreateInstance ("Hello Subclassed")!) { - Assert.AreEqual ("Hello Subclassed", obj.StringValue, "C1 StringValue"); - Assert.IsNull (obj.DateValue, "C1 DateValue"); + Assert.That (obj.StringValue, Is.EqualTo ("Hello Subclassed"), "C1 StringValue"); + Assert.That (obj.DateValue, Is.Null, "C1 DateValue"); } using (var obj = IConstructorProtocol.CreateInstance (dateNow)!) { - Assert.IsNull (obj.StringValue, "C2 StringValue"); - Assert.AreEqual (dateNow, obj.DateValue, "C2 DateValue"); + Assert.That (obj.StringValue, Is.Null, "C2 StringValue"); + Assert.That (obj.DateValue, Is.EqualTo (dateNow), "C2 DateValue"); } if (global::XamarinTests.ObjCRuntime.Registrar.IsDynamicRegistrar) { @@ -71,8 +71,8 @@ public void Constructors () }, "D1 Exception"); } else { using (var obj = IConstructorProtocol.CreateInstance ("Hello Subclassed 2")!) { - Assert.AreEqual ("Managed interceptor! Hello Subclassed 2", obj.StringValue, "D1 StringValue"); - Assert.IsNull (obj.DateValue, "D1 DateValue"); + Assert.That (obj.StringValue, Is.EqualTo ("Managed interceptor! Hello Subclassed 2"), "D1 StringValue"); + Assert.That (obj.DateValue, Is.Null, "D1 DateValue"); } } @@ -82,8 +82,8 @@ public void Constructors () }, "D2 Exception"); } else { using (var obj = IConstructorProtocol.CreateInstance (dateNow)!) { - Assert.IsNull (obj.StringValue, "D2 StringValue"); - Assert.AreEqual (dateNow.AddSeconds (42), obj.DateValue, "D2 DateValue"); + Assert.That (obj.StringValue, Is.Null, "D2 StringValue"); + Assert.That (obj.DateValue, Is.EqualTo (dateNow.AddSeconds (42)), "D2 DateValue"); } } } @@ -118,27 +118,27 @@ public void OnlyProtocol () // the interface must be created var IP1 = bindingAssembly.GetType ("Bindings.Test.Protocol.IP1")!; - Assert.IsNotNull (IP1, "IP1"); + Assert.That (IP1, Is.Not.Null, "IP1"); // with a [Protocol] attribute var IP1Attributes = IP1.GetCustomAttributes (typeof (ProtocolAttribute), false); if (HasProtocolAttributes) { - Assert.AreEqual (1, IP1Attributes.Length, "[Protocol] IP1"); + Assert.That (IP1Attributes.Length, Is.EqualTo (1), "[Protocol] IP1"); var IP1Protocol = (ProtocolAttribute) IP1Attributes [0]; - Assert.AreEqual ("P1", IP1Protocol.Name, "Name"); + Assert.That (IP1Protocol.Name, Is.EqualTo ("P1"), "Name"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P1Wrapper"); - Assert.IsNotNull (wrapperType, "P1_Wrapper"); - Assert.AreEqual (wrapperType, IP1Protocol.WrapperType, "WrapperType"); + Assert.That (wrapperType, Is.Not.Null, "P1_Wrapper"); + Assert.That (IP1Protocol.WrapperType, Is.EqualTo (wrapperType), "WrapperType"); } else { - Assert.AreEqual (0, IP1Attributes.Length, "[Protocol] IP1"); + Assert.That (IP1Attributes.Length, Is.EqualTo (0), "[Protocol] IP1"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P1Wrapper"); - Assert.IsNotNull (wrapperType, "P1_Wrapper"); + Assert.That (wrapperType, Is.Not.Null, "P1_Wrapper"); } // but not the model - Assert.IsNull (bindingAssembly.GetType ("Bindings.Test.Protocol.P1"), "P1"); + Assert.That (bindingAssembly.GetType ("Bindings.Test.Protocol.P1"), Is.Null, "P1"); } [Test] @@ -150,32 +150,32 @@ public void ProtocolWithBaseType () // the interface must be created var IP2 = bindingAssembly.GetType ("Bindings.Test.Protocol.IP2")!; - Assert.IsNotNull (IP2, "IP2"); + Assert.That (IP2, Is.Not.Null, "IP2"); // with a [Protocol] attribute var IP2Attributes = IP2.GetCustomAttributes (typeof (ProtocolAttribute), false); if (HasProtocolAttributes) { - Assert.AreEqual (1, IP2Attributes.Length, "[Protocol] IP2"); + Assert.That (IP2Attributes.Length, Is.EqualTo (1), "[Protocol] IP2"); var IP2Protocol = (ProtocolAttribute) IP2Attributes [0]; - Assert.AreEqual ("P2", IP2Protocol.Name, "Name"); + Assert.That (IP2Protocol.Name, Is.EqualTo ("P2"), "Name"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P2Wrapper"); - Assert.IsNotNull (wrapperType, "P2_Wrapper"); - Assert.AreEqual (wrapperType, IP2Protocol.WrapperType, "WrapperType"); + Assert.That (wrapperType, Is.Not.Null, "P2_Wrapper"); + Assert.That (IP2Protocol.WrapperType, Is.EqualTo (wrapperType), "WrapperType"); } else { - Assert.AreEqual (0, IP2Attributes.Length, "[Protocol] IP2"); + Assert.That (IP2Attributes.Length, Is.EqualTo (0), "[Protocol] IP2"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P2Wrapper"); - Assert.IsNotNull (wrapperType, "P2_Wrapper"); + Assert.That (wrapperType, Is.Not.Null, "P2_Wrapper"); } // and a model-like class var model = bindingAssembly.GetType ("Bindings.Test.Protocol.P2")!; - Assert.IsNotNull (model, "P2"); + Assert.That (model, Is.Not.Null, "P2"); // but without the [Model] attribute - Assert.False (model.IsDefined (typeof (ModelAttribute), false), "model"); + Assert.That (model.IsDefined (typeof (ModelAttribute), false), Is.False, "model"); } [Test] @@ -187,32 +187,32 @@ public void ProtocolWithBaseTypeAndModel () // the interface must be created var IP3 = bindingAssembly.GetType ("Bindings.Test.Protocol.IP3")!; - Assert.IsNotNull (IP3, "IP3"); + Assert.That (IP3, Is.Not.Null, "IP3"); // with a [Protocol] attribute var IP3Attributes = IP3.GetCustomAttributes (typeof (ProtocolAttribute), false); if (HasProtocolAttributes) { - Assert.AreEqual (1, IP3Attributes.Length, "[Protocol] IP3"); + Assert.That (IP3Attributes.Length, Is.EqualTo (1), "[Protocol] IP3"); var IP3Protocol = (ProtocolAttribute) IP3Attributes [0]; - Assert.AreEqual ("P3", IP3Protocol.Name, "Name"); + Assert.That (IP3Protocol.Name, Is.EqualTo ("P3"), "Name"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P3Wrapper"); - Assert.IsNotNull (wrapperType, "P3_Wrapper"); - Assert.AreEqual (wrapperType, IP3Protocol.WrapperType, "WrapperType"); + Assert.That (wrapperType, Is.Not.Null, "P3_Wrapper"); + Assert.That (IP3Protocol.WrapperType, Is.EqualTo (wrapperType), "WrapperType"); } else { - Assert.AreEqual (0, IP3Attributes.Length, "[Protocol] IP3"); + Assert.That (IP3Attributes.Length, Is.EqualTo (0), "[Protocol] IP3"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P3Wrapper"); - Assert.IsNotNull (wrapperType, "P3_Wrapper"); + Assert.That (wrapperType, Is.Not.Null, "P3_Wrapper"); } // and a model class var model = bindingAssembly.GetType ("Bindings.Test.Protocol.P3")!; - Assert.IsNotNull (model, "P3"); + Assert.That (model, Is.Not.Null, "P3"); // with a [Model] attribute - Assert.True (model.IsDefined (typeof (ModelAttribute), false), "model"); + Assert.That (model.IsDefined (typeof (ModelAttribute), false), Is.True, "model"); } class MembersImplementation : NSObject, Bindings.Test.Protocol.IMemberAttributes { @@ -241,14 +241,14 @@ void CleanupSignatures (objc_method_description [] methods) public void ProtocolMembers () { IntPtr protocol = objc_getProtocol ("MemberAttributes"); - Assert.AreNotEqual (IntPtr.Zero, protocol, "a"); + Assert.That (protocol, Is.Not.EqualTo (IntPtr.Zero), "a"); objc_method_description [] methods; // Required instance methods methods = protocol_copyMethodDescriptionList (protocol, true, true); CleanupSignatures (methods); - Assert.AreEqual (4, methods.Length, "Required Instance Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (4), "Required Instance Methods: Count"); AssertContains (methods, new objc_method_description ("requiredInstanceMethod", "v@:"), "Required Instance Methods: requiredInstanceMethod"); AssertContains (methods, new objc_method_description ("requiredInstanceProperty", "@@:"), "Required Instance Methods: requiredInstanceProperty"); AssertContains (methods, new objc_method_description ("setRequiredInstanceProperty:", "v@:@"), "Required Instance Methods: setRequiredInstanceProperty"); @@ -257,7 +257,7 @@ public void ProtocolMembers () // Required static methods methods = protocol_copyMethodDescriptionList (protocol, true, false); CleanupSignatures (methods); - Assert.AreEqual (3, methods.Length, "Required Static Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (3), "Required Static Methods: Count"); AssertContains (methods, new objc_method_description ("requiredStaticMethod", "v@:"), "Required Static Methods: requiredStaticMethod"); AssertContains (methods, new objc_method_description ("setRequiredStaticProperty:", "v@:@"), "Required Static Methods: setRequiredStaticProperty:"); AssertContains (methods, new objc_method_description ("requiredStaticProperty", "@@:"), "Required Static Methods: requiredStaticProperty"); @@ -265,7 +265,7 @@ public void ProtocolMembers () // Optional instance methods methods = protocol_copyMethodDescriptionList (protocol, false, true); CleanupSignatures (methods); - Assert.AreEqual (19, methods.Length, "Optional Instance Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (19), "Optional Instance Methods: Count"); AssertContains (methods, new objc_method_description ("variadicMethod:", "v@:^v"), "Optional Instance Methods: variadicMethod:"); AssertContains (methods, new objc_method_description ("methodWithReturnType", "@@:"), "Optional Instance Methods: methodWithReturnType"); AssertContains (methods, new objc_method_description ("methodWithParameter:", "v@:i"), "Optional Instance Methods: methodWithParameter:"); @@ -289,7 +289,7 @@ public void ProtocolMembers () // Optional static methods methods = protocol_copyMethodDescriptionList (protocol, false, false); CleanupSignatures (methods); - Assert.AreEqual (3, methods.Length, "Optional Static Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (3), "Optional Static Methods: Count"); AssertContains (methods, new objc_method_description ("optionalStaticMethod", "v@:"), "Optional Static Methods: optionalStaticMethod"); AssertContains (methods, new objc_method_description ("optionalStaticProperty", "@@:"), "Optional Static Methods: optionalStaticProperty"); AssertContains (methods, new objc_method_description ("setOptionalStaticProperty:", "v@:@"), "Optional Static Methods: setOptionalStaticProperty:"); @@ -301,9 +301,9 @@ public void ProtocolMembers () // see file objc4-647/runtime/objc-runtime-old.mm in Apple's open source code), // so we need to verify differently for the dynamic registrar. if (XamarinTests.ObjCRuntime.Registrar.IsStaticRegistrar) { - Assert.AreEqual (9, properties.Length, "Properties: Count"); + Assert.That (properties.Length, Is.EqualTo (9), "Properties: Count"); } else { - Assert.AreEqual (2, properties.Length, "Properties: Count"); + Assert.That (properties.Length, Is.EqualTo (2), "Properties: Count"); } AssertContains (properties, new objc_property ("requiredInstanceProperty", "T@\"NSString\",N", new objc_property_attribute [] { diff --git a/tests/bindings-test/RegistrarBindingTest.cs b/tests/bindings-test/RegistrarBindingTest.cs index 93bba2d9c9e2..fb3cf6821c83 100644 --- a/tests/bindings-test/RegistrarBindingTest.cs +++ b/tests/bindings-test/RegistrarBindingTest.cs @@ -57,7 +57,7 @@ public static void OptionalStaticCallback (Action completionHandler) public Action RequiredReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -65,7 +65,7 @@ public Action RequiredReturnValue () public Action OptionalReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -73,7 +73,7 @@ public Action OptionalReturnValue () public static Action RequiredStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -81,7 +81,7 @@ public static Action RequiredStaticReturnValue () public static Action OptionalStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } } @@ -99,10 +99,10 @@ public void DerivedClassBlockCallback () ObjCBlockTester.CallOptionalStaticCallback (); DerivedBlockCallbackClass.Answer = 2; - Assert.IsFalse (obj.InvokeNullableCallbackNatively (null), "NullableCallback A rv"); + Assert.That (obj.InvokeNullableCallbackNatively (null), Is.False, "NullableCallback A rv"); int nullableResult = -1; - Assert.IsTrue (obj.InvokeNullableCallbackNatively ((v) => nullableResult = v), "NullableCallback B rv"); - Assert.AreEqual (24, nullableResult, "NullableCallback result"); + Assert.That (obj.InvokeNullableCallbackNatively ((v) => nullableResult = v), Is.True, "NullableCallback B rv"); + Assert.That (nullableResult, Is.EqualTo (24), "NullableCallback result"); } } @@ -141,7 +141,7 @@ public static void OptionalStaticCallback (Action completionHandler) public override Action RequiredReturnValue () { return new Action ((v) => { - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } @@ -150,7 +150,7 @@ public Action OptionalReturnValue () { return new Action ((v) => { Console.WriteLine ("OptionalReturnValue"); - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } @@ -158,7 +158,7 @@ public Action OptionalReturnValue () public static Action RequiredStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } @@ -167,7 +167,7 @@ public static Action OptionalStaticReturnValue () { return new Action ((v) => { Console.WriteLine ("OptionalStaticReturnValue"); - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } } @@ -201,7 +201,7 @@ public static void OptionalRequiredCallback (Action completionHandler) Action IObjCProtocolBlockTest.RequiredReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -209,7 +209,7 @@ Action IObjCProtocolBlockTest.RequiredReturnValue () public Action OptionalReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -217,7 +217,7 @@ public Action OptionalReturnValue () public static Action RequiredStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -225,7 +225,7 @@ public static Action RequiredStaticReturnValue () public static Action OptionalStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } } @@ -311,7 +311,7 @@ public void ProtocolWithBlockProperties (bool required, bool instance) } } ObjCBlockTester.CallProtocolWithBlockProperties (pb, required, instance); - Assert.IsTrue (callbackCalled, "Callback"); + Assert.That (callbackCalled, Is.True, "Callback"); } } @@ -338,7 +338,7 @@ public void ProtocolWithNativeBlockProperties (bool required, bool instance) PropertyBlock.MyOptionalStaticProperty! (); } } - Assert.AreEqual (calledCounter + 1, ObjCBlockTester.CalledBlockCount, "Blocks called"); + Assert.That (ObjCBlockTester.CalledBlockCount, Is.EqualTo (calledCounter + 1), "Blocks called"); } } [Test] @@ -372,7 +372,7 @@ public void LinkedAway (bool required, bool instance) if (re.Code == 8009) { Assert.That (re.Message, Does.StartWith ("Unable to locate the block to delegate conversion method for the method Xamarin.BindingTests.RegistrarBindingTest+FakePropertyBlock.set_"), re.Message, "Message"); } else { - Assert.AreEqual ("The runtime function get_block_wrapper_creator has been linked away.", re.Message, "Message"); + Assert.That (re.Message, Is.EqualTo ("The runtime function get_block_wrapper_creator has been linked away."), "Message"); } } } diff --git a/tests/bindings-test/RuntimeTest.cs b/tests/bindings-test/RuntimeTest.cs index aea647585f60..f445ec7bca9e 100644 --- a/tests/bindings-test/RuntimeTest.cs +++ b/tests/bindings-test/RuntimeTest.cs @@ -9,7 +9,7 @@ public class RuntimeTest { [Test] public void GlobalStringTest () { - Assert.AreEqual ("There's nothing cruvus here!", (string) Globals.GlobalString, "Global string"); + Assert.That ((string) Globals.GlobalString, Is.EqualTo ("There's nothing cruvus here!"), "Global string"); } [Test] @@ -95,7 +95,7 @@ public void SwiftTest () { TestRuntime.AssertXcodeVersion (13, 0); using var obj = new SwiftTestClass (); - Assert.AreEqual ("Hello from Swift", obj.SayHello (), "Hello"); + Assert.That (obj.SayHello (), Is.EqualTo ("Hello from Swift"), "Hello"); } [Test] @@ -105,18 +105,18 @@ public void SwiftTypeEncodings () using var obj = new SwiftTestClass (); - Assert.AreEqual ("42", obj.DoSomething ("42"), "DoSomething"); + Assert.That (obj.DoSomething ("42"), Is.EqualTo ("42"), "DoSomething"); string? asyncResult = null; obj.DoSomethingAsync ("dolphins", (v) => asyncResult = v); var done = TestRuntime.RunAsync (TimeSpan.FromSeconds (5), () => asyncResult is not null); - Assert.AreEqual ("dolphins", asyncResult, "DoSomethingAsync"); - Assert.IsTrue (done, "Done"); + Assert.That (asyncResult, Is.EqualTo ("dolphins"), "DoSomethingAsync"); + Assert.That (done, Is.True, "Done"); obj.DoSomethingComplexAsync ("fish", IntPtr.Zero, (v) => asyncResult = v); done = TestRuntime.RunAsync (TimeSpan.FromSeconds (5), () => asyncResult is not null); - Assert.AreEqual ("fish", asyncResult, "DoSomethingComplexAsync"); - Assert.IsTrue (done, "Done 2"); + Assert.That (asyncResult, Is.EqualTo ("fish"), "DoSomethingComplexAsync"); + Assert.That (done, Is.True, "Done 2"); } [Test] @@ -124,7 +124,7 @@ public void SwiftTestClass2 () { TestRuntime.AssertXcodeVersion (13, 0); using var obj = new SwiftTestClass2 (); - Assert.AreEqual ("Hello from Swift 2", obj.SayHello2 (), "Hello"); + Assert.That (obj.SayHello2 (), Is.EqualTo ("Hello from Swift 2"), "Hello"); } [Test] diff --git a/tests/bindings-test2/BindingTest.cs b/tests/bindings-test2/BindingTest.cs index 7da68e8bbfc5..803e3bf91624 100644 --- a/tests/bindings-test2/BindingTest.cs +++ b/tests/bindings-test2/BindingTest.cs @@ -9,8 +9,8 @@ public class BindingTest { [Test] public void Test () { - Assert.AreEqual (42, CFunctions.getIntOfChocolate (), "chocolate"); - Assert.AreEqual (42, Bindings.Test.CFunctions.theUltimateAnswer (), "theUltimateAnswer"); + Assert.That (CFunctions.getIntOfChocolate (), Is.EqualTo (42), "chocolate"); + Assert.That (Bindings.Test.CFunctions.theUltimateAnswer (), Is.EqualTo (42), "theUltimateAnswer"); } } } diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt index 259d2d5ebdf1..9e1603a34248 100644 --- a/tests/cecil-tests/Documentation.KnownFailures.txt +++ b/tests/cecil-tests/Documentation.KnownFailures.txt @@ -25152,7 +25152,6 @@ T:AppKit.NSPrintingPageOrder T:AppKit.NSPrintingPaginationMode T:AppKit.NSPrintPanelOptions T:AppKit.NSPrintPanelResult -T:AppKit.NSPrintPreviewGraphicsContext T:AppKit.NSPrintRenderingQuality T:AppKit.NSProgressIndicatorStyle T:AppKit.NSProgressIndicatorThickness diff --git a/tests/common/Assert.cs b/tests/common/Assert.cs index 5f1b7bb0f344..e16866ee8362 100644 --- a/tests/common/Assert.cs +++ b/tests/common/Assert.cs @@ -92,7 +92,7 @@ protected virtual void SetUp () public static void Assert (string msg, bool condition) { - NUnit.Framework.Assert.True (condition, msg); + Assert.That (condition, Is.True, msg); } public static void AssertEquals (object a, object b) diff --git a/tests/common/AssertHelpers.cs b/tests/common/AssertHelpers.cs index cb4aba3fe4ca..4975c7d26110 100644 --- a/tests/common/AssertHelpers.cs +++ b/tests/common/AssertHelpers.cs @@ -11,7 +11,7 @@ public static void Throws (Action action, string expectedExceptionMessage, st action (); throw new AssertionException (string.Format ("Expected {0}, but no exception was thrown. {1}.", typeof (T).FullName, message)); } catch (T ex) { - Assert.AreEqual (expectedExceptionMessage, ex.Message, message); + Assert.That (ex.Message, Is.EqualTo (expectedExceptionMessage), message); } } diff --git a/tests/common/BinLog.cs b/tests/common/BinLog.cs index f02f5123bfec..e8afbc729d96 100644 --- a/tests/common/BinLog.cs +++ b/tests/common/BinLog.cs @@ -210,6 +210,9 @@ public static IEnumerable GetBuildLogWarnings (string path) .Where (v => v.Type == BuildLogEventType.Warning) // We're often referencing earlier .NET projects (Touch.Unit/MonoTouch.Dialog), so ignore any out-of-support warnings. .Where (v => v.Message?.Contains ("is out of support and will not receive security updates in the future") != true) + // Ignore any messages about the settings files, we get *a lot* of those + .Where (v => !(v.Message?.Contains ("The settings file '/Users/") == true && v.Message?.Contains ("/Library/Preferences/maui/Settings.plist' is deprecated, and will be ignored in .NET 11+. ") == true)) + .Where (v => !(v.Message?.Contains ("The settings file '/Users/") == true && v.Message?.Contains ("/Library/Preferences/Xamarin/Settings.plist' is deprecated, and will be ignored in .NET 11+. ") == true)) ; } diff --git a/tests/common/BundlerTool.cs b/tests/common/BundlerTool.cs index 7a5754620653..3f45c28b1bf7 100644 --- a/tests/common/BundlerTool.cs +++ b/tests/common/BundlerTool.cs @@ -321,7 +321,7 @@ public virtual void AssertExecute (string message = null) public void AssertExecuteFailure (string message = null) { - Assert.AreEqual (1, Execute (), message); + Assert.That (Execute (), Is.EqualTo (1), message); } public abstract void CreateTemporaryApp (Profile profile, string appName = "testApp", string code = null, IList extraArgs = null, string extraCode = null, string usings = null); diff --git a/tests/common/Configuration.cs b/tests/common/Configuration.cs index 3e048d52eab1..8154d4e9b100 100644 --- a/tests/common/Configuration.cs +++ b/tests/common/Configuration.cs @@ -694,7 +694,7 @@ public static void SetBuildVariables (ApplePlatform platform, [NotNullIfNotNull if (environment is null) environment = new Dictionary (); - environment ["MD_APPLE_SDK_ROOT"] = Path.GetDirectoryName (Path.GetDirectoryName (xcode_root)!)!; + environment ["DEVELOPER_DIR"] = Path.GetDirectoryName (Path.GetDirectoryName (xcode_root)!)!; // This is set by `dotnet test` and can cause building legacy projects to fail to build with: // Microsoft.NET.Build.Extensions.ConflictResolution.targets(30,5): diff --git a/tests/common/ErrorHelper.tests.cs b/tests/common/ErrorHelper.tests.cs index eb2c7d952b10..495ed26053ff 100644 --- a/tests/common/ErrorHelper.tests.cs +++ b/tests/common/ErrorHelper.tests.cs @@ -3,6 +3,7 @@ #nullable enable using System.Linq; +using System.Runtime.CompilerServices; using Mono.Cecil; using Mono.Cecil.Cil; @@ -13,10 +14,9 @@ namespace Xamarin.Bundler { public static partial class ErrorHelper { public static ApplePlatform Platform; - internal static string Prefix { - get { - return "TESTS"; - } + internal static string GetPrefix (IToolLog? log) + { + return "TESTS"; } public enum WarningLevel { @@ -25,33 +25,32 @@ public enum WarningLevel { Disable = 1, } - static Dictionary? warning_levels; + static ConditionalWeakTable> warning_levels = new (); - public static WarningLevel GetWarningLevel (int code) + public static WarningLevel GetWarningLevel (IToolLog log, int code) { - WarningLevel level; - - if (warning_levels is null) - return WarningLevel.Warning; + if (warning_levels.TryGetValue (log, out var log_warning_levels)) { + // code -1: all codes + if (log_warning_levels.TryGetValue (-1, out var level)) + return level; - // code -1: all codes - if (warning_levels.TryGetValue (-1, out level)) - return level; - - if (warning_levels.TryGetValue (code, out level)) - return level; + if (log_warning_levels.TryGetValue (code, out level)) + return level; + } return WarningLevel.Warning; } - public static void SetWarningLevel (WarningLevel level, int? code = null /* if null, apply to all warnings */) + public static void SetWarningLevel (IToolLog log, WarningLevel level, int? code = null /* if null, apply to all warnings */) { - if (warning_levels is null) - warning_levels = new Dictionary (); + if (!warning_levels.TryGetValue (log, out var log_warning_levels)) { + log_warning_levels = new Dictionary (); + warning_levels.Add (log, log_warning_levels); + } if (code.HasValue) { - warning_levels [code.Value] = level; + log_warning_levels [code.Value] = level; } else { - warning_levels [-1] = level; // code -1: all codes. + log_warning_levels [-1] = level; // code -1: all codes. } } } diff --git a/tests/common/ProductTests.cs b/tests/common/ProductTests.cs index ec1d1bc53569..8d4a4d3d1063 100644 --- a/tests/common/ProductTests.cs +++ b/tests/common/ProductTests.cs @@ -71,7 +71,7 @@ public void MinOSVersion (Profile profile, MachO.LoadCommands load_command, Mach Version lc_min_version; var mincmd = lc as MinCommand; if (mincmd is not null) { - Assert.AreEqual (load_command, mincmd.Command, "Unexpected min load command"); + Assert.That (mincmd.Command, Is.EqualTo (load_command), "Unexpected min load command"); lc_min_version = mincmd.Version; } else { // starting from iOS SDK 12 the LC_BUILD_VERSION is used instead @@ -159,7 +159,7 @@ public void MinOSVersion (Profile profile, MachO.LoadCommands load_command, Mach failed.Add ($"No minOS version found in {machoFile}."); } } - CollectionAssert.IsEmpty (failed, "Failures"); + Assert.That (failed, Is.Empty, "Failures"); } } diff --git a/tests/common/TestRuntime.cs b/tests/common/TestRuntime.cs index 68ab6699c66b..f7a8394faf62 100644 --- a/tests/common/TestRuntime.cs +++ b/tests/common/TestRuntime.cs @@ -210,7 +210,7 @@ public static void AssertXcodeVersion (int major, int minor, int build = 0) if (CheckXcodeVersion (major, minor, build)) return; - NUnit.Framework.Assert.Ignore ("Requires the platform version shipped with Xcode {0}.{1}", major, minor); + NUnit.Framework.Assert.Ignore ($"Requires the platform version shipped with Xcode {major}.{minor}"); } public static void AssertDevice (string message = "This test only runs on device.") @@ -299,12 +299,10 @@ public static void AssertSimulatorOrDesktop (string message = "This test only wo public static void AssertNotVirtualMachine () { -#if MONOMAC || __MACCATALYST__ // enviroment variable set by the CI when running on a VM var vmVendor = Environment.GetEnvironmentVariable ("VM_VENDOR"); if (!string.IsNullOrEmpty (vmVendor)) NUnit.Framework.Assert.Ignore ($"This test only runs on device. Found vm vendor: {vmVendor}"); -#endif } public static bool IsVSTS => @@ -1625,6 +1623,7 @@ public static void IgnoreInCIIfBadNetwork (Exception? ex) IgnoreInCIIfDnsResolutionFailed (ex); IgnoreInCIIfSshConnectionError (ex); IgnoreInCIIfTimedOut (ex); + IgnoreInCIIfHttpClientTimedOut (ex); } public static void IgnoreInCIIfBadNetwork (NSError? error) @@ -1666,6 +1665,26 @@ public static void IgnoreInCIIfTimedOut (NSError error) IgnoreNetworkError (error, CFNetworkErrors.TimedOut); } + public static void IgnoreInCIIfHttpClientTimedOut () + { + IgnoreInCI ("Ignored due to HTTP client timeout."); + } + + public static void IgnoreInCIIfHttpClientTimedOut (Exception? ex) + { + if (ex is null) + return; + + var tce = FindInner (ex); + if (tce is null) + return; + + if (FindInner (tce) is not null || + tce.Message.Contains ("HttpClient.Timeout", StringComparison.Ordinal)) { + IgnoreInCI ($"Ignored due to HTTP client timeout: {tce.Message}"); + } + } + public static void IgnoreInCIIfTimedOut (Exception ex) { if (ex is WebException wex) { @@ -1867,7 +1886,7 @@ public static void AssertNoNonNUnitException (Exception ex, string message) case InconclusiveException: throw new InconclusiveException (ex.Message, ex); case ResultStateException: throw ex; default: - Assert.IsNull (ex, message); + Assert.That (ex, Is.Null, message); break; } } diff --git a/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs b/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs index 880741dcc9a2..c9f1ef8af194 100644 --- a/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs +++ b/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs @@ -32,7 +32,7 @@ namespace MonoTouch.NUnit.UI { class TestResultElement : StyledMultilineElement { public TestResultElement (TestResult result) : - base (result.Message ?? "Unknown error", result.StackTrace, UITableViewCellStyle.Subtitle) + base (result.Message ?? "Unknown error", result.StackTrace ?? "", UITableViewCellStyle.Subtitle) { } } diff --git a/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs b/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs index a2a873e133e8..1c23046fb905 100644 --- a/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs +++ b/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs @@ -568,8 +568,8 @@ public virtual void TestFinished (ITestResult r) #endif string? stacktrace = result.StackTrace; - if (!String.IsNullOrEmpty (result.StackTrace)) { - string [] lines = stacktrace.Split (new char [] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (!String.IsNullOrEmpty (stacktrace)) { + string [] lines = stacktrace!.Split (new char [] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) writer.WriteLine ("\t\t{0}", line); } @@ -689,9 +689,11 @@ public void Run (Test test) var tsr = new TestSuiteResult (suite); foreach (var runner in runners) { - var rv = (TestResult) (find_result (runner.Result) ?? runner.Result); - if (rv is not null) - tsr.AddResult (rv); + var runnerResult = runner.Result is not null ? (find_result (runner.Result) ?? runner.Result) : null; + if (runnerResult is null) + continue; + var rv = (TestResult) runnerResult; + tsr.AddResult (rv); } Result = tsr; #else diff --git a/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj b/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj index ada75cd79283..97edb9f41e74 100644 --- a/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj +++ b/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj @@ -55,10 +55,10 @@ - 3.12.0 + $(NUnitLitePackageVersion) - 3.6.0 + $(NUnitV2ResultWriterPackageVersion) 6.12.0.148 diff --git a/tests/common/shared-dotnet.csproj b/tests/common/shared-dotnet.csproj index 06243b83489f..27ee7da59ae3 100644 --- a/tests/common/shared-dotnet.csproj +++ b/tests/common/shared-dotnet.csproj @@ -80,6 +80,11 @@ $(DefineConstants);NATIVEAOT false + + true + false @@ -101,13 +106,17 @@ true + + true + + - + @@ -126,6 +135,11 @@ $(DefineConstants);NATIVEAOT false + + true + false + true + <_IsPublishing>true + full + + strict + $(DefineConstants);STATIC_NATIVE_SYMBOL_LOOKUP + + strict + managed-static + + <_TestVariationApplied>true + + partial <_TestVariationApplied>true @@ -161,6 +179,17 @@ $(DefineConstants);STATIC_NATIVE_SYMBOL_LOOKUP + + compatibility + <_TestVariationApplied>true + + + + strict + managed-static + <_TestVariationApplied>true + + <_InvalidTestVariations Include="$(TestVariation.Split('|'))" Exclude="@(TestVariations)" /> diff --git a/tests/dotnet/AppWithComposerIcon/AppDelegate.cs b/tests/dotnet/AppWithComposerIcon/AppDelegate.cs new file mode 100644 index 000000000000..13cf28d17265 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/AppDelegate.cs @@ -0,0 +1,35 @@ +using System; +using Foundation; + +#if !__MACOS__ +using UIKit; +#endif + +#nullable enable + +namespace AppWithComposerIcon { +#if !(__MACCATALYST__ || __MACOS__) + public class AppDelegate : UIApplicationDelegate { + public override bool FinishedLaunching (UIApplication app, NSDictionary? options) + { + return true; + } + } +#endif + + public class Program { + static int Main (string [] args) + { +#if __MACCATALYST__ || __MACOS__ +GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly + +Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD")); + +return args.Length; +#else + UIApplication.Main (args, null, typeof (AppDelegate)); + return 0; +#endif + } + } +} diff --git a/tests/dotnet/AppWithComposerIcon/MacCatalyst/AppWithComposerIcon.csproj b/tests/dotnet/AppWithComposerIcon/MacCatalyst/AppWithComposerIcon.csproj new file mode 100644 index 000000000000..6b0e2c773180 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/MacCatalyst/AppWithComposerIcon.csproj @@ -0,0 +1,7 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst + + + diff --git a/tests/dotnet/AppWithComposerIcon/MacCatalyst/Makefile b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/Assets/back.png b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/Assets/back.png new file mode 100644 index 000000000000..00c6bc6118f0 Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/Assets/back.png differ diff --git a/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/Assets/front.png b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/Assets/front.png new file mode 100644 index 000000000000..6dc4283df45a Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/Assets/front.png differ diff --git a/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/icon.json b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/icon.json new file mode 100644 index 000000000000..9cb9eee03bd1 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/MacCatalyst/Resources/AppIcon.icon/icon.json @@ -0,0 +1,16 @@ +{ + "groups" : [ + { + "layers" : [ + { + "image-name" : "back.png", + "name" : "back" + }, + { + "image-name" : "front.png", + "name" : "front" + } + ] + } + ] +} diff --git a/tests/dotnet/AppWithComposerIcon/iOS/AppWithComposerIcon.csproj b/tests/dotnet/AppWithComposerIcon/iOS/AppWithComposerIcon.csproj new file mode 100644 index 000000000000..86d408734aa8 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/iOS/AppWithComposerIcon.csproj @@ -0,0 +1,7 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-ios + + + diff --git a/tests/dotnet/AppWithComposerIcon/iOS/Makefile b/tests/dotnet/AppWithComposerIcon/iOS/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/iOS/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/Assets/back.png b/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/Assets/back.png new file mode 100644 index 000000000000..00c6bc6118f0 Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/Assets/back.png differ diff --git a/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/Assets/front.png b/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/Assets/front.png new file mode 100644 index 000000000000..6dc4283df45a Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/Assets/front.png differ diff --git a/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/icon.json b/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/icon.json new file mode 100644 index 000000000000..9cb9eee03bd1 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/iOS/Resources/AppIcon.icon/icon.json @@ -0,0 +1,16 @@ +{ + "groups" : [ + { + "layers" : [ + { + "image-name" : "back.png", + "name" : "back" + }, + { + "image-name" : "front.png", + "name" : "front" + } + ] + } + ] +} diff --git a/tests/dotnet/AppWithComposerIcon/macOS/AppWithComposerIcon.csproj b/tests/dotnet/AppWithComposerIcon/macOS/AppWithComposerIcon.csproj new file mode 100644 index 000000000000..a77287b9ba00 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/macOS/AppWithComposerIcon.csproj @@ -0,0 +1,7 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-macos + + + diff --git a/tests/dotnet/AppWithComposerIcon/macOS/Makefile b/tests/dotnet/AppWithComposerIcon/macOS/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/macOS/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/Assets/back.png b/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/Assets/back.png new file mode 100644 index 000000000000..00c6bc6118f0 Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/Assets/back.png differ diff --git a/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/Assets/front.png b/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/Assets/front.png new file mode 100644 index 000000000000..6dc4283df45a Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/Assets/front.png differ diff --git a/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/icon.json b/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/icon.json new file mode 100644 index 000000000000..9cb9eee03bd1 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/macOS/Resources/AppIcon.icon/icon.json @@ -0,0 +1,16 @@ +{ + "groups" : [ + { + "layers" : [ + { + "image-name" : "back.png", + "name" : "back" + }, + { + "image-name" : "front.png", + "name" : "front" + } + ] + } + ] +} diff --git a/tests/dotnet/AppWithComposerIcon/shared.csproj b/tests/dotnet/AppWithComposerIcon/shared.csproj new file mode 100644 index 000000000000..702960b9dd8e --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/shared.csproj @@ -0,0 +1,23 @@ + + + + Exe + + AppWithComposerIcon + com.xamarin.appwithcomposericon + + true + + + + + + AppIcon + + + + + + + + diff --git a/tests/dotnet/AppWithComposerIcon/shared.mk b/tests/dotnet/AppWithComposerIcon/shared.mk new file mode 100644 index 000000000000..de0244100278 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/shared.mk @@ -0,0 +1,3 @@ +TOP=../../../.. +TESTNAME=AppWithComposerIcon +include $(TOP)/tests/common/shared-dotnet.mk diff --git a/tests/dotnet/AppWithComposerIcon/tvOS/AppWithComposerIcon.csproj b/tests/dotnet/AppWithComposerIcon/tvOS/AppWithComposerIcon.csproj new file mode 100644 index 000000000000..bd487ddcd88d --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/tvOS/AppWithComposerIcon.csproj @@ -0,0 +1,7 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-tvos + + + diff --git a/tests/dotnet/AppWithComposerIcon/tvOS/Makefile b/tests/dotnet/AppWithComposerIcon/tvOS/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/tvOS/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/Assets/back.png b/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/Assets/back.png new file mode 100644 index 000000000000..00c6bc6118f0 Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/Assets/back.png differ diff --git a/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/Assets/front.png b/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/Assets/front.png new file mode 100644 index 000000000000..6dc4283df45a Binary files /dev/null and b/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/Assets/front.png differ diff --git a/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/icon.json b/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/icon.json new file mode 100644 index 000000000000..9cb9eee03bd1 --- /dev/null +++ b/tests/dotnet/AppWithComposerIcon/tvOS/Resources/AppIcon.icon/icon.json @@ -0,0 +1,16 @@ +{ + "groups" : [ + { + "layers" : [ + { + "image-name" : "back.png", + "name" : "back" + }, + { + "image-name" : "front.png", + "name" : "front" + } + ] + } + ] +} diff --git a/tests/dotnet/ContentWithPublishFolderType/AppDelegate.cs b/tests/dotnet/ContentWithPublishFolderType/AppDelegate.cs new file mode 100644 index 000000000000..b99d6adb454a --- /dev/null +++ b/tests/dotnet/ContentWithPublishFolderType/AppDelegate.cs @@ -0,0 +1,12 @@ +using System; +using Foundation; + +namespace ContentWithPublishFolderType { + public class Program { + static int Main (string [] args) + { + GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly + return 0; + } + } +} diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/.gitignore b/tests/dotnet/ContentWithPublishFolderType/helper/.gitignore new file mode 100644 index 000000000000..9a16fc334d87 --- /dev/null +++ b/tests/dotnet/ContentWithPublishFolderType/helper/.gitignore @@ -0,0 +1,2 @@ +# Override root .gitignore to allow test DLL files +!*.dll diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/HeartBeatHandlerMac.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/HeartBeatHandlerMac.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.CSharp.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.CSharp.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/AsyncIO.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/AsyncIO.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/HeartbeatHandlerLib.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/HeartbeatHandlerLib.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/System.ServiceModel.Security.dll b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/System.ServiceModel.Security.dll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/libclrgc.dylib b/tests/dotnet/ContentWithPublishFolderType/helper/SubApp.app/Contents/MonoBundle/libclrgc.dylib new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/ContentWithPublishFolderType/macOS/ContentWithPublishFolderType.csproj b/tests/dotnet/ContentWithPublishFolderType/macOS/ContentWithPublishFolderType.csproj new file mode 100644 index 000000000000..f72ebb8816e7 --- /dev/null +++ b/tests/dotnet/ContentWithPublishFolderType/macOS/ContentWithPublishFolderType.csproj @@ -0,0 +1,22 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-macos + Exe + ContentWithPublishFolderType + com.xamarin.contentwithpublishfoldertype + + + + + + + + + + + RootDirectory + Contents/SharedSupport/%(RecursiveDir)%(Filename)%(Extension) + + + diff --git a/tests/dotnet/UnitTests/AppIconTest.cs b/tests/dotnet/UnitTests/AppIconTest.cs index 970676172b53..a5eb8dc0d9c3 100644 --- a/tests/dotnet/UnitTests/AppIconTest.cs +++ b/tests/dotnet/UnitTests/AppIconTest.cs @@ -672,5 +672,39 @@ void TestXCAssetsImpl (ApplePlatform platform, string runtimeIdentifiers, Dictio throw; } } + + [TestCase (ApplePlatform.iOS, "iossimulator-arm64")] + [TestCase (ApplePlatform.TVOS, "tvossimulator-arm64")] + [TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64")] + [TestCase (ApplePlatform.MacOSX, "osx-arm64")] + public void ComposerIcon (ApplePlatform platform, string runtimeIdentifiers) + { + Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers); + Configuration.IgnoreIfIgnoredPlatform (platform); + + var project = "AppWithComposerIcon"; + var projectPath = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath); + Clean (projectPath); + + var properties = GetDefaultProperties (runtimeIdentifiers); + DotNet.Execute ("build", projectPath, properties); + + var resourcesDirectory = GetResourcesDirectory (platform, appPath); + + // Verify that the raw .icon files are not in the app bundle as BundleResources + var iconJsonInBundle = Path.Combine (resourcesDirectory, "AppIcon.icon", "icon.json"); + Assert.That (iconJsonInBundle, Does.Not.Exist, "icon.json should not be in the app bundle as a raw BundleResource"); + + var frontPngInBundle = Path.Combine (resourcesDirectory, "AppIcon.icon", "Assets", "front.png"); + Assert.That (frontPngInBundle, Does.Not.Exist, "front.png should not be in the app bundle as a raw BundleResource"); + + var backPngInBundle = Path.Combine (resourcesDirectory, "AppIcon.icon", "Assets", "back.png"); + Assert.That (backPngInBundle, Does.Not.Exist, "back.png should not be in the app bundle as a raw BundleResource"); + + // Verify that the compiled asset catalog exists in the app bundle + var assetsCar = Path.Combine (resourcesDirectory, "Assets.car"); + Assert.That (assetsCar, Does.Exist, "Assets.car"); + } } } + diff --git a/tests/dotnet/UnitTests/AppSizeTest.cs b/tests/dotnet/UnitTests/AppSizeTest.cs index 33ab7cbcefe5..b5078291ccd3 100644 --- a/tests/dotnet/UnitTests/AppSizeTest.cs +++ b/tests/dotnet/UnitTests/AppSizeTest.cs @@ -131,7 +131,8 @@ void Run (ApplePlatform platform, string runtimeIdentifiers, string configuratio DotNet.AssertBuild (project_path, properties); // FORCE_UPDATE_KNOWN_FAILURES will update the known failures files even if the test doesn't actually fail - // WRITE_KNOWN_FAILURES will only update the known failures files if the test fails + // WRITE_KNOWN_FAILURES will only update the known failures files if the test fails (and mark the test as passed) + // If neither is set, the updated expected file is uploaded as an Azure DevOps artifact. var forceUpdate = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("FORCE_UPDATE_KNOWN_FAILURES")); var update = forceUpdate || !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("WRITE_KNOWN_FAILURES")); @@ -184,30 +185,21 @@ static void AssertAppSize (ApplePlatform platform, string name, string appPath, msg = $"App size changed significantly ({FormatBytes (appSizeDifference, true)} different > tolerance of +-{FormatBytes (toleranceInBytes)}). Expected app size: {FormatBytes (expectedAppBundleSize)}, actual app size: {FormatBytes (appBundleSize)}."; } - var updated = false; - if (forceUpdate || (update && !withinTolerance)) { - Directory.CreateDirectory (expectedDirectory); - File.WriteAllText (expectedSizeReportPath, report.ToString ()); - msg += " Check the modified files for more information."; - updated = true; - } else if (!withinTolerance) { - msg += " Set the environment variable WRITE_KNOWN_FAILURES=1, run the test again, and verify the modified files for more information."; - } - Console.WriteLine ($" {msg}"); + // Compare individual files in the app bundle var expectedLines = expectedSizeReport.SplitLines ().Skip (2).Where (v => v.IndexOf (':') >= 0).ToDictionary (v => v [..v.IndexOf (':')], v => v [(v.IndexOf (':') + 1)..]); var actualLines = report.ToString ().SplitLines ().Skip (2).Where (v => v.IndexOf (':') >= 0).ToDictionary (v => v [..v.IndexOf (':')], v => v [(v.IndexOf (':') + 1)..]); var allKeys = expectedLines.Keys.Union (actualLines.Keys).OrderBy (v => v); + var filesAdded = new List (); + var filesRemoved = new List (); foreach (var key in allKeys) { if (!expectedLines.TryGetValue (key, out var expectedLine)) { Console.WriteLine ($" File '{key}' was added to app bundle: {actualLines [key]}"); - if (!updated) - Assert.Fail ($"The file '{key}' was added to the app bundle."); + filesAdded.Add (key); } else if (!actualLines.TryGetValue (key, out var actualLine)) { Console.WriteLine ($" File '{key}' was removed from app bundle: {expectedLine}"); - if (!updated) - Assert.Fail ($"The file '{key}' was removed from the app bundle."); + filesRemoved.Add (key); } else if (expectedLine != actualLine) { Console.WriteLine ($" File '{key}' changed in app bundle:"); Console.WriteLine ($" -{expectedLine}"); @@ -215,8 +207,28 @@ static void AssertAppSize (ApplePlatform platform, string name, string appPath, } } - if (!updated && !withinTolerance) - Assert.Fail (msg); + // Determine if there are any meaningful differences + var hasFileDifferences = filesAdded.Count > 0 || filesRemoved.Count > 0; + var hasSizeDifference = !withinTolerance; + var hasDifferences = hasFileDifferences || hasSizeDifference; + + if (forceUpdate || (update && hasDifferences)) { + Directory.CreateDirectory (expectedDirectory); + File.WriteAllText (expectedSizeReportPath, report.ToString ()); + Console.WriteLine ($" Updated expected file: {expectedSizeReportPath}"); + } else if (hasDifferences) { + UploadUpdatedExpectedFile (expectedSizeReportPath, report.ToString ()); + var updateHint = GetUpdateHint (); + if (hasFileDifferences) { + var details = new List (); + foreach (var key in filesAdded) + details.Add ($"added: '{key}'"); + foreach (var key in filesRemoved) + details.Add ($"removed: '{key}'"); + Assert.Fail ($"The app bundle's file list changed ({string.Join (", ", details)}). {updateHint}"); + } + Assert.Fail ($"{msg} {updateHint}"); + } } // Create a file with all the APIs that survived the trimmer; this can be useful to determine what is not trimmed away. @@ -255,11 +267,38 @@ void AssertAssemblyReport (ApplePlatform platform, string name, string appPath, } if (!update) { - Assert.That (addedAPIs, Is.Empty, "No added APIs (set the environment variable WRITE_KNOWN_FAILURES=1 and run the test again to update the expected set of APIs)"); - Assert.That (removedAPIs, Is.Empty, "No removed APIs (set the environment variable WRITE_KNOWN_FAILURES=1 and run the test again to update the expected set of APIs)"); + if (addedAPIs.Count > 0 || removedAPIs.Count > 0) { + UploadUpdatedExpectedFile (expectedFile, string.Join ('\n', preservedAPIs) + "\n"); + var updateHint = " " + GetUpdateHint (); + Assert.That (addedAPIs, Is.Empty, "Unexpected APIs were added to the preserved set." + updateHint); + Assert.That (removedAPIs, Is.Empty, "APIs were unexpectedly removed from the preserved set." + updateHint); + } } } + static void UploadUpdatedExpectedFile (string expectedFilePath, string content) + { + var fileName = Path.GetFileName (expectedFilePath); + var artifactStagingDir = Environment.GetEnvironmentVariable ("BUILD_ARTIFACTSTAGINGDIRECTORY"); + string outputDir; + if (!string.IsNullOrEmpty (artifactStagingDir)) { + outputDir = Path.Combine (artifactStagingDir, "updated-expected-sizes"); + } else { + outputDir = Path.Combine (Cache.CreateTemporaryDirectory ("AppSizeTest"), "updated-expected-sizes"); + } + Directory.CreateDirectory (outputDir); + var outputFile = Path.Combine (outputDir, fileName); + File.WriteAllText (outputFile, content); + Console.WriteLine ($" Updated expected file written to: {outputFile}"); + } + + static string GetUpdateHint () + { + if (IsInCI) + return "The updated expected file is available as a build artifact (set WRITE_KNOWN_FAILURES=1 to update locally)."; + return "Set WRITE_KNOWN_FAILURES=1 to update the expected files in-place."; + } + static string FormatBytes (long bytes, bool alwaysShowSign = false) { return $"{(alwaysShowSign && bytes > 0 ? "+" : "")}{bytes:N0} bytes ({bytes / 1024.0:N1} KB = {bytes / (1024.0 * 1024.0):N1} MB)"; diff --git a/tests/dotnet/UnitTests/ContentWithPublishFolderTypeTest.cs b/tests/dotnet/UnitTests/ContentWithPublishFolderTypeTest.cs new file mode 100644 index 000000000000..edd961ca624c --- /dev/null +++ b/tests/dotnet/UnitTests/ContentWithPublishFolderTypeTest.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Xamarin.Tests { + [TestFixture] + public class ContentWithPublishFolderTypeTest : TestBaseClass { + + [Test] + [TestCase (ApplePlatform.MacOSX, "osx-arm64")] + public void ContentFilesWithSdkAssemblyNamesAreIncluded (ApplePlatform platform, string runtimeIdentifiers) + { + // Regression test for https://github.com/dotnet/macios/issues/25497 + // When Content items have PublishFolderType=RootDirectory and filenames matching + // SDK assemblies (e.g., Microsoft.macOS.dll) or runtime files (e.g., libclrgc.dylib), + // they should still be copied to the app bundle. + var project = "ContentWithPublishFolderType"; + Configuration.IgnoreIfIgnoredPlatform (platform); + Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers); + + var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath); + Clean (project_path); + + var properties = GetDefaultProperties (runtimeIdentifiers); + DotNet.AssertBuild (project_path, properties); + + // These are files in our helper directory that have the same names as SDK assemblies / runtime files. + // They should all be present in the app bundle's SharedSupport directory. + var expectedFiles = new string [] { + // Files that match SDK assembly names (these are the ones that go missing per the bug report) + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll", + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.CSharp.dll", + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.dll", + // A runtime dylib that matches a known runtime file name + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/libclrgc.dylib", + // Files that don't match SDK assembly names (these work fine) + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/.xamarin/osx-arm64/HeartBeatHandlerMac.dll", + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/AsyncIO.dll", + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/HeartbeatHandlerLib.dll", + "Contents/SharedSupport/SubApp.app/Contents/MonoBundle/System.ServiceModel.Security.dll", + }; + + foreach (var expectedFile in expectedFiles) { + var fullPath = Path.Combine (appPath, expectedFile); + Assert.That (fullPath, Does.Exist, $"Expected file '{expectedFile}' to be in the app bundle"); + } + } + } +} diff --git a/tests/dotnet/UnitTests/DotNetUnitTests.csproj b/tests/dotnet/UnitTests/DotNetUnitTests.csproj index f78948890a0e..e0bbb37b7ce5 100644 --- a/tests/dotnet/UnitTests/DotNetUnitTests.csproj +++ b/tests/dotnet/UnitTests/DotNetUnitTests.csproj @@ -45,6 +45,9 @@ external\Cache.cs + + external\IToolLog.cs + external\TargetFramework.cs diff --git a/tests/dotnet/UnitTests/Extensions.cs b/tests/dotnet/UnitTests/Extensions.cs index ba97980be9a9..249cf21297cc 100644 --- a/tests/dotnet/UnitTests/Extensions.cs +++ b/tests/dotnet/UnitTests/Extensions.cs @@ -113,6 +113,33 @@ public static void AssertWarnings (this IEnumerable actualWarning Assert.Fail ($"Missing warning: {evt.File}: {evt.Message}"); }); } + + public static IEnumerable FilterWarnings (this IEnumerable actualWarnings, ApplePlatform platform, bool filterSupportediPhoneOrientations = true, bool filterXcodeLocation = true) + { + return actualWarnings.Where (v => !IsFilteredWarning (v, platform, filterSupportediPhoneOrientations, filterXcodeLocation)); + } + + public static bool IsFilteredWarning (BuildLogEvent evt, ApplePlatform platform, bool filterSupportediPhoneOrientations = true, bool filterXcodeLocation = true) + { + var v = evt.Message?.Trim (); + + if (string.IsNullOrEmpty (v)) + return false; + + if (filterSupportediPhoneOrientations && platform == ApplePlatform.iOS && v == "Supported iPhone orientations have not been set") + return true; + + if (filterXcodeLocation) { + if (v.Contains ("The environment variable 'MD_APPLE_SDK_ROOT' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use.")) + return true; + if (v.Contains ($"The settings file '{Environment.GetEnvironmentVariable ("HOME")}/Library/Preferences/maui/Settings.plist' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use.")) + return true; + if (v.Contains ($"The settings file '{Environment.GetEnvironmentVariable ("HOME")}/Library/Preferences/Xamarin/Settings.plist' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use.")) + return true; + } + + return false; + } } public class ExpectedBuildMessage { diff --git a/tests/dotnet/UnitTests/ExtensionsTest.cs b/tests/dotnet/UnitTests/ExtensionsTest.cs index cf50e2098e90..cba31ce61c92 100644 --- a/tests/dotnet/UnitTests/ExtensionsTest.cs +++ b/tests/dotnet/UnitTests/ExtensionsTest.cs @@ -59,7 +59,7 @@ public void AdditionalAppExtensionTest (ApplePlatform platform, string runtimeId } else { var rv = DotNet.AssertBuild (project_path, properties); var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath) - .Where (v => v?.Message?.Contains ("Supported iPhone orientations have not been set") != true) + .FilterWarnings (platform) .ToArray (); var extensionPath = Path.Combine (appPath, GetPlugInsRelativePath (platform), $"{extensionProject}.appex"); AssertWarningMessages (warnings, [ diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs index f56013f3811d..383344886774 100644 --- a/tests/dotnet/UnitTests/ProjectTest.cs +++ b/tests/dotnet/UnitTests/ProjectTest.cs @@ -524,7 +524,7 @@ public void IsOverrideRuntimeIdentifier (ApplePlatform platform, string runtimeI properties.Remove ("RuntimeIdentifiers"); properties ["cmdline:RuntimeIdentifier"] = "maccatalyst-x64"; var rv = DotNet.AssertBuild (project_path, properties); - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform).ToArray (); Assert.That (warnings.Length, Is.EqualTo (1), "Warning Count"); Assert.That (warnings [0].Message, Is.EqualTo ("RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file."), "Warning message"); } @@ -667,7 +667,7 @@ public void FilesInAppBundle (ApplePlatform platform, string runtimeIdentifiers) // Build again - this time it'll fail var rv = DotNet.Build (project_path, properties); - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform).ToArray (); Assert.That (rv.ExitCode, Is.Not.EqualTo (0), "Unexpected success"); Assert.That (warnings.Length, Is.EqualTo (1), "Warning Count"); Assert.That (warnings [0].Message, Is.EqualTo ($"Found files in the root directory of the app bundle. This will likely cause codesign to fail. Files:\nbin/Debug/{Configuration.DotNetTfm}-maccatalyst/maccatalyst-x64/MySimpleApp.app/otherfile.txt\nbin/Debug/{Configuration.DotNetTfm}-maccatalyst/maccatalyst-x64/MySimpleApp.app/otherdir\nbin/Debug/{Configuration.DotNetTfm}-maccatalyst/maccatalyst-x64/MySimpleApp.app/otherdir/otherfile.log"), "Warning"); @@ -676,7 +676,7 @@ public void FilesInAppBundle (ApplePlatform platform, string runtimeIdentifiers) var enableAutomaticCleanupProperties = new Dictionary (properties); enableAutomaticCleanupProperties ["EnableAutomaticAppBundleRootDirectoryCleanup"] = "true"; rv = DotNet.AssertBuild (project_path, enableAutomaticCleanupProperties); - warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); + warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform).ToArray (); Assert.That (warnings.Length, Is.EqualTo (0), "Warning Count"); // Verify that the files were in fact removed. @@ -784,7 +784,7 @@ public void BindingWithDefaultCompileInclude (ApplePlatform platform) Assert.That (myStruct, Is.Not.Null, "MyStruct type"); Assert.That (myStruct!.IsValueType, Is.True, "MyStruct"); - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).Select (v => v.Message); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform).Select (v => v.Message); Assert.That (warnings, Is.Empty, $"Build warnings:\n\t{string.Join ("\n\t", warnings)}"); } @@ -1601,12 +1601,7 @@ public void AppWithDuplicatedResources (ApplePlatform platform, string runtimeId throw new NotImplementedException (scenario.ToString ()); } } - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath) - .Where (evt => { - if (platform == ApplePlatform.iOS && evt.Message?.Trim () == "Supported iPhone orientations have not been set") - return false; - return true; - }); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform); warnings.AssertWarnings (expectedWarnings); if (bundleOriginalResources && expectedWarnings.Length > 0) { @@ -2578,12 +2573,10 @@ public void BuildMyNativeAotAppWithTrimAnalysisWarning (ApplePlatform platform, var rv = DotNet.AssertBuild (project_path, properties); // We expect to get a warning from the trim analzyer in Debug build - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath) + .FilterWarnings (platform) + .ToArray (); - // Ignore warnings we haven't fixed yet - if (platform == ApplePlatform.iOS) { - warnings = warnings.Where (w => w.Message?.Trim () != "Supported iPhone orientations have not been set").ToArray (); - } Assert.That (warnings.Length, Is.EqualTo (1), "Warning count"); Assert.That (warnings [0].Code, Is.EqualTo ("IL2075"), "Warning code"); @@ -2639,12 +2632,7 @@ void PublishAotImpl (ApplePlatform platform, string runtimeIdentifiers, string c // Verify that we have no warnings, but unfortunately we still have some we haven't fixed yet. // Ignore those, and fail the test if we stop getting them (so that we can update the test to not ignore them anymore). - rv.AssertNoWarnings ((evt) => { - if (platform == ApplePlatform.iOS && evt.Message?.Trim () == "Supported iPhone orientations have not been set") - return false; - - return true; - }); + rv.AssertNoWarnings ((evt) => !Extensions.IsFilteredWarning (evt, platform)); } [Test] @@ -2668,11 +2656,7 @@ public void PublishAotMonoTouchTest_NoIL2009 (ApplePlatform platform, string run var config = "Debug"; var runtimeIdentifierInfix = $"/{runtimeIdentifiers}/"; var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath) - .Where (evt => { - if (platform == ApplePlatform.iOS && evt.Message?.Trim () == "Supported iPhone orientations have not been set") - return false; - return true; - }); + .FilterWarnings (platform); var expectedWarnings = new ExpectedBuildMessage [] { new ExpectedBuildMessage ($"ILLINK", $"It's not safe to remove the dynamic registrar, because monotouchtest references 'ObjCRuntime.Runtime.ConnectMethod (System.Reflection.MethodInfo, ObjCRuntime.Selector)'."), new ExpectedBuildMessage ($"ILLINK", $"It's not safe to remove the dynamic registrar, because monotouchtest references 'ObjCRuntime.Runtime.ConnectMethod (System.Type, System.Reflection.MethodInfo, Foundation.ExportAttribute)'."), @@ -2793,7 +2777,7 @@ public void UnsupportedTargetPlatformVersion (ApplePlatform platform) if (IsTargetPlatformVersionCompatEnabled) { var rv = DotNet.AssertBuild (project_path, properties); - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform).ToArray (); AssertWarningMessages (warnings, $"{minSupportedOSVersion} is not a valid TargetPlatformVersion for {platform.AsString ()}. This warning will become an error in future versions of the {platform.AsString ()} workload. Valid versions include:\n{string.Join ('\n', supportedApiVersions)}"); } else { var rv = DotNet.AssertBuildFailure (project_path, properties); diff --git a/tests/dotnet/UnitTests/RegistrarTest.cs b/tests/dotnet/UnitTests/RegistrarTest.cs index 003efbdc3281..f7aad07cb565 100644 --- a/tests/dotnet/UnitTests/RegistrarTest.cs +++ b/tests/dotnet/UnitTests/RegistrarTest.cs @@ -76,6 +76,7 @@ public void ClassRewriterTest (ApplePlatform platform, bool rewriteHandles) // enable the linker (so that the main assembly is modified) properties ["LinkMode"] = "full"; properties ["MtouchLink"] = "full"; + properties ["InlineClassGetHandle"] = "disabled"; if (rewriteHandles) properties ["MtouchExtraArgs"] = "--optimize=redirect-class-handles"; diff --git a/tests/dotnet/UnitTests/TemplateTest.cs b/tests/dotnet/UnitTests/TemplateTest.cs index ae13075a9db7..2b7667a909b0 100644 --- a/tests/dotnet/UnitTests/TemplateTest.cs +++ b/tests/dotnet/UnitTests/TemplateTest.cs @@ -224,7 +224,7 @@ public void CreateAndBuildProjectTemplate (TemplateInfo info) var proj = Path.Combine (outputDir, $"{info.Template}.{language.AsFileExtension ()}"); var properties = GetDefaultProperties (); var rv = DotNet.AssertBuild (proj, properties); - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).Select (v => v.Message); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (info.Platform).Select (v => v.Message); Assert.That (warnings, Is.Empty, $"Build warnings:\n\t{string.Join ("\n\t", warnings)}"); if (info.Execute) { diff --git a/tests/dotnet/UnitTests/TrimmerWarningsTest.cs b/tests/dotnet/UnitTests/TrimmerWarningsTest.cs index 719f8a8112ce..ab5b77f88d7e 100644 --- a/tests/dotnet/UnitTests/TrimmerWarningsTest.cs +++ b/tests/dotnet/UnitTests/TrimmerWarningsTest.cs @@ -128,11 +128,7 @@ void TrimmerWarnings (ApplePlatform platform, string runtimeIdentifiers, string var rv = DotNet.AssertBuild (project_path, properties); var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath) - .Where (evt => { - if (platform == ApplePlatform.iOS && evt.Message?.Trim () == "Supported iPhone orientations have not been set") - return false; - return true; - }); + .FilterWarnings (platform); warnings.AssertWarnings (expectedWarnings); } } diff --git a/tests/dotnet/UnitTests/WindowsTest.cs b/tests/dotnet/UnitTests/WindowsTest.cs index e9ac09f1b7a9..c95bfc8ff73e 100644 --- a/tests/dotnet/UnitTests/WindowsTest.cs +++ b/tests/dotnet/UnitTests/WindowsTest.cs @@ -150,7 +150,7 @@ void BundleStructureWithRemoteMac (ApplePlatform platform, string runtimeIdentif var rv = DotNet.AssertBuild (project_path, properties); var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); - var warningMessages = BundleStructureTest.FilterWarnings (warnings, canonicalizePaths: true); + var warningMessages = BundleStructureTest.FilterWarnings (warnings, platform, canonicalizePaths: true); var isReleaseBuild = string.Equals (configuration, "Release", StringComparison.OrdinalIgnoreCase); var isCoreCLR = !useMonoRuntime; @@ -225,7 +225,7 @@ void BundleStructureWithRemoteMac (ApplePlatform platform, string runtimeIdentif rv = DotNet.AssertBuild (project_path, properties); var allTargets = BinLog.GetAllTargets (rv.BinLogPath); warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); - warningMessages = BundleStructureTest.FilterWarnings (warnings, canonicalizePaths: true); + warningMessages = BundleStructureTest.FilterWarnings (warnings, platform, canonicalizePaths: true); BundleStructureTest.CheckZippedAppBundleContents (platform, zippedAppBundlePath, rids, signature, isReleaseBuild, isCoreCLR: isCoreCLR); AssertWarningsEqual (expectedWarnings, warningMessages, "Warnings Rebuild 1"); @@ -245,7 +245,7 @@ void BundleStructureWithRemoteMac (ApplePlatform platform, string runtimeIdentif rv = DotNet.AssertBuild (project_path, properties); allTargets = BinLog.GetAllTargets (rv.BinLogPath); warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); - warningMessages = BundleStructureTest.FilterWarnings (warnings, canonicalizePaths: true); + warningMessages = BundleStructureTest.FilterWarnings (warnings, platform, canonicalizePaths: true); BundleStructureTest.CheckZippedAppBundleContents (platform, zippedAppBundlePath, rids, signature, isReleaseBuild, isCoreCLR: isCoreCLR); AssertWarningsEqual (expectedWarnings, warningMessages, "Warnings Rebuild 2"); @@ -262,7 +262,7 @@ void BundleStructureWithRemoteMac (ApplePlatform platform, string runtimeIdentif rv = DotNet.AssertBuild (project_path, properties); allTargets = BinLog.GetAllTargets (rv.BinLogPath); warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).ToArray (); - warningMessages = BundleStructureTest.FilterWarnings (warnings, canonicalizePaths: true); + warningMessages = BundleStructureTest.FilterWarnings (warnings, platform, canonicalizePaths: true); BundleStructureTest.CheckZippedAppBundleContents (platform, zippedAppBundlePath, rids, signature, isReleaseBuild, isCoreCLR: isCoreCLR); AssertWarningsEqual (expectedWarnings, warningMessages, "Warnings Rebuild 3"); diff --git a/tests/dotnet/UnitTests/XcodeProjectTests.cs b/tests/dotnet/UnitTests/XcodeProjectTests.cs index 2c3c8089cd8d..9a26dce042c7 100644 --- a/tests/dotnet/UnitTests/XcodeProjectTests.cs +++ b/tests/dotnet/UnitTests/XcodeProjectTests.cs @@ -149,7 +149,7 @@ public class Binding var properties = GetDefaultProperties (); var rv = DotNet.AssertBuild (proj, properties); - var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).Select (v => v.Message); + var warnings = BinLog.GetBuildLogWarnings (rv.BinLogPath).FilterWarnings (platform).Select (v => v.Message); Assert.That (warnings, Is.Empty, $"Build warnings:\n\t{string.Join ("\n\t", warnings)}"); AssertXcFrameworkOutput (platform, testDir, xcodeProjName); } diff --git a/tests/dotnet/UnitTests/XcodeVersionTest.cs b/tests/dotnet/UnitTests/XcodeVersionTest.cs index a365af92f75e..301eb5e57fe0 100644 --- a/tests/dotnet/UnitTests/XcodeVersionTest.cs +++ b/tests/dotnet/UnitTests/XcodeVersionTest.cs @@ -35,16 +35,11 @@ public void Test (ApplePlatform platform, string xcodePath, Version xcodeVersion Clean (project_path); var properties = GetDefaultProperties (runtimeIdentifiers); properties ["BundleOriginalResources"] = "true"; // this prevents a different and unrelated error message from failing to build library projects + properties ["XcodeLocation"] = xcodePath; - var existingDeveloperDir = Environment.GetEnvironmentVariable ("MD_APPLE_SDK_ROOT"); - try { - Environment.SetEnvironmentVariable ("MD_APPLE_SDK_ROOT", Path.GetDirectoryName (Path.GetDirectoryName (xcodePath))); - var rv = DotNet.AssertBuildFailure (project_path, properties); - var errors = BinLog.GetBuildLogErrors (rv.BinLogPath).ToArray (); - AssertErrorMessages (errors, $"This version of .NET for {platform.AsString ()} ({Configuration.GetNuGetVersionNoMetadata (platform)}) requires Xcode {Configuration.XcodeVersion}. The current version of Xcode is {xcodeVersion}. Either install Xcode {Configuration.XcodeVersion}, or use a different version of .NET for {platform.AsString ()}. See https://aka.ms/xcode-requirement for more information."); - } finally { - Environment.SetEnvironmentVariable ("MD_APPLE_SDK_ROOT", existingDeveloperDir); - } + var rv = DotNet.AssertBuildFailure (project_path, properties); + var errors = BinLog.GetBuildLogErrors (rv.BinLogPath).ToArray (); + AssertErrorMessages (errors, $"This version of .NET for {platform.AsString ()} ({Configuration.GetNuGetVersionNoMetadata (platform)}) requires Xcode {Configuration.XcodeVersion}. The current version of Xcode is {xcodeVersion}. Either install Xcode {Configuration.XcodeVersion}, or use a different version of .NET for {platform.AsString ()}. See https://aka.ms/xcode-requirement for more information."); } } } diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt index c7c2da2860f1..c892d1141145 100644 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt @@ -195,12 +195,9 @@ Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NS Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.MacCatalyst.dll:Foundation.NSObjectData -Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -252,6 +249,12 @@ Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsStubClass() Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsWrapper() Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_Name() Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_SkipRegistration() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.Finalize() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.get_Value() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.MacCatalyst.dll:ObjCRuntime.__Registrar__ @@ -495,7 +498,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_pt Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSString::class_ptr Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSString::ClassHandle() @@ -592,7 +594,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__Constru Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -1334,6 +1335,8 @@ Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject::__data Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.AdoptsAttribute::ProtocolHandle() Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle @@ -1497,9 +1500,10 @@ Microsoft.MacCatalyst.dll:System.Reflection.MethodBase Registrar.Registrar/ObjCM Microsoft.MacCatalyst.dll:System.Reflection.PropertyInfo Registrar.Registrar/ObjCProperty::Property Microsoft.MacCatalyst.dll:System.Reflection.TypeFilter Registrar.SharedDynamic/<>c::<>9__0_0 Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-size.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-size.txt deleted file mode 100644 index c5b49813ddcd..000000000000 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-size.txt +++ /dev/null @@ -1,13 +0,0 @@ -AppBundleSize: 5,811,790 bytes (5,675.6 KB = 5.5 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 3,310 bytes (3.2 KB = 0.0 MB) -Contents/Info.plist: 1,115 bytes (1.1 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 4,569,552 bytes (4,462.5 KB = 4.4 MB) -Contents/MonoBundle/Microsoft.MacCatalyst.dll: 157,184 bytes (153.5 KB = 0.1 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,405 bytes (1.4 KB = 0.0 MB) -Contents/MonoBundle/SizeTestApp.dll: 7,680 bytes (7.5 KB = 0.0 MB) -Contents/MonoBundle/System.Private.CoreLib.aotdata.arm64: 41,392 bytes (40.4 KB = 0.0 MB) -Contents/MonoBundle/System.Private.CoreLib.dll: 1,020,416 bytes (996.5 KB = 1.0 MB) -Contents/MonoBundle/System.Runtime.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.InteropServices.dll: 4,608 bytes (4.5 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt index ff8f163f0c33..0ee0a83429a6 100644 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt @@ -178,12 +178,9 @@ Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NS Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.MacCatalyst.dll:Foundation.NSObjectData -Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -194,6 +191,12 @@ Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute..ctor(System.String, System.Boolean) Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute..ctor(System.String) Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsWrapper() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.Finalize() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.get_Value() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.MacCatalyst.dll:ObjCRuntime.__Registrar__ @@ -375,7 +378,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_pt Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::handle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::Handle() @@ -450,7 +452,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__Constru Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -721,6 +722,8 @@ Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject::__data Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.NativeHandle::handle @@ -852,9 +855,10 @@ Microsoft.MacCatalyst.dll:System.Object ObjCRuntime.Class::verification_lock Microsoft.MacCatalyst.dll:System.Object ObjCRuntime.Runtime::lock_obj Microsoft.MacCatalyst.dll:System.Reflection.Assembly Foundation.NSObject::PlatformAssembly Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-size.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-size.txt deleted file mode 100644 index 588c4b7338ae..000000000000 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-size.txt +++ /dev/null @@ -1,18 +0,0 @@ -AppBundleSize: 16,624,634 bytes (16,235.0 KB = 15.9 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 4,134 bytes (4.0 KB = 0.0 MB) -Contents/Info.plist: 1,115 bytes (1.1 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 14,066,048 bytes (13,736.4 KB = 13.4 MB) -Contents/MonoBundle/aot-instances.aotdata.arm64: 1,051,776 bytes (1,027.1 KB = 1.0 MB) -Contents/MonoBundle/Microsoft.MacCatalyst.aotdata.arm64: 36,368 bytes (35.5 KB = 0.0 MB) -Contents/MonoBundle/Microsoft.MacCatalyst.dll: 50,688 bytes (49.5 KB = 0.0 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,481 bytes (1.4 KB = 0.0 MB) -Contents/MonoBundle/SizeTestApp.aotdata.arm64: 1,552 bytes (1.5 KB = 0.0 MB) -Contents/MonoBundle/SizeTestApp.dll: 7,680 bytes (7.5 KB = 0.0 MB) -Contents/MonoBundle/System.Private.CoreLib.aotdata.arm64: 850,376 bytes (830.4 KB = 0.8 MB) -Contents/MonoBundle/System.Private.CoreLib.dll: 542,720 bytes (530.0 KB = 0.5 MB) -Contents/MonoBundle/System.Runtime.aotdata.arm64: 472 bytes (0.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.InteropServices.aotdata.arm64: 488 bytes (0.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.InteropServices.dll: 4,608 bytes (4.5 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-TrimmableStatic-size.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-TrimmableStatic-size.txt deleted file mode 100644 index 325f12b01243..000000000000 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-TrimmableStatic-size.txt +++ /dev/null @@ -1,7 +0,0 @@ -AppBundleSize: 8,818,945 bytes (8,612.3 KB = 8.4 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 2,358 bytes (2.3 KB = 0.0 MB) -Contents/Info.plist: 1,115 bytes (1.1 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 8,813,568 bytes (8,607.0 KB = 8.4 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,896 bytes (1.9 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-size.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-size.txt deleted file mode 100644 index 2cbda9171d3b..000000000000 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-size.txt +++ /dev/null @@ -1,7 +0,0 @@ -AppBundleSize: 2,815,321 bytes (2,749.3 KB = 2.7 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 2,358 bytes (2.3 KB = 0.0 MB) -Contents/Info.plist: 1,115 bytes (1.1 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 2,810,032 bytes (2,744.2 KB = 2.7 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,808 bytes (1.8 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-TrimmableStatic-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-TrimmableStatic-size.txt deleted file mode 100644 index ce1d6de10b70..000000000000 --- a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-TrimmableStatic-size.txt +++ /dev/null @@ -1,313 +0,0 @@ -AppBundleSize: 259,938,648 bytes (253,846.3 KB = 247.9 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 56,016 bytes (54.7 KB = 0.1 MB) -Contents/Info.plist: 746 bytes (0.7 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 7,394,336 bytes (7,221.0 KB = 7.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/_Microsoft.macOS.TypeMap.dll: 4,847,616 bytes (4,734.0 KB = 4.6 MB) -Contents/MonoBundle/.xamarin/osx-arm64/_Microsoft.macOS.TypeMaps.dll: 2,048 bytes (2.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/_SizeTestApp.TypeMap.dll: 3,072 bytes (3.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.CSharp.dll: 882,176 bytes (861.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Caching.Abstractions.dll: 56,320 bytes (55.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Configuration.Abstractions.dll: 28,160 bytes (27.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.DependencyInjection.Abstractions.dll: 140,800 bytes (137.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Diagnostics.Abstractions.dll: 19,456 bytes (19.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.FileProviders.Abstractions.dll: 15,360 bytes (15.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Hosting.Abstractions.dll: 38,912 bytes (38.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Logging.Abstractions.dll: 150,528 bytes (147.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Options.dll: 135,168 bytes (132.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Primitives.dll: 70,144 bytes (68.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll: 38,509,056 bytes (37,606.5 KB = 36.7 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.Core.dll: 1,321,472 bytes (1,290.5 KB = 1.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Win32.Registry.dll: 23,552 bytes (23.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/SizeTestApp.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.Concurrent.dll: 136,704 bytes (133.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.dll: 317,952 bytes (310.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.Immutable.dll: 1,111,552 bytes (1,085.5 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.NonGeneric.dll: 94,208 bytes (92.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.Specialized.dll: 94,720 bytes (92.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.Annotations.dll: 206,336 bytes (201.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.EventBasedAsync.dll: 28,672 bytes (28.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.Primitives.dll: 69,632 bytes (68.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.TypeConverter.dll: 867,840 bytes (847.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Console.dll: 215,040 bytes (210.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Data.Common.dll: 3,212,288 bytes (3,137.0 KB = 3.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.DiagnosticSource.dll: 549,888 bytes (537.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.FileVersionInfo.dll: 35,840 bytes (35.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.Process.dll: 371,200 bytes (362.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.StackTrace.dll: 26,112 bytes (25.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.TextWriterTraceListener.dll: 55,296 bytes (54.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.TraceSource.dll: 141,312 bytes (138.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Drawing.Primitives.dll: 118,272 bytes (115.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Formats.Asn1.dll: 249,344 bytes (243.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Formats.Tar.dll: 314,368 bytes (307.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Compression.Brotli.dll: 73,216 bytes (71.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Compression.dll: 537,600 bytes (525.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Compression.ZipFile.dll: 90,624 bytes (88.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.FileSystem.AccessControl.dll: 22,528 bytes (22.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.FileSystem.DriveInfo.dll: 78,848 bytes (77.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.FileSystem.Watcher.dll: 111,616 bytes (109.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.IsolatedStorage.dll: 73,728 bytes (72.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.MemoryMappedFiles.dll: 84,480 bytes (82.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Pipelines.dll: 189,440 bytes (185.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Pipes.AccessControl.dll: 13,824 bytes (13.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Pipes.dll: 136,192 bytes (133.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.AsyncEnumerable.dll: 1,592,320 bytes (1,555.0 KB = 1.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.dll: 807,936 bytes (789.0 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.Expressions.dll: 4,638,208 bytes (4,529.5 KB = 4.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.Parallel.dll: 882,176 bytes (861.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.Queryable.dll: 210,432 bytes (205.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Memory.dll: 154,624 bytes (151.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Http.dll: 1,869,312 bytes (1,825.5 KB = 1.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Http.Json.dll: 119,296 bytes (116.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.HttpListener.dll: 316,928 bytes (309.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Mail.dll: 529,408 bytes (517.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.NameResolution.dll: 105,472 bytes (103.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.NetworkInformation.dll: 142,336 bytes (139.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Ping.dll: 88,064 bytes (86.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Primitives.dll: 241,152 bytes (235.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Quic.dll: 371,712 bytes (363.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Requests.dll: 405,504 bytes (396.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Security.dll: 791,040 bytes (772.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.ServerSentEvents.dll: 67,584 bytes (66.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Sockets.dll: 694,784 bytes (678.5 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebClient.dll: 166,912 bytes (163.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebHeaderCollection.dll: 52,224 bytes (51.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebProxy.dll: 26,624 bytes (26.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebSockets.Client.dll: 89,088 bytes (87.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebSockets.dll: 237,056 bytes (231.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ObjectModel.dll: 67,072 bytes (65.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.CoreLib.dll: 17,898,496 bytes (17,479.0 KB = 17.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.DataContractSerialization.dll: 2,375,168 bytes (2,319.5 KB = 2.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.Uri.dll: 252,928 bytes (247.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.Xml.dll: 8,758,784 bytes (8,553.5 KB = 8.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.Xml.Linq.dll: 412,160 bytes (402.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.DispatchProxy.dll: 62,976 bytes (61.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.Emit.dll: 335,872 bytes (328.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.Metadata.dll: 1,272,832 bytes (1,243.0 KB = 1.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.TypeExtensions.dll: 24,064 bytes (23.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Resources.Writer.dll: 35,840 bytes (35.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.CompilerServices.VisualC.dll: 8,704 bytes (8.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.InteropServices.dll: 100,864 bytes (98.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.InteropServices.JavaScript.dll: 27,136 bytes (26.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.Numerics.dll: 441,856 bytes (431.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.Serialization.Formatters.dll: 118,784 bytes (116.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.Serialization.Primitives.dll: 19,968 bytes (19.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.AccessControl.dll: 45,056 bytes (44.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.Claims.dll: 91,648 bytes (89.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.Cryptography.dll: 2,458,112 bytes (2,400.5 KB = 2.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.Principal.Windows.dll: 27,648 bytes (27.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.Encoding.CodePages.dll: 856,576 bytes (836.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.Encodings.Web.dll: 113,152 bytes (110.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.Json.dll: 2,176,000 bytes (2,125.0 KB = 2.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.RegularExpressions.dll: 1,179,648 bytes (1,152.0 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.AccessControl.dll: 23,552 bytes (23.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.Channels.dll: 155,136 bytes (151.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.dll: 71,168 bytes (69.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.Tasks.Dataflow.dll: 522,240 bytes (510.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.Tasks.Parallel.dll: 122,880 bytes (120.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Transactions.Local.dll: 386,048 bytes (377.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Web.HttpUtility.dll: 47,104 bytes (46.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Xml.XPath.XDocument.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/_Microsoft.macOS.TypeMap.dll: 4,847,616 bytes (4,734.0 KB = 4.6 MB) -Contents/MonoBundle/.xamarin/osx-x64/_Microsoft.macOS.TypeMaps.dll: 2,048 bytes (2.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/_SizeTestApp.TypeMap.dll: 3,072 bytes (3.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.CSharp.dll: 785,408 bytes (767.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Caching.Abstractions.dll: 52,224 bytes (51.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Configuration.Abstractions.dll: 26,624 bytes (26.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.DependencyInjection.Abstractions.dll: 123,392 bytes (120.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Diagnostics.Abstractions.dll: 18,432 bytes (18.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.FileProviders.Abstractions.dll: 14,336 bytes (14.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Hosting.Abstractions.dll: 36,352 bytes (35.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Logging.Abstractions.dll: 134,656 bytes (131.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Options.dll: 119,808 bytes (117.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Primitives.dll: 63,488 bytes (62.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.macOS.dll: 38,509,056 bytes (37,606.5 KB = 36.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.VisualBasic.Core.dll: 1,152,000 bytes (1,125.0 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Win32.Registry.dll: 23,040 bytes (22.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/SizeTestApp.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.Concurrent.dll: 122,368 bytes (119.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.dll: 278,016 bytes (271.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.Immutable.dll: 979,456 bytes (956.5 KB = 0.9 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.NonGeneric.dll: 82,432 bytes (80.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.Specialized.dll: 82,432 bytes (80.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.Annotations.dll: 181,248 bytes (177.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.EventBasedAsync.dll: 26,112 bytes (25.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.Primitives.dll: 60,416 bytes (59.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.TypeConverter.dll: 752,640 bytes (735.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Console.dll: 188,416 bytes (184.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Data.Common.dll: 2,783,744 bytes (2,718.5 KB = 2.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.DiagnosticSource.dll: 488,960 bytes (477.5 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.FileVersionInfo.dll: 33,280 bytes (32.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.Process.dll: 321,536 bytes (314.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.StackTrace.dll: 25,088 bytes (24.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.TextWriterTraceListener.dll: 48,640 bytes (47.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.TraceSource.dll: 120,832 bytes (118.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Drawing.Primitives.dll: 113,152 bytes (110.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Formats.Asn1.dll: 222,208 bytes (217.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Formats.Tar.dll: 273,408 bytes (267.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Compression.Brotli.dll: 63,488 bytes (62.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Compression.dll: 463,360 bytes (452.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Compression.ZipFile.dll: 81,408 bytes (79.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.FileSystem.AccessControl.dll: 22,528 bytes (22.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.FileSystem.DriveInfo.dll: 69,120 bytes (67.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.FileSystem.Watcher.dll: 96,256 bytes (94.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.IsolatedStorage.dll: 66,560 bytes (65.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.MemoryMappedFiles.dll: 72,704 bytes (71.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Pipelines.dll: 171,520 bytes (167.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Pipes.AccessControl.dll: 13,824 bytes (13.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Pipes.dll: 117,248 bytes (114.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.AsyncEnumerable.dll: 1,416,192 bytes (1,383.0 KB = 1.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.dll: 707,584 bytes (691.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.Expressions.dll: 3,709,952 bytes (3,623.0 KB = 3.5 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.Parallel.dll: 766,464 bytes (748.5 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.Queryable.dll: 173,568 bytes (169.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Memory.dll: 142,336 bytes (139.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Http.dll: 1,648,640 bytes (1,610.0 KB = 1.6 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Http.Json.dll: 109,568 bytes (107.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.HttpListener.dll: 279,552 bytes (273.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Mail.dll: 461,824 bytes (451.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.NameResolution.dll: 92,160 bytes (90.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.NetworkInformation.dll: 123,904 bytes (121.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Ping.dll: 78,336 bytes (76.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Primitives.dll: 212,480 bytes (207.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Quic.dll: 330,240 bytes (322.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Requests.dll: 351,744 bytes (343.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Security.dll: 687,104 bytes (671.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.ServerSentEvents.dll: 61,952 bytes (60.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Sockets.dll: 594,944 bytes (581.0 KB = 0.6 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebClient.dll: 147,456 bytes (144.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebHeaderCollection.dll: 44,544 bytes (43.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebProxy.dll: 24,064 bytes (23.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebSockets.Client.dll: 79,872 bytes (78.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebSockets.dll: 211,968 bytes (207.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ObjectModel.dll: 58,880 bytes (57.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.CoreLib.dll: 16,443,904 bytes (16,058.5 KB = 15.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.DataContractSerialization.dll: 2,049,024 bytes (2,001.0 KB = 2.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.Uri.dll: 229,888 bytes (224.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.Xml.dll: 7,635,968 bytes (7,457.0 KB = 7.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.Xml.Linq.dll: 357,376 bytes (349.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.DispatchProxy.dll: 56,832 bytes (55.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.Emit.dll: 294,400 bytes (287.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.Metadata.dll: 1,142,272 bytes (1,115.5 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.TypeExtensions.dll: 21,504 bytes (21.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Resources.Writer.dll: 32,256 bytes (31.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.CompilerServices.VisualC.dll: 8,704 bytes (8.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.InteropServices.dll: 92,160 bytes (90.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.InteropServices.JavaScript.dll: 27,136 bytes (26.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.Numerics.dll: 412,672 bytes (403.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.Serialization.Formatters.dll: 105,472 bytes (103.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.Serialization.Primitives.dll: 18,432 bytes (18.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.AccessControl.dll: 45,056 bytes (44.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.Claims.dll: 81,920 bytes (80.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.Cryptography.dll: 2,130,944 bytes (2,081.0 KB = 2.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.Principal.Windows.dll: 27,648 bytes (27.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.Encoding.CodePages.dll: 839,680 bytes (820.0 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.Encodings.Web.dll: 104,448 bytes (102.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.Json.dll: 1,947,136 bytes (1,901.5 KB = 1.9 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.RegularExpressions.dll: 1,052,160 bytes (1,027.5 KB = 1.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.AccessControl.dll: 23,040 bytes (22.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.Channels.dll: 139,264 bytes (136.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.dll: 64,512 bytes (63.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.Tasks.Dataflow.dll: 460,800 bytes (450.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.Tasks.Parallel.dll: 109,568 bytes (107.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Transactions.Local.dll: 341,504 bytes (333.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Web.HttpUtility.dll: 43,008 bytes (42.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Xml.XPath.XDocument.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/libclrgc.dylib: 2,038,208 bytes (1,990.4 KB = 1.9 MB) -Contents/MonoBundle/libclrgcexp.dylib: 2,198,640 bytes (2,147.1 KB = 2.1 MB) -Contents/MonoBundle/libclrjit.dylib: 6,539,344 bytes (6,386.1 KB = 6.2 MB) -Contents/MonoBundle/libcoreclr.dylib: 12,844,608 bytes (12,543.6 KB = 12.2 MB) -Contents/MonoBundle/libhostfxr.dylib: 833,536 bytes (814.0 KB = 0.8 MB) -Contents/MonoBundle/libhostpolicy.dylib: 776,624 bytes (758.4 KB = 0.7 MB) -Contents/MonoBundle/libmscordaccore.dylib: 4,453,664 bytes (4,349.3 KB = 4.2 MB) -Contents/MonoBundle/libmscordbi.dylib: 3,447,072 bytes (3,366.3 KB = 3.3 MB) -Contents/MonoBundle/libSystem.Globalization.Native.dylib: 286,816 bytes (280.1 KB = 0.3 MB) -Contents/MonoBundle/libSystem.IO.Compression.Native.dylib: 3,278,688 bytes (3,201.8 KB = 3.1 MB) -Contents/MonoBundle/libSystem.Native.dylib: 296,416 bytes (289.5 KB = 0.3 MB) -Contents/MonoBundle/libSystem.Net.Security.Native.dylib: 136,768 bytes (133.6 KB = 0.1 MB) -Contents/MonoBundle/libSystem.Security.Cryptography.Native.Apple.dylib: 460,880 bytes (450.1 KB = 0.4 MB) -Contents/MonoBundle/Microsoft.VisualBasic.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/Microsoft.Win32.Primitives.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/mscorlib.dll: 49,664 bytes (48.5 KB = 0.0 MB) -Contents/MonoBundle/netstandard.dll: 91,136 bytes (89.0 KB = 0.1 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,445 bytes (1.4 KB = 0.0 MB) -Contents/MonoBundle/System.AppContext.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Buffers.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.ComponentModel.DataAnnotations.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.Configuration.dll: 9,216 bytes (9.0 KB = 0.0 MB) -Contents/MonoBundle/System.Core.dll: 13,312 bytes (13.0 KB = 0.0 MB) -Contents/MonoBundle/System.Data.DataSetExtensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Data.dll: 15,360 bytes (15.0 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Contracts.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Debug.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Tools.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Tracing.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.dll: 40,448 bytes (39.5 KB = 0.0 MB) -Contents/MonoBundle/System.Drawing.dll: 10,240 bytes (10.0 KB = 0.0 MB) -Contents/MonoBundle/System.Dynamic.Runtime.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Globalization.Calendars.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Globalization.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Globalization.Extensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.IO.Compression.FileSystem.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.IO.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.IO.FileSystem.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.IO.FileSystem.Primitives.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.IO.UnmanagedMemoryStream.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Net.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Net.ServicePoint.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Numerics.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Numerics.Vectors.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Emit.ILGeneration.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Emit.Lightweight.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Extensions.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Primitives.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Resources.Reader.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Resources.ResourceManager.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.CompilerServices.Unsafe.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.dll: 35,328 bytes (34.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Extensions.dll: 7,680 bytes (7.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Handles.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.InteropServices.RuntimeInformation.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Intrinsics.dll: 8,704 bytes (8.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Loader.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Serialization.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Serialization.Json.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Serialization.Xml.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Algorithms.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Cng.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Csp.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Encoding.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.OpenSsl.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Primitives.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.X509Certificates.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.dll: 8,192 bytes (8.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Principal.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.SecureString.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.ServiceModel.Web.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.ServiceProcess.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Text.Encoding.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Text.Encoding.Extensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Overlapped.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Tasks.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Tasks.Extensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Thread.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.ThreadPool.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Timer.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Transactions.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.ValueTuple.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Web.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Windows.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.dll: 13,312 bytes (13.0 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.Linq.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.ReaderWriter.dll: 11,776 bytes (11.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.Serialization.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XDocument.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XmlDocument.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XmlSerializer.dll: 7,680 bytes (7.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XPath.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/WindowsBase.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -Contents/Resources/archived-expanded-entitlements.xcent: 241 bytes (0.2 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt deleted file mode 100644 index afdb9a86512a..000000000000 --- a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt +++ /dev/null @@ -1,307 +0,0 @@ -AppBundleSize: 248,097,882 bytes (242,283.1 KB = 236.6 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 54,948 bytes (53.7 KB = 0.1 MB) -Contents/Info.plist: 746 bytes (0.7 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 8,050,592 bytes (7,861.9 KB = 7.7 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.CSharp.dll: 882,176 bytes (861.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Caching.Abstractions.dll: 56,320 bytes (55.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Configuration.Abstractions.dll: 28,160 bytes (27.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.DependencyInjection.Abstractions.dll: 140,800 bytes (137.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Diagnostics.Abstractions.dll: 19,456 bytes (19.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.FileProviders.Abstractions.dll: 15,360 bytes (15.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Hosting.Abstractions.dll: 38,912 bytes (38.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Logging.Abstractions.dll: 150,528 bytes (147.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Options.dll: 135,168 bytes (132.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Primitives.dll: 70,144 bytes (68.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll: 37,112,832 bytes (36,243.0 KB = 35.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.Core.dll: 1,321,472 bytes (1,290.5 KB = 1.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Win32.Registry.dll: 23,552 bytes (23.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/SizeTestApp.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.Concurrent.dll: 136,704 bytes (133.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.dll: 317,952 bytes (310.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.Immutable.dll: 1,111,552 bytes (1,085.5 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.NonGeneric.dll: 94,208 bytes (92.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Collections.Specialized.dll: 94,720 bytes (92.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.Annotations.dll: 206,336 bytes (201.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.EventBasedAsync.dll: 28,672 bytes (28.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.Primitives.dll: 69,632 bytes (68.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ComponentModel.TypeConverter.dll: 867,840 bytes (847.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Console.dll: 215,040 bytes (210.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Data.Common.dll: 3,212,288 bytes (3,137.0 KB = 3.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.DiagnosticSource.dll: 549,888 bytes (537.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.FileVersionInfo.dll: 35,840 bytes (35.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.Process.dll: 371,200 bytes (362.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.StackTrace.dll: 26,112 bytes (25.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.TextWriterTraceListener.dll: 55,296 bytes (54.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Diagnostics.TraceSource.dll: 141,312 bytes (138.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Drawing.Primitives.dll: 118,272 bytes (115.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Formats.Asn1.dll: 249,344 bytes (243.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Formats.Tar.dll: 314,368 bytes (307.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Compression.Brotli.dll: 73,216 bytes (71.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Compression.dll: 537,600 bytes (525.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Compression.ZipFile.dll: 90,624 bytes (88.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.FileSystem.AccessControl.dll: 22,528 bytes (22.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.FileSystem.DriveInfo.dll: 78,848 bytes (77.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.FileSystem.Watcher.dll: 111,616 bytes (109.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.IsolatedStorage.dll: 73,728 bytes (72.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.MemoryMappedFiles.dll: 84,480 bytes (82.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Pipelines.dll: 189,440 bytes (185.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Pipes.AccessControl.dll: 13,824 bytes (13.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.IO.Pipes.dll: 136,192 bytes (133.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.AsyncEnumerable.dll: 1,592,320 bytes (1,555.0 KB = 1.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.dll: 807,936 bytes (789.0 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.Expressions.dll: 4,638,208 bytes (4,529.5 KB = 4.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.Parallel.dll: 882,176 bytes (861.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Linq.Queryable.dll: 210,432 bytes (205.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Memory.dll: 154,624 bytes (151.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Http.dll: 1,869,312 bytes (1,825.5 KB = 1.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Http.Json.dll: 119,296 bytes (116.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.HttpListener.dll: 316,928 bytes (309.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Mail.dll: 529,408 bytes (517.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.NameResolution.dll: 105,472 bytes (103.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.NetworkInformation.dll: 142,336 bytes (139.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Ping.dll: 88,064 bytes (86.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Primitives.dll: 241,152 bytes (235.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Quic.dll: 371,712 bytes (363.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Requests.dll: 405,504 bytes (396.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Security.dll: 791,040 bytes (772.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.ServerSentEvents.dll: 67,584 bytes (66.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.Sockets.dll: 694,784 bytes (678.5 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebClient.dll: 166,912 bytes (163.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebHeaderCollection.dll: 52,224 bytes (51.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebProxy.dll: 26,624 bytes (26.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebSockets.Client.dll: 89,088 bytes (87.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Net.WebSockets.dll: 237,056 bytes (231.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.ObjectModel.dll: 67,072 bytes (65.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.CoreLib.dll: 17,898,496 bytes (17,479.0 KB = 17.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.DataContractSerialization.dll: 2,375,168 bytes (2,319.5 KB = 2.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.Uri.dll: 252,928 bytes (247.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.Xml.dll: 8,758,784 bytes (8,553.5 KB = 8.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Private.Xml.Linq.dll: 412,160 bytes (402.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.DispatchProxy.dll: 62,976 bytes (61.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.Emit.dll: 335,872 bytes (328.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.Metadata.dll: 1,272,832 bytes (1,243.0 KB = 1.2 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Reflection.TypeExtensions.dll: 24,064 bytes (23.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Resources.Writer.dll: 35,840 bytes (35.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.CompilerServices.VisualC.dll: 8,704 bytes (8.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.InteropServices.dll: 100,864 bytes (98.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.InteropServices.JavaScript.dll: 27,136 bytes (26.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.Numerics.dll: 441,856 bytes (431.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.Serialization.Formatters.dll: 118,784 bytes (116.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Runtime.Serialization.Primitives.dll: 19,968 bytes (19.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.AccessControl.dll: 45,056 bytes (44.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.Claims.dll: 91,648 bytes (89.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.Cryptography.dll: 2,458,112 bytes (2,400.5 KB = 2.3 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Security.Principal.Windows.dll: 27,648 bytes (27.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.Encoding.CodePages.dll: 856,576 bytes (836.5 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.Encodings.Web.dll: 113,152 bytes (110.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.Json.dll: 2,176,000 bytes (2,125.0 KB = 2.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Text.RegularExpressions.dll: 1,179,648 bytes (1,152.0 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.AccessControl.dll: 23,552 bytes (23.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.Channels.dll: 155,136 bytes (151.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.dll: 71,168 bytes (69.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.Tasks.Dataflow.dll: 522,240 bytes (510.0 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Threading.Tasks.Parallel.dll: 122,880 bytes (120.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Transactions.Local.dll: 386,048 bytes (377.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Web.HttpUtility.dll: 47,104 bytes (46.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-arm64/System.Xml.XPath.XDocument.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.CSharp.dll: 785,408 bytes (767.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Caching.Abstractions.dll: 52,224 bytes (51.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Configuration.Abstractions.dll: 26,624 bytes (26.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.DependencyInjection.Abstractions.dll: 123,392 bytes (120.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Diagnostics.Abstractions.dll: 18,432 bytes (18.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.FileProviders.Abstractions.dll: 14,336 bytes (14.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Hosting.Abstractions.dll: 36,352 bytes (35.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Logging.Abstractions.dll: 134,656 bytes (131.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Options.dll: 119,808 bytes (117.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Primitives.dll: 63,488 bytes (62.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.macOS.dll: 37,112,832 bytes (36,243.0 KB = 35.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.VisualBasic.Core.dll: 1,152,000 bytes (1,125.0 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Win32.Registry.dll: 23,040 bytes (22.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/SizeTestApp.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.Concurrent.dll: 122,368 bytes (119.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.dll: 278,016 bytes (271.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.Immutable.dll: 979,456 bytes (956.5 KB = 0.9 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.NonGeneric.dll: 82,432 bytes (80.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Collections.Specialized.dll: 82,432 bytes (80.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.Annotations.dll: 181,248 bytes (177.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.EventBasedAsync.dll: 26,112 bytes (25.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.Primitives.dll: 60,416 bytes (59.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ComponentModel.TypeConverter.dll: 752,640 bytes (735.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Console.dll: 188,416 bytes (184.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Data.Common.dll: 2,783,744 bytes (2,718.5 KB = 2.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.DiagnosticSource.dll: 488,960 bytes (477.5 KB = 0.5 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.FileVersionInfo.dll: 33,280 bytes (32.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.Process.dll: 321,536 bytes (314.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.StackTrace.dll: 25,088 bytes (24.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.TextWriterTraceListener.dll: 48,640 bytes (47.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Diagnostics.TraceSource.dll: 120,832 bytes (118.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Drawing.Primitives.dll: 113,152 bytes (110.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Formats.Asn1.dll: 222,208 bytes (217.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Formats.Tar.dll: 273,408 bytes (267.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Compression.Brotli.dll: 63,488 bytes (62.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Compression.dll: 463,360 bytes (452.5 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Compression.ZipFile.dll: 81,408 bytes (79.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.FileSystem.AccessControl.dll: 22,528 bytes (22.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.FileSystem.DriveInfo.dll: 69,120 bytes (67.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.FileSystem.Watcher.dll: 96,256 bytes (94.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.IsolatedStorage.dll: 66,560 bytes (65.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.MemoryMappedFiles.dll: 72,704 bytes (71.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Pipelines.dll: 171,520 bytes (167.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Pipes.AccessControl.dll: 13,824 bytes (13.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.IO.Pipes.dll: 117,248 bytes (114.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.AsyncEnumerable.dll: 1,416,192 bytes (1,383.0 KB = 1.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.dll: 707,584 bytes (691.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.Expressions.dll: 3,709,952 bytes (3,623.0 KB = 3.5 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.Parallel.dll: 766,464 bytes (748.5 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Linq.Queryable.dll: 173,568 bytes (169.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Memory.dll: 142,336 bytes (139.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Http.dll: 1,648,640 bytes (1,610.0 KB = 1.6 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Http.Json.dll: 109,568 bytes (107.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.HttpListener.dll: 279,552 bytes (273.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Mail.dll: 461,824 bytes (451.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.NameResolution.dll: 92,160 bytes (90.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.NetworkInformation.dll: 123,904 bytes (121.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Ping.dll: 78,336 bytes (76.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Primitives.dll: 212,480 bytes (207.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Quic.dll: 330,240 bytes (322.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Requests.dll: 351,744 bytes (343.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Security.dll: 687,104 bytes (671.0 KB = 0.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.ServerSentEvents.dll: 61,952 bytes (60.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.Sockets.dll: 594,944 bytes (581.0 KB = 0.6 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebClient.dll: 147,456 bytes (144.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebHeaderCollection.dll: 44,544 bytes (43.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebProxy.dll: 24,064 bytes (23.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebSockets.Client.dll: 79,872 bytes (78.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Net.WebSockets.dll: 211,968 bytes (207.0 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.ObjectModel.dll: 58,880 bytes (57.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.CoreLib.dll: 16,443,904 bytes (16,058.5 KB = 15.7 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.DataContractSerialization.dll: 2,049,024 bytes (2,001.0 KB = 2.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.Uri.dll: 229,888 bytes (224.5 KB = 0.2 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.Xml.dll: 7,635,968 bytes (7,457.0 KB = 7.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Private.Xml.Linq.dll: 357,376 bytes (349.0 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.DispatchProxy.dll: 56,832 bytes (55.5 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.Emit.dll: 294,400 bytes (287.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.Metadata.dll: 1,142,272 bytes (1,115.5 KB = 1.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Reflection.TypeExtensions.dll: 21,504 bytes (21.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Resources.Writer.dll: 32,256 bytes (31.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.CompilerServices.VisualC.dll: 8,704 bytes (8.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.InteropServices.dll: 92,160 bytes (90.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.InteropServices.JavaScript.dll: 27,136 bytes (26.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.Numerics.dll: 412,672 bytes (403.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.Serialization.Formatters.dll: 105,472 bytes (103.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Runtime.Serialization.Primitives.dll: 18,432 bytes (18.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.AccessControl.dll: 45,056 bytes (44.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.Claims.dll: 81,920 bytes (80.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.Cryptography.dll: 2,130,944 bytes (2,081.0 KB = 2.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Security.Principal.Windows.dll: 27,648 bytes (27.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.Encoding.CodePages.dll: 839,680 bytes (820.0 KB = 0.8 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.Encodings.Web.dll: 104,448 bytes (102.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.Json.dll: 1,947,136 bytes (1,901.5 KB = 1.9 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Text.RegularExpressions.dll: 1,052,160 bytes (1,027.5 KB = 1.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.AccessControl.dll: 23,040 bytes (22.5 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.Channels.dll: 139,264 bytes (136.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.dll: 64,512 bytes (63.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.Tasks.Dataflow.dll: 460,800 bytes (450.0 KB = 0.4 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Threading.Tasks.Parallel.dll: 109,568 bytes (107.0 KB = 0.1 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Transactions.Local.dll: 341,504 bytes (333.5 KB = 0.3 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Web.HttpUtility.dll: 43,008 bytes (42.0 KB = 0.0 MB) -Contents/MonoBundle/.xamarin/osx-x64/System.Xml.XPath.XDocument.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/libclrgc.dylib: 2,038,208 bytes (1,990.4 KB = 1.9 MB) -Contents/MonoBundle/libclrgcexp.dylib: 2,198,640 bytes (2,147.1 KB = 2.1 MB) -Contents/MonoBundle/libclrjit.dylib: 6,539,344 bytes (6,386.1 KB = 6.2 MB) -Contents/MonoBundle/libcoreclr.dylib: 12,844,608 bytes (12,543.6 KB = 12.2 MB) -Contents/MonoBundle/libhostfxr.dylib: 833,536 bytes (814.0 KB = 0.8 MB) -Contents/MonoBundle/libhostpolicy.dylib: 776,624 bytes (758.4 KB = 0.7 MB) -Contents/MonoBundle/libmscordaccore.dylib: 4,453,664 bytes (4,349.3 KB = 4.2 MB) -Contents/MonoBundle/libmscordbi.dylib: 3,447,072 bytes (3,366.3 KB = 3.3 MB) -Contents/MonoBundle/libSystem.Globalization.Native.dylib: 286,816 bytes (280.1 KB = 0.3 MB) -Contents/MonoBundle/libSystem.IO.Compression.Native.dylib: 3,278,688 bytes (3,201.8 KB = 3.1 MB) -Contents/MonoBundle/libSystem.Native.dylib: 296,416 bytes (289.5 KB = 0.3 MB) -Contents/MonoBundle/libSystem.Net.Security.Native.dylib: 136,768 bytes (133.6 KB = 0.1 MB) -Contents/MonoBundle/libSystem.Security.Cryptography.Native.Apple.dylib: 460,880 bytes (450.1 KB = 0.4 MB) -Contents/MonoBundle/Microsoft.VisualBasic.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/Microsoft.Win32.Primitives.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/mscorlib.dll: 49,664 bytes (48.5 KB = 0.0 MB) -Contents/MonoBundle/netstandard.dll: 91,136 bytes (89.0 KB = 0.1 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,363 bytes (1.3 KB = 0.0 MB) -Contents/MonoBundle/System.AppContext.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Buffers.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.ComponentModel.DataAnnotations.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.Configuration.dll: 9,216 bytes (9.0 KB = 0.0 MB) -Contents/MonoBundle/System.Core.dll: 13,312 bytes (13.0 KB = 0.0 MB) -Contents/MonoBundle/System.Data.DataSetExtensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Data.dll: 15,360 bytes (15.0 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Contracts.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Debug.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Tools.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Diagnostics.Tracing.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.dll: 40,448 bytes (39.5 KB = 0.0 MB) -Contents/MonoBundle/System.Drawing.dll: 10,240 bytes (10.0 KB = 0.0 MB) -Contents/MonoBundle/System.Dynamic.Runtime.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Globalization.Calendars.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Globalization.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Globalization.Extensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.IO.Compression.FileSystem.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.IO.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.IO.FileSystem.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.IO.FileSystem.Primitives.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.IO.UnmanagedMemoryStream.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Net.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Net.ServicePoint.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Numerics.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Numerics.Vectors.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Emit.ILGeneration.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Emit.Lightweight.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Extensions.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Reflection.Primitives.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Resources.Reader.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Resources.ResourceManager.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.CompilerServices.Unsafe.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.dll: 35,328 bytes (34.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Extensions.dll: 7,680 bytes (7.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Handles.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.InteropServices.RuntimeInformation.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Intrinsics.dll: 8,704 bytes (8.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Loader.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Serialization.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Serialization.Json.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Runtime.Serialization.Xml.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Algorithms.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Cng.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Csp.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Encoding.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.OpenSsl.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.Primitives.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Cryptography.X509Certificates.dll: 7,168 bytes (7.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.dll: 8,192 bytes (8.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.Principal.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Security.SecureString.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.ServiceModel.Web.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.ServiceProcess.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Text.Encoding.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Text.Encoding.Extensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Overlapped.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Tasks.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Tasks.Extensions.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Thread.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.ThreadPool.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Threading.Timer.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Transactions.dll: 6,656 bytes (6.5 KB = 0.0 MB) -Contents/MonoBundle/System.ValueTuple.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Web.dll: 5,120 bytes (5.0 KB = 0.0 MB) -Contents/MonoBundle/System.Windows.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.dll: 13,312 bytes (13.0 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.Linq.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.ReaderWriter.dll: 11,776 bytes (11.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.Serialization.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XDocument.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XmlDocument.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XmlSerializer.dll: 7,680 bytes (7.5 KB = 0.0 MB) -Contents/MonoBundle/System.Xml.XPath.dll: 5,632 bytes (5.5 KB = 0.0 MB) -Contents/MonoBundle/WindowsBase.dll: 6,144 bytes (6.0 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -Contents/Resources/archived-expanded-entitlements.xcent: 241 bytes (0.2 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt deleted file mode 100644 index 6f5cf15dbe99..000000000000 --- a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt +++ /dev/null @@ -1,8 +0,0 @@ -AppBundleSize: 18,705,615 bytes (18,267.2 KB = 17.8 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 2,644 bytes (2.6 KB = 0.0 MB) -Contents/Info.plist: 746 bytes (0.7 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 18,700,128 bytes (18,261.8 KB = 17.8 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,848 bytes (1.8 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -Contents/Resources/archived-expanded-entitlements.xcent: 241 bytes (0.2 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt deleted file mode 100644 index 863fce7b7179..000000000000 --- a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt +++ /dev/null @@ -1,8 +0,0 @@ -AppBundleSize: 6,087,805 bytes (5,945.1 KB = 5.8 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -Contents/_CodeSignature/CodeResources: 2,644 bytes (2.6 KB = 0.0 MB) -Contents/Info.plist: 746 bytes (0.7 KB = 0.0 MB) -Contents/MacOS/SizeTestApp: 6,082,400 bytes (5,939.8 KB = 5.8 MB) -Contents/MonoBundle/runtimeconfig.bin: 1,766 bytes (1.7 KB = 0.0 MB) -Contents/PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -Contents/Resources/archived-expanded-entitlements.xcent: 241 bytes (0.2 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt index 23d1748debc9..1fe483d5e304 100644 --- a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt @@ -187,12 +187,9 @@ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.tvOS.dll:Foundation.NSObjectData -Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle Microsoft.tvOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.tvOS.dll:Foundation.NSObjectFlag Microsoft.tvOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -244,6 +241,12 @@ Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_IsStubClass() Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_IsWrapper() Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_Name() Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_SkipRegistration() +Microsoft.tvOS.dll:Foundation.TrackedMemory +Microsoft.tvOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.tvOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.tvOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.tvOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.tvOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.tvOS.dll:ObjCRuntime.__Registrar__ @@ -490,7 +493,6 @@ Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::class_ptr Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::ClassHandle() @@ -588,7 +590,6 @@ Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructINati Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.tvOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -1324,6 +1325,8 @@ Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.AdoptsAttribute::ProtocolHandle() Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle @@ -1485,9 +1488,10 @@ Microsoft.tvOS.dll:System.Reflection.MethodBase Registrar.Registrar/ObjCMethod:: Microsoft.tvOS.dll:System.Reflection.PropertyInfo Registrar.Registrar/ObjCProperty::Property Microsoft.tvOS.dll:System.Reflection.TypeFilter Registrar.SharedDynamic/<>c::<>9__0_0 Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-size.txt b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-size.txt deleted file mode 100644 index 250487f0078a..000000000000 --- a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-size.txt +++ /dev/null @@ -1,14 +0,0 @@ -AppBundleSize: 3,634,778 bytes (3,549.6 KB = 3.5 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 3,999 bytes (3.9 KB = 0.0 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,134 bytes (1.1 KB = 0.0 MB) -Microsoft.tvOS.dll: 154,624 bytes (151.0 KB = 0.1 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,405 bytes (1.4 KB = 0.0 MB) -SizeTestApp: 2,404,688 bytes (2,348.3 KB = 2.3 MB) -SizeTestApp.dll: 7,680 bytes (7.5 KB = 0.0 MB) -System.Private.CoreLib.aotdata.arm64: 41,464 bytes (40.5 KB = 0.0 MB) -System.Private.CoreLib.dll: 1,009,664 bytes (986.0 KB = 1.0 MB) -System.Runtime.dll: 5,120 bytes (5.0 KB = 0.0 MB) -System.Runtime.InteropServices.dll: 4,608 bytes (4.5 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt index 0067b7a14131..9fd004271447 100644 --- a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt @@ -170,12 +170,9 @@ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.tvOS.dll:Foundation.NSObjectData -Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle Microsoft.tvOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.tvOS.dll:Foundation.NSObjectFlag Microsoft.tvOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -186,6 +183,12 @@ Microsoft.tvOS.dll:Foundation.RegisterAttribute Microsoft.tvOS.dll:Foundation.RegisterAttribute..ctor(System.String, System.Boolean) Microsoft.tvOS.dll:Foundation.RegisterAttribute..ctor(System.String) Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_IsWrapper() +Microsoft.tvOS.dll:Foundation.TrackedMemory +Microsoft.tvOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.tvOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.tvOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.tvOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.tvOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.tvOS.dll:ObjCRuntime.__Registrar__ @@ -370,7 +373,6 @@ Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::handle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::Handle() @@ -446,7 +448,6 @@ Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructINati Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.tvOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -716,6 +717,8 @@ Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.NativeHandle::handle @@ -845,9 +848,10 @@ Microsoft.tvOS.dll:System.Object Foundation.NSObject/NSObject_Disposer::lock_obj Microsoft.tvOS.dll:System.Object ObjCRuntime.Runtime::lock_obj Microsoft.tvOS.dll:System.Reflection.Assembly Foundation.NSObject::PlatformAssembly Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-size.txt b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-size.txt deleted file mode 100644 index 75680b1883b6..000000000000 --- a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-size.txt +++ /dev/null @@ -1,19 +0,0 @@ -AppBundleSize: 9,563,600 bytes (9,339.5 KB = 9.1 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 5,233 bytes (5.1 KB = 0.0 MB) -aot-instances.aotdata.arm64: 829,256 bytes (809.8 KB = 0.8 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,134 bytes (1.1 KB = 0.0 MB) -Microsoft.tvOS.aotdata.arm64: 22,984 bytes (22.4 KB = 0.0 MB) -Microsoft.tvOS.dll: 48,640 bytes (47.5 KB = 0.0 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,481 bytes (1.4 KB = 0.0 MB) -SizeTestApp: 7,426,896 bytes (7,252.8 KB = 7.1 MB) -SizeTestApp.aotdata.arm64: 1,464 bytes (1.4 KB = 0.0 MB) -SizeTestApp.dll: 7,680 bytes (7.5 KB = 0.0 MB) -System.Private.CoreLib.aotdata.arm64: 667,992 bytes (652.3 KB = 0.6 MB) -System.Private.CoreLib.dll: 539,136 bytes (526.5 KB = 0.5 MB) -System.Runtime.aotdata.arm64: 784 bytes (0.8 KB = 0.0 MB) -System.Runtime.dll: 5,120 bytes (5.0 KB = 0.0 MB) -System.Runtime.InteropServices.aotdata.arm64: 800 bytes (0.8 KB = 0.0 MB) -System.Runtime.InteropServices.dll: 4,608 bytes (4.5 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/TVOS-NativeAOT-TrimmableStatic-size.txt b/tests/dotnet/UnitTests/expected/TVOS-NativeAOT-TrimmableStatic-size.txt deleted file mode 100644 index 97860fcbed6c..000000000000 --- a/tests/dotnet/UnitTests/expected/TVOS-NativeAOT-TrimmableStatic-size.txt +++ /dev/null @@ -1,8 +0,0 @@ -AppBundleSize: 7,975,268 bytes (7,788.3 KB = 7.6 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 2,589 bytes (2.5 KB = 0.0 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,134 bytes (1.1 KB = 0.0 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,889 bytes (1.8 KB = 0.0 MB) -SizeTestApp: 7,969,264 bytes (7,782.5 KB = 7.6 MB) diff --git a/tests/dotnet/UnitTests/expected/TVOS-NativeAOT-size.txt b/tests/dotnet/UnitTests/expected/TVOS-NativeAOT-size.txt deleted file mode 100644 index 7b50f3993bc5..000000000000 --- a/tests/dotnet/UnitTests/expected/TVOS-NativeAOT-size.txt +++ /dev/null @@ -1,8 +0,0 @@ -AppBundleSize: 2,849,475 bytes (2,782.7 KB = 2.7 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 2,589 bytes (2.5 KB = 0.0 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,134 bytes (1.1 KB = 0.0 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,808 bytes (1.8 KB = 0.0 MB) -SizeTestApp: 2,843,552 bytes (2,776.9 KB = 2.7 MB) diff --git a/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt index e6bc0a0de743..d841183c5eaf 100644 --- a/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt @@ -187,12 +187,9 @@ Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/X Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.iOS.dll:Foundation.NSObjectData -Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.iOS.dll:Foundation.NSObjectDataHandle Microsoft.iOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.iOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.iOS.dll:Foundation.NSObjectFlag Microsoft.iOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -244,6 +241,12 @@ Microsoft.iOS.dll:Foundation.RegisterAttribute.get_IsStubClass() Microsoft.iOS.dll:Foundation.RegisterAttribute.get_IsWrapper() Microsoft.iOS.dll:Foundation.RegisterAttribute.get_Name() Microsoft.iOS.dll:Foundation.RegisterAttribute.get_SkipRegistration() +Microsoft.iOS.dll:Foundation.TrackedMemory +Microsoft.iOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.iOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.iOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.iOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.iOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.iOS.dll:ObjCRuntime.__Registrar__ @@ -490,7 +493,6 @@ Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::class_ptr Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::ClassHandle() @@ -588,7 +590,6 @@ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructINativ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.iOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.iOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -1324,6 +1325,8 @@ Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.iOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.iOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.iOS.dll:System.IntPtr ObjCRuntime.AdoptsAttribute::ProtocolHandle() Microsoft.iOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.iOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle @@ -1485,9 +1488,10 @@ Microsoft.iOS.dll:System.Reflection.MethodBase Registrar.Registrar/ObjCMethod::M Microsoft.iOS.dll:System.Reflection.PropertyInfo Registrar.Registrar/ObjCProperty::Property Microsoft.iOS.dll:System.Reflection.TypeFilter Registrar.SharedDynamic/<>c::<>9__0_0 Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-size.txt b/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-size.txt deleted file mode 100644 index 642c33fbe658..000000000000 --- a/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-size.txt +++ /dev/null @@ -1,14 +0,0 @@ -AppBundleSize: 3,635,071 bytes (3,549.9 KB = 3.5 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 3,997 bytes (3.9 KB = 0.0 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,157 bytes (1.1 KB = 0.0 MB) -Microsoft.iOS.dll: 154,624 bytes (151.0 KB = 0.1 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,405 bytes (1.4 KB = 0.0 MB) -SizeTestApp: 2,404,960 bytes (2,348.6 KB = 2.3 MB) -SizeTestApp.dll: 7,680 bytes (7.5 KB = 0.0 MB) -System.Private.CoreLib.aotdata.arm64: 41,464 bytes (40.5 KB = 0.0 MB) -System.Private.CoreLib.dll: 1,009,664 bytes (986.0 KB = 1.0 MB) -System.Runtime.dll: 5,120 bytes (5.0 KB = 0.0 MB) -System.Runtime.InteropServices.dll: 4,608 bytes (4.5 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt index f42a3a8a15ef..6fb32b4c79df 100644 --- a/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt @@ -170,12 +170,9 @@ Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/X Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.iOS.dll:Foundation.NSObjectData -Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.iOS.dll:Foundation.NSObjectDataHandle Microsoft.iOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.iOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.iOS.dll:Foundation.NSObjectFlag Microsoft.iOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -186,6 +183,12 @@ Microsoft.iOS.dll:Foundation.RegisterAttribute Microsoft.iOS.dll:Foundation.RegisterAttribute..ctor(System.String, System.Boolean) Microsoft.iOS.dll:Foundation.RegisterAttribute..ctor(System.String) Microsoft.iOS.dll:Foundation.RegisterAttribute.get_IsWrapper() +Microsoft.iOS.dll:Foundation.TrackedMemory +Microsoft.iOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.iOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.iOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.iOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.iOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.iOS.dll:ObjCRuntime.__Registrar__ @@ -370,7 +373,6 @@ Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.iOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::handle Microsoft.iOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::Handle() @@ -446,7 +448,6 @@ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructINativ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.iOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.iOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -716,6 +717,8 @@ Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.iOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.iOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.iOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.iOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle Microsoft.iOS.dll:System.IntPtr ObjCRuntime.NativeHandle::handle @@ -845,9 +848,10 @@ Microsoft.iOS.dll:System.Object Foundation.NSObject/NSObject_Disposer::lock_obj Microsoft.iOS.dll:System.Object ObjCRuntime.Runtime::lock_obj Microsoft.iOS.dll:System.Reflection.Assembly Foundation.NSObject::PlatformAssembly Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/iOS-MonoVM-size.txt b/tests/dotnet/UnitTests/expected/iOS-MonoVM-size.txt deleted file mode 100644 index 5f2ec89a5c22..000000000000 --- a/tests/dotnet/UnitTests/expected/iOS-MonoVM-size.txt +++ /dev/null @@ -1,19 +0,0 @@ -AppBundleSize: 9,563,651 bytes (9,339.5 KB = 9.1 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 5,229 bytes (5.1 KB = 0.0 MB) -aot-instances.aotdata.arm64: 829,256 bytes (809.8 KB = 0.8 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,157 bytes (1.1 KB = 0.0 MB) -Microsoft.iOS.aotdata.arm64: 23,336 bytes (22.8 KB = 0.0 MB) -Microsoft.iOS.dll: 48,640 bytes (47.5 KB = 0.0 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,481 bytes (1.4 KB = 0.0 MB) -SizeTestApp: 7,426,576 bytes (7,252.5 KB = 7.1 MB) -SizeTestApp.aotdata.arm64: 1,464 bytes (1.4 KB = 0.0 MB) -SizeTestApp.dll: 7,680 bytes (7.5 KB = 0.0 MB) -System.Private.CoreLib.aotdata.arm64: 667,992 bytes (652.3 KB = 0.6 MB) -System.Private.CoreLib.dll: 539,136 bytes (526.5 KB = 0.5 MB) -System.Runtime.aotdata.arm64: 784 bytes (0.8 KB = 0.0 MB) -System.Runtime.dll: 5,120 bytes (5.0 KB = 0.0 MB) -System.Runtime.InteropServices.aotdata.arm64: 800 bytes (0.8 KB = 0.0 MB) -System.Runtime.InteropServices.dll: 4,608 bytes (4.5 KB = 0.0 MB) diff --git a/tests/dotnet/UnitTests/expected/iOS-NativeAOT-TrimmableStatic-size.txt b/tests/dotnet/UnitTests/expected/iOS-NativeAOT-TrimmableStatic-size.txt deleted file mode 100644 index df146f8b95aa..000000000000 --- a/tests/dotnet/UnitTests/expected/iOS-NativeAOT-TrimmableStatic-size.txt +++ /dev/null @@ -1,8 +0,0 @@ -AppBundleSize: 9,184,010 bytes (8,968.8 KB = 8.8 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 2,589 bytes (2.5 KB = 0.0 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,157 bytes (1.1 KB = 0.0 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,888 bytes (1.8 KB = 0.0 MB) -SizeTestApp: 9,177,984 bytes (8,962.9 KB = 8.8 MB) diff --git a/tests/dotnet/UnitTests/expected/iOS-NativeAOT-size.txt b/tests/dotnet/UnitTests/expected/iOS-NativeAOT-size.txt deleted file mode 100644 index 4fd201b269e6..000000000000 --- a/tests/dotnet/UnitTests/expected/iOS-NativeAOT-size.txt +++ /dev/null @@ -1,8 +0,0 @@ -AppBundleSize: 2,866,330 bytes (2,799.2 KB = 2.7 MB) -# The following list of files and their sizes is just informational / for review, and isn't used in the test: -_CodeSignature/CodeResources: 2,589 bytes (2.5 KB = 0.0 MB) -archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB) -Info.plist: 1,157 bytes (1.1 KB = 0.0 MB) -PkgInfo: 8 bytes (0.0 KB = 0.0 MB) -runtimeconfig.bin: 1,808 bytes (1.8 KB = 0.0 MB) -SizeTestApp: 2,860,384 bytes (2,793.3 KB = 2.7 MB) diff --git a/tests/framework-test/FrameworkTests.cs b/tests/framework-test/FrameworkTests.cs index da279d818e21..6092954415c4 100644 --- a/tests/framework-test/FrameworkTests.cs +++ b/tests/framework-test/FrameworkTests.cs @@ -19,10 +19,10 @@ public class FrameworkTests { [Test] public void CFunction () { - Assert.AreEqual (42, CFunctions.theUltimateAnswer (), "a"); + Assert.That (CFunctions.theUltimateAnswer (), Is.EqualTo (42), "a"); #if !__MACOS__ - Assert.AreEqual (42, CFunctions.object_theUltimateAnswer (), "object"); - Assert.AreEqual (42, CFunctions.ar_theUltimateAnswer (), "ar"); + Assert.That (CFunctions.object_theUltimateAnswer (), Is.EqualTo (42), "object"); + Assert.That (CFunctions.ar_theUltimateAnswer (), Is.EqualTo (42), "ar"); #endif } @@ -30,7 +30,7 @@ public void CFunction () public void ObjCClass () { using (var obj = new FrameworkTest ()) { - Assert.AreEqual (42, obj.Func (), "a"); + Assert.That (obj.Func (), Is.EqualTo (42), "a"); } } } diff --git a/tests/fsharp/FSharpTests.fs b/tests/fsharp/FSharpTests.fs index ed4c75bb2031..5e05fcec9dc8 100644 --- a/tests/fsharp/FSharpTests.fs +++ b/tests/fsharp/FSharpTests.fs @@ -24,4 +24,4 @@ type FSharpTest () = let e = 5555 let pr = sprintf "%d %d %d %d %d" a b c d e - Assert.AreEqual ("1111 2222 3333 4444 5555", pr) + Assert.That (pr, Is.EqualTo ("1111 2222 3333 4444 5555")) diff --git a/tests/interdependent-binding-projects/Main.cs b/tests/interdependent-binding-projects/Main.cs index 2c08bd2dc725..892a12493f39 100644 --- a/tests/interdependent-binding-projects/Main.cs +++ b/tests/interdependent-binding-projects/Main.cs @@ -15,6 +15,6 @@ static partial void AddTestAssembliesImpl (HashSet assemblies) public class LoaderTest { public void TestAssemblyCount () { - Assert.AreEqual (3, TestLoader.GetTestAssemblies ().Count (), "Test assembly count"); + Assert.That (TestLoader.GetTestAssemblies ().Count (), Is.EqualTo (3), "Test assembly count"); } } diff --git a/tests/introspection/ApiSelectorTest.cs b/tests/introspection/ApiSelectorTest.cs index d22c7b8829d2..98aa1316d090 100644 --- a/tests/introspection/ApiSelectorTest.cs +++ b/tests/introspection/ApiSelectorTest.cs @@ -242,15 +242,6 @@ protected virtual bool Skip (Type type, string selectorName) return true; } break; - case "CIFilterGenerator": - switch (selectorName) { - case "filterGenerator": - case "filterGeneratorWithContentsOfURL:": - if (TestRuntime.IsSimulatorOrDesktop) - return true; - break; - } - break; } // This ctors needs to be manually bound switch (type.Name) { diff --git a/tests/linker/link all/LinkAllMacTest.cs b/tests/linker/link all/LinkAllMacTest.cs index 363e29d8d920..fad1a76cf15f 100644 --- a/tests/linker/link all/LinkAllMacTest.cs +++ b/tests/linker/link all/LinkAllMacTest.cs @@ -2,6 +2,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Threading; +using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; @@ -73,6 +74,75 @@ public SerializeMe () SetMe = 1; } } + + // https://github.com/xamarin/bugzilla-archives/blob/main/16/16505/bug.html + [Test] + public void PrintPreview_NSGraphicsContextCurrentContext () + { + TestRuntime.AssertXcodeVersion (26, 0); + + // Verify that accessing NSGraphicsContext.CurrentContext during print preview + // doesn't crash due to the linker trimming NSPrintPreviewGraphicsContext. + var printableView = new PrintableView (new CoreGraphics.CGRect (0, 0, 100, 100)); + + var printInfo = (NSPrintInfo) NSPrintInfo.SharedPrintInfo.Copy (); + printInfo.JobDisposition = "NSPrintPreviewJob"; + + var printOp = NSPrintOperation.FromView (printableView, printInfo); + printOp.ShowsPrintPanel = true; // this is required to trigger the bug + printOp.ShowsProgressPanel = true; + + var closedPreview = false; + var closeAction = new Action (() => { + if (closedPreview) + return; + NSApplication.SharedApplication.AbortModal (); + closedPreview = true; + }); + + printableView.TaskCompletionSource.Task.ContinueWith (task => { + closeAction (); + }, TaskScheduler.FromCurrentSynchronizationContext ()); + + // Auto-close after 3 seconds in case something goes wrong + var timer = NSTimer.CreateScheduledTimer (3.0, (t) => closeAction ()); + NSRunLoop.Current.AddTimer (timer, NSRunLoopMode.ModalPanel); + + printOp.RunOperation (); + + Assert.That (printableView.TaskCompletionSource.Task.IsCompletedSuccessfully, Is.True, "DrawPageBorder was called successfully"); + var context = printableView.TaskCompletionSource.Task.Result; + Assert.That (context, Is.Not.Null, "NSGraphicsContext.CurrentContext was not null during print preview"); + } + } + + class PrintableView : NSView { + public PrintableView (CoreGraphics.CGRect frame) : base (frame) { } + + public TaskCompletionSource TaskCompletionSource = new (); + + public override void DrawPageBorder (CoreGraphics.CGSize borderSize) + { + try { + var context = NSGraphicsContext.CurrentContext; + base.DrawPageBorder (borderSize); + TaskCompletionSource.TrySetResult (context); + } catch (Exception e) { + Console.WriteLine ($"Unexpected exception occurred: {e}"); + TaskCompletionSource.TrySetException (e); + } + } + + public override bool KnowsPageRange (ref Foundation.NSRange range) + { + range = new Foundation.NSRange (1, 1); + return true; + } + + public override CoreGraphics.CGRect RectForPage (nint pageNumber) + { + return Bounds; + } } } #endif // __MACOS__ diff --git a/tests/linker/link all/LinkAllTest.cs b/tests/linker/link all/LinkAllTest.cs index 2ff37fa27fd0..8a21b29c7d13 100644 --- a/tests/linker/link all/LinkAllTest.cs +++ b/tests/linker/link all/LinkAllTest.cs @@ -466,15 +466,6 @@ public void AppleTls () Assert.That (Helper.GetType (fqn), Is.Null, "Should NOT be included (no SslStream or Socket support)"); } - [Test] - // https://bugzilla.xamarin.com/show_bug.cgi?id=59247 - public void WebKit_NSProxy () - { - // this test works only because "Link all" does not use WebKit - var fqn = typeof (NSObject).AssemblyQualifiedName!.Replace ("Foundation.NSObject", "Foundation.NSProxy"); - Assert.That (Helper.GetType (fqn), Is.Null, fqn); - } - static Type type_Task = typeof (Task); [Test] diff --git a/tests/linker/link all/dotnet/shared.csproj b/tests/linker/link all/dotnet/shared.csproj index f11e80546aac..6b75ec2a2d4e 100644 --- a/tests/linker/link all/dotnet/shared.csproj +++ b/tests/linker/link all/dotnet/shared.csproj @@ -86,4 +86,10 @@ + + + + + + diff --git a/tests/linker/link sdk/LinkSdkRegressionTest.cs b/tests/linker/link sdk/LinkSdkRegressionTest.cs index b75d223ed24a..0f147186f702 100644 --- a/tests/linker/link sdk/LinkSdkRegressionTest.cs +++ b/tests/linker/link sdk/LinkSdkRegressionTest.cs @@ -789,11 +789,11 @@ void SpecialFolderImpl () #else var myExists = false; #endif - path = TestFolder (Environment.SpecialFolder.MyMusic, exists: myExists); + path = TestFolderIfAvailableInCI (Environment.SpecialFolder.MyMusic, myExists); - path = TestFolder (Environment.SpecialFolder.MyVideos, exists: myExists); + path = TestFolderIfAvailableInCI (Environment.SpecialFolder.MyVideos, myExists); - path = TestFolder (Environment.SpecialFolder.DesktopDirectory, exists: myExists); + path = TestFolderIfAvailableInCI (Environment.SpecialFolder.DesktopDirectory, myExists); #if __TVOS__ path = TestFolder (Environment.SpecialFolder.Fonts, exists: null, supported: true); @@ -811,7 +811,7 @@ void SpecialFolderImpl () path = TestFolder (Environment.SpecialFolder.Templates, exists: false); #endif - path = TestFolder (Environment.SpecialFolder.MyPictures, exists: myExists); + path = TestFolderIfAvailableInCI (Environment.SpecialFolder.MyPictures, myExists); #if __MACOS__ path = TestFolder (Environment.SpecialFolder.CommonTemplates, supported: false); @@ -897,6 +897,17 @@ void SpecialFolderImpl () path = TestFolder (Environment.SpecialFolder.Resources, readOnly: tvos && device); Assert.That (path.EndsWith ("/Library", StringComparison.Ordinal), Is.True, "Resources"); #endif + // Some CI VM images don't initialize all standard user directories, so keep this + // tolerance limited to CI VMs and preserve the stricter check for other runs. + string TestFolderIfAvailableInCI (Environment.SpecialFolder folder, bool exists) + { +#if __MACOS__ + var path = Environment.GetFolderPath (folder); + if (string.IsNullOrEmpty (path) && TestRuntime.IsInCI && TestRuntime.IsVM) + return path; +#endif + return TestFolder (folder, exists: exists); + } } #if !__MACOS__ diff --git a/tests/linker/trimmode link/dotnet/shared.csproj b/tests/linker/trimmode link/dotnet/shared.csproj index 525978b17599..48401810a36d 100644 --- a/tests/linker/trimmode link/dotnet/shared.csproj +++ b/tests/linker/trimmode link/dotnet/shared.csproj @@ -88,4 +88,10 @@ + + + + + + diff --git a/tests/monotouch-test/AppKit/NSPasteboard.cs b/tests/monotouch-test/AppKit/NSPasteboard.cs index cdfe371a71eb..82455b33b237 100644 --- a/tests/monotouch-test/AppKit/NSPasteboard.cs +++ b/tests/monotouch-test/AppKit/NSPasteboard.cs @@ -129,7 +129,7 @@ public void DetectPatternTests_StronglyTyped () Assert.That (evt.WaitOne (TimeSpan.FromSeconds (1)), "StronglyTyped DetectPatterns #2 wait"); Assert.That (detectedPatterns, Is.Not.Null, "StronglyTyped DetectedPatterns #2 patterns"); Assert.That ((int) detectedPatterns.Count, Is.EqualTo (1), "StronglyTyped DetectedPatterns #2 count"); - Assert.That (detectedPatterns, Does.Contain (NSPasteboardDetectionPattern.EmailAddress), "StronglyTyped DetectedPatterns #2 email"); + Assert.That (detectedPatterns.Contains (NSPasteboardDetectionPattern.EmailAddress), "StronglyTyped DetectedPatterns #2 email"); Assert.That (error, Is.Null, "StronglyTyped DetectedPatterns #2 error"); } finally { pasteboard.ReleaseGlobally (); @@ -294,7 +294,7 @@ public void DetectValuesTests_StronglyTyped () Assert.That (evt.WaitOne (TimeSpan.FromSeconds (1)), "StronglyTyped DetectValues #2 wait"); Assert.That (detected, Is.Not.Null, "StronglyTyped DetectValues #2 patterns"); Assert.That ((int) detected.Count, Is.EqualTo (1), "StronglyTyped DetectValues #2 count"); - Assert.That (detected.Keys, Does.Contain (NSPasteboardDetectionPattern.EmailAddress), "StronglyTyped DetectValues #2 email"); + Assert.That (detected.Keys.Contains (NSPasteboardDetectionPattern.EmailAddress), "StronglyTyped DetectValues #2 email"); matches = detected.Values.First (); Assert.That (matches.Length, Is.EqualTo (1), "StronglyTyped DetectValues #2 matches.Length"); match = matches [0]; @@ -312,7 +312,7 @@ public void DetectValuesTests_StronglyTyped () Assert.That (evt.WaitOne (TimeSpan.FromSeconds (1)), "StronglyTyped DetectValues #3 wait"); Assert.That (detected, Is.Not.Null, "StronglyTyped DetectValues #3 patterns"); Assert.That ((int) detected.Count, Is.EqualTo (1), "StronglyTyped DetectValues #3 count"); - Assert.That (detected.Keys, Does.Contain (NSPasteboardDetectionPattern.EmailAddress), "StronglyTyped DetectValues #3 email"); + Assert.That (detected.Keys.Contains (NSPasteboardDetectionPattern.EmailAddress), "StronglyTyped DetectValues #3 email"); matches = detected.Values.First (); Assert.That (matches.Length, Is.EqualTo (1), "StronglyTyped DetectValues #3 matches.Length"); match = matches [0]; diff --git a/tests/monotouch-test/AppKit/NSView.cs b/tests/monotouch-test/AppKit/NSView.cs index 8fc42eaf1828..aaeb7031e712 100644 --- a/tests/monotouch-test/AppKit/NSView.cs +++ b/tests/monotouch-test/AppKit/NSView.cs @@ -50,6 +50,11 @@ public void NSViewShouldChangeGestureRecognizers () [Test] [UnconditionalSuppressMessage ("Trimming", "IL2075", Justification = "This test handles APIs that have been linked away, so it's trimmer-safe.")] + [DynamicDependency ("Menu", typeof (AppKit.NSCell))] + [DynamicDependency ("Menu", typeof (AppKit.NSMenuItem))] + [DynamicDependency ("Menu", typeof (AppKit.NSPathControl))] + [DynamicDependency ("Menu", typeof (AppKit.NSPopUpButton))] + [DynamicDependency ("Menu", typeof (AppKit.NSPopUpButtonCell))] public void AllItemsWithNSMenuShouldAllowNull () { // Can't test NSResponder since it is abstract diff --git a/tests/monotouch-test/AudioToolbox/AudioQueueTest.cs b/tests/monotouch-test/AudioToolbox/AudioQueueTest.cs index a5249b42ea58..abe7b02f3266 100644 --- a/tests/monotouch-test/AudioToolbox/AudioQueueTest.cs +++ b/tests/monotouch-test/AudioToolbox/AudioQueueTest.cs @@ -30,6 +30,8 @@ public void Properties () [Test] public void ChannelAssignments () { + TestRuntime.AssertNotVirtualMachine (); + var aq = new OutputAudioQueue (AudioStreamBasicDescription.CreateLinearPCM ()); var route = global::AVFoundation.AVAudioSession.SharedInstance ().CurrentRoute; diff --git a/tests/monotouch-test/CoreAnimation/LayerTest.cs b/tests/monotouch-test/CoreAnimation/LayerTest.cs index 5cf0be59a801..8c689285b031 100644 --- a/tests/monotouch-test/CoreAnimation/LayerTest.cs +++ b/tests/monotouch-test/CoreAnimation/LayerTest.cs @@ -131,9 +131,11 @@ public void TestBug26532 () } catch (Exception e) { ex = e; } - }); + }) { + IsBackground = true, + }; thread.Start (); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (10)), Is.True, "Thread.Join timed out"); var watch = new Stopwatch (); watch.Start (); @@ -181,7 +183,7 @@ public void TestCALayerDelegateDispose () IsBackground = true, }; t.Start (); - t.Join (); + Assert.That (t.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); GC.Collect (); NSRunLoop.Main.RunUntil (NSDate.Now.AddSeconds (0.1)); diff --git a/tests/monotouch-test/CoreImage/CIKernelTests.cs b/tests/monotouch-test/CoreImage/CIKernelTests.cs index 87cf3717ede0..3376f816d7e0 100644 --- a/tests/monotouch-test/CoreImage/CIKernelTests.cs +++ b/tests/monotouch-test/CoreImage/CIKernelTests.cs @@ -153,9 +153,11 @@ public void CIKernel_BasicTest () } catch (Exception ex2) { ex = ex2; } - }); + }) { + IsBackground = true, + }; t.Start (); - t.Join (); + Assert.That (t.Join (TimeSpan.FromSeconds (30)), Is.True, "Thread.Join timed out"); if (ex is not null) throw ex; } diff --git a/tests/monotouch-test/Foundation/NSStreamTest.cs b/tests/monotouch-test/Foundation/NSStreamTest.cs index d6c441e6403a..ce64ceed03cd 100644 --- a/tests/monotouch-test/Foundation/NSStreamTest.cs +++ b/tests/monotouch-test/Foundation/NSStreamTest.cs @@ -63,7 +63,9 @@ public void ConnectToHost () return; } - var listenThread = new Thread (new ParameterizedThreadStart (DebugListener)); + var listenThread = new Thread (new ParameterizedThreadStart (DebugListener)) { + IsBackground = true, + }; listenThread.Start (listener); NSStream.CreatePairWithSocketToHost (new IPEndPoint (IPAddress.Loopback, port), out read, out write); read.Open (); @@ -74,7 +76,7 @@ public void ConnectToHost () Assert.That (read.Read (result, 5), Is.EqualTo ((nint) 5)); for (int i = 0; i < 5; i++) Assert.That (result [i], Is.EqualTo (send [i] * 10)); - listenThread.Join (); + Assert.That (listenThread.Join (TimeSpan.FromSeconds (10)), Is.True, "listenThread.Join timed out"); listener.Stop (); read.Close (); write.Close (); diff --git a/tests/monotouch-test/Foundation/NotificationCenter.cs b/tests/monotouch-test/Foundation/NotificationCenter.cs index cab2406ee854..adea6d9968d4 100644 --- a/tests/monotouch-test/Foundation/NotificationCenter.cs +++ b/tests/monotouch-test/Foundation/NotificationCenter.cs @@ -140,7 +140,7 @@ public void ThreadSafe () // OK, we're done now, time to stop. stopSignal.Set (); for (var i = 0; i < threadCount; i++) { - threads [i].Join (); + Assert.That (threads [i].Join (TimeSpan.FromSeconds (5)), Is.True, $"Thread {i} failed to join within 5 seconds"); } Assert.That (ex, Is.Null, "Exception"); } diff --git a/tests/monotouch-test/Foundation/ObjectTest.cs b/tests/monotouch-test/Foundation/ObjectTest.cs index 31060e58eed3..61a613419cb6 100644 --- a/tests/monotouch-test/Foundation/ObjectTest.cs +++ b/tests/monotouch-test/Foundation/ObjectTest.cs @@ -270,7 +270,6 @@ public void ObserverTest () } [Test] - [Timeout (5000)] public void InvokeTest () { var evt = new ManualResetEvent (false); diff --git a/tests/monotouch-test/Foundation/ThreadTest.cs b/tests/monotouch-test/Foundation/ThreadTest.cs index 120d545ebc14..93028e29763b 100644 --- a/tests/monotouch-test/Foundation/ThreadTest.cs +++ b/tests/monotouch-test/Foundation/ThreadTest.cs @@ -40,7 +40,7 @@ public void GetEntryAssemblyReturnsOk () IsBackground = true, }; t.Start (); - t.Join (); + Assert.That (t.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); Assert.That (rv, Is.EqualTo (0)); } diff --git a/tests/monotouch-test/Foundation/TimerTest.cs b/tests/monotouch-test/Foundation/TimerTest.cs index 7e7ad52f4db4..be39f8e5be9b 100644 --- a/tests/monotouch-test/Foundation/TimerTest.cs +++ b/tests/monotouch-test/Foundation/TimerTest.cs @@ -42,7 +42,7 @@ public void Bug17793 () thread.Start (); Assert.That (evt.Wait (TimeSpan.FromSeconds (5)), Is.True, "Not signalled twice in 5s"); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (10)), Is.True, "Thread.Join timed out"); } } @@ -70,7 +70,7 @@ public void Bug2443 () thread.Start (); Assert.That (evt.Wait (TimeSpan.FromSeconds (5)), Is.True, "Not signalled twice in 5s"); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (10)), Is.True, "Thread.Join timed out"); } } @@ -101,7 +101,7 @@ public void CreateTimer_NewSignature () Assert.That (evt.WaitOne (TimeSpan.FromSeconds (5)), Is.True, "WaitOne"); Assert.That (result, Is.True, "result"); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (10)), Is.True, "Thread.Join timed out"); } } } diff --git a/tests/monotouch-test/HttpClient/HttpClientTest.cs b/tests/monotouch-test/HttpClient/HttpClientTest.cs index ba17c5427721..77efe890d8fb 100644 --- a/tests/monotouch-test/HttpClient/HttpClientTest.cs +++ b/tests/monotouch-test/HttpClient/HttpClientTest.cs @@ -80,7 +80,9 @@ public static IHandlerWrapper GetWrapper (Type handlerType) } [TestCase (typeof (HttpClientHandler), 8)] - [TestCase (typeof (CFNetworkHandler), 8)] + // There are known issues (deadlocks) with CFNetworkHandler: https://github.com/dotnet/macios/issues/25634 + // CFNetworkHandler is obsolete, so we won't fix any such issues, so to avoid deadlocks, just avoid testing CFNetworkHandler. + [TestCase (typeof (CFNetworkHandler), 8, Ignore = "There are known issues (deadlocks) with CFNetworkHandler: https://github.com/dotnet/macios/issues/25634")] [TestCase (typeof (NSUrlSessionHandler), 9)] public void EnsureModifiabilityPostSend (Type handlerType, int macOSMinVersion) { diff --git a/tests/monotouch-test/Metal/MTLDeviceTests.cs b/tests/monotouch-test/Metal/MTLDeviceTests.cs index 2a6a38b51134..948737e2749b 100644 --- a/tests/monotouch-test/Metal/MTLDeviceTests.cs +++ b/tests/monotouch-test/Metal/MTLDeviceTests.cs @@ -86,6 +86,8 @@ public void ReturnReleaseTest () if (device is null) Assert.Inconclusive ("Metal is not supported"); + TestRuntime.AssertNotVirtualMachine (); + // Apple claims that "Indirect command buffers" are available with MTLGPUFamilyCommon2, but it crashes on at least one machine. // Log what the current device supports, just to have it in the log. foreach (MTLFeatureSet fs in Enum.GetValues ()) { diff --git a/tests/monotouch-test/ObjCRuntime/DelegateAndDataSourceTest.cs b/tests/monotouch-test/ObjCRuntime/DelegateAndDataSourceTest.cs index 2332d2ec96fd..748cc67173d7 100644 --- a/tests/monotouch-test/ObjCRuntime/DelegateAndDataSourceTest.cs +++ b/tests/monotouch-test/ObjCRuntime/DelegateAndDataSourceTest.cs @@ -68,6 +68,8 @@ public void DelegateAndDataSourceAllowsNull () dataSource.SetValue (instance, null, null); } } + } catch (NotSupportedException e) when (e.Message.Contains ("This object cannot be invoked because no code was generated for it")) { + Console.WriteLine ($"Not testing {t.FullName}, because it's been partially trimmed away."); } catch (TargetInvocationException e) { failingTypes.Add (t, e.InnerException.Message); } catch (Exception e) { diff --git a/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs b/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs index fd82fd56373f..c72e97e531d4 100644 --- a/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs +++ b/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs @@ -1027,7 +1027,7 @@ public virtual NSObject TestOverriddenRetainNSObject () [Export ("testNativeEnum1:")] public virtual void TestNativeEnum1 (NSWritingDirection twd) { - Assert.That (Enum.GetValues (), Contains.Item (twd), "TestNativeEnum1"); + Assert.That (Enum.GetValues ().Contains (twd), "TestNativeEnum1"); } public virtual UIPopoverArrowDirection TestNativeEnum2 { @@ -2122,9 +2122,11 @@ public void BlockCollection () } catch (Exception e) { ex = e; } - }); + }) { + IsBackground = true, + }; thread.Start (); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (30)), Is.True, "Thread.Join timed out"); GC.Collect (); GC.WaitForPendingFinalizers (); TestRuntime.RunAsync (TimeSpan.FromSeconds (30), () => { }, () => ObjCBlockTester.FreedBlockCount > initialFreedCount); diff --git a/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs b/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs index 0fc4318e3168..10a84df16946 100644 --- a/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs +++ b/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs @@ -198,7 +198,7 @@ public bool UsableUntilDeadImpl () IsBackground = true, }; t.Start (); - t.Join (); + Assert.That (t.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); // Now we have a handle to an object that may be garbage collected at any time. int counter = 0; @@ -297,7 +297,7 @@ public void FinalizationRaceCondition () IsBackground = true }; thread.Start (); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); var getter1 = new Func ((key) => dict [key] as NSString); var getter2 = new Func ((key) => dict [key] as NSString); @@ -555,9 +555,11 @@ public void ResurrectedObjectsDisposedTest (Type type) var t1 = new Thread (() => { for (int i = 0; i < objects.Length; i++) Messaging.bool_objc_msgSend_IntPtr_int (invokerClassHandle, Selector.GetHandle ("invokeMe:wait:"), objects [i], 0); - }); + }) { + IsBackground = true, + }; t1.Start (); - t1.Join (); + Assert.That (t1.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); // Collect all those managed wrappers, and make sure their finalizers are executed. GC.Collect (); diff --git a/tests/monotouch-test/Security/SecSharedCredentialTest.cs b/tests/monotouch-test/Security/SecSharedCredentialTest.cs index 0136f253edf0..11e0667623eb 100644 --- a/tests/monotouch-test/Security/SecSharedCredentialTest.cs +++ b/tests/monotouch-test/Security/SecSharedCredentialTest.cs @@ -44,9 +44,7 @@ public void AddSharedWebCredentialNullAccount () } [Test] - // We do not want to block for a long period of time if the event is not set. // We are testing the fact that the trampoline works. - [Timeout (5000)] public void AddSharedWebCredentialNotNullPassword () { Action handler = (NSError e) => { @@ -56,9 +54,7 @@ public void AddSharedWebCredentialNotNullPassword () } [Test] - // We do not want to block for a long period of time if the event is not set. // We are testing the fact that the trampoline works. - [Timeout (5000)] public void AddSharedWebCredentialNullPassword () { password = null; @@ -69,9 +65,7 @@ public void AddSharedWebCredentialNullPassword () } [Test] - // We do not want to block for a long period of time if the event is not set. // We are testing the fact that the trampoline works. - [Timeout (5000)] public void RequestSharedWebCredentialTest () { Action handler = (SecSharedCredentialInfo [] creds, NSError e) => { @@ -81,9 +75,7 @@ public void RequestSharedWebCredentialTest () } [Test] - // We do not want to block for a long period of time if the event is not set. // We are testing the fact that the trampoline works. - [Timeout (5000)] public void RequestSharedWebCredentialNullDomainAndAccountTest () { Action handler = (SecSharedCredentialInfo [] creds, NSError e) => { diff --git a/tests/monotouch-test/System.Net.Http/MessageHandlers.cs b/tests/monotouch-test/System.Net.Http/MessageHandlers.cs index 2accb1397400..2811dd23ee2c 100644 --- a/tests/monotouch-test/System.Net.Http/MessageHandlers.cs +++ b/tests/monotouch-test/System.Net.Http/MessageHandlers.cs @@ -3,6 +3,7 @@ // using System.Collections; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using System.Net; @@ -25,6 +26,9 @@ namespace MonoTests.System.Net.Http { [TestFixture] [Preserve (AllMembers = true)] public class MessageHandlerTest { + const string AllowSameOriginRedirectCredentialsSwitch = "Foundation.NSUrlSessionHandler.AllowSameOriginRedirectCredentials"; + const string UseSharedCredentialStorageSwitch = "Foundation.NSUrlSessionHandler.UseSharedCredentialStorage"; + public MessageHandlerTest () { // Https seems broken on our macOS 10.9 bot, so skip this test. @@ -48,7 +52,9 @@ HttpMessageHandler GetHandler (Type handler_type) [Test] [TestCase (typeof (HttpClientHandler))] - [TestCase (typeof (CFNetworkHandler))] + // There are known issues (deadlocks) with CFNetworkHandler: https://github.com/dotnet/macios/issues/25634 + // CFNetworkHandler is obsolete, so we won't fix any such issues, so to avoid deadlocks, just avoid testing CFNetworkHandler. + [TestCase (typeof (CFNetworkHandler), Ignore = "There are known issues (deadlocks) with CFNetworkHandler: https://github.com/dotnet/macios/issues/25634")] [TestCase (typeof (SocketsHttpHandler))] [TestCase (typeof (NSUrlSessionHandler))] public void DnsFailure (Type handlerType) @@ -434,7 +440,9 @@ public void TestNSUrlSessionTimeoutExceptionWhileStreamingContent () // ensure that if we have a redirect, we do not have the auth headers in the following requests [TestCase (typeof (HttpClientHandler))] - [TestCase (typeof (CFNetworkHandler))] + // There are known issues (deadlocks) with CFNetworkHandler: https://github.com/dotnet/macios/issues/25634 + // CFNetworkHandler is obsolete, so we won't fix any such issues, so to avoid deadlocks, just avoid testing CFNetworkHandler. + [TestCase (typeof (CFNetworkHandler), Ignore = "There are known issues (deadlocks) with CFNetworkHandler: https://github.com/dotnet/macios/issues/25634")] [TestCase (typeof (NSUrlSessionHandler))] public void RedirectionWithAuthorizationHeaders (Type handlerType) { @@ -446,12 +454,15 @@ public void RedirectionWithAuthorizationHeaders (Type handlerType) bool containsHeaders = false; string json = ""; + using var handler = GetHandler (handlerType); var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { - HttpClient client = new HttpClient (GetHandler (handlerType)); + using var client = new HttpClient (handler, disposeHandler: false) { + Timeout = TimeSpan.FromSeconds (20), + }; client.BaseAddress = NetworkResources.Httpbin.Uri; var byteArray = new UTF8Encoding ().GetBytes ("username:password"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Basic", Convert.ToBase64String (byteArray)); - var result = await client.GetAsync (NetworkResources.Httpbin.GetRedirectUrl (3)); + using var result = await client.GetAsync (NetworkResources.Httpbin.GetRedirectUrl (3)); // get the data returned from httpbin which contains the details of the requested performed. json = await result.Content.ReadAsStringAsync (); containsAuthorizarion = json.Contains ("Authorization"); @@ -459,12 +470,147 @@ public void RedirectionWithAuthorizationHeaders (Type handlerType) }, out var ex); if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail + TestRuntime.IgnoreInCIIfHttpClientTimedOut (); Assert.Inconclusive ("Request timedout."); + } else if (ex is not null) { + TestRuntime.IgnoreInCIIfBadNetwork (ex); + Assert.That (ex, Is.Null, $"Exception {ex} for {json}"); } else if (!containsHeaders) { Assert.Inconclusive ("Response from httpbin does not contain headers, therefore we cannot ensure that if the authoriation is present."); } else { Assert.That (containsAuthorizarion, Is.False, $"Authorization header did reach the final destination. {json}"); - Assert.That (ex, Is.Null, $"Exception {ex} for {json}"); + } + } + + [TestCase (true, false, HttpStatusCode.Unauthorized, false, TestName = "NSUrlSessionHandlerOriginCredentialCacheNotSentToCrossOriginRedirectTarget")] + [TestCase (true, true, HttpStatusCode.OK, true, TestName = "NSUrlSessionHandlerTargetCredentialCacheSentToCrossOriginRedirectTarget")] + [TestCase (false, false, HttpStatusCode.Unauthorized, false, TestName = "NSUrlSessionHandlerNetworkCredentialNotSentToCrossOriginRedirectTarget")] + public void NSUrlSessionHandlerCredentialsCrossOriginRedirectTarget (bool useCredentialCache, bool cacheRedirectTarget, HttpStatusCode expectedStatusCode, bool expectAuthorizationHeader) + { + if (!HttpListener.IsSupported) { + Assert.Inconclusive ("HttpListener is not supported"); + } + + using var server = new RedirectBasicAuthServer (crossOrigin: true); + using var handler = new NSUrlSessionHandler (); + var username = "origin-user"; + var password = "origin-password"; + + if (useCredentialCache) { + var cache = new CredentialCache (); + var credentialUri = cacheRedirectTarget ? new Uri (server.TargetUri, "protected") : server.OriginUri; + cache.Add (credentialUri, "basic", new NetworkCredential (username, password)); + handler.Credentials = cache; + } else { + handler.Credentials = new NetworkCredential (username, password); + } + + HttpStatusCode statusCode = HttpStatusCode.NotFound; + var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { + using var client = new HttpClient (handler); + using var response = await client.GetAsync (new Uri (server.OriginUri, "start")); + statusCode = response.StatusCode; + }, out var ex); + + Assert.That (done, Is.True, "Request timed out."); + Assert.That (ex, Is.Null, "Exception"); + Assert.That (statusCode, Is.EqualTo (expectedStatusCode), "StatusCode"); + Assert.That (server.TargetRequestCount, Is.GreaterThanOrEqualTo (1), "Target request count"); + Assert.That (server.TargetAuthorizationHeaders.Length > 0, Is.EqualTo (expectAuthorizationHeader), "Authorization header presence."); + } + + [TestCase (false, HttpStatusCode.Unauthorized, TestName = "NSUrlSessionHandlerNetworkCredentialNotSentAfterSameOriginRedirectByDefault")] + [TestCase (true, HttpStatusCode.OK, TestName = "NSUrlSessionHandlerNetworkCredentialSentAfterSameOriginRedirectWithAppContextSwitch")] + public void NSUrlSessionHandlerNetworkCredentialSameOriginRedirectCredentials (bool allowSameOriginRedirectCredentials, HttpStatusCode expectedStatusCode) + { + if (!HttpListener.IsSupported) { + Assert.Inconclusive ("HttpListener is not supported"); + } + + AppContext.TryGetSwitch (AllowSameOriginRedirectCredentialsSwitch, out var originalValue); + try { + AppContext.SetSwitch (AllowSameOriginRedirectCredentialsSwitch, allowSameOriginRedirectCredentials); + + using var server = new RedirectBasicAuthServer (crossOrigin: false); + using var handler = new NSUrlSessionHandler { + Credentials = new NetworkCredential ("origin-user", "origin-password"), + }; + + HttpStatusCode statusCode = HttpStatusCode.NotFound; + var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { + using var client = new HttpClient (handler); + using var response = await client.GetAsync (new Uri (server.OriginUri, "start")); + statusCode = response.StatusCode; + }, out var ex); + + Assert.That (done, Is.True, "Request timed out."); + Assert.That (ex, Is.Null, "Exception"); + Assert.That (statusCode, Is.EqualTo (expectedStatusCode), "StatusCode"); + Assert.That (server.TargetRequestCount, Is.GreaterThanOrEqualTo (1), "Target request count"); + Assert.That (server.TargetAuthorizationHeaders.Length > 0, Is.EqualTo (allowSameOriginRedirectCredentials), "Authorization header presence."); + } finally { + AppContext.SetSwitch (AllowSameOriginRedirectCredentialsSwitch, originalValue); + } + } + + [TestCase (false, HttpStatusCode.Unauthorized, false, TestName = "NSUrlSessionHandlerNetworkCredentialNotSentToCrossOriginRedirectWithDefaultCredentialStorage")] + [TestCase (true, HttpStatusCode.OK, true, TestName = "NSUrlSessionHandlerNetworkCredentialSentToCrossOriginRedirectWithSharedCredentialStorage")] + public void NSUrlSessionHandlerUseSharedCredentialStorage (bool useSharedCredentialStorage, HttpStatusCode expectedStatusCode, bool expectSecondRequestAuthorizationHeader) + { + if (!HttpListener.IsSupported) { + Assert.Inconclusive ("HttpListener is not supported"); + } + + AppContext.TryGetSwitch (UseSharedCredentialStorageSwitch, out var originalValue); + try { + AppContext.SetSwitch (UseSharedCredentialStorageSwitch, useSharedCredentialStorage); + + using var server = new RedirectBasicAuthServer (crossOrigin: true); + + // First, prime the shared credential storage by making a successful auth request + // using a CredentialCache with the target URI. When shared storage is enabled, + // NSUrlSession stores the credential with ForSession persistence in SharedCredentialStorage, + // making it available to subsequent handlers targeting the same host:port. + var cache = new CredentialCache (); + cache.Add (new Uri (server.TargetUri, "protected"), "basic", new NetworkCredential ("origin-user", "origin-password")); + + using (var primingHandler = new NSUrlSessionHandler { Credentials = cache }) { + var primingDone = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { + using var client = new HttpClient (primingHandler); + using var response = await client.GetAsync (new Uri (server.OriginUri, "start")); + }, out var primingEx); + + Assert.That (primingDone, Is.True, "Priming request timed out."); + Assert.That (primingEx, Is.Null, "Priming exception"); + } + + // Record how many auth headers the server received from the priming request + var authHeadersAfterPriming = server.TargetAuthorizationHeaders.Length; + + // Now make a second request with a NetworkCredential (not CredentialCache) to the same server. + // With shared storage enabled, NSUrlSession finds cached credentials in SharedCredentialStorage + // and pre-emptively authenticates the redirect target without calling DidReceiveChallenge. + // With shared storage disabled (default), no stored credentials exist, and the + // DidReceiveChallenge delegate blocks the NetworkCredential after the cross-origin redirect. + using var handler = new NSUrlSessionHandler { + Credentials = new NetworkCredential ("origin-user", "origin-password"), + }; + + HttpStatusCode statusCode = HttpStatusCode.NotFound; + var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { + using var client = new HttpClient (handler); + using var response = await client.GetAsync (new Uri (server.OriginUri, "start")); + statusCode = response.StatusCode; + }, out var ex); + + Assert.That (done, Is.True, "Request timed out."); + Assert.That (ex, Is.Null, "Exception"); + Assert.That (statusCode, Is.EqualTo (expectedStatusCode), "StatusCode"); + + var authHeadersFromSecondRequest = server.TargetAuthorizationHeaders.Length - authHeadersAfterPriming; + Assert.That (authHeadersFromSecondRequest > 0, Is.EqualTo (expectSecondRequestAuthorizationHeader), "Authorization header on second request."); + } finally { + AppContext.SetSwitch (UseSharedCredentialStorageSwitch, originalValue); } } @@ -867,6 +1013,154 @@ static NWListener CreateNWTlsListener (bool requireClientCert) return (cert.Export (X509ContentType.Pfx, password), password); } + sealed class RedirectBasicAuthServer : IDisposable { + readonly bool crossOrigin; + readonly HttpListener originListener; + readonly HttpListener? targetListener; + readonly Task originTask; + readonly Task? targetTask; + readonly object targetAuthorizationHeadersLock = new object (); + readonly List targetAuthorizationHeaders = new List (); + readonly string expectedBasicAuth; + int targetRequestCount; + + public Uri OriginUri { get; } + public Uri TargetUri { get; } + public int TargetRequestCount => Volatile.Read (ref targetRequestCount); + + public string [] TargetAuthorizationHeaders { + get { + lock (targetAuthorizationHeadersLock) + return targetAuthorizationHeaders.ToArray (); + } + } + + public RedirectBasicAuthServer (bool crossOrigin, string username = "origin-user", string password = "origin-password") + { + this.crossOrigin = crossOrigin; + expectedBasicAuth = "Basic " + Convert.ToBase64String (global::System.Text.Encoding.UTF8.GetBytes ($"{username}:{password}")); + originListener = CreateStartedHttpListener (out var originUri); + OriginUri = originUri; + + if (crossOrigin) { + targetListener = CreateStartedHttpListener (out var targetUri); + TargetUri = targetUri; + } else { + TargetUri = OriginUri; + } + + originTask = Task.Run (RunOrigin); + if (targetListener is not null) + targetTask = Task.Run (RunTarget); + } + + async Task RunOrigin () + { + while (true) { + var context = await GetContextAsync (originListener); + if (context is null) + return; + + if (!crossOrigin && string.Equals (context.Request.Url?.AbsolutePath, "/protected", StringComparison.Ordinal)) { + RespondToProtectedResource (context); + } else { + RespondWithRedirect (context); + } + } + } + + async Task RunTarget () + { + if (targetListener is null) + return; + + while (true) { + var context = await GetContextAsync (targetListener); + if (context is null) + return; + + RespondToProtectedResource (context); + } + } + + void RespondWithRedirect (HttpListenerContext context) + { + var response = context.Response; + response.StatusCode = (int) HttpStatusCode.Redirect; + response.RedirectLocation = new Uri (TargetUri, "protected").AbsoluteUri; + response.Close (); + } + + void RespondToProtectedResource (HttpListenerContext context) + { + Interlocked.Increment (ref targetRequestCount); + + var authorization = context.Request.Headers ["Authorization"]; + if (!string.IsNullOrEmpty (authorization)) { + lock (targetAuthorizationHeadersLock) + targetAuthorizationHeaders.Add (authorization); + } + + var response = context.Response; + if (string.Equals (authorization, expectedBasicAuth, StringComparison.Ordinal)) { + response.StatusCode = (int) HttpStatusCode.OK; + } else { + response.StatusCode = (int) HttpStatusCode.Unauthorized; + response.AddHeader ("WWW-Authenticate", "Basic realm=\"redirect-target\""); + } + response.Close (); + } + + static async Task GetContextAsync (HttpListener listener) + { + try { + return await listener.GetContextAsync (); + } catch (HttpListenerException) { + return null; + } catch (ObjectDisposedException) { + return null; + } catch (InvalidOperationException) { + return null; + } + } + + static HttpListener CreateStartedHttpListener (out Uri uri) + { + const int MinPort = 49215; + const int MaxPort = 65535; + + for (var port = MinPort; port < MaxPort; port++) { + var listener = new HttpListener (); + var url = $"http://127.0.0.1:{port}/"; + listener.Prefixes.Add (url); + try { + listener.Start (); + uri = new Uri (url); + return listener; + } catch { + listener.Close (); + } + } + + throw new InvalidOperationException ("Could not start a local HTTP listener."); + } + + public void Dispose () + { + originListener.Close (); + targetListener?.Close (); + + try { + if (targetTask is null) + Task.WaitAll (new [] { originTask }, TimeSpan.FromSeconds (1)); + else + Task.WaitAll (new [] { originTask, targetTask }, TimeSpan.FromSeconds (1)); + } catch { + // Listener disposal wakes the request loops. + } + } + } + [Test] public void AssertDefaultValuesNSUrlSessionHandler () { @@ -1069,18 +1363,22 @@ public void UpdateRequestUriAfterRedirect (Type handlerType) { // https://github.com/dotnet/macios/issues/20629 + using var handler = GetHandler (handlerType); var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { - var client = new HttpClient (GetHandler (handlerType)); + using var client = new HttpClient (handler, disposeHandler: false) { + Timeout = TimeSpan.FromSeconds (20), + }; var postRequestUri = NetworkResources.Httpbin.Url + "/"; var initialRequestUri = NetworkResources.Httpbin.GetRedirectToUrl (postRequestUri); - var request = new HttpRequestMessage (HttpMethod.Get, initialRequestUri); + using var request = new HttpRequestMessage (HttpMethod.Get, initialRequestUri); Assert.That (request.RequestUri.ToString (), Is.EqualTo (initialRequestUri), "Initial RequestUri"); - var response = await client.SendAsync (request); + using var response = await client.SendAsync (request); TestRuntime.IgnoreInCIIfBadNetwork (response.StatusCode); Assert.That (request.RequestUri.ToString (), Is.EqualTo (postRequestUri), "Post RequestUri"); }, out var ex); if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc. we do not want to fail + TestRuntime.IgnoreInCIIfHttpClientTimedOut (); Assert.Inconclusive ("Request timedout."); } else { TestRuntime.IgnoreInCIIfBadNetwork (ex); @@ -1094,17 +1392,21 @@ public void RequestUriNotUpdatedIfNotRedirect (Type handlerType) { // https://github.com/dotnet/macios/issues/20629 + using var handler = GetHandler (handlerType); var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { - var client = new HttpClient (GetHandler (handlerType)); + using var client = new HttpClient (handler, disposeHandler: false) { + Timeout = TimeSpan.FromSeconds (20), + }; var requestUri = NetworkResources.Httpbin.Uri + "?stuffHere=[]{}"; - var request = new HttpRequestMessage (HttpMethod.Get, requestUri); + using var request = new HttpRequestMessage (HttpMethod.Get, requestUri); Assert.That (request.RequestUri.ToString (), Is.EqualTo (requestUri), "Initial RequestUri"); - var response = await client.SendAsync (request); + using var response = await client.SendAsync (request); TestRuntime.IgnoreInCIIfBadNetwork (response.StatusCode); Assert.That (request.RequestUri.ToString (), Is.EqualTo (requestUri), "Post RequestUri"); }, out var ex); if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc. we do not want to fail + TestRuntime.IgnoreInCIIfHttpClientTimedOut (); Assert.Inconclusive ("Request timedout."); } else { TestRuntime.IgnoreInCIIfBadNetwork (ex); diff --git a/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs b/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs index 86c0b0efb8b3..79c787d387c1 100644 --- a/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs +++ b/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs @@ -3,7 +3,10 @@ // using System; +using System.Net; using System.Net.Http; +using System.Text; +using System.Threading; using System.Threading.Tasks; using Foundation; using NUnit.Framework; @@ -216,5 +219,129 @@ void IgnoreIfExceptionDueToBackgroundServiceInUseByAnotherProcess (Exception? e) Assert.Ignore ("The background service is in use by another process."); } + + // https://github.com/dotnet/macios/issues/25485 + [Test] + public void BasicAuthWorksWhenBearerIsAdvertisedFirst () + { + if (!HttpListener.IsSupported) { + Assert.Inconclusive ("HttpListener is not supported"); + } + + const string username = "admin"; + const string password = "secret"; + var expectedBasicValue = Convert.ToBase64String (Encoding.UTF8.GetBytes ($"{username}:{password}")); + + var serverReady = new SemaphoreSlim (0, 1); + int requestIndex = 0; + int firstUnauthenticatedIndex = -1; + int firstAuthenticatedIndex = -1; + + var httpListener = StartListenerOnAvailablePort (out var listeningPort); + if (httpListener is null) { + Assert.Inconclusive ("Could not find an available port for the test server."); + return; + } + + var serverTask = Task.Run (async () => { + serverReady.Release (); + try { + while (httpListener.IsListening) { + var context = await httpListener.GetContextAsync ().ConfigureAwait (false); + var request = context.Request; + var response = context.Response; + + var authHeader = request.Headers ["Authorization"]; + var currentIndex = Interlocked.Increment (ref requestIndex); + if (authHeader is not null && authHeader == $"Basic {expectedBasicValue}") { + // Authenticated - return success + Interlocked.CompareExchange (ref firstAuthenticatedIndex, currentIndex, -1); + response.StatusCode = 200; + var body = Encoding.UTF8.GetBytes ("authenticated"); + response.ContentLength64 = body.Length; + response.OutputStream.Write (body, 0, body.Length); + } else { + // Return 401 with Bearer first, then Basic + Interlocked.CompareExchange (ref firstUnauthenticatedIndex, currentIndex, -1); + response.StatusCode = 401; + response.AddHeader ("WWW-Authenticate", "Bearer realm=\"test\", charset=\"UTF-8\""); + response.AppendHeader ("WWW-Authenticate", "Basic realm=\"test\", charset=\"UTF-8\""); + } + response.Close (); + } + } catch (ObjectDisposedException) { + // listener was stopped + } catch (HttpListenerException) { + // listener was stopped + } + }); + + HttpStatusCode? statusCode = null; + string responseBody = null; + + try { + var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { + await serverReady.WaitAsync ().ConfigureAwait (false); + + using var handler = new NSUrlSessionHandler (); + handler.Credentials = new NetworkCredential (username, password); + using var client = new HttpClient (handler); + // Use 127.0.0.1 instead of localhost to avoid IPv6 resolution + // issues where NSUrlSession may connect to ::1 while + // HttpListener only binds to IPv4. + using var request = new HttpRequestMessage (HttpMethod.Get, $"http://127.0.0.1:{listeningPort}/test"); + var response = await client.SendAsync (request).ConfigureAwait (false); + statusCode = response.StatusCode; + responseBody = await response.Content.ReadAsStringAsync ().ConfigureAwait (false); + }, out var ex); + + if (!done) { + TestRuntime.IgnoreInCI ("Transient localhost server failure - ignore in CI"); + Assert.Inconclusive ("Request timed out."); + } + TestRuntime.IgnoreInCIIfBadNetwork (ex); + Assert.That (ex, Is.Null, $"Exception: {ex}"); + // If no request reached the server, the failure is an infrastructure + // issue (e.g. port conflict), not a code bug. + if (Volatile.Read (ref requestIndex) == 0 && statusCode == HttpStatusCode.NotFound) { + TestRuntime.IgnoreInCI ($"Server received no requests and got status {statusCode} - infrastructure issue, ignore in CI"); + Assert.Inconclusive ($"Server received no requests; status was {statusCode}. Likely a port/binding issue."); + } + Assert.That (statusCode, Is.EqualTo (HttpStatusCode.OK), "Expected 200 OK after Basic auth negotiation"); + Assert.That (responseBody, Is.EqualTo ("authenticated"), "Response body"); + Assert.That (firstUnauthenticatedIndex, Is.GreaterThan (0), "Server should have received an unauthenticated request"); + Assert.That (firstAuthenticatedIndex, Is.GreaterThan (0), "Server should have received an authenticated request"); + Assert.That (firstUnauthenticatedIndex, Is.LessThan (firstAuthenticatedIndex), "Unauthenticated request should have arrived before the authenticated retry"); + + if (serverTask.IsFaulted) + Assert.Fail ($"Server task failed: {serverTask.Exception}"); + } finally { + httpListener.Stop (); + httpListener.Close (); + } + } + + static HttpListener? StartListenerOnAvailablePort (out int listeningPort) + { + // IANA suggested range for dynamic or private ports + const int MinPort = 49215; + const int MaxPort = 65535; + + for (var port = MinPort; port < MaxPort; port++) { + var listener = new HttpListener (); + listener.Prefixes.Add ($"http://127.0.0.1:{port}/"); + try { + listener.Start (); + listeningPort = port; + return listener; + } catch { + // port in use, try next + listener.Close (); + } + } + + listeningPort = -1; + return null; + } } } diff --git a/tests/monotouch-test/System.Net.Http/NetworkResources.cs b/tests/monotouch-test/System.Net.Http/NetworkResources.cs index 6fa21fe58507..2a887a52a3d6 100644 --- a/tests/monotouch-test/System.Net.Http/NetworkResources.cs +++ b/tests/monotouch-test/System.Net.Http/NetworkResources.cs @@ -10,6 +10,7 @@ public static class NetworkResources { public static string MicrosoftUrl => AssertNetworkConnection ("https://www.microsoft.com"); public static Uri MicrosoftUri => new Uri (MicrosoftUrl); public static string MicrosoftHttpUrl => AssertNetworkConnection ("http://www.microsoft.com"); + public static Uri MicrosoftHttpUri => new Uri (MicrosoftHttpUrl); public static string XamarinUrl => AssertNetworkConnection ("https://dotnet.microsoft.com/apps/xamarin"); public static string XamarinHttpUrl => AssertNetworkConnection ("http://dotnet.microsoft.com/apps/xamarin"); public static Uri XamarinUri => new Uri (XamarinUrl); diff --git a/tests/monotouch-test/SystemConfiguration/NetworkReachabilityTest.cs b/tests/monotouch-test/SystemConfiguration/NetworkReachabilityTest.cs index 0c57a89ef086..d1ceeeb70e39 100644 --- a/tests/monotouch-test/SystemConfiguration/NetworkReachabilityTest.cs +++ b/tests/monotouch-test/SystemConfiguration/NetworkReachabilityTest.cs @@ -220,10 +220,12 @@ public void SetNotification_GCHandleFreed () // Dispose to ensure GCHandle is freed reachability.Dispose (); } - }); + }) { + IsBackground = true, + }; thread.Start (); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); // Force garbage collection GC.Collect (); @@ -263,10 +265,12 @@ public void SetNotification_GCHandleFreedWithNull () // Store weak reference to track if object is collected weakRefs [i] = new WeakReference (reachability); } - }); + }) { + IsBackground = true, + }; thread.Start (); - thread.Join (); + Assert.That (thread.Join (TimeSpan.FromSeconds (5)), Is.True, "Thread.Join timed out"); // Force garbage collection GC.Collect (); diff --git a/tests/monotouch-test/VideoToolbox/VTCompressionSessionTests.cs b/tests/monotouch-test/VideoToolbox/VTCompressionSessionTests.cs index d72f372a878a..0c5a4f57af5f 100644 --- a/tests/monotouch-test/VideoToolbox/VTCompressionSessionTests.cs +++ b/tests/monotouch-test/VideoToolbox/VTCompressionSessionTests.cs @@ -236,6 +236,9 @@ public void TestCallbackBackground (bool stronglyTyped) public void TestMultiImage (bool stronglyTyped, bool customCallback) { TestRuntime.AssertXcodeVersion (26, 0); +#if __MACOS__ || __MACCATALYST__ + TestRuntime.AssertNotVirtualMachine (); +#endif if (!VTCompressionSession.IsStereoMvHevcEncodeSupported ()) Assert.Ignore ("Stereo MV-HEVC encoding is not supported on the current system."); diff --git a/tests/monotouch-test/VideoToolbox/VTFrameRateConversionConfigurationTest.cs b/tests/monotouch-test/VideoToolbox/VTFrameRateConversionConfigurationTest.cs index f2a0164b0f32..67a426f32de1 100644 --- a/tests/monotouch-test/VideoToolbox/VTFrameRateConversionConfigurationTest.cs +++ b/tests/monotouch-test/VideoToolbox/VTFrameRateConversionConfigurationTest.cs @@ -51,10 +51,10 @@ public void Properties () Assert.That (VTFrameRateConversionConfiguration.ProcessorSupported, Is.True, "ProcessorSupported"); Assert.That (VTFrameRateConversionConfiguration.SupportedRevisions, Is.Not.Null, "SupportedRevisions"); - Assert.That (VTFrameRateConversionConfiguration.SupportedRevisions, Does.Contain (VTFrameRateConversionConfigurationRevision.Revision1), "SupportedRevisions.Contains"); + Assert.That (VTFrameRateConversionConfiguration.SupportedRevisions.Contains (VTFrameRateConversionConfigurationRevision.Revision1), "SupportedRevisions.Contains"); Assert.That (VTFrameRateConversionConfiguration.WeakSupportedRevisions, Is.Not.Null, "WeakSupportedRevisions"); - Assert.That (VTFrameRateConversionConfiguration.WeakSupportedRevisions, Does.Contain ((nuint) 1), "WeakSupportedRevisions.Contains"); - Assert.That (Enum.GetValues (), Does.Contain (VTFrameRateConversionConfiguration.DefaultRevision), "DefaultRevision"); + Assert.That (VTFrameRateConversionConfiguration.WeakSupportedRevisions.Contains ((nuint) 1), "WeakSupportedRevisions.Contains"); + Assert.That (Enum.GetValues ().Contains (VTFrameRateConversionConfiguration.DefaultRevision), "DefaultRevision"); }); } } diff --git a/tests/monotouch-test/VideoToolbox/VTMotionBlurConfigurationTest.cs b/tests/monotouch-test/VideoToolbox/VTMotionBlurConfigurationTest.cs index b760f1114222..56fc4049401d 100644 --- a/tests/monotouch-test/VideoToolbox/VTMotionBlurConfigurationTest.cs +++ b/tests/monotouch-test/VideoToolbox/VTMotionBlurConfigurationTest.cs @@ -3,6 +3,8 @@ #if __MACOS__ +using System.Linq; + using AVFoundation; using CoreMedia; using CoreVideo; @@ -34,10 +36,10 @@ public void Properties () Assert.That (VTMotionBlurConfiguration.ProcessorSupported, Is.True, "ProcessorSupported"); Assert.That (VTMotionBlurConfiguration.SupportedRevisions, Is.Not.Null, "SupportedRevisions"); - Assert.That (VTMotionBlurConfiguration.SupportedRevisions, Does.Contain (VTMotionBlurConfigurationRevision.Revision1), "SupportedRevisions.Contains"); + Assert.That (VTMotionBlurConfiguration.SupportedRevisions.Contains (VTMotionBlurConfigurationRevision.Revision1), "SupportedRevisions.Contains"); Assert.That (VTMotionBlurConfiguration.WeakSupportedRevisions, Is.Not.Null, "WeakSupportedRevisions"); - Assert.That (VTMotionBlurConfiguration.WeakSupportedRevisions, Does.Contain ((nuint) 1), "WeakSupportedRevisions.Contains"); - Assert.That (Enum.GetValues (), Does.Contain (VTMotionBlurConfiguration.DefaultRevision), "DefaultRevision"); + Assert.That (VTMotionBlurConfiguration.WeakSupportedRevisions.Contains ((nuint) 1), "WeakSupportedRevisions.Contains"); + Assert.That (Enum.GetValues ().Contains (VTMotionBlurConfiguration.DefaultRevision), "DefaultRevision"); }); } } diff --git a/tests/monotouch-test/VideoToolbox/VTMotionEstimationSessionTest.cs b/tests/monotouch-test/VideoToolbox/VTMotionEstimationSessionTest.cs index a8f49139e6ff..9e338d9d6ef9 100644 --- a/tests/monotouch-test/VideoToolbox/VTMotionEstimationSessionTest.cs +++ b/tests/monotouch-test/VideoToolbox/VTMotionEstimationSessionTest.cs @@ -24,6 +24,9 @@ public class VTMotionEstimationSessionTest { public void CreateTest () { TestRuntime.AssertXcodeVersion (26, 0); +#if __MACOS__ || __MACCATALYST__ + TestRuntime.AssertNotVirtualMachine (); +#endif // VTMotionEstimationSessionCreate just returns in the simulator (a single 'ret' instruction), // which means it returns with status=VTStatus.Ok, but no session actually created. So ignore // this test in the simulator. @@ -49,6 +52,9 @@ public void CreateTest () public void CreateStronglyTypedTest () { TestRuntime.AssertXcodeVersion (26, 0); +#if __MACOS__ || __MACCATALYST__ + TestRuntime.AssertNotVirtualMachine (); +#endif // VTMotionEstimationSessionCreate just returns in the simulator (a single 'ret' instruction), // which means it returns with status=VTStatus.Ok, but no session actually created. So ignore // this test in the simulator. diff --git a/tests/monotouch-test/VideoToolbox/VTOpticalFlowConfigurationTest.cs b/tests/monotouch-test/VideoToolbox/VTOpticalFlowConfigurationTest.cs index 58fa9115ef4b..aa3a88cb8d4b 100644 --- a/tests/monotouch-test/VideoToolbox/VTOpticalFlowConfigurationTest.cs +++ b/tests/monotouch-test/VideoToolbox/VTOpticalFlowConfigurationTest.cs @@ -3,6 +3,8 @@ #if __MACOS__ +using System.Linq; + using AVFoundation; using CoreMedia; using CoreVideo; @@ -33,10 +35,10 @@ public void Properties () Assert.That (VTOpticalFlowConfiguration.ProcessorSupported, Is.True, "ProcessorSupported"); Assert.That (VTOpticalFlowConfiguration.SupportedRevisions, Is.Not.Null, "SupportedRevisions"); - Assert.That (VTOpticalFlowConfiguration.SupportedRevisions, Does.Contain (VTOpticalFlowConfigurationRevision.Revision1), "SupportedRevisions.Contains"); + Assert.That (VTOpticalFlowConfiguration.SupportedRevisions.Contains (VTOpticalFlowConfigurationRevision.Revision1), "SupportedRevisions.Contains"); Assert.That (VTOpticalFlowConfiguration.WeakSupportedRevisions, Is.Not.Null, "WeakSupportedRevisions"); - Assert.That (VTOpticalFlowConfiguration.WeakSupportedRevisions, Does.Contain ((nuint) 1), "WeakSupportedRevisions.Contains"); - Assert.That (Enum.GetValues (), Does.Contain (VTOpticalFlowConfiguration.DefaultRevision), "DefaultRevision"); + Assert.That (VTOpticalFlowConfiguration.WeakSupportedRevisions.Contains ((nuint) 1), "WeakSupportedRevisions.Contains"); + Assert.That (Enum.GetValues ().Contains (VTOpticalFlowConfiguration.DefaultRevision), "DefaultRevision"); }); } } diff --git a/tests/monotouch-test/dotnet/shared.csproj b/tests/monotouch-test/dotnet/shared.csproj index 52b2396eff16..ecb61eeb4914 100644 --- a/tests/monotouch-test/dotnet/shared.csproj +++ b/tests/monotouch-test/dotnet/shared.csproj @@ -13,7 +13,7 @@ $(RootTestsDirectory)\monotouch-test - true + true $(DefineConstants);DEBUG @@ -54,6 +54,10 @@ + + + + diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs index db3cb3520b67..5059aab86236 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs @@ -17,7 +17,7 @@ public void AssemblyInitialization () const string msbuild_exe_path = "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/msbuild/15.0/bin/MSBuild.dll"; if (is_in_vsmac) { var env = new Dictionary { - { "MD_APPLE_SDK_ROOT", Path.GetDirectoryName (Path.GetDirectoryName (Configuration.xcode_root)) ?? string.Empty }, + { "DEVELOPER_DIR", Path.GetDirectoryName (Path.GetDirectoryName (Configuration.xcode_root)) ?? string.Empty }, { "MSBUILD_EXE_PATH", msbuild_exe_path }, }; diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs index f0f790709c06..218b3cf4fa9e 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs @@ -22,9 +22,9 @@ ACTool CreateACToolTask (ApplePlatform platform, string projectDir, out string i intermediateOutputPath = Cache.CreateTemporaryDirectory (); - var sdk = Sdks.GetAppleSdk (platform); + var task = CreateTask (); + var version = AppleSdkVersion.UseDefault.ToString (); - var root = sdk.GetSdkPath (version, false); string sdkPlatform; var uiDeviceFamily = ""; @@ -47,7 +47,6 @@ ACTool CreateACToolTask (ApplePlatform platform, string projectDir, out string i throw new NotImplementedException (platform.ToString ()); } - var task = CreateTask (); task.ImageAssets = imageAssets .Select (v => { var spl = v.Split ('|'); @@ -634,5 +633,215 @@ public void XSAppIconAssetsAndAppIcon (ApplePlatform platform) ExecuteTask (actool, 1); Assert.That (Engine.Logger.ErrorEvents [0].Message, Is.EqualTo ("Can't specify both 'XSAppIconAssets' in the Info.plist and 'AppIcon' in the project file. Please select one or the other."), "Error message"); } + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.TVOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.MacOSX)] + public void IconFileSupport (ApplePlatform platform) + { + // Test that .icon folders (Icon Composer format) are recognized as app icons + var projectDir = Cache.CreateTemporaryDirectory (); + var iconFolderPath = Path.Combine (projectDir, "Resources", "AppIcon.icon"); + var assetsPath = Path.Combine (iconFolderPath, "Assets"); + Directory.CreateDirectory (assetsPath); + + // Create a placeholder icon.json file (simplified structure for testing) + var iconJsonPath = Path.Combine (iconFolderPath, "icon.json"); + File.WriteAllText (iconJsonPath, @"{""groups"":[{""layers"":[{""image-name"":""icon_512x512.png"",""name"":""icon""}]}]}"); + + // Create a placeholder image file in the Assets folder + var imagePath = Path.Combine (assetsPath, "icon_512x512.png"); + File.WriteAllText (imagePath, "placeholder image"); + + var actool = CreateACToolTask ( + platform, + projectDir, + out var _, + iconJsonPath + "|Resources/AppIcon.icon/icon.json", + imagePath + "|Resources/AppIcon.icon/Assets/icon_512x512.png" + ); + actool.AppIcon = "AppIcon"; + + // actool may fail on the placeholder .icon content, but the validation phase should pass + actool.Execute (); + + // Verify that no icon validation errors were logged + AssertNoIconValidationErrors (); + } + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.TVOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.MacOSX)] + public void IconFileSupportWithIncludeAllAppIcons (ApplePlatform platform) + { + // Test that .icon folders work with IncludeAllAppIcons + var projectDir = Cache.CreateTemporaryDirectory (); + var iconFolderPath = Path.Combine (projectDir, "Resources", "AppIcon.icon"); + var assetsPath = Path.Combine (iconFolderPath, "Assets"); + Directory.CreateDirectory (assetsPath); + + var iconJsonPath = Path.Combine (iconFolderPath, "icon.json"); + File.WriteAllText (iconJsonPath, @"{""groups"":[{""layers"":[{""image-name"":""icon_512x512.png"",""name"":""icon""}]}]}"); + + var imagePath = Path.Combine (assetsPath, "icon_512x512.png"); + File.WriteAllText (imagePath, "placeholder image"); + + var actool = CreateACToolTask ( + platform, + projectDir, + out var _, + iconJsonPath + "|Resources/AppIcon.icon/icon.json", + imagePath + "|Resources/AppIcon.icon/Assets/icon_512x512.png" + ); + actool.AppIcon = "AppIcon"; + actool.IncludeAllAppIcons = true; + + // actool may fail on the placeholder .icon content, but the validation phase should pass + actool.Execute (); + + // Verify that no icon validation errors were logged + AssertNoIconValidationErrors (); + } + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.TVOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.MacOSX)] + public void IconFileSupportAsAlternateIcon (ApplePlatform platform) + { + // Test that .icon folders work as alternate app icons + var projectDir = Cache.CreateTemporaryDirectory (); + var iconFolderPath = Path.Combine (projectDir, "Resources", "AlternateIcon.icon"); + var assetsPath = Path.Combine (iconFolderPath, "Assets"); + Directory.CreateDirectory (assetsPath); + + var iconJsonPath = Path.Combine (iconFolderPath, "icon.json"); + File.WriteAllText (iconJsonPath, @"{""groups"":[{""layers"":[{""image-name"":""icon_512x512.png"",""name"":""icon""}]}]}"); + + var imagePath = Path.Combine (assetsPath, "icon_512x512.png"); + File.WriteAllText (imagePath, "placeholder image"); + + // Also need a primary icon for the alternate icon test to make sense + var primaryIconPath = Path.Combine (projectDir, "Resources", "AppIcon.icon"); + var primaryAssetsPath = Path.Combine (primaryIconPath, "Assets"); + Directory.CreateDirectory (primaryAssetsPath); + + var primaryIconJsonPath = Path.Combine (primaryIconPath, "icon.json"); + File.WriteAllText (primaryIconJsonPath, @"{""groups"":[{""layers"":[{""image-name"":""icon_512x512.png"",""name"":""icon""}]}]}"); + + var primaryImagePath = Path.Combine (primaryAssetsPath, "icon_512x512.png"); + File.WriteAllText (primaryImagePath, "placeholder image"); + + var actool = CreateACToolTask ( + platform, + projectDir, + out var _, + iconJsonPath + "|Resources/AlternateIcon.icon/icon.json", + imagePath + "|Resources/AlternateIcon.icon/Assets/icon_512x512.png", + primaryIconJsonPath + "|Resources/AppIcon.icon/icon.json", + primaryImagePath + "|Resources/AppIcon.icon/Assets/icon_512x512.png" + ); + actool.AppIcon = "AppIcon"; + actool.AlternateAppIcons = new ITaskItem [] { new TaskItem ("AlternateIcon") }; + + // actool may fail on the placeholder .icon content, but the validation phase should pass + actool.Execute (); + + // Verify that no icon validation errors were logged + AssertNoIconValidationErrors (); + } + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.TVOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.MacOSX)] + public void InexistentIconFile (ApplePlatform platform) + { + // Test that an inexistent .icon-based app icon is correctly reported + var projectDir = Cache.CreateTemporaryDirectory (); + var iconFolderPath = Path.Combine (projectDir, "Resources", "AppIcon.icon"); + var assetsPath = Path.Combine (iconFolderPath, "Assets"); + Directory.CreateDirectory (assetsPath); + + var iconJsonPath = Path.Combine (iconFolderPath, "icon.json"); + File.WriteAllText (iconJsonPath, @"{""groups"":[{""layers"":[{""image-name"":""icon_512x512.png"",""name"":""icon""}]}]}"); + + var imagePath = Path.Combine (assetsPath, "icon_512x512.png"); + File.WriteAllText (imagePath, "placeholder image"); + + var actool = CreateACToolTask ( + platform, + projectDir, + out var _, + iconJsonPath + "|Resources/AppIcon.icon/icon.json", + imagePath + "|Resources/AppIcon.icon/Assets/icon_512x512.png" + ); + actool.AppIcon = "InexistentIcon"; + + ExecuteTask (actool, 1); + + var errorMessages = Engine.Logger.ErrorEvents.Select (e => e.Message).ToList (); + Assert.That (errorMessages.Any (m => m?.Contains ("Can't find the AppIcon 'InexistentIcon'") == true), Is.True, "Should report that InexistentIcon is not found among image resources"); + } + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.MacOSX)] + public void MixedXCAssetsAndIconFile (ApplePlatform platform) + { + // Test that .icon folders and .xcassets can coexist in the validation phase + var projectDir = Path.Combine (Configuration.SourceRoot, "tests", "dotnet", "AppWithXCAssets", platform.AsString ()); + var files = Directory.GetFiles (Path.Combine (projectDir, "Resources", "Images.xcassets"), "*", SearchOption.AllDirectories); + var imageAssets = files.Select (v => v + "|" + v.Substring (projectDir.Length + 1)).ToList (); + + // Add a .icon folder alongside the existing .xcassets + var tmpDir = Cache.CreateTemporaryDirectory (); + var iconFolderPath = Path.Combine (tmpDir, "ComposerIcon.icon"); + var assetsPath = Path.Combine (iconFolderPath, "Assets"); + Directory.CreateDirectory (assetsPath); + + var iconJsonPath = Path.Combine (iconFolderPath, "icon.json"); + File.WriteAllText (iconJsonPath, @"{""groups"":[{""layers"":[{""image-name"":""icon_512x512.png"",""name"":""icon""}]}]}"); + + var imagePath = Path.Combine (assetsPath, "icon_512x512.png"); + File.WriteAllText (imagePath, "placeholder image"); + + imageAssets.Add (iconJsonPath + "|Resources/ComposerIcon.icon/icon.json"); + imageAssets.Add (imagePath + "|Resources/ComposerIcon.icon/Assets/icon_512x512.png"); + + var actool = CreateACToolTask ( + platform, + projectDir, + out var _, + imageAssets.ToArray () + ); + actool.AppIcon = "AppIcons"; + + // actool may fail on the placeholder .icon content, but the validation phase should pass + actool.Execute (); + + // Verify that no icon validation errors were logged + AssertNoIconValidationErrors (); + } + + void AssertNoIconValidationErrors () + { + var errorMessages = Engine.Logger.ErrorEvents.Select (e => e.Message).ToList (); + Assert.That (errorMessages, Has.None.Contain ("Can't find the AppIcon"), + "Should not report that AppIcon is not found among image resources"); + Assert.That (errorMessages, Has.None.Contain ("Can't find the AlternateAppIcon"), + "Should not report that AlternateAppIcon is not found among image resources"); + Assert.That (errorMessages, Has.None.Contain ("is specified as both 'AppIcon' and 'AlternateAppIcon'"), + "Should not report icon conflict between AppIcon and AlternateAppIcon"); + Assert.That (errorMessages, Has.None.Contain ("Can't specify both 'XSAppIconAssets'"), + "Should not report XSAppIconAssets conflict"); + } } } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs index 963fc4e4ad83..e07a1d80c94d 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs @@ -20,11 +20,11 @@ CompileAppManifest CreateTask (string? tmpdir = null, ApplePlatform platform = A var task = CreateTask (); task.AppBundleName = "AppBundleName"; task.CompiledAppManifest = new TaskItem (Path.Combine (tmpdir, "TemporaryAppManifest.plist")); - task.DefaultSdkVersion = Sdks.GetAppleSdk (platform).GetInstalledSdkVersions (false).First ().ToString ()!; task.MinSupportedOSPlatformVersion = "10.0"; task.SupportedOSPlatformVersion = "15.0"; task.SdkVersion = task.DefaultSdkVersion ?? string.Empty; task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform).ToString (); + task.DefaultSdkVersion = task.CurrentSdk.GetInstalledSdkVersions (false).First ().ToString ()!; return task; } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs index c98886bb4f40..f6b0181548aa 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs @@ -46,6 +46,7 @@ protected virtual void ConfigureTask () Task.MinSupportedOSPlatformVersion = "10.0"; Task.SupportedOSPlatformVersion = "15.0"; Task.SdkVersion = "10.0"; + Task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (Platform).ToString (); Plist = new PDictionary (); Plist ["CFBundleDisplayName"] = displayName; diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs index 144e00166d4f..eec87ffd32f5 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs @@ -15,7 +15,7 @@ protected override void ConfigureTask () Configuration.IgnoreIfIgnoredPlatform (ApplePlatform.iOS); base.ConfigureTask (); - Task.DefaultSdkVersion = Sdks.IOS.GetClosestInstalledSdk (AppleSdkVersion.V6_1, true).ToString (); + Task.DefaultSdkVersion = Task.CurrentSdk.GetClosestInstalledSdk (AppleSdkVersion.V6_1, true).ToString () ?? ""; Task.TargetFrameworkMoniker = TargetFramework.DotNet_iOS_String; Task.TargetArchitectures = "ARM64"; } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs index b77904722891..06ab59fadfbe 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs @@ -14,7 +14,7 @@ protected override void ConfigureTask () Configuration.IgnoreIfIgnoredPlatform (ApplePlatform.TVOS); base.ConfigureTask (); - Task.DefaultSdkVersion = Sdks.TVOS.GetClosestInstalledSdk (AppleSdkVersion.V9_0, true).ToString (); + Task.DefaultSdkVersion = Task.CurrentSdk.GetClosestInstalledSdk (AppleSdkVersion.V9_0, true).ToString () ?? ""; Task.TargetFrameworkMoniker = TargetFramework.DotNet_tvOS_String; } } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GetAvailableDevicesTest.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GetAvailableDevicesTest.cs index 1d874fcb732c..c202f5e615aa 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GetAvailableDevicesTest.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GetAvailableDevicesTest.cs @@ -679,6 +679,30 @@ public void Ctl1_AppleTV () }); } + [Test] + [TestCase ("iossimulator-x64", "iossimulator-x64")] + [TestCase ("iossimulator-arm64", "iossimulator-arm64")] + [TestCase ("", null)] // null means it depends on CanRunArm64 + public void SimCtl_MultiArch_RuntimeIdentifier (string runtimeIdentifier, string? expectedRid) + { + var platform = ApplePlatform.iOS; + var task = CreateTask (platform, SIMCTL_JSON_MULTIARCH, ""); + task.RuntimeIdentifier = runtimeIdentifier; + Assert.That (task.Execute (), Is.True, "Task should have succeeded."); + Assert.Multiple (() => { + Assert.That (task.Devices.Count, Is.EqualTo (1), "Devices count mismatch."); + + Assert.That (task.Devices [0].ItemSpec, Is.EqualTo ("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"), "Device 1 mismatch."); + Assert.That (task.Devices [0].GetMetadata ("Description"), Is.EqualTo ("iPhone 11 - iOS 26.1"), "Device 1 Name mismatch."); + Assert.That (task.Devices [0].GetMetadata ("OSVersion"), Is.EqualTo ("26.1"), "Device 1 OSVersion mismatch."); + Assert.That (task.Devices [0].GetMetadata ("UDID"), Is.EqualTo ("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"), "Device 1 UDID mismatch."); + if (expectedRid is null) + expectedRid = GetAvailableDevices.CanRunArm64 ? "iossimulator-arm64" : "iossimulator-x64"; + Assert.That (task.Devices [0].GetMetadata ("RuntimeIdentifier"), Is.EqualTo (expectedRid), "Device 1 RuntimeIdentifier mismatch."); + Assert.That (task.Devices [0].GetMetadata ("DiscardedReason"), Is.Empty, "Device 1 discarded reason mismatch."); + }); + } + [Test] public void DeviceCtl2_Mac () { @@ -1108,5 +1132,67 @@ public void DeviceCtl2_Mac () } } """; + + const string SIMCTL_JSON_MULTIARCH = + """ + { + "devicetypes" : [ + { + "productFamily" : "iPhone", + "bundlePath" : "\/Library\/Developer\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 11.simdevicetype", + "maxRuntimeVersion" : 4294967295, + "maxRuntimeVersionString" : "65535.255.255", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-11", + "modelIdentifier" : "iPhone12,1", + "minRuntimeVersionString" : "13.0.0", + "minRuntimeVersion" : 851968, + "name" : "iPhone 11" + } + ], + "runtimes" : [ + { + "isAvailable" : true, + "version" : "26.1", + "isInternal" : false, + "buildversion" : "23B80", + "supportedArchitectures" : [ + "arm64", + "x86_64" + ], + "supportedDeviceTypes" : [ + { + "bundlePath" : "\/Library\/Developer\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 11.simdevicetype", + "name" : "iPhone 11", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-11", + "productFamily" : "iPhone" + } + ], + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-26-1", + "platform" : "iOS", + "bundlePath" : "\/Library\/Developer\/CoreSimulator\/Volumes\/iOS_23B80\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS 26.1.simruntime", + "runtimeRoot" : "\/Library\/Developer\/CoreSimulator\/Volumes\/iOS_23B80\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS 26.1.simruntime\/Contents\/Resources\/RuntimeRoot", + "name" : "iOS 26.1" + } + ], + "devices" : { + "com.apple.CoreSimulator.SimRuntime.iOS-26-1" : [ + { + "dataPath" : "\/Users\/rolf\/Library\/Developer\/CoreSimulator\/Devices\/AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE\/data", + "dataPathSize" : 2274861056, + "logPath" : "\/Users\/rolf\/Library\/Logs\/CoreSimulator\/AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE", + "udid" : "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE", + "isAvailable" : true, + "logPathSize" : 253952, + "deviceTypeIdentifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-11", + "state" : "Shutdown", + "name" : "iPhone 11 - iOS 26.1" + } + ] + }, + "pairs" : { + + } + } + """; } } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs index 54819e3ef1cf..2b66ae4a5f93 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs @@ -18,10 +18,10 @@ namespace Xamarin.MacDev.Tasks { public class IBToolTaskTests : TestBase { IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string intermediateOutputPath) { + var task = CreateTask (); + var interfaceDefinitions = new List (); - var sdk = Sdks.GetSdk (framework); - var version = AppleSdkVersion.GetDefault (sdk, false); - var root = sdk.GetSdkPath (version, false); + var version = AppleSdkVersion.UseDefault.ToString (); string platform; switch (framework) { @@ -39,7 +39,6 @@ IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string inte foreach (var item in Directory.EnumerateFiles (projectDir, "*.xib", SearchOption.AllDirectories)) interfaceDefinitions.Add (new TaskItem (item)); - var task = CreateTask (); task.InterfaceDefinitions = interfaceDefinitions.ToArray (); task.IntermediateOutputPath = intermediateOutputPath; task.MinimumOSVersion = PDictionary.OpenFile (Path.Combine (projectDir, "Info.plist")).GetMinimumOSVersion (); @@ -48,8 +47,8 @@ IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string inte task.SdkDevPath = Configuration.xcode_root; task.SdkPlatform = platform; task.SdkVersion = version.ToString (); - task.SdkRoot = root; task.TargetFrameworkMoniker = TargetFramework.DotNet_iOS_String; + task.SdkRoot = task.CurrentSdk.GetSdkPath (version, false); return task; } @@ -62,7 +61,7 @@ public void TestBasicIBToolFunctionality () var ibtool = CreateIBToolTask (ApplePlatform.iOS, srcdir, tmp); var bundleResources = new HashSet (); - Assert.That (ibtool.Execute (), Is.True, "Execution of IBTool task failed."); + ExecuteTask (ibtool); foreach (var bundleResource in ibtool.BundleResources) { Assert.That (File.Exists (bundleResource.ItemSpec), Is.True, $"File does not exist: {bundleResource.ItemSpec}"); @@ -104,7 +103,7 @@ public void TestAdvancedIBToolFunctionality () ibtool.EnableOnDemandResources = true; - Assert.That (ibtool.Execute (), Is.True, "Execution of IBTool task failed."); + ExecuteTask (ibtool); foreach (var bundleResource in ibtool.BundleResources) { var bundleName = bundleResource.GetMetadata ("LogicalName"); @@ -179,7 +178,7 @@ void TestGenericAndDeviceSpecificXibsGeneric (params string [] fileNames) ibtool.EnableOnDemandResources = true; - Assert.That (ibtool.Execute (), Is.True, "Execution of IBTool task failed."); + ExecuteTask (ibtool); foreach (var bundleResource in ibtool.BundleResources) { var bundleName = bundleResource.GetMetadata ("LogicalName"); diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ParseBundlerArgumentsTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ParseBundlerArgumentsTests.cs index bea30b23b970..48ea288f44ad 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ParseBundlerArgumentsTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ParseBundlerArgumentsTests.cs @@ -250,7 +250,7 @@ public void Verbosity (string input, string output) var task = CreateTask (); task.ExtraArgs = input; ExecuteTask (task, message: input); - Assert.That (task.Verbosity, Is.EqualTo (output), "Equality"); + Assert.That (task.BundlerVerbosity, Is.EqualTo (output), "Equality"); } [TestCase ("--nowarn", "-1")] diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/VerbosityTest.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/VerbosityTest.cs index 87765cf7267e..4930ef8dc74c 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/VerbosityTest.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/VerbosityTest.cs @@ -43,15 +43,15 @@ public void FromString (string commandLine, LoggerVerbosity expected) Assert.That (VerbosityUtils.GetVerbosityLevel (commandLine), Is.EqualTo (result), commandLine); } - [TestCase (LoggerVerbosity.Quiet, "-q -q -q -q")] - [TestCase (LoggerVerbosity.Minimal, "-q -q")] - [TestCase (LoggerVerbosity.Normal, "")] - [TestCase (LoggerVerbosity.Detailed, "-v -v")] - [TestCase (LoggerVerbosity.Diagnostic, "-v -v -v -v")] - [TestCase ((LoggerVerbosity) (-1), "")] - public void FromLoggerVerbosity (LoggerVerbosity v, string expectedResult) + [TestCase (LoggerVerbosity.Quiet, -4)] + [TestCase (LoggerVerbosity.Minimal, -2)] + [TestCase (LoggerVerbosity.Normal, 0)] + [TestCase (LoggerVerbosity.Detailed, 2)] + [TestCase (LoggerVerbosity.Diagnostic, 4)] + [TestCase ((LoggerVerbosity) (-1), 0)] + public void FromLoggerVerbosity (LoggerVerbosity v, int expectedResult) { - var s = String.Join (" ", VerbosityUtils.GetVerbosityLevel (v)); + var s = VerbosityUtils.GetVerbosityLevel (v); Assert.That (s, Is.EqualTo (expectedResult), v.ToString ()); } } diff --git a/tests/nunit.framework.targets b/tests/nunit.framework.targets index bfb7b169a8b4..4cd86d4018b2 100644 --- a/tests/nunit.framework.targets +++ b/tests/nunit.framework.targets @@ -4,6 +4,6 @@ $(MSBuildThisFileDirectory)nunit.framework.xml --xml=$(XmlLinkerFile) $(AppBundleExtraOptions) - --dlsym:+nunit.framework.dll $(AppBundleExtraOptions) + --dlsym:+nunit.framework.dll --dlsym:+nunit.framework.legacy.dll $(AppBundleExtraOptions) diff --git a/tests/package-mac-tests.sh b/tests/package-mac-tests.sh index ce02bb0d67eb..0b8dc92d6dab 100755 --- a/tests/package-mac-tests.sh +++ b/tests/package-mac-tests.sh @@ -19,7 +19,7 @@ cat test.config INCLUDE_MAC=$(grep ^INCLUDE_MAC= test.config | sed 's/.*=//') INCLUDE_MACCATALYST=$(grep ^INCLUDE_MACCATALYST= test.config | sed 's/.*=//') XCODE_DEVELOPER_ROOT=$(grep ^XCODE_DEVELOPER_ROOT= test.config | sed 's/.*=//') -export MD_APPLE_SDK_ROOT="$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")")" +export DEVELOPER_DIR="$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")")" export RootTestsDirectory="$(pwd)" make diff --git a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/ArrayValidatorTests.cs b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/ArrayValidatorTests.cs index 5d265504094a..74b3a943027b 100644 --- a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/ArrayValidatorTests.cs +++ b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/ArrayValidatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma warning disable APL0003 +#pragma warning disable CS0618 // DisableZeroCopy is obsolete using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/FieldValidatorTests.cs b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/FieldValidatorTests.cs index 7d9c84e75903..9571b1eb590f 100644 --- a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/FieldValidatorTests.cs +++ b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/FieldValidatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma warning disable APL0003 +#pragma warning disable CS0618 // DisableZeroCopy is obsolete using Microsoft.Macios.Bindings.Analyzer.Validators; using Xunit; diff --git a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/PropertyOrFieldValidatorTests.cs b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/PropertyOrFieldValidatorTests.cs index 738eded7d1a6..ca019c36bc7e 100644 --- a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/PropertyOrFieldValidatorTests.cs +++ b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/Validators/PropertyOrFieldValidatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma warning disable APL0003 +#pragma warning disable CS0618 // DisableZeroCopy is obsolete using Microsoft.Macios.Bindings.Analyzer.Validators; using Xunit; diff --git a/tests/test-libraries/testgenerator.cs b/tests/test-libraries/testgenerator.cs index b50e7b191a8c..c118503a9a17 100644 --- a/tests/test-libraries/testgenerator.cs +++ b/tests/test-libraries/testgenerator.cs @@ -953,7 +953,7 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t\tusing (var tc = new ObjCRegistrarTest ()) {"); w.AppendLine ($"\t\t\t\tvar s = tc.PS{s};"); for (int i = 0; i < s.Length; i++) - w.AppendLine ($"\t\t\t\tAssert.AreEqual (0, s.x{i}, \"pre-#{i}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (s.x{i}, Is.EqualTo (0), \"pre-#{i}\");"); w.Append ($"\t\t\t\tvar k = new S{s} () {{ "); for (int i = 0; i < s.Length; i++) w.Append ($"x{i} = ").Append (GetValue (s [i], i)).Append (", "); @@ -962,7 +962,7 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\t\ttc.PS{s} = k;"); w.AppendLine ($"\t\t\t\ts = tc.PS{s};"); for (int i = 0; i < s.Length; i++) - w.AppendLine ($"\t\t\t\tAssert.AreEqual (k.x{i}, s.x{i}, \"post-#{i}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (s.x{i}, Is.EqualTo (k.x{i}), \"post-#{i}\");"); w.AppendLine (); w.Append ($"\t\t\t\tvar v = new S{s} () {{ "); @@ -975,7 +975,7 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\t\ttc.SetProperty{s} (v);"); w.AppendLine ($"\t\t\t\ts = tc.PS{s};"); for (int i = 0; i < s.Length; i++) - w.AppendLine ($"\t\t\t\tAssert.AreEqual (v.x{i}, s.x{i}, \"set-#{i}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (s.x{i}, Is.EqualTo (v.x{i}), \"set-#{i}\");"); w.AppendLine ("\t\t\t}"); w.AppendLine ("\t\t}"); @@ -1066,32 +1066,32 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Number, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}NumberNullable, \"initial nullable null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}NumberNullable (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Number, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.Null, \"initial nullable null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}? value = default ({v.Managed});"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}NumberNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}NumberNullable, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}NumberNonNullable, \"non-nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}NumberNullable (), \"nullable get method after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}NumberNonNullable (), \"non-nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.EqualTo (value), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}NumberNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}NumberNullable, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}NumberNonNullable, \"non-nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}NumberNullable (), \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}NumberNonNullable (), \"non-nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.EqualTo (value), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.EqualTo (value), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting custom value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}NumberNullable (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Number, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}NumberNullable, \"nullable null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}NumberNullable (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Number, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.Null, \"nullable null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1102,43 +1102,43 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Number, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Number, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Number, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tusing (var input = new NSNumber ({v.ToNSNumberCastExpression}value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Number, \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.EqualTo (value), \"after setting A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = null;"); w.AppendLine ($"\t\t\t\tusing (var input = new NSNumber ({v.ToNSNumberCastExpression}value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNonNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Number.Value, \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number.Value, Is.EqualTo (value), \"after setting B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = null;"); w.AppendLine ($"\t\t\t\tvar number = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}NumberNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (number, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (number, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = value;"); w.AppendLine ($"\t\t\t\tnumber = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}NumberNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.FromNSNumberCastExpression}number{v.Map}, \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.FromNSNumberCastExpression}number{v.Map}, Is.EqualTo (value), \"getter B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = value;"); w.AppendLine ($"\t\t\t\tnumber = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}NumberNonNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.FromNSNumberCastExpression}number{v.Map}, \"getter C\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.FromNSNumberCastExpression}number{v.Map}, Is.EqualTo (value), \"getter C\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); @@ -1148,28 +1148,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}[] value = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}Array, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}Array (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.P{v.Managed}Array.Length, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.Get{v.Managed}Array ().Length, \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.P{v.Managed}Array [0], \"nullable property after setting custom value element\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.Get{v.Managed}Array () [0], \"nullable get method after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array.Length, Is.EqualTo (1), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array ().Length, Is.EqualTo (1), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array [0], Is.EqualTo (value [0]), \"nullable property after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array () [0], Is.EqualTo (value [0]), \"nullable get method after setting custom value element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1180,40 +1180,40 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => new NSNumber ({v.ToNSNumberCastExpression}v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting A\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting A element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting A element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => new NSNumber ({v.ToNSNumberCastExpression}v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tvar array = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (array, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = value;"); w.AppendLine ($"\t\t\t\tarray = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nuint) value.Length, array.Count, \"getter B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], {v.FromNSNumberCastExpression}array.GetItem (0){v.Map}, \"getter B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.Count, Is.EqualTo ((nuint) value.Length), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.FromNSNumberCastExpression}array.GetItem (0){v.Map}, Is.EqualTo (value [0]), \"getter B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t}}"); @@ -1236,32 +1236,32 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Value, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}ValueNullable, \"initial nullable null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}ValueNullable (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Value, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.Null, \"initial nullable null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}? value = default ({v.Managed});"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}ValueNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}ValueNullable, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}ValueNonNullable, \"non-nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}ValueNullable (), \"nullable get method after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}ValueNonNullable (), \"non-nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.EqualTo (value), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}ValueNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}ValueNullable, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}ValueNonNullable, \"non-nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}ValueNullable (), \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}ValueNonNullable (), \"non-nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.EqualTo (value), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.EqualTo (value), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting custom value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}ValueNullable (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Value, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}ValueNullable, \"nullable null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}ValueNullable (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Value, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.Null, \"nullable null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1272,43 +1272,43 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Value, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Value, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Value, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tusing (var input = NSValue.{v.MapFrom} (value))"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Value, \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.EqualTo (value), \"after setting A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSValue.{v.MapFrom} (value))"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNonNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Value, \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.EqualTo (value), \"after setting B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = null;"); w.AppendLine ($"\t\t\t\tvar Value = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}ValueNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (Value, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}ValueNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, Value{v.Map}, \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value{v.Map}, Is.EqualTo (value), \"getter B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}ValueNonNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, Value{v.Map}, \"getter C\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value{v.Map}, Is.EqualTo (value), \"getter C\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); @@ -1318,28 +1318,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}[] value = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}Array, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}Array (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.P{v.Managed}Array.Length, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.Get{v.Managed}Array ().Length, \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.P{v.Managed}Array [0], \"nullable property after setting custom value element\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.Get{v.Managed}Array () [0], \"nullable get method after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array.Length, Is.EqualTo (1), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array ().Length, Is.EqualTo (1), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array [0], Is.EqualTo (value [0]), \"nullable property after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array () [0], Is.EqualTo (value [0]), \"nullable get method after setting custom value element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1350,40 +1350,40 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => NSValue.{v.MapFrom} (v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting A\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting A element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting A element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => NSValue.{v.MapFrom} (v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tvar array = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (array, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = value;"); w.AppendLine ($"\t\t\t\tarray = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nuint) value.Length, array.Count, \"getter B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], array.GetItem (0){v.Map}, \"getter B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.Count, Is.EqualTo ((nuint) value.Length), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.GetItem (0){v.Map}, Is.EqualTo (value [0]), \"getter B element\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1406,28 +1406,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.PSmart{v.Managed}Property); }}, \"initial zero property\");"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.GetSmart{v.Managed}Value ()); }}, \"initial zero method\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmartNullable{v.Managed}Value (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}? value = default ({v.Managed});"); w.AppendLine ($"\t\t\t\tobj.SetSmartNullable{v.Managed}Value (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.PSmart{v.Managed}Property, \"zero property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.GetSmart{v.Managed}Value (), \"non-nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.GetSmartNullable{v.Managed}Value (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value.Value), \"zero property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Value (), Is.EqualTo (value.Value), \"non-nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Value (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.PSmart{v.Managed}Property, \"non-nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.GetSmartNullable{v.Managed}Value (), \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.GetSmart{v.Managed}Value (), \"non-nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value.Value), \"non-nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.EqualTo (value), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Value (), Is.EqualTo (value.Value), \"non-nullable get method after setting custom value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.SetSmartNullable{v.Managed}Value (value);"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.PSmart{v.Managed}Property); }}, \"null property after setting null value\");"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.GetSmart{v.Managed}Value ()); }}, \"non-nullable method after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmartNullable{v.Managed}Value (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1451,30 +1451,30 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\t\tvar value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tusing (var input = value.GetConstant ())"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmartNullable{v.Managed}Value:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.PSmart{v.Managed}Property, \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value), \"after setting A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = 0;"); w.AppendLine ($"\t\t\t\tusing (var input = value.GetConstant ())"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Value:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.PSmart{v.Managed}Property, \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value), \"after setting B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = 0;"); w.AppendLine ($"\t\t\t\tvar Value = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmartNullable{v.Managed}Value\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (default ({v.Managed}).GetConstant ().ToString (), Value.ToString (), \"zero from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value.ToString (), Is.EqualTo (default ({v.Managed}).GetConstant ().ToString ()), \"zero from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmartNullable{v.Managed}Value\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.Managed}Extensions.GetValue (Value), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.Managed}Extensions.GetValue (Value), Is.EqualTo (value), \"getter B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmart{v.Managed}Value\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.Managed}Extensions.GetValue (Value), \"getter C\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.Managed}Extensions.GetValue (Value), Is.EqualTo (value), \"getter C\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); @@ -1484,28 +1484,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmart{v.Managed}Values (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}[] value = null;"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Values (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.PSmart{v.Managed}Properties, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.GetSmart{v.Managed}Values (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Values (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.PSmart{v.Managed}Properties.Length, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.GetSmart{v.Managed}Values ().Length, \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.PSmart{v.Managed}Properties [0], \"nullable property after setting custom value element\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.GetSmart{v.Managed}Values () [0], \"nullable get method after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties.Length, Is.EqualTo (1), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values ().Length, Is.EqualTo (1), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties [0], Is.EqualTo (value [0]), \"nullable property after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values () [0], Is.EqualTo (value [0]), \"nullable get method after setting custom value element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Values (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmart{v.Managed}Values (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1516,40 +1516,40 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => v.GetConstant (), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.PSmart{v.Managed}Properties.Length, \"after setting A\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.PSmart{v.Managed}Properties [0], \"after setting A element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties.Length, Is.EqualTo (value.Length), \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties [0], Is.EqualTo (value [0]), \"after setting A element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => v.GetConstant (), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.PSmart{v.Managed}Properties.Length, \"after setting B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.PSmart{v.Managed}Properties [0], \"after setting B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties.Length, Is.EqualTo (value.Length), \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties [0], Is.EqualTo (value [0]), \"after setting B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = null;"); w.AppendLine ($"\t\t\t\tvar array = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmart{v.Managed}Values\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (array, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = value;"); w.AppendLine ($"\t\t\t\tarray = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmart{v.Managed}Values\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nuint) value.Length, array.Count, \"getter B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], {v.Managed}Extensions.GetValue (array.GetItem (0)), \"getter B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.Count, Is.EqualTo ((nuint) value.Length), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.Managed}Extensions.GetValue (array.GetItem (0)), Is.EqualTo (value [0]), \"getter B element\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1720,7 +1720,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}Struct\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 1)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 1)}).ToString ()), \"a\");"); w.AppendLine (); WriteStretConditions (w, s, out never); @@ -1732,7 +1732,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}Struct\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 2)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 2)}).ToString ()), \"a\");"); w.AppendLine (); WriteStretConditions (w, s, out never); @@ -1744,7 +1744,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}StructProperty\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 3)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 3)}).ToString ()), \"a\");"); w.AppendLine (); WriteStretConditions (w, s, out never); @@ -1756,7 +1756,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}StructProperty\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 4)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 4)}).ToString ()), \"a\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\trvd = 0;"); @@ -1769,8 +1769,8 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend_out_double (obj.Handle, new Selector (\"Test_{s}Struct_out_double:\").Handle, out rvd);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 5)}).ToString (), rv.ToString (), \"a\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (3.14, rvd, \"double out\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 5)}).ToString ()), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rvd, Is.EqualTo (3.14), \"double out\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\trvf = 0;"); @@ -1783,8 +1783,8 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend_out_float (class_ptr, new Selector (\"Test_Static{s}Struct_out_float:\").Handle, out rvf);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 6)}).ToString (), rv.ToString (), \"a\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (3.15f, rvf, \"float out\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 6)}).ToString ()), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rvf, Is.EqualTo (3.15f), \"float out\");"); w.AppendLine (); w.AppendLine ($"\t\t\t}}"); @@ -1793,7 +1793,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\tusing (var obj = new OverrideRegistrarTest ()) {{"); w.AppendLine ($"\t\t\t\tvar structValue = {GenerateNewExpression (s, 7)};"); w.AppendLine ($"\t\t\t\tvoid_objc_msgSend_{s} (obj.Handle, Selector.GetHandle (\"setProperty{s}:\"), structValue);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#1\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#1\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine (); @@ -1813,9 +1813,9 @@ public partial class TrampolineTestGenerated {"); for (var x = 1; x <= i + 1; x++) { if (x == i) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#2-S{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#2-S{x}\");"); } else { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nint) {x}, obj.ManagedVoidArg{x}, \"SetProperty#2-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedVoidArg{x}, Is.EqualTo ((nint) {x}), \"SetProperty#2-X{x}\");"); } } w.AppendLine ($"\t\t\t}}"); @@ -1838,11 +1838,11 @@ public partial class TrampolineTestGenerated {"); for (var x = 1; x <= i + 1; x++) { if (x == 1) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((float) {x}, obj.ManagedFloatArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedFloatArg{x}, Is.EqualTo ((float) {x}), \"SetProperty#3-X{x}\");"); } else if (x == i) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#3-S{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#3-S{x}\");"); } else { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nint) {x}, obj.ManagedVoidArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedVoidArg{x}, Is.EqualTo ((nint) {x}), \"SetProperty#3-X{x}\");"); } } w.AppendLine ($"\t\t\t}}"); @@ -1865,11 +1865,11 @@ public partial class TrampolineTestGenerated {"); for (var x = 1; x <= i + 1; x++) { if (x == 1) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((double) {x}, obj.ManagedDoubleArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedDoubleArg{x}, Is.EqualTo ((double) {x}), \"SetProperty#3-X{x}\");"); } else if (x == i) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#3-S{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#3-S{x}\");"); } else { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nint) {x}, obj.ManagedVoidArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedVoidArg{x}, Is.EqualTo ((nint) {x}), \"SetProperty#3-X{x}\");"); } } w.AppendLine ($"\t\t\t}}"); diff --git a/tests/xcframework-test/XCFrameworkTests.cs b/tests/xcframework-test/XCFrameworkTests.cs index 206951ea19b0..2926ee397ed8 100644 --- a/tests/xcframework-test/XCFrameworkTests.cs +++ b/tests/xcframework-test/XCFrameworkTests.cs @@ -19,14 +19,14 @@ public class FrameworkTests { [Test] public void CFunction () { - Assert.AreEqual (42, CFunctions.theUltimateAnswer (), "a"); + Assert.That (CFunctions.theUltimateAnswer (), Is.EqualTo (42), "a"); } [Test] public void ObjCClass () { using (var obj = new FrameworkTest ()) { - Assert.AreEqual (42, obj.Func (), "a"); + Assert.That (obj.Func (), Is.EqualTo (42), "a"); } } } diff --git a/tests/xharness/AppRunner.cs b/tests/xharness/AppRunner.cs index 4cc1a11b2690..8f79f259d1ae 100644 --- a/tests/xharness/AppRunner.cs +++ b/tests/xharness/AppRunner.cs @@ -225,6 +225,13 @@ public async Task RunAsync () if (harness.InCI) { // We use the 'BUILD_REVISION' variable to detect whether we're running CI or not. args.Add (new SetEnvVariableArgument ("BUILD_REVISION", Environment.GetEnvironmentVariable ("BUILD_REVISION"))); + + // Forward VM_VENDOR (set by the pipeline when running on a VM-backed + // pool such as ACES) so TestRuntime.AssertNotVirtualMachine works + // inside the iOS/tvOS simulator process. + var vmVendor = Environment.GetEnvironmentVariable ("VM_VENDOR"); + if (!string.IsNullOrEmpty (vmVendor)) + args.Add (new SetEnvVariableArgument ("VM_VENDOR", vmVendor)); } if (!harness.GetIncludeSystemPermissionTests (TestPlatform.iOS, !isSimulator)) diff --git a/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs b/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs index 896e9a506d18..851fb2a9d42e 100644 --- a/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs +++ b/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs @@ -35,7 +35,7 @@ public override void SetEnvironmentVariables (Process process) var xcodeRoot = Jenkins.Harness.XcodeRoot; process.StartInfo.EnvironmentVariables ["RootTestsDirectory"] = HarnessConfiguration.RootDirectory; - process.StartInfo.EnvironmentVariables ["MD_APPLE_SDK_ROOT"] = xcodeRoot; + process.StartInfo.EnvironmentVariables ["DEVELOPER_DIR"] = xcodeRoot; foreach (var kvp in Environment) { if (kvp.Value is null) { diff --git a/tests/xtro-sharpie/UnitTests/UnitTests.csproj b/tests/xtro-sharpie/UnitTests/UnitTests.csproj index dd9a60e4b579..5bd7b152f1f2 100644 --- a/tests/xtro-sharpie/UnitTests/UnitTests.csproj +++ b/tests/xtro-sharpie/UnitTests/UnitTests.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/tests/xtro-sharpie/UnitTests/Xtro.cs b/tests/xtro-sharpie/UnitTests/Xtro.cs index 9b4dd819c721..6037f79e44c1 100644 --- a/tests/xtro-sharpie/UnitTests/Xtro.cs +++ b/tests/xtro-sharpie/UnitTests/Xtro.cs @@ -29,7 +29,7 @@ public void RunTest () TestContext.AddTestAttachment (zippedReport, "HTML report (zipped)"); } - Assert.AreEqual (0, rv, "ExitCode"); + Assert.That (rv, Is.EqualTo (0), "ExitCode"); } } } diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreImage.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreImage.ignore deleted file mode 100644 index c0280351bfe4..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreImage.ignore +++ /dev/null @@ -1,2 +0,0 @@ -# removed in XAMCORE_5_0 -!unknown-type! CIFilterGenerator bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreML.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreML.ignore deleted file mode 100644 index 0d896ca7254b..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreML.ignore +++ /dev/null @@ -1,4 +0,0 @@ -# These types are marked as unavailable in the headers if the min OS version is >= Xcode 16's OS versions, so xtro doesn't detect them as available. -# We're removing them in XAMCORE_5_0. -!unknown-type! MLModelCollection bound -!unknown-type! MLModelCollectionEntry bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreImage.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreImage.ignore index 03cc1b262fdd..704f52f5418b 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreImage.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreImage.ignore @@ -1,5 +1,3 @@ ## OSX-only API, rdar #22524785 ## see https://trello.com/c/kpksFWto/6-22524785-coreimage-headers-discrepancies !missing-selector! CIKernel::setROISelector: not bound -# removed in XAMCORE_5_0 -!unknown-type! CIFilterGenerator bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreML.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreML.ignore deleted file mode 100644 index 0d896ca7254b..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreML.ignore +++ /dev/null @@ -1,4 +0,0 @@ -# These types are marked as unavailable in the headers if the min OS version is >= Xcode 16's OS versions, so xtro doesn't detect them as available. -# We're removing them in XAMCORE_5_0. -!unknown-type! MLModelCollection bound -!unknown-type! MLModelCollectionEntry bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-PhotosUI.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-PhotosUI.ignore deleted file mode 100644 index 9fb677a7aaab..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-PhotosUI.ignore +++ /dev/null @@ -1,2 +0,0 @@ -# Removed in Xcode 14 from header -!unknown-type! PHEditingExtensionContext bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore index 268a5aeb27fa..a9a43afadb4c 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore @@ -1,9 +1,6 @@ ## https://bugzilla.xamarin.com/show_bug.cgi?id=30717 !duplicate-register! _NSDatePickerCellDelegate exists as both AppKit.NSDatePickerCell/_NSDatePickerCellDelegate and AppKit.NSDatePicker/_NSDatePickerCellDelegate -## Proxy class for NSGraphicsContext internal to AppKit -!unknown-type! NSPrintPreviewGraphicsContext bound - ## In header as old style unnamaed enum !unknown-native-enum! NSModalResponse bound !unknown-native-enum! NSWindowLevel bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-CoreML.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-CoreML.ignore deleted file mode 100644 index 0d896ca7254b..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-CoreML.ignore +++ /dev/null @@ -1,4 +0,0 @@ -# These types are marked as unavailable in the headers if the min OS version is >= Xcode 16's OS versions, so xtro doesn't detect them as available. -# We're removing them in XAMCORE_5_0. -!unknown-type! MLModelCollection bound -!unknown-type! MLModelCollectionEntry bound diff --git a/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs b/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs index 1fe2e1d2773a..8904e46aa7a1 100644 --- a/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs +++ b/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs @@ -136,6 +136,28 @@ public static bool HasAnyDeprecationForCurrentPlatform (ICustomAttributeProvider return false; } + public static bool HasUnsupportedOSPlatform (ICustomAttributeProvider item) + { + if (Skip (item)) + return false; + + // Properties are a special case as it is generated on the property itself and not the individual get_ \ set_ methods + // Cecil does not have a link between the MethodDefinition we have and the hosting PropertyDefinition, so we have to dig to find the match + if (item is MethodDefinition method) { + var property = method.DeclaringType.Properties.FirstOrDefault (p => p.GetMethod == method || p.SetMethod == method); + if (property is not null && HasUnsupportedOSPlatform (property)) { + return true; + } + } + + foreach (var attribute in item.CustomAttributes) { + if (AttributeHelpers.HasUnsupportedOSPlatform (attribute, Helpers.Platform)) + return true; + } + + return false; + } + public static bool HasAnyObsoleted (ICustomAttributeProvider item) { if (Skip (item)) diff --git a/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs b/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs index 5d0fbaa6645f..a98cdd02f6fe 100644 --- a/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs +++ b/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs @@ -142,6 +142,8 @@ public override void EndVisit () // internal inner classes are not mapped to native ones if (type.IsNestedAssembly) continue; + if (AttributeHelpers.HasUnsupportedOSPlatform (type)) + continue; var framework = Helpers.MapFramework (type.Namespace); Log.On (framework).Add ($"!unknown-type! {extra} bound"); } diff --git a/tools/api-tools/mono-api-html/ApiChange.cs b/tools/api-tools/mono-api-html/ApiChange.cs index 3bf895a47b00..18cc90285b5c 100644 --- a/tools/api-tools/mono-api-html/ApiChange.cs +++ b/tools/api-tools/mono-api-html/ApiChange.cs @@ -10,6 +10,7 @@ class ApiChange { public string Header = ""; public TextChunk Member = new TextChunk (); public bool AnyChange; + public bool IsNullabilityChange; public string SourceDescription; public State State; @@ -45,6 +46,76 @@ public ApiChange AppendModified (string old, string @new) AnyChange = true; return this; } + + // Renders a type change: uses inline nullability rendering if the only + // difference is '?' annotations, otherwise falls back to full modification. + public ApiChange AppendTypeModified (string old, string @new) + { + if (Helper.DiffersOnlyByNullability (old, @new)) + return AppendNullabilityModified (old, @new); + return AppendModified (old, @new); + } + + // Renders a type modification where only nullability annotations ('?') differ. + // Only the added/removed '?' characters are highlighted; the rest is plain text. + public ApiChange AppendNullabilityModified (string old, string @new) + { + int si = 0; + int ti = 0; + while (si < old.Length && ti < @new.Length) { + if (old [si] == @new [ti]) { + Member.Append (old [si]); + si++; + ti++; + } else if (old [si] == '?' && IsNullabilitySuffix (old, si)) { + State.Formatter.DiffRemoval (Member, "?"); + AnyChange = true; + si++; + } else if (@new [ti] == '?' && IsNullabilitySuffix (@new, ti)) { + State.Formatter.DiffAddition (Member, "?"); + AnyChange = true; + ti++; + } else { + // Shouldn't happen for nullability-only diffs, fall back to full modification + State.Formatter.DiffModification (Member, old.Substring (si), @new.Substring (ti)); + AnyChange = true; + return this; + } + } + // Handle remaining characters + while (si < old.Length) { + if (old [si] == '?' && IsNullabilitySuffix (old, si)) { + State.Formatter.DiffRemoval (Member, "?"); + AnyChange = true; + si++; + } else { + Member.Append (old [si]); + si++; + } + } + while (ti < @new.Length) { + if (@new [ti] == '?' && IsNullabilitySuffix (@new, ti)) { + State.Formatter.DiffAddition (Member, "?"); + AnyChange = true; + ti++; + } else { + Member.Append (@new [ti]); + ti++; + } + } + return this; + } + + static bool IsNullabilitySuffix (string text, int index) + { + // A '?' is a nullability suffix if it's at the end, or before a type separator. + // The input type names are already formatted (via GetTypeName + Formatter), so generic + // brackets appear as HTML entities (< / >). A '?' before '&' catches the > case. + if (index + 1 >= text.Length) + return true; + char next = text [index + 1]; + return next == ']' || next == ',' || next == '>' || next == '&' || next == ' '; + } } class ApiChanges : Dictionary> { @@ -61,12 +132,66 @@ public void Add (XElement source, XElement target, ApiChange change) if (!change.AnyChange) return; + // Detect if this change is nullability-only + if (DiffersOnlyByNullability (source, target)) + change.IsNullabilityChange = true; + if (!TryGetValue (change.Header, out List? list)) { list = new List (); base.Add (change.Header, list); } list.Add (change); } + + static bool DiffersOnlyByNullability (XElement source, XElement target) + { + // Compare all attributes, stripping nullability from type-related attributes + var typeAttributes = new HashSet { "returntype", "fieldtype", "ptype", "eventtype", "type" }; + + if (source.Name != target.Name) + return false; + + // Check that all non-type-related attributes are the same + var srcAttrs = source.Attributes ().ToDictionary (a => a.Name.LocalName, a => a.Value); + var tgtAttrs = target.Attributes ().ToDictionary (a => a.Name.LocalName, a => a.Value); + + if (srcAttrs.Count != tgtAttrs.Count) + return false; + + bool hasNullabilityDiff = false; + foreach (var kvp in srcAttrs) { + if (!tgtAttrs.TryGetValue (kvp.Key, out var tgtValue)) + return false; + + if (kvp.Value == tgtValue) + continue; + + if (typeAttributes.Contains (kvp.Key)) { + if (Helper.DiffersOnlyByNullability (kvp.Value, tgtValue)) + hasNullabilityDiff = true; + else + return false; + } else { + return false; + } + } + + // Always check child elements — a non-nullability child diff means this + // is not a nullability-only change, even if the parent attributes differ only by nullability. + var srcChildren = source.Elements ().ToList (); + var tgtChildren = target.Elements ().ToList (); + if (srcChildren.Count != tgtChildren.Count) + return false; + + for (int i = 0; i < srcChildren.Count; i++) { + if (XNode.DeepEquals (srcChildren [i], tgtChildren [i])) + continue; + if (!DiffersOnlyByNullability (srcChildren [i], tgtChildren [i])) + return false; + hasNullabilityDiff = true; + } + + return hasNullabilityDiff; + } } } - diff --git a/tools/api-tools/mono-api-html/ConstructorComparer.cs b/tools/api-tools/mono-api-html/ConstructorComparer.cs index e541861f2093..5ae44bf7ee6d 100644 --- a/tools/api-tools/mono-api-html/ConstructorComparer.cs +++ b/tools/api-tools/mono-api-html/ConstructorComparer.cs @@ -59,7 +59,7 @@ void RenderReturnType (XElement source, XElement target, ApiChange change) var tgtType = target.GetTypeName ("returntype", State); if (srcType != tgtType) { - change.AppendModified (srcType ?? "", tgtType ?? ""); + change.AppendTypeModified (srcType ?? "", tgtType ?? ""); change.Append (" "); } else if (srcType is not null) { // ctor don't have a return type diff --git a/tools/api-tools/mono-api-html/EventComparer.cs b/tools/api-tools/mono-api-html/EventComparer.cs index 302d483a5008..123cfe850897 100644 --- a/tools/api-tools/mono-api-html/EventComparer.cs +++ b/tools/api-tools/mono-api-html/EventComparer.cs @@ -59,7 +59,7 @@ public override bool Equals (XElement source, XElement target, ApiChanges change var tgtEventType = target.GetTypeName ("eventtype", State) ?? ""; if (srcEventType != tgtEventType) { - change.AppendModified (srcEventType, tgtEventType); + change.AppendTypeModified (srcEventType, tgtEventType); } else { change.Append (srcEventType); } diff --git a/tools/api-tools/mono-api-html/FieldComparer.cs b/tools/api-tools/mono-api-html/FieldComparer.cs index ba600ba548c2..d0b6169cbf73 100644 --- a/tools/api-tools/mono-api-html/FieldComparer.cs +++ b/tools/api-tools/mono-api-html/FieldComparer.cs @@ -146,7 +146,7 @@ public override bool Equals (XElement source, XElement target, ApiChanges change var tgtType = target.GetTypeName ("fieldtype", State) ?? ""; if (srcType != tgtType) { - change.AppendModified (srcType, tgtType); + change.AppendTypeModified (srcType, tgtType); } else { change.Append (srcType); } diff --git a/tools/api-tools/mono-api-html/Formatter.cs b/tools/api-tools/mono-api-html/Formatter.cs index a7be2f256c0b..0fce910fc46c 100644 --- a/tools/api-tools/mono-api-html/Formatter.cs +++ b/tools/api-tools/mono-api-html/Formatter.cs @@ -211,6 +211,13 @@ public void Append (string value) cachedOutput.Append (value); } + public void Append (char value) + { + foreach (var kvp in stringbuilders) + kvp.StringBuilder.Append (value); + cachedOutput.Append (value); + } + public override string ToString () { throw new InvalidOperationException (); diff --git a/tools/api-tools/mono-api-html/Helpers.cs b/tools/api-tools/mono-api-html/Helpers.cs index 975eefacd838..9a98857a0826 100644 --- a/tools/api-tools/mono-api-html/Helpers.cs +++ b/tools/api-tools/mono-api-html/Helpers.cs @@ -127,6 +127,7 @@ static bool TryGetAttributeProperty (this XElement? self, string attributeName, StringBuilder sb = null!; bool is_nullable = false; + bool is_nullable_ref = false; if (type.StartsWith ("System.Nullable`1[", StringComparison.Ordinal)) { is_nullable = true; sb = new StringBuilder (type, 18, type.Length - 19, 1024); @@ -134,6 +135,12 @@ static bool TryGetAttributeProperty (this XElement? self, string attributeName, sb = new StringBuilder (type); } + // Handle nullable reference type annotation (trailing '?' added by mono-api-info) + if (!is_nullable && sb.Length > 0 && sb [sb.Length - 1] == '?') { + is_nullable_ref = true; + sb.Remove (sb.Length - 1, 1); + } + bool is_ref = (sb [sb.Length - 1] == '&'); if (is_ref) sb.Remove (sb.Length - 1, 1); @@ -159,6 +166,8 @@ static bool TryGetAttributeProperty (this XElement? self, string attributeName, sb.Append ("[]"); if (is_nullable) sb.Append ('?'); + if (is_nullable_ref) + sb.Append ('?'); if (is_pointer) sb.Append ('*'); return sb.ToString (); @@ -245,5 +254,32 @@ public static FieldAttributes GetFieldAttributes (this XElement element) var srcAttribs = element.Attribute ("attrib"); return (FieldAttributes) (srcAttribs is not null ? Int32.Parse (srcAttribs.Value) : 0); } + + // Strips trailing '?' nullability annotations from a type name for comparison purposes. + // Handles both top-level (System.String?) and nested generics (List`1[System.String?]). + public static string? StripNullability (string? type) + { + if (type is null) + return null; + // Remove all '?' that appear before ']', at end of string, before ',', + // before '>' or '&' (HTML entities like >), or before ' ' (before param name) + var sb = new StringBuilder (type.Length); + for (int i = 0; i < type.Length; i++) { + if (type [i] == '?') { + if (i + 1 >= type.Length || type [i + 1] == ']' || type [i + 1] == ',' || type [i + 1] == '>' || type [i + 1] == '&' || type [i + 1] == ' ') + continue; + } + sb.Append (type [i]); + } + return sb.ToString (); + } + + // Returns true if two type names differ only in nullability annotations. + public static bool DiffersOnlyByNullability (string? source, string? target) + { + if (source == target) + return false; + return StripNullability (source) == StripNullability (target); + } } } diff --git a/tools/api-tools/mono-api-html/MemberComparer.cs b/tools/api-tools/mono-api-html/MemberComparer.cs index d5a0ebfa216c..f0f5915c384b 100644 --- a/tools/api-tools/mono-api-html/MemberComparer.cs +++ b/tools/api-tools/mono-api-html/MemberComparer.cs @@ -134,11 +134,24 @@ void Add (IEnumerable elements) void Modify (ApiChanges modified) { foreach (var changes in modified) { - Formatter.BeginMemberModification (changes.Key); - foreach (var element in changes.Value) { - Formatter.Diff (element); + var nonNullability = changes.Value.Where (c => !c.IsNullabilityChange).ToList (); + var nullabilityOnly = changes.Value.Where (c => c.IsNullabilityChange).ToList (); + + if (nonNullability.Count > 0) { + Formatter.BeginMemberModification (changes.Key); + foreach (var element in nonNullability) { + Formatter.Diff (element); + } + Formatter.EndMemberModification (); + } + + if (nullabilityOnly.Count > 0) { + Formatter.BeginMemberModification (changes.Key + " (nullability)"); + foreach (var element in nullabilityOnly) { + Formatter.Diff (element); + } + Formatter.EndMemberModification (); } - Formatter.EndMemberModification (); } } @@ -315,7 +328,7 @@ protected void RenderParameters (XElement source, XElement target, ApiChange cha } if (paramSourceType != paramTargetType) { - change.AppendModified (paramSourceType ?? "", paramTargetType ?? ""); + change.AppendTypeModified (paramSourceType ?? "", paramTargetType ?? ""); } else { change.Append (paramSourceType ?? ""); } diff --git a/tools/api-tools/mono-api-html/MethodComparer.cs b/tools/api-tools/mono-api-html/MethodComparer.cs index 677a5136bdf1..6846c1cf6b4f 100644 --- a/tools/api-tools/mono-api-html/MethodComparer.cs +++ b/tools/api-tools/mono-api-html/MethodComparer.cs @@ -52,7 +52,7 @@ public override bool Find (XElement e) if (e.GetAttribute ("name") != Source.GetAttribute ("name")) return false; - if (e.GetAttribute ("returntype") != Source.GetAttribute ("returntype")) + if (Helper.StripNullability (e.GetAttribute ("returntype")) != Helper.StripNullability (Source.GetAttribute ("returntype"))) return false; var eGP = e.Element ("generic-parameters"); diff --git a/tools/api-tools/mono-api-html/PropertyComparer.cs b/tools/api-tools/mono-api-html/PropertyComparer.cs index 205600a6a199..a2783f0782d0 100644 --- a/tools/api-tools/mono-api-html/PropertyComparer.cs +++ b/tools/api-tools/mono-api-html/PropertyComparer.cs @@ -103,7 +103,7 @@ void RenderPropertyType (XElement source, XElement target, ApiChange change) if (srcType == tgtType) { change.Append (tgtType); } else { - change.AppendModified (srcType, tgtType); + change.AppendTypeModified (srcType, tgtType); } change.Append (" "); } @@ -150,7 +150,7 @@ void RenderIndexers (List srcIndexers, List tgtIndexers, Api if (srcType == tgtType) { change.Append (tgtType); } else { - change.AppendModified (srcType, tgtType); + change.AppendTypeModified (srcType, tgtType); } change.Append (" "); diff --git a/tools/api-tools/mono-api-info/mono-api-info.cs b/tools/api-tools/mono-api-info/mono-api-info.cs index b0c8a4d9d542..1b22201ef597 100644 --- a/tools/api-tools/mono-api-info/mono-api-info.cs +++ b/tools/api-tools/mono-api-info/mono-api-info.cs @@ -1014,7 +1014,9 @@ protected override void AddExtraAttributes (MemberReference memberDefinition) base.AddExtraAttributes (memberDefinition); FieldDefinition field = (FieldDefinition) memberDefinition; - AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType)); + var fieldTypeName = Utils.CleanupTypeName (field.FieldType); + fieldTypeName = NullabilityHelper.AppendNullabilityToTypeName (fieldTypeName, field.FieldType, field, field.DeclaringType); + AddAttribute ("fieldtype", fieldTypeName); if (field.IsLiteral) { object value = field.Constant;//object value = field.GetValue (null); @@ -1083,7 +1085,9 @@ protected override void AddExtraAttributes (MemberReference memberDefinition) base.AddExtraAttributes (memberDefinition); PropertyDefinition prop = (PropertyDefinition) memberDefinition; - AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType)); + var ptypeName = Utils.CleanupTypeName (prop.PropertyType); + ptypeName = NullabilityHelper.AppendNullabilityToTypeName (ptypeName, prop.PropertyType, prop, prop.DeclaringType); + AddAttribute ("ptype", ptypeName); bool haveParameters; MethodDefinition []? methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters); @@ -1149,7 +1153,9 @@ protected override void AddExtraAttributes (MemberReference memberDefinition) base.AddExtraAttributes (memberDefinition); EventDefinition evt = (EventDefinition) memberDefinition; - AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType)); + var evtTypeName = Utils.CleanupTypeName (evt.EventType); + evtTypeName = NullabilityHelper.AppendNullabilityToTypeName (evtTypeName, evt.EventType, evt, evt.DeclaringType); + AddAttribute ("eventtype", evtTypeName); } public override string ParentTag { @@ -1217,8 +1223,10 @@ protected override void AddExtraAttributes (MemberReference memberDefinition) AddAttribute ("is-override", "true"); } string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType); - if (rettype != "System.Void" || !mbase.IsConstructor) + if (rettype != "System.Void" || !mbase.IsConstructor) { + rettype = NullabilityHelper.AppendNullabilityToTypeName (rettype, mbase.MethodReturnType.ReturnType, mbase.MethodReturnType, mbase); AddAttribute ("returntype", (rettype)); + } // // if (mbase.MethodReturnType.HasCustomAttributes) // AttributeData.OutputAttributes (writer, mbase.MethodReturnType); @@ -1302,7 +1310,7 @@ public override void DoOutput () pt = brt.ElementType; } - AddAttribute ("type", Utils.CleanupTypeName (pt)); + AddAttribute ("type", NullabilityHelper.AppendNullabilityToTypeName (Utils.CleanupTypeName (pt), pt, parameter, parameter.Method as ICustomAttributeProvider)); if (parameter.IsOptional) { AddAttribute ("optional", "true"); @@ -1456,6 +1464,130 @@ public static string GetSignature (IList infos) } + static class NullabilityHelper { + const string NullableAttributeName = "System.Runtime.CompilerServices.NullableAttribute"; + const string NullableContextAttributeName = "System.Runtime.CompilerServices.NullableContextAttribute"; + + // Returns the nullability flag for the top-level type: + // 0 = oblivious, 1 = not-null, 2 = nullable + public static byte GetTopLevelNullability (ICustomAttributeProvider provider, ICustomAttributeProvider? context) + { + // Check for NullableAttribute directly on the member/parameter/return type + var flag = GetNullableFlagFromProvider (provider); + if (flag.HasValue) + return flag.Value; + + // Fall back to NullableContextAttribute on the containing method/type + if (context is not null) { + var contextFlag = GetNullableContextFlag (context); + if (contextFlag.HasValue) + return contextFlag.Value; + } + + return 0; // oblivious + } + + // Gets the NullableContextAttribute flag from a method or type + public static byte? GetNullableContextFlag (ICustomAttributeProvider provider) + { + if (provider is null) + return null; + + if (!provider.HasCustomAttributes) + return GetNullableContextFromParent (provider); + + foreach (var attr in provider.CustomAttributes) { + if (attr.AttributeType.FullName != NullableContextAttributeName) + continue; + if (attr.ConstructorArguments.Count == 1 && attr.ConstructorArguments [0].Value is byte b) + return b; + } + + return GetNullableContextFromParent (provider); + } + + static byte? GetNullableContextFromParent (ICustomAttributeProvider? provider) + { + if (provider is MethodDefinition method) + return GetNullableContextFlag (method.DeclaringType); + if (provider is PropertyDefinition prop) + return GetNullableContextFlag (prop.DeclaringType); + if (provider is FieldDefinition field) + return GetNullableContextFlag (field.DeclaringType); + if (provider is EventDefinition evt) + return GetNullableContextFlag (evt.DeclaringType); + if (provider is TypeDefinition type) { + if (type.DeclaringType is not null) + return GetNullableContextFlag (type.DeclaringType); + // Fall back to module-level NullableContextAttribute + return GetNullableContextFlagFromAttributes (type.Module); + } + return null; + } + + static byte? GetNullableContextFlagFromAttributes (ICustomAttributeProvider? provider) + { + if (provider is null || !provider.HasCustomAttributes) + return null; + + foreach (var attr in provider.CustomAttributes) { + if (attr.AttributeType.FullName != NullableContextAttributeName) + continue; + if (attr.ConstructorArguments.Count == 1 && attr.ConstructorArguments [0].Value is byte b) + return b; + } + return null; + } + + static byte? GetNullableFlagFromProvider (ICustomAttributeProvider provider) + { + if (!provider.HasCustomAttributes) + return null; + + foreach (var attr in provider.CustomAttributes) { + if (attr.AttributeType.FullName != NullableAttributeName) + continue; + if (attr.ConstructorArguments.Count != 1) + continue; + + var arg = attr.ConstructorArguments [0]; + if (arg.Value is byte b) + return b; + if (arg.Value is CustomAttributeArgument [] arr && arr.Length > 0 && arr [0].Value is byte b2) + return b2; + } + + return null; + } + + public static bool IsNullableReferenceType (TypeReference type, ICustomAttributeProvider provider, ICustomAttributeProvider? context) + { + if (type is null) + return false; + + // Value types use Nullable for nullability, not annotations + if (type.IsValueType) + return false; + + // ByReference types (ref/out parameters): check the element type + if (type.IsByReference) { + var elementType = ((ByReferenceType) type).ElementType; + if (elementType.IsValueType) + return false; + } + + var flag = GetTopLevelNullability (provider, context); + return flag == 2; + } + + public static string AppendNullabilityToTypeName (string typeName, TypeReference type, ICustomAttributeProvider provider, ICustomAttributeProvider? context) + { + if (IsNullableReferenceType (type, provider, context)) + return typeName + "?"; + return typeName; + } + } + class TypeReferenceComparer : IComparer { public static TypeReferenceComparer Default = new TypeReferenceComparer (); diff --git a/tools/common/Application.cs b/tools/common/Application.cs index f2b8f7fc1882..41849edd41a4 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -68,7 +68,7 @@ public enum RegistrarMode { TrimmableStatic, } - public partial class Application { + public partial class Application : IToolLog { public Cache? Cache; public string AppDirectory = "."; public bool DeadStrip = true; @@ -104,7 +104,8 @@ public partial class Application { public HashSet WeakFrameworks = new HashSet (); public bool IsExtension; - public ApplePlatform Platform { get { return Driver.TargetFramework.Platform; } } + public TargetFramework TargetFramework { get; set; } + public ApplePlatform Platform { get { return TargetFramework.Platform; } } public List DylibsToConvertToFrameworks = new List (); public List MonoLibraries = new List (); @@ -268,6 +269,14 @@ public bool PackageManagedDebugSymbols { public Version GetMacCatalystiOSVersion (Version macOSVersion) { +#if LEGACY_TOOLS + if (macOSVersion.Major >= 26 && SdkRoot is null) { + // this shouldn't happen for normal builds, nor for customers, so just show an internal 99 warning. + ErrorHelper.Warning (this, 99, Errors.MX0099, $"No Xcode configured, assuming the macOS version {macOSVersion} is identical to the Mac Catalyst/iOS version."); + return macOSVersion; + } +#endif + if (!MacCatalystSupport.TryGetiOSVersion (Driver.GetFrameworkDirectory (this), macOSVersion, out var value, out var knownMacOSVersions)) throw ErrorHelper.CreateError (184, Errors.MX0184 /* Could not map the macOS version {0} to a corresponding Mac Catalyst version. Valid macOS versions are: {1} */, macOSVersion.ToString (), string.Join (", ", knownMacOSVersions.OrderBy (v => v))); @@ -281,6 +290,8 @@ public Application (LinkerConfiguration configuration) this.LinkContext = new Tuner.DerivedLinkContext (configuration, this); #endif this.StaticRegistrar = new StaticRegistrar (this); + this.Resolver = new PlatformResolver (this); + SetDefaultHiddenWarnings (); } #if !LEGACY_TOOLS @@ -414,9 +425,9 @@ public string PlatformName { } } - public static bool IsUptodate (string source, string target, bool check_contents = false, bool check_stamp = true) + public static bool IsUptodate (IToolLog log, string source, string target, bool check_contents = false, bool check_stamp = true) { - return FileCopier.IsUptodate (source, target, check_contents, check_stamp); + return FileCopier.IsUptodate (log, source, target, check_contents, check_stamp); } public static void RemoveResource (ModuleDefinition module, string name) @@ -488,14 +499,14 @@ public static bool ExtractResource (ModuleDefinition module, string name, string // // If check_stamp is true, the function will use the timestamp of a "target".stamp file // if it's later than the timestamp of the "target" file itself. - public static bool IsUptodate (IEnumerable sources, IEnumerable targets, bool check_stamp = true) + public static bool IsUptodate (IToolLog log, IEnumerable sources, IEnumerable targets, bool check_stamp = true) { - return FileCopier.IsUptodate (sources, targets, check_stamp); + return FileCopier.IsUptodate (log, sources, targets, check_stamp); } - public static void UpdateDirectory (string source, string target) + public static void UpdateDirectory (IToolLog log, string source, string target) { - FileCopier.UpdateDirectory (source, target); + FileCopier.UpdateDirectory (log, source, target); } public void InitializeCommon () @@ -534,13 +545,13 @@ public void InitializeCommon () if (!package_managed_debug_symbols.HasValue) { package_managed_debug_symbols = EnableDebug; } else if (package_managed_debug_symbols.Value && IsLLVM) { - ErrorHelper.Warning (3007, Errors.MX3007); + ErrorHelper.Warning (this, 3007, Errors.MX3007); } Optimizations.Initialize (this, out var messages); - ErrorHelper.Show (messages); - if (Driver.Verbosity > 3) - Driver.Log (4, $"Enabled optimizations: {Optimizations}"); + ErrorHelper.Show (this, messages); + if (this.Verbosity > 3) + this.Log (4, $"Enabled optimizations: {Optimizations}"); } void InitializeDeploymentTarget () @@ -570,7 +581,7 @@ public void RunRegistrar () throw ErrorHelper.CreateError (99, "RegistrarOutputLibrary must be specified."); var RootAssembly = RootAssemblies [0]; var resolvedAssemblies = new Dictionary (); - var resolver = new PlatformResolver () { + var resolver = new PlatformResolver (this) { RootDirectory = Path.GetDirectoryName (RootAssembly), }; resolver.Configure (); @@ -578,7 +589,7 @@ public void RunRegistrar () var ps = new ReaderParameters (); ps.AssemblyResolver = resolver; foreach (var reference in References) { - var r = resolver.Load (reference); + var r = resolver.Load (this, reference); if (r is null) throw ErrorHelper.CreateError (2002, Errors.MT2002, reference); } @@ -593,21 +604,21 @@ public void RunRegistrar () try { AssemblyDefinition lastAssembly = ps.AssemblyResolver.Resolve (AssemblyNameReference.Parse (rootName), new ReaderParameters ()); if (lastAssembly is null) { - ErrorHelper.Warning (7, Errors.MX0007, rootName); + ErrorHelper.Warning (this, 7, Errors.MX0007, rootName); continue; } if (resolvedAssemblies.TryGetValue (rootName, out var previousAssembly)) { if (lastAssembly.MainModule.RuntimeVersion != previousAssembly.MainModule.RuntimeVersion) { - Driver.Log (2, "Attemping to load an assembly another time {0} (previous {1})", lastAssembly.FullName, previousAssembly.FullName); + this.Log (2, "Attemping to load an assembly another time {0} (previous {1})", lastAssembly.FullName, previousAssembly.FullName); } continue; } resolvedAssemblies.Add (rootName, lastAssembly); - Driver.Log (3, "Loaded {0}", lastAssembly.MainModule.FileName); + this.Log (3, "Loaded {0}", lastAssembly.MainModule.FileName); } catch (Exception ex) { - ErrorHelper.Warning (9, ex, Errors.MX0009, $"{rootName}: {ex.Message}"); + ErrorHelper.Warning (this, 9, ex, Errors.MX0009, $"{rootName}: {ex.Message}"); continue; } } @@ -1026,7 +1037,7 @@ public void GetAotArguments (string filename, Abi abi, string outputDir, string if (!string.IsNullOrEmpty (llvm_path)) { aotArguments.Add ($"llvm-path={llvm_path}"); } else { - aotArguments.Add ($"llvm-path={Driver.GetFrameworkCurrentDirectory (app)}/LLVM/bin/"); + aotArguments.Add ($"llvm-path={app.FrameworkCurrentDirectory}/LLVM/bin/"); } } @@ -1186,23 +1197,84 @@ public bool VerifyDynamicFramework (string framework_path) } if (!dynamic) - Driver.Log (1, "The framework {0} is a framework of static libraries, and will not be copied to the app.", framework_path); + this.Log (1, "The framework {0} is a framework of static libraries, and will not be copied to the app.", framework_path); return dynamic; } #endif // !LEGACY_TOOLS - static Application () + public void SetDefaultHiddenWarnings () { - SetDefaultHiddenWarnings (); + // People don't like these warnings (#20670), and they also complicate our tests, so ignore them. + ErrorHelper.ParseWarningLevel (this, ErrorHelper.WarningLevel.Disable, "4178"); // The class '{0}' will not be registered because the {1} framework has been removed from the {2} SDK. + ErrorHelper.ParseWarningLevel (this, ErrorHelper.WarningLevel.Disable, "4189"); // The class '{0}' will not be registered because it has been removed from the {1} SDK. + ErrorHelper.ParseWarningLevel (this, ErrorHelper.WarningLevel.Disable, "4190"); // The class '{0}' will not be registered because the {1} framework has been deprecated from the {2} SDK. } - public static void SetDefaultHiddenWarnings () + public void Log (string message) { - // People don't like these warnings (#20670), and they also complicate our tests, so ignore them. - ErrorHelper.ParseWarningLevel (ErrorHelper.WarningLevel.Disable, "4178"); // The class '{0}' will not be registered because the {1} framework has been removed from the {2} SDK. - ErrorHelper.ParseWarningLevel (ErrorHelper.WarningLevel.Disable, "4189"); // The class '{0}' will not be registered because it has been removed from the {1} SDK. - ErrorHelper.ParseWarningLevel (ErrorHelper.WarningLevel.Disable, "4190"); // The class '{0}' will not be registered because the {1} framework has been deprecated from the {2} SDK. + Console.WriteLine (message); + } + + public void LogError (string message) + { + Console.Error.WriteLine (message); + } + + public void LogError (Exception exception) + { + ErrorHelper.Show (this, exception); + } + + public void LogException (Exception exception) + { + ErrorHelper.Show (this, exception); + } + + int verbosity = Driver.GetDefaultVerbosity (); + public int Verbosity { + get => verbosity; + set => verbosity = value; } + + public string? SdkRoot { get; set; } + public string? DeveloperDirectory { get; set; } + + string? framework_dir; + public string FrameworkCurrentDirectory { + get { + if (framework_dir is null) + throw new InvalidOperationException ($"Teh current framework directory hasn't been set."); + return framework_dir; + } + set { + framework_dir = value; + } + } + + /// + /// This returns the /Applications/Xcode*.app/Contents/Developer/Platforms directory + /// + public string PlatformsDirectory { + get { + if (DeveloperDirectory is null) + throw new InvalidOperationException ("DeveloperDirectory is not set"); + return Path.Combine (DeveloperDirectory, "Platforms"); + } + } + + Version? xcode_version; + public Version XcodeVersion { + get { + if (xcode_version is null) + throw ErrorHelper.CreateError (99, Errors.MX0099, "The Xcode version has not been configured. Pass --xcode-version or configure an Xcode installation."); + return xcode_version; + } + set { + xcode_version = value; + } + } + + public string? XcodeProductVersion { get; set; } } } diff --git a/tools/common/Assembly.cs b/tools/common/Assembly.cs index 1ec7535fa828..6ad8d9141958 100644 --- a/tools/common/Assembly.cs +++ b/tools/common/Assembly.cs @@ -69,7 +69,7 @@ public string FullPath { #if !LEGACY_TOOLS is_framework_assembly = App.Configuration.FrameworkAssemblies.Contains (GetIdentity (full_path)); #else - var real_full_path = Application.GetRealPath (full_path); + var real_full_path = Application.GetRealPath (App, full_path); is_framework_assembly = real_full_path.StartsWith (Path.GetDirectoryName (Path.GetDirectoryName (App.Resolver.FrameworkDirectory))!, StringComparison.Ordinal); #endif } @@ -132,7 +132,7 @@ public void LoadSymbols () } } catch { // do not let stale file crash us - Driver.Log (3, "Invalid debugging symbols for {0} ignored", FullPath); + App.Log (3, "Invalid debugging symbols for {0} ignored", FullPath); } } @@ -155,12 +155,12 @@ public void ExtractNativeLinkInfo () string resourceBundlePath = Path.ChangeExtension (FullPath, ".resources"); if (Directory.Exists (resourceBundlePath)) { - Driver.Log (3, $"Found a binding resource package for the assembly '{FullPath}' in {resourceBundlePath}, so not looking for any libraries embedded in the assembly."); + App.Log (3, $"Found a binding resource package for the assembly '{FullPath}' in {resourceBundlePath}, so not looking for any libraries embedded in the assembly."); return; } var zipPath = resourceBundlePath + ".zip"; if (File.Exists (zipPath)) { - Driver.Log (3, $"Found a binding resource package for the assembly '{FullPath}' in {zipPath}, so not looking for any libraries embedded in the assembly."); + App.Log (3, $"Found a binding resource package for the assembly '{FullPath}' in {zipPath}, so not looking for any libraries embedded in the assembly."); return; } @@ -242,7 +242,7 @@ void ProcessNativeReferenceOptions (NativeReferenceMetadata metadata) { // We can't add -dead_strip if there are any LinkWith attributes where smart linking is disabled. if (!metadata.SmartLink) { - Driver.Log (3, $"The library '{metadata.LibraryName}', shipped with the assembly '{FullPath}', sets SmartLink=false, which will disable passing -dead_strip to the native linker (and make the app bigger)."); + App.Log (3, $"The library '{metadata.LibraryName}', shipped with the assembly '{FullPath}', sets SmartLink=false, which will disable passing -dead_strip to the native linker (and make the app bigger)."); App.DeadStrip = false; } @@ -290,23 +290,23 @@ bool TryExtractNativeLibrary (AssemblyDefinition assembly, NativeReferenceMetada library = null; return false; } - var path = Path.Combine (App.Cache.Location, metadata.LibraryName); + var path = Path.Combine (App.Cache.GetLocation (App), metadata.LibraryName); library = null; - if (!Application.IsUptodate (FullPath, path)) { + if (!Application.IsUptodate (App, FullPath, path)) { if (!Application.ExtractResource (assembly.MainModule, metadata.LibraryName, path, false)) { - ErrorHelper.Warning (1308, Errors.MX1308 /* Could not extract the native library '{0}' from the assembly '{1}', because it doesn't contain the resource '{2}'. */, metadata.LibraryName, FullPath, metadata.LibraryName); + ErrorHelper.Warning (App, 1308, Errors.MX1308 /* Could not extract the native library '{0}' from the assembly '{1}', because it doesn't contain the resource '{2}'. */, metadata.LibraryName, FullPath, metadata.LibraryName); return false; } - Driver.Log (3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", metadata.LibraryName, FullPath, path); + App.Log (3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", metadata.LibraryName, FullPath, path); LogNativeReference (metadata); } else { - Driver.Log (3, "Target '{0}' is up-to-date.", path); + App.Log (3, "Target '{0}' is up-to-date.", path); } if (!File.Exists (path)) - ErrorHelper.Warning (1302, Errors.MT1302, metadata.LibraryName, path); + ErrorHelper.Warning (App, 1302, Errors.MT1302, metadata.LibraryName, path); library = path; return true; @@ -318,39 +318,39 @@ bool TryExtractFramework (AssemblyDefinition assembly, NativeReferenceMetadata m framework = null; return false; } - var path = Path.Combine (App.Cache.Location, metadata.LibraryName); + var path = Path.Combine (App.Cache.GetLocation (App), metadata.LibraryName); var zipPath = path + ".zip"; framework = null; - if (!Application.IsUptodate (FullPath, zipPath)) { + if (!Application.IsUptodate (App, FullPath, zipPath)) { if (!Application.ExtractResource (assembly.MainModule, metadata.LibraryName, zipPath, false)) { - ErrorHelper.Warning (1307, Errors.MX1307 /* Could not extract the native framework '{0}' from the assembly '{1}', because it doesn't contain the resource '{2}'. */, metadata.LibraryName, FullPath, metadata.LibraryName); + ErrorHelper.Warning (App, 1307, Errors.MX1307 /* Could not extract the native framework '{0}' from the assembly '{1}', because it doesn't contain the resource '{2}'. */, metadata.LibraryName, FullPath, metadata.LibraryName); return false; } - Driver.Log (3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", metadata.LibraryName, FullPath, zipPath); + App.Log (3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", metadata.LibraryName, FullPath, zipPath); LogNativeReference (metadata); } else { - Driver.Log (3, "Target '{0}' is up-to-date.", path); + App.Log (3, "Target '{0}' is up-to-date.", path); } if (!File.Exists (zipPath)) { - ErrorHelper.Warning (1302, Errors.MT1302, metadata.LibraryName, FullPath); + ErrorHelper.Warning (App, 1302, Errors.MT1302, metadata.LibraryName, FullPath); if (assembly.MainModule.HasResources) { - Driver.Log (3, $"The assembly {FullPath} has {assembly.MainModule.Resources.Count} resources:"); + App.Log (3, $"The assembly {FullPath} has {assembly.MainModule.Resources.Count} resources:"); foreach (var res in assembly.MainModule.Resources) { - Driver.Log (3, $" {res.ResourceType}: {res.Name}"); + App.Log (3, $" {res.ResourceType}: {res.Name}"); } } else { - Driver.Log (3, $"The assembly {FullPath} does not have any resources."); + App.Log (3, $"The assembly {FullPath} does not have any resources."); } } else { if (!Directory.Exists (path)) Directory.CreateDirectory (path); - if (Driver.RunCommand ("/usr/bin/unzip", "-u", "-o", "-d", path, zipPath) != 0) + if (Driver.RunCommand (App, "/usr/bin/unzip", "-u", "-o", "-d", path, zipPath) != 0) throw ErrorHelper.CreateError (1303, Errors.MT1303, metadata.LibraryName, zipPath); } @@ -358,19 +358,19 @@ bool TryExtractFramework (AssemblyDefinition assembly, NativeReferenceMetadata m return true; } - static void LogNativeReference (NativeReferenceMetadata metadata) + void LogNativeReference (NativeReferenceMetadata metadata) { - Driver.Log (3, " LibraryName: {0}", metadata.LibraryName); - Driver.Log (3, " From: {0}", metadata.Attribute is not null ? "LinkWith" : "Binding Manifest"); - Driver.Log (3, " ForceLoad: {0}", metadata.ForceLoad); - Driver.Log (3, " Frameworks: {0}", metadata.Frameworks); - Driver.Log (3, " IsCxx: {0}", metadata.IsCxx); - Driver.Log (3, " LinkWithSwiftSystemLibraries: {0}", metadata.LinkWithSwiftSystemLibraries); - Driver.Log (3, " LinkerFlags: {0}", metadata.LinkerFlags); - Driver.Log (3, " LinkTarget: {0}", metadata.LinkTarget); - Driver.Log (3, " NeedsGccExceptionHandling: {0}", metadata.NeedsGccExceptionHandling); - Driver.Log (3, " SmartLink: {0}", metadata.SmartLink); - Driver.Log (3, " WeakFrameworks: {0}", metadata.WeakFrameworks); + App.Log (3, " LibraryName: {0}", metadata.LibraryName); + App.Log (3, " From: {0}", metadata.Attribute is not null ? "LinkWith" : "Binding Manifest"); + App.Log (3, " ForceLoad: {0}", metadata.ForceLoad); + App.Log (3, " Frameworks: {0}", metadata.Frameworks); + App.Log (3, " IsCxx: {0}", metadata.IsCxx); + App.Log (3, " LinkWithSwiftSystemLibraries: {0}", metadata.LinkWithSwiftSystemLibraries); + App.Log (3, " LinkerFlags: {0}", metadata.LinkerFlags); + App.Log (3, " LinkTarget: {0}", metadata.LinkTarget); + App.Log (3, " NeedsGccExceptionHandling: {0}", metadata.NeedsGccExceptionHandling); + App.Log (3, " SmartLink: {0}", metadata.SmartLink); + App.Log (3, " WeakFrameworks: {0}", metadata.WeakFrameworks); } public static LinkWithAttribute GetLinkWithAttribute (CustomAttribute attr) @@ -438,12 +438,12 @@ void AddFramework (string file) { if (Driver.GetFrameworks (App).TryGetValue (file, out var framework)) { if (framework.IsFrameworkUnavailable (App)) { - ErrorHelper.Warning (182, Errors.MX0182 /* Not linking with the framework {0} (referenced by a module reference in {1}) because it's not available on the current platform ({2}). */, framework.Name, FileName, App.PlatformName); + ErrorHelper.Warning (App, 182, Errors.MX0182 /* Not linking with the framework {0} (referenced by a module reference in {1}) because it's not available on the current platform ({2}). */, framework.Name, FileName, App.PlatformName); return; } if (framework.Version > App.SdkVersion) { - ErrorHelper.Warning (135, Errors.MX0135, file, FileName, App.PlatformName, framework.Version, App.SdkVersion); + ErrorHelper.Warning (App, 135, Errors.MX0135, file, FileName, App.PlatformName, framework.Version, App.SdkVersion); return; } } @@ -451,10 +451,10 @@ void AddFramework (string file) var strong = (framework is null) || (App.DeploymentTarget >= (App.IsSimulatorBuild ? framework.VersionAvailableInSimulator ?? framework.Version : framework.Version)); if (strong) { if (Frameworks.Add (file)) - Driver.Log (3, "Linking with the framework {0} because it's referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with the framework {0} because it's referenced by a module reference in {1}", file, FileName); } else { if (WeakFrameworks.Add (file)) - Driver.Log (3, "Linking (weakly) with the framework {0} because it's referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking (weakly) with the framework {0} because it's referenced by a module reference in {1}", file, FileName); } } @@ -491,7 +491,7 @@ public void ComputeLinkerFlags () string file = Path.GetFileNameWithoutExtension (name); if (App.IsFrameworkUnavailable (file)) { - Driver.Log (3, "Not linking with {0} (referenced by a module reference in {1}) because it's not available in the current SDK.", file, FileName); + App.Log (3, "Not linking with {0} (referenced by a module reference in {1}) because it's not available in the current SDK.", file, FileName); continue; } @@ -510,12 +510,12 @@ public void ComputeLinkerFlags () break; case "sqlite3": LinkerFlags.Add ("-lsqlite3"); - Driver.Log (3, "Linking with {0} because it's referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with {0} because it's referenced by a module reference in {1}", file, FileName); break; case "libsqlite3": // remove lib prefix LinkerFlags.Add ("-l" + file.Substring (3)); - Driver.Log (3, "Linking with {0} because it's referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with {0} because it's referenced by a module reference in {1}", file, FileName); break; case "libcompression": LinkerFlags.Add (GetCompressionLinkingFlag ()); @@ -524,22 +524,22 @@ public void ComputeLinkerFlags () case "libGLESv2": // special case for OpenGLES.framework if (Frameworks.Add ("OpenGLES")) - Driver.Log (3, "Linking with the framework OpenGLES because {0} is referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with the framework OpenGLES because {0} is referenced by a module reference in {1}", file, FileName); break; case "vImage": case "vecLib": // sub-frameworks if (Frameworks.Add ("Accelerate")) - Driver.Log (3, "Linking with the framework Accelerate because {0} is referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with the framework Accelerate because {0} is referenced by a module reference in {1}", file, FileName); break; case "openal32": if (Frameworks.Add ("OpenAL")) - Driver.Log (3, "Linking with the framework OpenAL because {0} is referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with the framework OpenAL because {0} is referenced by a module reference in {1}", file, FileName); break; #if !LEGACY_TOOLS case "Carbon": if (App.Platform != ApplePlatform.MacOSX) { - Driver.Log (3, $"Not linking with the framework {file} (referenced by a module reference in {FileName}) because it doesn't exist on the target platform."); + App.Log (3, $"Not linking with the framework {file} (referenced by a module reference in {FileName}) because it doesn't exist on the target platform."); break; } break; @@ -553,13 +553,13 @@ public void ComputeLinkerFlags () // CoreServices has multiple sub-frameworks that can be used by customer code if (path.StartsWith ("/System/Library/Frameworks/CoreServices.framework/", StringComparison.Ordinal)) { if (Frameworks.Add ("CoreServices")) - Driver.Log (3, "Linking with the framework CoreServices because {0} is referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with the framework CoreServices because {0} is referenced by a module reference in {1}", file, FileName); break; } // ApplicationServices has multiple sub-frameworks that can be used by customer code if (path.StartsWith ("/System/Library/Frameworks/ApplicationServices.framework/", StringComparison.Ordinal)) { if (Frameworks.Add ("ApplicationServices")) - Driver.Log (3, "Linking with the framework ApplicationServices because {0} is referenced by a module reference in {1}", file, FileName); + App.Log (3, "Linking with the framework ApplicationServices because {0} is referenced by a module reference in {1}", file, FileName); break; } } @@ -572,7 +572,7 @@ public void ComputeLinkerFlags () if (UnresolvedModuleReferences is null) UnresolvedModuleReferences = new HashSet (); UnresolvedModuleReferences.Add (mr); - Driver.Log (3, "Could not resolve the module reference {0} in {1}", file, FileName); + App.Log (3, "Could not resolve the module reference {0} in {1}", file, FileName); } break; } @@ -698,14 +698,14 @@ public void Update (Application app, IEnumerable assemblies) // new assembly var asm = new Assembly (app, assembly); Add (asm); - Driver.Log (1, "The linker added the assembly '{0}' to '{1}' to satisfy a reference.", asm.Identity, app.Name); + app.Log (1, "The linker added the assembly '{0}' to '{1}' to satisfy a reference.", asm.Identity, app.Name); } else { this [identity].AssemblyDefinition = assembly; } } foreach (var removed in current) { - Driver.Log (1, "The linker removed the assembly '{0}' from '{1}' since there is no more reference to it.", this [removed].Identity, app.Name); + app.Log (1, "The linker removed the assembly '{0}' from '{1}' since there is no more reference to it.", this [removed].Identity, app.Name); Remove (removed); } } diff --git a/tools/common/CoreResolver.cs b/tools/common/CoreResolver.cs index 458da5cf086c..b35f575c9fc1 100644 --- a/tools/common/CoreResolver.cs +++ b/tools/common/CoreResolver.cs @@ -60,7 +60,7 @@ protected ReaderParameters CreateDefaultReaderParameters (string path) return parameters; } - public virtual AssemblyDefinition? Load (string fileName) + public virtual AssemblyDefinition? Load (IToolLog log, string fileName) { if (!File.Exists (fileName)) return null; @@ -70,7 +70,7 @@ protected ReaderParameters CreateDefaultReaderParameters (string path) return assembly; try { - fileName = Application.GetRealPath (fileName); + fileName = Application.GetRealPath (log, fileName); // Check the architecture-specific directory if (Path.GetDirectoryName (fileName) == FrameworkDirectory && !string.IsNullOrEmpty (ArchDirectory)) { @@ -89,14 +89,14 @@ protected ReaderParameters CreateDefaultReaderParameters (string path) // Warn about this. var pdb = Path.ChangeExtension (fileName, "pdb"); if (File.Exists (pdb)) - ErrorHelper.Show (ErrorHelper.CreateWarning (178, Errors.MX0178, fileName)); + ErrorHelper.Show (log, ErrorHelper.CreateWarning (178, Errors.MX0178, fileName)); } // Don't load native .pdb symbols, because we won't be able to write them back out again (so just drop them) if (assembly.MainModule?.SymbolReader?.GetType ()?.FullName == "Mono.Cecil.Pdb.NativePdbReader") { parameters.ReadSymbols = false; parameters.SymbolReaderProvider = null; assembly = ModuleDefinition.ReadModule (fileName, parameters).Assembly; - ErrorHelper.Show (ErrorHelper.CreateWarning (178, Errors.MX0178, fileName)); + ErrorHelper.Show (log, ErrorHelper.CreateWarning (178, Errors.MX0178, fileName)); } } catch (IOException ex) when (ex.GetType ().FullName == "Microsoft.Cci.Pdb.PdbException") { // Microsoft.Cci.Pdb.PdbException is not public, so we have to check the runtime type :/ symbolLoadFailure = true; @@ -108,7 +108,7 @@ protected ReaderParameters CreateDefaultReaderParameters (string path) parameters.SymbolReaderProvider = null; assembly = ModuleDefinition.ReadModule (fileName, parameters).Assembly; // only report the warning (on symbols) if we can actually load the assembly itself (otherwise it's more confusing than helpful) - ErrorHelper.Show (ErrorHelper.CreateWarning (129, Errors.MX0129, fileName)); + ErrorHelper.Show (log, ErrorHelper.CreateWarning (129, Errors.MX0129, fileName)); } } catch (Exception e) { throw new ProductException (9, true, e, Errors.MX0009, fileName); @@ -126,23 +126,23 @@ public AssemblyDefinition CacheAssembly (AssemblyDefinition assembly) return assembly; } - protected AssemblyDefinition? SearchDirectory (string name, string directory, string extension = ".dll") + protected AssemblyDefinition? SearchDirectory (IToolLog log, string name, string directory, string extension = ".dll") { if (!Directory.Exists (directory)) return null; - var file = DirectoryGetFile (directory, name + extension); + var file = DirectoryGetFile (log, directory, name + extension); if (file.Length > 0) - return Load (file); + return Load (log, file); return null; } - static string DirectoryGetFile (string directory, string file) + static string DirectoryGetFile (IToolLog log, string directory, string file) { var files = Directory.GetFiles (directory, file); if (files is not null && files.Length > 0) { if (files.Length > 1) { - ErrorHelper.Warning (133, Errors.MX0133, file, Environment.NewLine, string.Join ("\n", files)); + ErrorHelper.Warning (log, 133, Errors.MX0133, file, Environment.NewLine, string.Join ("\n", files)); } return files [0]; } diff --git a/tools/common/DerivedLinkContext.cs b/tools/common/DerivedLinkContext.cs index 743b1b768461..0f639be2e7b5 100644 --- a/tools/common/DerivedLinkContext.cs +++ b/tools/common/DerivedLinkContext.cs @@ -41,6 +41,9 @@ public class DerivedLinkContext : LinkContext { // true/false = corresponding constant value Dictionary? isdirectbinding_value; + // A map from Objective-C class name to C# type + Dictionary? objectiveCTypeInfo; + // Store interfaces the linker has linked away so that the static registrar can access them. public Dictionary> ProtocolImplementations { get; private set; } = new Dictionary> (); // Store types the linker has linked away so that the static registrar can access them. @@ -73,6 +76,7 @@ public AssemblyDefinition Corlib { return corlib; } } + public HashSet? CachedIsNSObject { get { return cached_isnsobject; } set { cached_isnsobject = value; } @@ -83,6 +87,11 @@ public HashSet? CachedIsNSObject { set { isdirectbinding_value = value; } } + public Dictionary? ObjectiveCTypeInfo { + get { return objectiveCTypeInfo; } + set { objectiveCTypeInfo = value; } + } + public IList DataContract { get { return srs_data_contract; @@ -237,8 +246,11 @@ public void AddLinkedAwayType (TypeDefinition td) } #if !LEGACY_TOOLS - public bool HasAvailabilityAttributesShowingUnavailableInSimulator (ICustomAttributeProvider provider, MethodDefinition? methodForErrorReporting = null) + public bool HasAvailabilityAttributesShowingUnavailableInSimulator (ICustomAttributeProvider? provider, MethodDefinition? methodForErrorReporting = null) { + if (provider is null) + return false; + if (!App.IsSimulatorBuild) { LinkerConfiguration.Report (LinkerConfiguration.Context, ErrorHelper.CreateError (99, "HasAvailabilityAttributesShowingUnavailableInSimulator should not be called when not building for the simulator. Please file an issue at https://github.com/dotnet/macios/issues.")); return false; diff --git a/tools/common/Driver.cs b/tools/common/Driver.cs index 50bd8dbd3cce..fe912e00e4a8 100644 --- a/tools/common/Driver.cs +++ b/tools/common/Driver.cs @@ -7,9 +7,8 @@ */ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.IO; +using System.Globalization; using System.Linq; using System.Text; @@ -20,19 +19,15 @@ namespace Xamarin.Bundler { public partial class Driver { - public static bool Force { get; set; } - #if LEGACY_TOOLS public static int Main (string [] args) { try { Console.OutputEncoding = new UTF8Encoding (false, false); - SetCurrentLanguage (); + SetCurrentLanguage (ConsoleLog.Instance); return Main2 (args); } catch (Exception e) { - ErrorHelper.Show (e); - } finally { - Watch ("Total time", 0); + ErrorHelper.Show (ConsoleLog.Instance, e); } return 0; } @@ -40,10 +35,10 @@ public static int Main (string [] args) // Returns true if the process should exit (with a 0 exit code; failures are propagated using exceptions) static void ParseOptions (Application app, Mono.Options.OptionSet options, string [] args) { - options.Add ("v|verbose", "Specify how verbose the output should be. This can be passed multiple times to increase the verbosity.", v => Verbosity++); - options.Add ("q|quiet", "Specify how quiet the output should be. This can be passed multiple times to increase the silence.", v => Verbosity--); + options.Add ("v|verbose", "Specify how verbose the output should be. This can be passed multiple times to increase the verbosity.", v => app.Verbosity++); + options.Add ("q|quiet", "Specify how quiet the output should be. This can be passed multiple times to increase the silence.", v => app.Verbosity--); options.Add ("reference=", "Add an assembly to be processed.", v => app.References.Add (v)); - options.Add ("sdkroot=", "Specify the location of Apple SDKs, default to 'xcode-select' value.", v => sdk_root = v); + options.Add ("sdkroot=", "Specify the location of Apple SDKs, default to 'xcode-select' value.", v => app.SdkRoot = v); options.Add ("sdk=", "Specifies the SDK version to compile against (version, for example \"10.9\"). For Mac Catalyst, this is the macOS version of the SDK.", v => { try { app.SdkVersion = StringUtils.ParseVersion (v); @@ -53,7 +48,7 @@ static void ParseOptions (Application app, Mono.Options.OptionSet options, strin } }); options.Add ("target-framework=", "Specify target framework to use. Currently supported: '" + string.Join ("', '", TargetFramework.ValidFrameworks.Select ((v) => v.ToString ())) + "'.", v => { - targetFramework = TargetFramework.Parse (v); + app.TargetFramework = TargetFramework.Parse (v); }); options.Add ("abi=", "Comma-separated list of ABIs to target.", v => app.ParseAbi (v)); options.Add ("runregistrar:", "Runs the registrar on the input assembly and outputs a corresponding native library.", @@ -69,6 +64,11 @@ static void ParseOptions (Application app, Mono.Options.OptionSet options, strin options.Add ("rid=", "The runtime identifier we're building for", v => { app.RuntimeIdentifier = v; }); + options.Add ("xcode-version=", "The Xcode version we're building with", v => { + if (!Version.TryParse (v, out var xcodeVersion)) + throw ErrorHelper.CreateError (26, Errors.MX0026, $"xcode-version:{v}", "Expected a valid version string."); + app.XcodeVersion = xcodeVersion; + }); try { app.RootAssemblies.AddRange (options.Parse (args)); @@ -80,17 +80,7 @@ static void ParseOptions (Application app, Mono.Options.OptionSet options, strin } #endif // !LEGACY_TOOLS - public static int Verbosity { - get { return ErrorHelper.Verbosity; } - set { ErrorHelper.Verbosity = value; } - } - - static Driver () - { - Verbosity = GetDefaultVerbosity (); - } - - static int GetDefaultVerbosity () + public static int GetDefaultVerbosity () { var v = 0; var fn = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), $".{NAME}-verbosity"); @@ -102,49 +92,13 @@ static int GetDefaultVerbosity () return v; } - public static void Log (string value) - { - Log (0, value); - } - - public static void Log (string format, params object? [] args) - { - Log (0, format, args); - } - - public static void Log (int min_verbosity, string value) - { - if (min_verbosity > Verbosity) - return; - - Console.WriteLine (value); - } - - public static void Log (int min_verbosity, string format, params object? [] args) - { - if (min_verbosity > Verbosity) - return; - - if (args.Length > 0) - Console.WriteLine (format, args); - else - Console.WriteLine (format); - } - - static TargetFramework targetFramework; - - public static TargetFramework TargetFramework { - get { return targetFramework; } - set { targetFramework = value; } - } - static void FileMove (string source, string target) { File.Delete (target); File.Move (source, target); } - static void MoveIfDifferent (string path, string tmp, bool use_stamp = false) + static void MoveIfDifferent (IToolLog log, string path, string tmp, bool use_stamp = false) { // Don't read the entire file into memory, it can be quite big in certain cases. @@ -153,10 +107,10 @@ static void MoveIfDifferent (string path, string tmp, bool use_stamp = false) using (var fs1 = new FileStream (path, FileMode.Open, FileAccess.Read)) { using (var fs2 = new FileStream (tmp, FileMode.Open, FileAccess.Read)) { if (fs1.Length != fs2.Length) { - Log (3, "New file '{0}' has different length, writing new file.", path); + log.Log (3, "New file '{0}' has different length, writing new file.", path); move = true; } else { - move = !Cache.CompareStreams (fs1, fs2); + move = !Cache.CompareStreams (log, fs1, fs2); } } } @@ -164,13 +118,13 @@ static void MoveIfDifferent (string path, string tmp, bool use_stamp = false) if (move) { FileMove (tmp, path); } else { - Log (3, "Target {0} is up-to-date.", path); + log.Log (3, "Target {0} is up-to-date.", path); if (use_stamp) - Driver.Touch (path + ".stamp"); + Driver.Touch (log, path + ".stamp"); } } - public static void WriteIfDifferent (string path, string contents, bool use_stamp = false) + public static void WriteIfDifferent (IToolLog log, string path, string contents, bool use_stamp = false) { var tmp = path + ".tmp"; @@ -180,36 +134,36 @@ public static void WriteIfDifferent (string path, string contents, bool use_stam if (!string.IsNullOrEmpty (dir)) Directory.CreateDirectory (dir); File.WriteAllText (path, contents); - Log (3, "File '{0}' does not exist, creating it.", path); + log.Log (3, "File '{0}' does not exist, creating it.", path); return; } File.WriteAllText (tmp, contents); - MoveIfDifferent (path, tmp, use_stamp); + MoveIfDifferent (log, path, tmp, use_stamp); } catch (Exception e) { File.WriteAllText (path, contents); - ErrorHelper.Warning (1014, e, Errors.MT1014, path, e.Message); + ErrorHelper.Warning (log, 1014, e, Errors.MT1014, path, e.Message); } finally { File.Delete (tmp); } } - public static void WriteIfDifferent (string path, byte [] contents, bool use_stamp = false) + public static void WriteIfDifferent (IToolLog log, string path, byte [] contents, bool use_stamp = false) { var tmp = path + ".tmp"; try { if (!File.Exists (path)) { File.WriteAllBytes (path, contents); - Log (3, "File '{0}' does not exist, creating it.", path); + log.Log (3, "File '{0}' does not exist, creating it.", path); return; } File.WriteAllBytes (tmp, contents); - MoveIfDifferent (path, tmp, use_stamp); + MoveIfDifferent (log, path, tmp, use_stamp); } catch (Exception e) { File.WriteAllBytes (path, contents); - ErrorHelper.Warning (1014, e, Errors.MT1014, path, e.Message); + ErrorHelper.Warning (log, 1014, e, Errors.MT1014, path, e.Message); } finally { File.Delete (tmp); } @@ -220,21 +174,8 @@ internal static string GetFullPath () return System.Reflection.Assembly.GetExecutingAssembly ().Location; } - static string? xcode_product_version; - public static string? XcodeProductVersion { - get { - return xcode_product_version; - } - } - - static Version? xcode_version; - public static Version XcodeVersion { - get { - return xcode_version!; - } - } - - static void SetCurrentLanguage () +#if LEGACY_TOOLS + static void SetCurrentLanguage (IToolLog log) { // There's no way to change the current culture from the command-line // without changing the system settings, so honor LANG if set. @@ -259,14 +200,15 @@ static void SetCurrentLanguage () var culture = CultureInfo.GetCultureInfo (lang); if (culture is not null) { CultureInfo.DefaultThreadCurrentCulture = culture; - Log (2, $"The current language was set to '{culture.DisplayName}' according to the LANG environment variable (LANG={lang_variable})."); + log.Log (2, $"The current language was set to '{culture.DisplayName}' according to the LANG environment variable (LANG={lang_variable})."); } } catch (Exception e) { - ErrorHelper.Warning (124, e, Errors.MT0124, lang, lang_variable, e.Message); + ErrorHelper.Warning (log, 124, e, Errors.MT0124, lang, lang_variable, e.Message); } } +#endif - public static void Touch (IEnumerable filenames, DateTime? timestamp = null) + public static void Touch (IToolLog log, IEnumerable filenames, DateTime? timestamp = null) { if (timestamp is null) timestamp = DateTime.Now; @@ -280,40 +222,17 @@ public static void Touch (IEnumerable filenames, DateTime? timestamp = n } fi.LastWriteTime = timestamp.Value; } catch (Exception e) { - ErrorHelper.Warning (128, Errors.MT0128, filename, e.Message); + ErrorHelper.Warning (log, 128, Errors.MT0128, filename, e.Message); } } } - public static void Touch (params string [] filenames) + public static void Touch (IToolLog log, params string [] filenames) { - Touch ((IEnumerable) filenames); + Touch (log, (IEnumerable) filenames); } - static int watch_level; - static Stopwatch? watch; - - public static int WatchLevel { - get { return watch_level; } - set { - watch_level = value; - if ((watch_level > 0) && (watch is null)) { - watch = new Stopwatch (); - watch.Start (); - } - } - } - - public static void Watch (string msg, int level) - { - if ((watch is null) || (level > WatchLevel)) - return; - for (int i = 0; i < level; i++) - Console.Write ("!"); - Console.WriteLine ("Timestamp {0}: {1} ms", msg, watch.ElapsedMilliseconds); - } - - internal static PDictionary? FromPList (string name) + internal static PDictionary FromPList (string name) { if (!File.Exists (name)) throw ErrorHelper.CreateError (24, Errors.MT0024, name); @@ -322,58 +241,16 @@ public static void Watch (string msg, int level) const string XcodeDefault = "/Applications/Xcode.app"; - static string? FindSystemXcode () + static string? FindSystemXcode (IToolLog log) { var output = new StringBuilder (); - if (Driver.RunCommand ("xcode-select", new [] { "-p" }, output: output) != 0) { - ErrorHelper.Warning (59, Errors.MX0059, output.ToString ()); + if (Driver.RunCommand (log, "xcode-select", new [] { "-p" }, output: output) != 0) { + ErrorHelper.Warning (log, 59, Errors.MX0059, output.ToString ()); return null; } return output.ToString ().Trim (); } - static string? sdk_root; - static string? developer_directory = null; - - public static string? SdkRoot { - get => sdk_root; - set => sdk_root = value; - } - - public static string? DeveloperDirectory { - get { - return developer_directory; - } - } - - // This returns the /Applications/Xcode*.app/Contents/Developer/Platforms directory - public static string PlatformsDirectory { - get { - if (DeveloperDirectory is null) - throw new InvalidOperationException ("DeveloperDirectory is not set"); - return Path.Combine (DeveloperDirectory, "Platforms"); - } - } - - // This returns the /Applications/Xcode*.app/Contents/Developer/Platforms/*.platform directory - public static string GetPlatformDirectory (Application app) - { - return Path.Combine (PlatformsDirectory, GetPlatform (app) + ".platform"); - } - - static string? framework_dir; - public static string GetFrameworkCurrentDirectory (Application app) - { - if (framework_dir is null) - throw new InvalidOperationException ($"Teh current framework directory hasn't been set."); - return framework_dir; - } - - public static void SetFrameworkCurrentDirectory (string value) - { - framework_dir = value; - } - // This returns the platform to use in /Applications/Xcode*.app/Contents/Developer/Platforms/*.platform public static string GetPlatform (Application app) { @@ -395,7 +272,7 @@ public static string GetFrameworkDirectory (Application app) { var platform = GetPlatform (app); var sdkVersion = app.NativeSdkVersion?.ToString () ?? ""; - return Path.Combine (PlatformsDirectory, platform + ".platform", "Developer", "SDKs", platform + sdkVersion + ".sdk"); + return Path.Combine (app.PlatformsDirectory, platform + ".platform", "Developer", "SDKs", platform + sdkVersion + ".sdk"); } public static string GetProductAssembly (Application app) @@ -416,32 +293,34 @@ public static string GetProductAssembly (Application app) public static void ValidateXcode (Application app, bool accept_any_xcode_version, bool warn_if_not_found) { + var sdk_root = app.SdkRoot; + if (sdk_root is null) { - sdk_root = FindSystemXcode (); + sdk_root = FindSystemXcode (app); if (sdk_root is null) { // FindSystemXcode showed a warning in this case. In particular do not use 'string.IsNullOrEmpty' here, // because FindSystemXcode may return an empty string (with no warning printed) if the xcode-select command // succeeds, but returns nothing. sdk_root = null; } else if (!Directory.Exists (sdk_root)) { - ErrorHelper.Warning (60, Errors.MX0060, sdk_root); + ErrorHelper.Warning (app, 60, Errors.MX0060, sdk_root); sdk_root = null; } else { if (!accept_any_xcode_version) - ErrorHelper.Warning (61, Errors.MT0061, sdk_root); + ErrorHelper.Warning (app, 61, Errors.MT0061, sdk_root); } if (sdk_root is null) { sdk_root = XcodeDefault; if (!Directory.Exists (sdk_root)) { if (warn_if_not_found) { // mmp: and now we give up, but don't throw like mtouch, because we don't want to change behavior (this sometimes worked it appears) - ErrorHelper.Warning (56, Errors.MX0056); + ErrorHelper.Warning (app, 56, Errors.MX0056); return; // Can't validate the version below if we can't even find Xcode... } throw ErrorHelper.CreateError (56, Errors.MX0056); } - ErrorHelper.Warning (62, Errors.MT0062, sdk_root); + ErrorHelper.Warning (app, 62, Errors.MT0062, sdk_root); } } else if (!Directory.Exists (sdk_root)) { throw ErrorHelper.CreateError (55, Errors.MT0055, sdk_root); @@ -450,28 +329,28 @@ public static void ValidateXcode (Application app, bool accept_any_xcode_version // Check what kind of path we got if (File.Exists (Path.Combine (sdk_root, "Contents", "MacOS", "Xcode"))) { // path to the Xcode.app - developer_directory = Path.Combine (sdk_root, "Contents", "Developer"); + app.DeveloperDirectory = Path.Combine (sdk_root, "Contents", "Developer"); } else if (File.Exists (Path.Combine (sdk_root, "..", "MacOS", "Xcode"))) { // path to Contents/Developer - developer_directory = Path.GetFullPath (Path.Combine (sdk_root, "..", "..", "Contents", "Developer")); + app.DeveloperDirectory = Path.GetFullPath (Path.Combine (sdk_root, "..", "..", "Contents", "Developer")); } else { throw ErrorHelper.CreateError (57, Errors.MT0057, sdk_root); } - var plist_path = Path.Combine (Path.GetDirectoryName (DeveloperDirectory)!, "version.plist"); + var plist_path = Path.Combine (Path.GetDirectoryName (app.DeveloperDirectory)!, "version.plist"); if (File.Exists (plist_path)) { var plist = FromPList (plist_path); - var version = plist?.GetString ("CFBundleShortVersionString"); + var version = plist.GetString ("CFBundleShortVersionString"); if (version is null) - throw ErrorHelper.CreateError (58, Errors.MT0058, Path.GetDirectoryName (Path.GetDirectoryName (DeveloperDirectory)), plist_path); - xcode_version = new Version (version); - xcode_product_version = plist!.GetString ("ProductBuildVersion"); + throw ErrorHelper.CreateError (58, Errors.MT0058, Path.GetDirectoryName (Path.GetDirectoryName (app.DeveloperDirectory)), plist_path); + app.XcodeVersion = new Version (version); + app.XcodeProductVersion = plist.GetString ("ProductBuildVersion"); } else { - throw ErrorHelper.CreateError (58, Errors.MT0058, Path.GetDirectoryName (Path.GetDirectoryName (DeveloperDirectory)), plist_path); + throw ErrorHelper.CreateError (58, Errors.MT0058, Path.GetDirectoryName (Path.GetDirectoryName (app.DeveloperDirectory)), plist_path); } - Driver.Log (1, "Using Xcode {0} ({2}) found in {1}", XcodeVersion, sdk_root, XcodeProductVersion); + app.Log (1, "Using Xcode {0} ({2}) found in {1}", app.XcodeVersion, sdk_root, app.XcodeProductVersion); } internal static bool TryParseBool (string value, out bool result) @@ -507,210 +386,6 @@ internal static bool ParseBool (string value, string name, bool show_error = tru return result; } -#if !LEGACY_TOOLS - static readonly Dictionary tools = new Dictionary (); - static string FindTool (Application app, string tool) - { - lock (tools) { - if (tools.TryGetValue (tool, out var path) && path is not null) - return path; - } - - var foundPath = LocateTool (app, tool); - static string? LocateTool (Application app, string tool) - { - if (XcrunFind (app, tool, out var path)) - return path; - - if (DeveloperDirectory is null) - return null; - - // either /Developer (Xcode 4.2 and earlier), /Applications/Xcode.app/Contents/Developer (Xcode 4.3) or user override - path = Path.Combine (DeveloperDirectory, "usr", "bin", tool); - if (File.Exists (path)) - return path; - - // Xcode 4.3 (without command-line tools) also has a copy of 'strip' - path = Path.Combine (DeveloperDirectory, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", tool); - if (File.Exists (path)) - return path; - - // Xcode "Command-Line Tools" install a copy in /usr/bin (and it can be there afterward) - path = Path.Combine ("/usr", "bin", tool); - if (File.Exists (path)) - return path; - - return null; - } - - // We can end up finding the same tool multiple times. - // That's not a problem. - lock (tools) - tools [tool] = foundPath; - - if (foundPath is null) - throw ErrorHelper.CreateError (5307, Errors.MX5307 /* Missing '{0}' tool. Please install Xcode 'Command-Line Tools' component */, tool); - - return foundPath; - } - - static bool XcrunFind (Application app, string tool, [NotNullWhen (true)] out string? path) - { - return XcrunFind (app, ApplePlatform.None, false, tool, out path); - } - - static bool XcrunFind (Application app, ApplePlatform platform, bool is_simulator, string tool, [NotNullWhen (true)] out string? path) - { - var env = new Dictionary (); - // Unset XCODE_DEVELOPER_DIR_PATH. See https://github.com/dotnet/macios/issues/3931. - env.Add ("XCODE_DEVELOPER_DIR_PATH", null); - // Set DEVELOPER_DIR if we have it - if (!string.IsNullOrEmpty (DeveloperDirectory)) - env.Add ("DEVELOPER_DIR", DeveloperDirectory); - - path = null; - - var args = new List (); - if (platform != ApplePlatform.None) { - args.Add ("-sdk"); - switch (platform) { - case ApplePlatform.iOS: - args.Add (is_simulator ? "iphonesimulator" : "iphoneos"); - break; - case ApplePlatform.MacOSX: - args.Add ("macosx"); - break; - case ApplePlatform.TVOS: - args.Add (is_simulator ? "appletvsimulator" : "appletvos"); - break; - default: - throw ErrorHelper.CreateError (71, Errors.MX0071 /* Unknown platform: {0}. This usually indicates a bug in {1}; please file a bug report at https://github.com/dotnet/macios/issues/new with a test case. */, platform.ToString (), app.ProductName); - } - } - args.Add ("-f"); - args.Add (tool); - - var stdout = new StringBuilder (); - var stderr = new StringBuilder (); - var both = new StringBuilder (); - // xcrun can write unrelated stuff to stderr even if it succeeds, so we need to separate stdout and stderr. - // We also want to print out what happened if something went wrong, and in that case we don't want stdout - // and stderr captured separately, because related lines could end up printed far from eachother in time, - // and that's confusing. So capture stdout and stderr by themselves, and also capture both together. - int ret = RunCommand ("xcrun", args, env, - (v) => { - lock (both) { - both.AppendLine (v); - stdout.AppendLine (v); - } - }, - (v) => { - lock (both) { - both.AppendLine (v); - stderr.AppendLine (v); - } - }); - - if (ret == 0) { - path = stdout.ToString ().Trim (); - if (!File.Exists (path)) { - ErrorHelper.Warning (5315, Errors.MX5315 /* The tool xcrun failed to return a valid result (the file {0} does not exist). Check build log for details. */, tool, path); - return false; - } - } else { - Log (1, "Failed to locate the developer tool '{0}', 'xcrun {1}' returned with the exit code {2}:\n{3}", tool, string.Join (" ", args), ret, both.ToString ()); - } - - return ret == 0; - } - - public static void RunXcodeTool (Application app, string tool, params string [] arguments) - { - RunXcodeTool (app, tool, (IList) arguments); - } - - public static void RunXcodeTool (Application app, string tool, IList arguments) - { - var executable = FindTool (app, tool); - var rv = RunCommand (executable, arguments); - if (rv != 0) - throw ErrorHelper.CreateError (5309, Errors.MX5309 /* Failed to execute the tool '{0}', it failed with an error code '{1}'. Please check the build log for details. */, tool, rv); - } - - public static void RunClang (Application app, IList arguments) - { - RunXcodeTool (app, "clang", arguments); - } - - public static void RunInstallNameTool (Application app, IList arguments) - { - RunXcodeTool (app, "install_name_tool", arguments); - } - - public static void RunBitcodeStrip (Application app, IList arguments) - { - RunXcodeTool (app, "bitcode_strip", arguments); - } - - public static void RunLipo (Application app, string output, IEnumerable inputs) - { - var sb = new List (); - sb.AddRange (inputs); - sb.Add ("-create"); - sb.Add ("-output"); - sb.Add (output); - RunLipo (app, sb); - } - - public static void RunLipoAndCreateDsym (Application app, string output, IEnumerable inputs) - { - RunLipo (app, output, inputs); - - var dsymFolders = inputs.Select (input => input + ".dSYM").Where (Directory.Exists).ToArray (); - if (dsymFolders.Length > 1) { - // Lipo the dSYMs into one big happy dSYM - var dsymLibsDir = dsymFolders.Select (dsym => Path.Combine (dsym, "Contents", "Resources", "DWARF")).ToArray (); - var allLibs = dsymLibsDir.Where (Directory.Exists).SelectMany (dir => Directory.EnumerateFiles (dir)).Select (dir => Path.GetFileName (dir)).Distinct ().ToArray (); - - foreach (var lib in allLibs) { - var outputLib = Path.Combine (dsymLibsDir [0], lib); - var allDsymInputs = dsymLibsDir.Select (libDir => Path.Combine (libDir, lib)).Where (File.Exists).ToArray (); - Driver.RunLipo (app, outputLib, allDsymInputs); - } - } - - // Move the dSYM next to its executable - if (dsymFolders.Length > 0) { - var outputDsymDir = output + ".dSYM"; - if (Directory.Exists (outputDsymDir)) - Directory.Delete (outputDsymDir, true); - Directory.Move (dsymFolders [0], outputDsymDir); - RunCommand ("/usr/bin/mdimport", outputDsymDir); - } - } - - public static void RunLipo (Application app, IList options) - { - RunXcodeTool (app, "lipo", options); - } - - public static void CreateDsym (Application app, string output_dir, string appname, string dsym_dir) - { - RunDsymUtil (app, Path.Combine (output_dir, appname), "-num-threads", "4", "-z", "-o", dsym_dir); - RunCommand ("/usr/bin/mdimport", dsym_dir); - } - - public static void RunDsymUtil (Application app, params string [] options) - { - RunXcodeTool (app, "dsymutil", options); - } - - public static void RunStrip (Application app, IList options) - { - RunXcodeTool (app, "strip", options); - } -#endif // !LEGACY_TOOLS - public static string CorlibName { get { return "System.Private.CoreLib"; diff --git a/tools/common/Driver.execution.cs b/tools/common/Driver.execution.cs index bb576ccec230..72c09d3a3d7f 100644 --- a/tools/common/Driver.execution.cs +++ b/tools/common/Driver.execution.cs @@ -18,76 +18,76 @@ namespace Xamarin.Bundler { public partial class Driver { - public static int RunCommand (string path, IList args, Dictionary? env, out StringBuilder output, bool suppressPrintOnErrors, int verbose) + public static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, out StringBuilder output, bool suppressPrintOnErrors, int verbose) { output = new StringBuilder (); - return RunCommand (path, args, env, output, suppressPrintOnErrors, verbose); + return RunCommand (log, path, args, env, output, suppressPrintOnErrors, verbose); } - public static int RunCommand (string path, IList args, Dictionary? env, out StringBuilder output, bool suppressPrintOnErrors) + public static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, out StringBuilder output, bool suppressPrintOnErrors) { output = new StringBuilder (); - return RunCommand (path, args, env, output, suppressPrintOnErrors, Verbosity); + return RunCommand (log, path, args, env, output, suppressPrintOnErrors, log.Verbosity); } - public static int RunCommand (string path, IList args, Dictionary? env, StringBuilder output, bool suppressPrintOnErrors, int verbosity) + public static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, StringBuilder output, bool suppressPrintOnErrors, int verbosity) { - return RunCommand (path, args, env, output, output, suppressPrintOnErrors, verbosity); + return RunCommand (log, path, args, env, output, output, suppressPrintOnErrors, verbosity); } - public static int RunCommand (string path, IList args, Dictionary? env, StringBuilder output, bool suppressPrintOnErrors = false) + public static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, StringBuilder output, bool suppressPrintOnErrors = false) { - return RunCommand (path, args, env, output, output, suppressPrintOnErrors, Verbosity); + return RunCommand (log, path, args, env, output, output, suppressPrintOnErrors, log.Verbosity); } - public static int RunCommand (string path, params string [] args) + public static int RunCommand (IToolLog log, string path, params string [] args) { - return RunCommand (path, args, null, (Action?) null, (Action?) null, false, Verbosity); + return RunCommand (log, path, args, null, (Action?) null, (Action?) null, false, log.Verbosity); } - public static int RunCommand (string path, IList args) + public static int RunCommand (IToolLog log, string path, IList args) { - return RunCommand (path, args, null, (Action?) null, (Action?) null, false, Verbosity); + return RunCommand (log, path, args, null, (Action?) null, (Action?) null, false, log.Verbosity); } - public static int RunCommand (string path, IList args, StringBuilder? output) + public static int RunCommand (IToolLog log, string path, IList args, StringBuilder? output) { - return RunCommand (path, args, null, output, output, false, Verbosity); + return RunCommand (log, path, args, null, output, output, false, log.Verbosity); } - public static int RunCommand (string path, IList args, StringBuilder? output, bool suppressPrintOnErrors) + public static int RunCommand (IToolLog log, string path, IList args, StringBuilder? output, bool suppressPrintOnErrors) { - return RunCommand (path, args, null, output, output, suppressPrintOnErrors, Verbosity); + return RunCommand (log, path, args, null, output, output, suppressPrintOnErrors, log.Verbosity); } - public static int RunCommand (string path, IList args, StringBuilder? output, StringBuilder? error) + public static int RunCommand (IToolLog log, string path, IList args, StringBuilder? output, StringBuilder? error) { - return RunCommand (path, args, null, output, error, false, Verbosity); + return RunCommand (log, path, args, null, output, error, false, log.Verbosity); } - public static int RunCommand (string path, IList args, StringBuilder? output, StringBuilder? error, bool suppressPrintOnErrors) + public static int RunCommand (IToolLog log, string path, IList args, StringBuilder? output, StringBuilder? error, bool suppressPrintOnErrors) { - return RunCommand (path, args, null, output, error, suppressPrintOnErrors, Verbosity); + return RunCommand (log, path, args, null, output, error, suppressPrintOnErrors, log.Verbosity); } - public static int RunCommand (string path, IList args, Dictionary? env, StringBuilder? output, StringBuilder? error, bool suppressPrintOnErrors, int verbosity) + public static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, StringBuilder? output, StringBuilder? error, bool suppressPrintOnErrors, int verbosity) { var output_received = output is null ? null : new Action ((v) => { if (v is not null) output.AppendLine (v); }); var error_received = error is null ? null : new Action ((v) => { if (v is not null) error.AppendLine (v); }); - return RunCommand (path, args, env, output_received, error_received, suppressPrintOnErrors, verbosity); + return RunCommand (log, path, args, env, output_received, error_received, suppressPrintOnErrors, verbosity); } - static int RunCommand (string path, IList args, Dictionary? env, Action? output_received, bool suppressPrintOnErrors) + static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, Action? output_received, bool suppressPrintOnErrors) { - return RunCommand (path, args, env, output_received, output_received, suppressPrintOnErrors, Verbosity); + return RunCommand (log, path, args, env, output_received, output_received, suppressPrintOnErrors, log.Verbosity); } - static int RunCommand (string path, IList args, Dictionary? env, Action? output_received, Action? error_received) + static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, Action? output_received, Action? error_received) { - return RunCommand (path, args, env, output_received, error_received, false, Verbosity); + return RunCommand (log, path, args, env, output_received, error_received, false, log.Verbosity); } - static int RunCommand (string path, IList args, Dictionary? env, Action? output_received, Action? error_received, bool suppressPrintOnErrors, int verbosity) + static int RunCommand (IToolLog log, string path, IList args, Dictionary? env, Action? output_received, Action? error_received, bool suppressPrintOnErrors, int verbosity) { var output = new StringBuilder (); var outputCallback = new Action ((line) => { @@ -103,8 +103,7 @@ static int RunCommand (string path, IList args, Dictionary 0) - Console.WriteLine ($"{path} {StringUtils.FormatArguments (args)}"); + log.Log (1, $"{path} {StringUtils.FormatArguments (args)}"); var p = Execution.RunWithCallbacksAsync (path, args, env, outputCallback, errorCallback).Result; @@ -118,33 +117,27 @@ static int RunCommand (string path, IList args, Dictionary 0 && output?.Length > 0 && !suppressPrintOnErrors) { - Console.WriteLine (output.ToString ()); + log.Log (output.ToString ()); } return p.ExitCode; } - public static Task RunCommandAsync (string path, IList args, Dictionary? env = null, Action? output_received = null, bool suppressPrintOnErrors = false, int? verbosity = null) + public static Task RunCommandAsync (IToolLog log, string path, IList args, Dictionary? env = null, Action? output_received = null, bool suppressPrintOnErrors = false, int? verbosity = null) { - return Task.Run (() => RunCommand (path, args, env, output_received, output_received, suppressPrintOnErrors, verbosity ?? Verbosity)); + return Task.Run (() => RunCommand (log, path, args, env, output_received, output_received, suppressPrintOnErrors, verbosity ?? log.Verbosity)); } - public static Task RunCommandAsync (string path, IList args, Dictionary? env = null, StringBuilder? output = null, bool suppressPrintOnErrors = false, int? verbosity = null) + public static Task RunCommandAsync (IToolLog log, string path, IList args, Dictionary? env = null, StringBuilder? output = null, bool suppressPrintOnErrors = false, int? verbosity = null) { - return Task.Run (() => RunCommand (path, args, env, output, output, suppressPrintOnErrors, verbosity ?? Verbosity)); + return Task.Run (() => RunCommand (log, path, args, env, output, output, suppressPrintOnErrors, verbosity ?? log.Verbosity)); } - -#if BGENERATOR - internal static int Verbosity => ErrorHelper.Verbosity; -#elif !LEGACY_TOOLS && !BUNDLER - internal static int Verbosity; -#endif } } diff --git a/tools/common/ErrorHelper.tools.cs b/tools/common/ErrorHelper.tools.cs index cbfef0ddb7d0..e930f95731f6 100644 --- a/tools/common/ErrorHelper.tools.cs +++ b/tools/common/ErrorHelper.tools.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; - +using System.Runtime.CompilerServices; using Mono.Cecil; using Mono.Cecil.Cil; @@ -13,22 +13,20 @@ namespace Xamarin.Bundler { public static partial class ErrorHelper { - public static ApplePlatform Platform; - - internal static string Prefix { - get { - switch (Platform) { - case ApplePlatform.iOS: - case ApplePlatform.TVOS: - case ApplePlatform.MacCatalyst: - case ApplePlatform.None: // Return "MT" by default instead of throwing an exception, because any exception here will most likely hide whatever other error we're trying to show. - return "MT"; - case ApplePlatform.MacOSX: - return "MM"; - default: - // Do not use the ErrorHandler machinery, because it will probably end up recursing and eventually throwing a StackOverflowException. - throw new InvalidOperationException ($"Unknown platform: {Platform}"); - } + internal static string GetPrefix (IToolLog? log) + { + switch (log?.Platform) { + case ApplePlatform.iOS: + case ApplePlatform.TVOS: + case ApplePlatform.MacCatalyst: + case ApplePlatform.None: // Return "MT" by default instead of throwing an exception, because any exception here will most likely hide whatever other error we're trying to show. + case null: + return "MT"; + case ApplePlatform.MacOSX: + return "MM"; + default: + // Do not use the ErrorHandler machinery, because it will probably end up recursing and eventually throwing a StackOverflowException. + throw new InvalidOperationException ($"Unknown platform: {log.Platform}"); } } @@ -38,49 +36,42 @@ public enum WarningLevel { Disable = 1, } - static Dictionary? warning_levels; - public static int Verbosity { get; set; } + static ConditionalWeakTable> warning_levels = new (); -#pragma warning disable 649 - public static Func? IsExpectedException; - public static Action? ExitCallback; -#pragma warning restore 649 - - public static WarningLevel GetWarningLevel (int code) + public static WarningLevel GetWarningLevel (IToolLog log, int code) { - WarningLevel level; - - if (warning_levels is null) - return WarningLevel.Warning; + if (warning_levels.TryGetValue (log, out var log_warning_levels)) { + // code -1: all codes + if (log_warning_levels.TryGetValue (-1, out var level)) + return level; - // code -1: all codes - if (warning_levels.TryGetValue (-1, out level)) - return level; - - if (warning_levels.TryGetValue (code, out level)) - return level; + if (log_warning_levels.TryGetValue (code, out level)) + return level; + } return WarningLevel.Warning; } - public static void SetWarningLevel (WarningLevel level, int? code = null /* if null, apply to all warnings */) + public static void SetWarningLevel (IToolLog log, WarningLevel level, int? code = null /* if null, apply to all warnings */) { - if (warning_levels is null) - warning_levels = new Dictionary (); + if (!warning_levels.TryGetValue (log, out var log_warning_levels)) { + log_warning_levels = new Dictionary (); + warning_levels.Add (log, log_warning_levels); + } if (code.HasValue) { - warning_levels [code.Value] = level; + log_warning_levels [code.Value] = level; } else { - warning_levels [-1] = level; // code -1: all codes. + log_warning_levels [-1] = level; // code -1: all codes. } } - public static void ParseWarningLevel (WarningLevel level, string value) + public static void ParseWarningLevel (IToolLog log, WarningLevel level, string value) { if (string.IsNullOrEmpty (value)) { - SetWarningLevel (level); + SetWarningLevel (log, level); } else { foreach (var code in value.Split (new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries)) - SetWarningLevel (level, int.Parse (code)); + SetWarningLevel (log, level, int.Parse (code)); } } @@ -253,102 +244,95 @@ public static ProductException Create (Application app, int code, bool error, Ex return e; } - public static void Warning (int code, string message, params object [] args) + public static void Warning (IToolLog log, int code, string message, params object [] args) { - Show (new ProductException (code, false, message, args)); + Show (log, new ProductException (code, false, null, message, args)); } - public static void Warning (int code, Exception innerException, string message, params object [] args) + public static void Warning (IToolLog log, int code, Exception innerException, string message, params object [] args) { - Show (new ProductException (code, false, innerException, message, args)); + Show (log, new ProductException (code, false, innerException, message, args)); } // Shows any warnings, and if there are any errors, throws an AggregateException. - public static void ThrowIfErrors (IList exceptions) + public static void ThrowIfErrors (IToolLog log, IList exceptions) { if (exceptions?.Any () != true) return; // Separate warnings from errors - var grouped = exceptions.GroupBy ((v) => (v as ProductException)?.Error == false); + var grouped = exceptions.GroupBy ((v) => (v as ProductException)?.IsError (log) == false); var warnings = grouped.SingleOrDefault ((v) => v.Key); if (warnings?.Any () == true) - Show (warnings); + Show (log, warnings); var errors = grouped.SingleOrDefault ((v) => !v.Key); if (errors?.Any () == true) throw new AggregateException (errors); } - public static void Show (IEnumerable list) + public static void Show (IToolLog log, IEnumerable list) { var exceptions = CollectExceptions (list); bool error = false; foreach (var ex in exceptions) - error |= ShowInternal (ex); + error |= ShowInternal (log, ex); if (error) Exit (1); } - public static void Show (Exception e) + public static void Show (IToolLog log, Exception e) { - Show (new Exception [] { e }); + Show (log, new Exception [] { e }); } static void Exit (int exitCode) { - if (ExitCallback is not null) - ExitCallback (exitCode); Environment.Exit (exitCode); } - static bool ShowInternal (Exception e) + static bool ShowInternal (IToolLog log, Exception e) { var mte = e as ProductException; bool error = true; if (mte is not null) { - error = mte.Error; + error = mte.IsError (log); - if (!error && GetWarningLevel (mte.Code) == WarningLevel.Disable) + if (!error && GetWarningLevel (log, mte.Code) == WarningLevel.Disable) return false; // This is an ignored warning. - Console.Error.WriteLine (mte.ToString ()); + log.LogError (mte.ToString ()); - ShowInner (e); + ShowInner (log, e); - if (Verbosity > 2 && !string.IsNullOrEmpty (e.StackTrace)) - Console.Error.WriteLine (e.StackTrace); - } else if (IsExpectedException is null || !IsExpectedException (e)) { - Console.Error.WriteLine ("error " + Prefix + "0000: Unexpected error - Please file a bug report at https://github.com/dotnet/macios/issues/new"); - Console.Error.WriteLine (e.ToString ()); + if (log.Verbosity > 2 && !string.IsNullOrEmpty (e.StackTrace)) + log.LogError (e.StackTrace); } else { - Console.Error.WriteLine (e.ToString ()); - ShowInner (e); - if (Verbosity > 2 && !string.IsNullOrEmpty (e.StackTrace)) - Console.Error.WriteLine (e.StackTrace); + log.LogError ("error " + GetPrefix (log) + "0000: Unexpected error - Please file a bug report at https://github.com/dotnet/macios/issues/new"); + log.LogError (e.ToString ()); } return error; } - static void ShowInner (Exception e) + static void ShowInner (IToolLog log, Exception e) { var ie = e.InnerException; if (ie is null) return; - if (Verbosity > 3) { - Console.Error.WriteLine ("--- inner exception"); - Console.Error.WriteLine (ie); - Console.Error.WriteLine ("---"); - } else if (Verbosity > 0 || ie is ProductException) { - Console.Error.WriteLine ("\t{0}", ie.Message); + if (log.Verbosity > 3) { + log.LogError ("--- inner exception"); + log.LogError (ie.ToString ()); + log.LogError ("---"); + } else if (log.Verbosity > 0 || ie is ProductException) { + log.LogError ($"\t{ie.Message}"); } - ShowInner (ie); + ShowInner (log, ie); } } } diff --git a/tools/common/FileCopier.cs b/tools/common/FileCopier.cs index 98a8e1a27f5d..d26254c1ba17 100644 --- a/tools/common/FileCopier.cs +++ b/tools/common/FileCopier.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -27,6 +28,7 @@ enum CopyFileFlags : uint { enum CopyFileState : uint { StatusCB = 6, + StatusCtx = 7, } enum CopyFileStep { @@ -57,81 +59,39 @@ enum CopyFileWhat { [DllImport ("/usr/lib/libSystem.dylib")] static extern int copyfile_state_free (IntPtr state); +#if NET [DllImport ("/usr/lib/libSystem.dylib")] - static extern int copyfile_state_set (IntPtr state, CopyFileState flag, IntPtr value); - + static extern unsafe int copyfile_state_set (IntPtr state, CopyFileState flag, delegate* unmanaged value); +#else delegate CopyFileResult CopyFileCallbackDelegate (CopyFileWhat what, CopyFileStep stage, IntPtr state, string src, string dst, IntPtr ctx); +#endif + + [DllImport ("/usr/lib/libSystem.dylib")] + static extern unsafe int copyfile_state_set (IntPtr state, CopyFileState flag, IntPtr value); [DllImport ("/usr/lib/libSystem.dylib", SetLastError = true)] static extern int copyfile (string @from, string @to, IntPtr state, CopyFileFlags flags); - // This code is shared between our packaging tools (mmp\mtouch) and msbuild tasks - public delegate void LogCallback (int verbosity, string format, params object? [] arguments); - public delegate void ReportErrorCallback (int code, string format, params object? [] arguments); - - [ThreadStatic] - static LogCallback? logCallback; - - [ThreadStatic] - static ReportErrorCallback? reportErrorCallback; - - static void Log (int min_verbosity, string format, params object? [] arguments) - { - if (logCallback is not null) { - logCallback (min_verbosity, format, arguments); - return; - } - -#if LEGACY_TOOLS || BUNDLER - // LogMessage and LogError are instance objects on the tasks themselves and bubbling an event up is not ideal - Driver.Log (min_verbosity, format, arguments); -#else - Console.WriteLine (format, arguments); -#endif - } - - static void ReportError (int code, string format, params object? [] arguments) + static void ReportError (IToolLog log, int code, string format, params object? [] arguments) { - if (reportErrorCallback is not null) { - reportErrorCallback (code, format, arguments); - return; - } - #if LEGACY_TOOLS || BUNDLER - throw ErrorHelper.CreateError (code, format, arguments); + log.LogError (ErrorHelper.CreateError (code, format, arguments)); #else - // msbuild handles uncaught exceptions as a task error - throw new Exception ($"{code} {string.Format (format, arguments)}"); + log.LogError (new Exception ($"{code} {string.Format (format, arguments)}")); #endif } - public static void UpdateDirectory (string source, string target, ReportErrorCallback reportErrorCallback, LogCallback logCallback) - { - try { - FileCopier.reportErrorCallback = reportErrorCallback; - FileCopier.logCallback = logCallback; - UpdateDirectory (source, target); - } finally { - FileCopier.reportErrorCallback = null; - FileCopier.logCallback = null; - } - } - -#if LEGACY_TOOLS || BUNDLER - public static void UpdateDirectory (string source, string target) -#else - static void UpdateDirectory (string source, string target) -#endif + public static void UpdateDirectory (IToolLog log, string source, string target) { // first chance, try to update existing content inside `target` - if (TryUpdateDirectory (source, target, out var err)) + if (TryUpdateDirectory (log, source, target, out var err)) return; // 2nd chance, remove `target` then copy everything - Log (1, "Could not update `{0}` content (error #{1} : {2}), trying to overwrite everything...", target, err, strerror (err)); + log.Log (1, "Could not update `{0}` content (error #{1} : {2}), trying to overwrite everything...", target, err, strerror (err)); Directory.Delete (target, true); - if (!TryUpdateDirectory (source, target, out err)) - ReportError (1022, Errors.MT1022, source, target, err, strerror (err)); + if (!TryUpdateDirectory (log, source, target, out err)) + ReportError (log, 1022, Errors.MT1022, source, target, err, strerror (err)); } static bool? use_managed_copying; @@ -150,16 +110,16 @@ static bool UseManagedCopying { } } - static bool TryUpdateDirectory (string source, string target, out int errno) + static bool TryUpdateDirectory (IToolLog log, string source, string target, out int errno) { if (UseManagedCopying) - return TryUpdateDirectoryWindows (source, target, out errno); - return TryUpdateDirectoryMacOS (source, target, out errno); + return TryUpdateDirectoryWindows (log, source, target, out errno); + return TryUpdateDirectoryMacOS (log, source, target, out errno); } - static bool TryUpdateDirectoryWindows (string source, string target, out int errno) + static bool TryUpdateDirectoryWindows (IToolLog log, string source, string target, out int errno) { - Log (1, $"Copying {source} to {target} recursively"); + log.Log (1, $"Copying {source} to {target} recursively"); errno = 0; Directory.CreateDirectory (target); @@ -170,39 +130,47 @@ static bool TryUpdateDirectoryWindows (string source, string target, out int err foreach (var sourceFile in dir.GetFiles ()) { var sourcePath = sourceFile.FullName; var targetPath = Path.Combine (target, Path.GetFileName (source), sourceFile.Name); - CopyIfNeeded (sourcePath, targetPath); + CopyIfNeeded (log, sourcePath, targetPath); } foreach (var subdir in dir.GetDirectories ()) { - rv &= TryUpdateDirectoryWindows (Path.Combine (source, subdir.Name), Path.Combine (target, Path.GetFileName (source)), out errno); + rv &= TryUpdateDirectoryWindows (log, Path.Combine (source, subdir.Name), Path.Combine (target, Path.GetFileName (source)), out errno); } } else { var targetPath = Path.Combine (target, Path.GetFileName (source)); - CopyIfNeeded (source, targetPath); + CopyIfNeeded (log, source, targetPath); } return rv; } - static void CopyIfNeeded (string source, string target) + static void CopyIfNeeded (IToolLog log, string source, string target) { - if (IsUptodate (source, target)) { - Log (3, "Target '{0}' is up-to-date", target); + if (IsUptodate (log, source, target)) { + log.Log (3, "Target '{0}' is up-to-date", target); } else { Directory.CreateDirectory (Path.GetDirectoryName (target)!); File.Copy (source, target, true); - Log (1, "Copied {0} to {1}", source, target); + log.Log (1, "Copied {0} to {1}", source, target); } } - static bool TryUpdateDirectoryMacOS (string source, string target, out int errno) + static bool TryUpdateDirectoryMacOS (IToolLog log, string source, string target, out int errno) { Directory.CreateDirectory (target); // Mono's File.Copy can't handle symlinks (the symlinks are followed instead of copied), // so we need to use native functions directly. Luckily OSX provides exactly what we need. IntPtr state = copyfile_state_alloc (); + var logHandle = GCHandle.Alloc (log); try { +#if NET + unsafe { + copyfile_state_set (state, CopyFileState.StatusCB, &CopyFileCallback); + } +#else CopyFileCallbackDelegate del = CopyFileCallback; copyfile_state_set (state, CopyFileState.StatusCB, Marshal.GetFunctionPointerForDelegate (del)); +#endif + copyfile_state_set (state, CopyFileState.StatusCtx, (IntPtr) logHandle); int rv = copyfile (source, target, state, CopyFileFlags.Data | CopyFileFlags.Recursive | CopyFileFlags.Nofollow | CopyFileFlags.Clone); if (rv == 0) { errno = 0; // satisfy compiler and make sure not to pick up some older error code @@ -212,25 +180,36 @@ static bool TryUpdateDirectoryMacOS (string source, string target, out int errno return false; } } finally { + logHandle.Free (); copyfile_state_free (state); } } // do not call `Marshal.GetLastWin32Error` inside this method since it's called while the p/invoke is executing and will return `260` +#if NET + [UnmanagedCallersOnly] + static CopyFileResult CopyFileCallback (CopyFileWhat what, CopyFileStep stage, IntPtr state, IntPtr sourcePtr, IntPtr targetPtr, IntPtr ctx) + { + var source = Marshal.PtrToStringUTF8 (sourcePtr)!; + var target = Marshal.PtrToStringUTF8 (targetPtr)!; +#else static CopyFileResult CopyFileCallback (CopyFileWhat what, CopyFileStep stage, IntPtr state, string source, string target, IntPtr ctx) { - // Console.WriteLine ("CopyFileCallback ({0}, {1}, 0x{2}, {3}, {4}, 0x{5})", what, stage, state.ToString ("x"), source, target, ctx.ToString ("x")); +#endif + var log = (IToolLog) GCHandle.FromIntPtr (ctx).Target!; + + // log.Log ("CopyFileCallback ({0}, {1}, 0x{2}, {3}, {4}, 0x{5})", what, stage, state.ToString ("x"), source, target, ctx.ToString ("x")); switch (what) { case CopyFileWhat.File: - if (!IsUptodate (source, target)) { + if (!IsUptodate (log, source, target)) { if (stage == CopyFileStep.Finish) - Log (1, "Copied {0} to {1}", source, target); + log.Log (1, "Copied {0} to {1}", source, target); else if (stage == CopyFileStep.Err) { - Log (1, "Could not copy the file '{0}' to '{1}'", source, target); + log.Log (1, "Could not copy the file '{0}' to '{1}'", source, target); return CopyFileResult.Quit; } else if (stage == CopyFileStep.Start) { if (File.Exists (target) || Directory.Exists (target)) { - Log (1, "Deleted target {0}, it's not up-to-date", target); + log.Log (1, "Deleted target {0}, it's not up-to-date", target); // This callback won't be called for directories, but we can get here for symlinks to directories. // This means that File.Delete should always work (no need to check for a directory to call Directory.Delete) File.Delete (target); @@ -238,7 +217,7 @@ static CopyFileResult CopyFileCallback (CopyFileWhat what, CopyFileStep stage, I } return CopyFileResult.Continue; } else { - Log (3, "Target '{0}' is up-to-date", target); + log.Log (3, "Target '{0}' is up-to-date", target); return CopyFileResult.Skip; } case CopyFileWhat.Dir: @@ -247,53 +226,32 @@ static CopyFileResult CopyFileCallback (CopyFileWhat what, CopyFileStep stage, I case CopyFileWhat.CopyXattr: return CopyFileResult.Continue; case CopyFileWhat.Error: - Log (1, "Could not copy the file '{0}' to '{1}'", source, target); + log.Log (1, "Could not copy the file '{0}' to '{1}'", source, target); return CopyFileResult.Quit; default: return CopyFileResult.Continue; } } - public static bool IsUptodate (string source, string target, ReportErrorCallback reportErrorCallback, LogCallback logCallback, bool check_contents = false, bool check_stamp = true) - { - try { - FileCopier.reportErrorCallback = reportErrorCallback; - FileCopier.logCallback = logCallback; - return IsUptodate (source, target, check_contents, check_stamp); - } finally { - FileCopier.reportErrorCallback = null; - FileCopier.logCallback = null; - } - } - // Checks if the source file has a time stamp later than the target file. // // Optionally check if the contents of the files are different after checking the timestamp. // // If check_stamp is true, the function will use the timestamp of a "target".stamp file // if it's later than the timestamp of the "target" file itself. -#if LEGACY_TOOLS || BUNDLER - public static bool IsUptodate (string source, string target, bool check_contents = false, bool check_stamp = true) -#else - static bool IsUptodate (string source, string target, bool check_contents = false, bool check_stamp = true) -#endif + public static bool IsUptodate (IToolLog log, string source, string target, bool check_contents = false, bool check_stamp = true) { -#if LEGACY_TOOLS || BUNDLER // msbuild does not have force - if (Driver.Force) - return false; -#endif - var tfi = new FileInfo (target); if (!tfi.Exists) { - Log (3, "Target '{0}' does not exist.", target); + log.Log (3, "Target '{0}' does not exist.", target); return false; } if (check_stamp) { var tfi_stamp = new FileInfo (target + ".stamp"); if (tfi_stamp.Exists && tfi_stamp.LastWriteTimeUtc > tfi.LastWriteTimeUtc) { - Log (3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", target, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc); + log.Log (3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", target, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc); tfi = tfi_stamp; } } @@ -301,13 +259,13 @@ static bool IsUptodate (string source, string target, bool check_contents = fals var sfi = new FileInfo (source); if (sfi.LastWriteTimeUtc <= tfi.LastWriteTimeUtc) { - Log (3, "Prerequisite '{0}' is older than the target '{1}'.", source, target); + log.Log (3, "Prerequisite '{0}' is older than the target '{1}'.", source, target); return true; } #if LEGACY_TOOLS || BUNDLER // msbuild usages do not require CompareFiles optimization - if (check_contents && Cache.CompareFiles (source, target)) { - Log (3, "Prerequisite '{0}' is newer than the target '{1}', but the contents are identical.", source, target); + if (check_contents && Cache.CompareFiles (log, source, target)) { + log.Log (3, "Prerequisite '{0}' is newer than the target '{1}', but the contents are identical.", source, target); return true; } #else @@ -315,37 +273,16 @@ static bool IsUptodate (string source, string target, bool check_contents = fals throw new NotImplementedException ("Checking file contents is not supported"); #endif - Log (3, "Prerequisite '{0}' is newer than the target '{1}'.", source, target); + log.Log (3, "Prerequisite '{0}' is newer than the target '{1}'.", source, target); return false; } - public static bool IsUptodate (IEnumerable sources, IEnumerable targets, ReportErrorCallback reportErrorCallback, LogCallback logCallback, bool check_stamp = true) - { - try { - FileCopier.reportErrorCallback = reportErrorCallback; - FileCopier.logCallback = logCallback; - return IsUptodate (sources, targets, check_stamp); - } finally { - FileCopier.reportErrorCallback = null; - FileCopier.logCallback = null; - } - } - // Checks if any of the source files have a time stamp later than any of the target files. // // If check_stamp is true, the function will use the timestamp of a "target".stamp file // if it's later than the timestamp of the "target" file itself. -#if LEGACY_TOOLS || BUNDLER - public static bool IsUptodate (IEnumerable sources, IEnumerable targets, bool check_stamp = true) -#else - static bool IsUptodate (IEnumerable sources, IEnumerable targets, bool check_stamp = true) -#endif + public static bool IsUptodate (IToolLog log, IEnumerable sources, IEnumerable targets, bool check_stamp = true) { -#if LEGACY_TOOLS || BUNDLER // msbuild does not have force - if (Driver.Force) - return false; -#endif - DateTime max_source = DateTime.MinValue; string? max_s = null; @@ -355,7 +292,7 @@ static bool IsUptodate (IEnumerable sources, IEnumerable targets foreach (var s in sources) { var sfi = new FileInfo (s); if (!sfi.Exists) { - Log (3, "Prerequisite '{0}' does not exist.", s); + log.Log (3, "Prerequisite '{0}' does not exist.", s); return false; } @@ -370,31 +307,31 @@ static bool IsUptodate (IEnumerable sources, IEnumerable targets foreach (var t in targets) { var tfi = new FileInfo (t); if (!tfi.Exists) { - Log (3, "Target '{0}' does not exist.", t); + log.Log (3, "Target '{0}' does not exist.", t); return false; } if (check_stamp) { var tfi_stamp = new FileInfo (t + ".stamp"); if (tfi_stamp.Exists && tfi_stamp.LastWriteTimeUtc > tfi.LastWriteTimeUtc) { - Log (3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", t, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc); + log.Log (3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", t, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc); tfi = tfi_stamp; } } var lwt = tfi.LastWriteTimeUtc; if (max_source > lwt) { - Log (3, "Prerequisite '{0}' is newer than target '{1}' ({2} vs {3}).", max_s, t, max_source, lwt); + log.Log (3, "Prerequisite '{0}' is newer than target '{1}' ({2} vs {3}).", max_s, t, max_source, lwt); return false; } } - Log (3, "Prerequisite(s) '{0}' are all older than the target(s) '{1}'.", string.Join ("', '", sources.ToArray ()), string.Join ("', '", targets.ToArray ())); + log.Log (3, "Prerequisite(s) '{0}' are all older than the target(s) '{1}'.", string.Join ("', '", sources.ToArray ()), string.Join ("', '", targets.ToArray ())); return true; } - [DllImport ("/usr/lib/libSystem.dylib", SetLastError = true, EntryPoint = "strerror")] + [DllImport ("libc", SetLastError = true, EntryPoint = "strerror")] static extern IntPtr _strerror (int errno); internal static string strerror (int errno) diff --git a/tools/common/FileUtils.cs b/tools/common/FileUtils.cs index f8b3c617674f..7b406fd24ed6 100644 --- a/tools/common/FileUtils.cs +++ b/tools/common/FileUtils.cs @@ -75,5 +75,19 @@ public static bool UpdateFile (string targetFile, Action createOutput) } } + + public static void WriteIfDifferent (string path, string contents, Action log) + { + if (!File.Exists (path)) { + log ($"File '{path}' contents are not up-to-date, because the file doesn't exist."); + File.WriteAllText (path, contents); + } else if (string.Equals (contents, File.ReadAllText (path), StringComparison.Ordinal)) { + log ($"File '{path}' contents are up-to-date."); + return; + } else { + log ($"File '{path}' contents are not up-to-date."); + File.WriteAllText (path, contents); + } + } } } diff --git a/tools/common/Frameworks.cs b/tools/common/Frameworks.cs index 8f626d2d973e..8e40602e764a 100644 --- a/tools/common/Frameworks.cs +++ b/tools/common/Frameworks.cs @@ -134,7 +134,7 @@ public void Add (string @namespace, string framework, Version version, Version? return null; } - static Version NotAvailableInSimulator = new Version (int.MaxValue, int.MaxValue); + static readonly Version NotAvailableInSimulator = new Version (int.MaxValue, int.MaxValue); static Frameworks? mac_frameworks; public static Frameworks MacFrameworks { @@ -841,7 +841,7 @@ static void Gather (Application app, IEnumerable assemblies, static bool FilterFrameworks (Application app, Framework framework) { if (framework.IsFrameworkUnavailable (app)) { - Driver.Log (3, "Not linking with the framework {0} because it's not available in the current SDK.", framework.Name); + app.Log (3, "Not linking with the framework {0} because it's not available in the current SDK.", framework.Name); return false; } diff --git a/tools/common/IToolLog.cs b/tools/common/IToolLog.cs new file mode 100644 index 000000000000..758cb136eaf4 --- /dev/null +++ b/tools/common/IToolLog.cs @@ -0,0 +1,73 @@ +using Xamarin.Utils; + +namespace Xamarin.Bundler; + +public interface IToolLog { + int Verbosity { get; } + ApplePlatform Platform { get; } + void Log (string message); + void LogError (string message); + // Log an error we raise ourselves (through an exception) + void LogError (Exception exception); + // Log an unexpected exception + void LogException (Exception exception); +} + +public static class IToolLogExtensions { + public static void Log (this IToolLog log, string format, params object? [] args) + { + log.Log (string.Format (format, args)); + } + + public static void Log (this IToolLog log, int min_verbosity, string message) + { + if (min_verbosity > log.Verbosity) + return; + + log.Log (message); + } + + public static void Log (this IToolLog log, int min_verbosity, string format, params object? [] args) + { + if (min_verbosity > log.Verbosity) + return; + + Log (log, format, args); + } +} + +#if !MSBUILD_TASKS +public class ConsoleLog : IToolLog { + public readonly static IToolLog Instance = new ConsoleLog (); + +#if TESTS + int verbosity = 0; +#else + int verbosity = Driver.GetDefaultVerbosity (); +#endif + + public int Verbosity { get => verbosity; } + + public ApplePlatform Platform => ApplePlatform.None; + + public void Log (string message) + { + Console.WriteLine (message); + } + + public void LogError (string message) + { + Console.Error.WriteLine (message); + } + + public void LogError (Exception exception) + { + Console.Error.WriteLine (exception); + } + + public void LogException (Exception exception) + { + Console.Error.WriteLine (exception); + } +} +#endif // !MSBUILD_TASKS diff --git a/tools/common/MachO.cs b/tools/common/MachO.cs index 0aa183a1cffc..ff06994660b7 100644 --- a/tools/common/MachO.cs +++ b/tools/common/MachO.cs @@ -269,7 +269,7 @@ public static IEnumerable Read (string filename) } } - public static List GetArchitectures (string file) + public static List GetArchitectures (IToolLog log, string file) { var result = new List (); @@ -309,7 +309,7 @@ public static List GetArchitectures (string file) result.Add (GetArch (System.Net.IPAddress.NetworkToHostOrder (reader.ReadInt32 ()), System.Net.IPAddress.NetworkToHostOrder (reader.ReadInt32 ()))); break; default: - Console.WriteLine ("File '{0}' is neither a Universal binary nor a Mach-O binary (magic: 0x{1})", file, magic.ToString ("x")); + log.Log ("File '{0}' is neither a Universal binary nor a Mach-O binary (magic: 0x{1})", file, magic.ToString ("x")); break; } } @@ -1023,10 +1023,10 @@ public MachO.LoadCommands Command { } #if DEBUG - public virtual void Dump () + public virtual void Dump (IToolLog log) { - Console.WriteLine (" cmd: {0}", cmd); - Console.WriteLine (" cmdsize: {0}", cmdsize); + log.Log (" cmd: {0}", cmd); + log.Log (" cmdsize: {0}", cmdsize); } #endif } @@ -1038,13 +1038,13 @@ public class DylibLoadCommand : LoadCommand { public uint compatibility_version; #if DEBUG - public override void Dump () + public override void Dump (IToolLog log) { - base.Dump (); - Console.WriteLine (" name: {0}", name); - Console.WriteLine (" timestamp: {0}", timestamp); - Console.WriteLine (" current_version: {0}", current_version); - Console.WriteLine (" compatibility_version: {0}", compatibility_version); + base.Dump (log); + log.Log (" name: {0}", name); + log.Log (" timestamp: {0}", timestamp); + log.Log (" current_version: {0}", current_version); + log.Log (" compatibility_version: {0}", compatibility_version); } #endif } @@ -1056,13 +1056,13 @@ public class DylibIdCommand : LoadCommand { public uint compatibility_version; #if DEBUG - public override void Dump () + public override void Dump (IToolLog log) { - base.Dump (); - Console.WriteLine (" name: {0}", name); - Console.WriteLine (" timestamp: {0}", timestamp); - Console.WriteLine (" current_version: {0}", current_version); - Console.WriteLine (" compatibility_version: {0}", compatibility_version); + base.Dump (log); + log.Log (" name: {0}", name); + log.Log (" timestamp: {0}", timestamp); + log.Log (" current_version: {0}", current_version); + log.Log (" compatibility_version: {0}", compatibility_version); } #endif } @@ -1071,11 +1071,11 @@ public class UuidCommand : LoadCommand { public byte []? uuid; #if DEBUG - public override void Dump () + public override void Dump (IToolLog log) { - base.Dump (); - Console.WriteLine (" cmd: {0}", cmd); - Console.WriteLine (" uuid: {0}", uuid); + base.Dump (log); + log.Log (" cmd: {0}", cmd); + log.Log (" uuid: {0}", uuid); } #endif } diff --git a/tools/common/Optimizations.cs b/tools/common/Optimizations.cs index 992d36ee118a..d243a9b39415 100644 --- a/tools/common/Optimizations.cs +++ b/tools/common/Optimizations.cs @@ -9,7 +9,7 @@ namespace Xamarin.Bundler { public class Optimizations { - static string [] opt_names = + static readonly string [] opt_names = { "remove-uithread-checks", "dead-code-elimination", @@ -31,7 +31,7 @@ public class Optimizations { "redirect-class-handles", }; - static ApplePlatform [] [] valid_platforms = new ApplePlatform [] [] { + static readonly ApplePlatform [] [] valid_platforms = new ApplePlatform [] [] { /* Opt.RemoveUIThreadChecks */ new ApplePlatform [] { ApplePlatform.iOS, ApplePlatform.MacOSX, ApplePlatform.TVOS, ApplePlatform.MacCatalyst }, /* Opt.DeadCodeElimination */ new ApplePlatform [] { ApplePlatform.iOS, ApplePlatform.MacOSX, ApplePlatform.TVOS, ApplePlatform.MacCatalyst }, /* Opt.InlineIsDirectBinding */ new ApplePlatform [] { ApplePlatform.iOS, ApplePlatform.MacOSX, ApplePlatform.TVOS, ApplePlatform.MacCatalyst }, diff --git a/tools/common/PInvokeWrapperGenerator.cs b/tools/common/PInvokeWrapperGenerator.cs index a0c4592a5ccb..d8ba33801ac6 100644 --- a/tools/common/PInvokeWrapperGenerator.cs +++ b/tools/common/PInvokeWrapperGenerator.cs @@ -70,8 +70,8 @@ public void End () Registrar.GeneratePInvokeWrappersEnd (); - Driver.WriteIfDifferent (HeaderPath, hdr.ToString () + "\n" + decls.ToString () + "\n" + ifaces.ToString () + "\n", true); - Driver.WriteIfDifferent (SourcePath, mthds.ToString () + "\n" + sb.ToString () + "\n", true); + Driver.WriteIfDifferent (App, HeaderPath, hdr.ToString () + "\n" + decls.ToString () + "\n" + ifaces.ToString () + "\n", true); + Driver.WriteIfDifferent (App, SourcePath, mthds.ToString () + "\n" + sb.ToString () + "\n", true); } public void ProcessMethod (MethodDefinition method) diff --git a/tools/common/PathUtils.cs b/tools/common/PathUtils.cs index 19dcc31df8fe..355253f5c2a7 100644 --- a/tools/common/PathUtils.cs +++ b/tools/common/PathUtils.cs @@ -38,7 +38,7 @@ static char ToOrdinalIgnoreCase (char c) return path; } - [DllImport ("/usr/lib/libc.dylib")] + [DllImport ("libc")] static extern IntPtr realpath (string path, IntPtr buffer); #if NET @@ -422,5 +422,25 @@ static bool IsLongPathsEnabledRegistry { } } } + + public static void CreateDirectoryForFile (string? file) + { +#if NET + if (string.IsNullOrEmpty (file)) +#else + if (string.IsNullOrEmpty (file) || file is null) +#endif + return; + + var dir = Path.GetDirectoryName (file); +#if NET + if (string.IsNullOrEmpty (dir)) +#else + if (string.IsNullOrEmpty (dir) || dir is null) +#endif + return; + + Directory.CreateDirectory (dir); + } } } diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 2170362d0c79..f6b55ec0a015 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -726,14 +726,14 @@ protected override bool LaxMode { } } - protected override void ReportError (int code, string message, params object [] args) + protected override void ReportError (int code, string message, params object? [] args) { throw ErrorHelper.CreateError (code, message, args); } - protected override void ReportWarning (int code, string message, params object [] args) + protected override void ReportWarning (int code, string message, params object? [] args) { - ErrorHelper.Show (ErrorHelper.CreateWarning (code, message, args)); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (code, message, args)); } public static int GetValueTypeSize (TypeDefinition type) @@ -1591,7 +1591,7 @@ protected override IEnumerable GetProtocolMemberAttribu } #if !LEGACY_TOOLS - bool GetDotNetAvailabilityAttribute (ICustomAttribute ca, ApplePlatform currentPlatform, out Version? sdkVersion, out string? message) + public bool GetDotNetAvailabilityAttribute (ICustomAttribute ca, ApplePlatform currentPlatform, out Version? sdkVersion, out string? message) { var caType = ca.AttributeType; @@ -1601,6 +1601,7 @@ bool GetDotNetAvailabilityAttribute (ICustomAttribute ca, ApplePlatform currentP string supportedPlatformAndVersion; switch (ca.ConstructorArguments.Count) { case 1: + case 2: // second argument can be a message supportedPlatformAndVersion = (string) ca.ConstructorArguments [0].Value; break; default: @@ -1679,7 +1680,7 @@ bool CollectAvailabilityAttributes (IEnumerable attributes, ou return false; } - protected override Version? GetSdkIntroducedVersion (TypeReference obj, out string? message) + public override Version? GetSdkIntroducedVersion (TypeReference obj, out string? message) { TypeDefinition td = obj.Resolve (); @@ -2025,7 +2026,7 @@ public bool IsCustomType (ObjCType type) return false; } - bool IsPlatformType (TypeReference type) + public bool IsPlatformType (TypeReference type) { if (type.IsNested) return false; @@ -2102,7 +2103,7 @@ void CheckNamespace (string ns, List exceptions) namespaces.Add (ns); if (Driver.GetFrameworks (App).TryGetValue (ns, out var fw) && fw.IsFrameworkUnavailable (App)) { - Driver.Log (5, "Not importing the framework {0} in the generated registrar code because it's not available in the current platform.", ns); + App.Log (5, "Not importing the framework {0} in the generated registrar code because it's not available in the current platform.", ns); return; } @@ -2685,7 +2686,7 @@ List GetAllTypes (List exceptions) if (!string.IsNullOrEmpty (single_assembly) && single_assembly != @class.Type.Module.Assembly.Name.Name) continue; - if (Driver.XcodeVersion.Major >= 15) { + if (App.XcodeVersion.Major >= 15) { if (@class.Type.Is ("PassKit", "PKDisbursementAuthorizationControllerDelegate") || @class.Type.Is ("PassKit", "IPKDisbursementAuthorizationControllerDelegate")) { exceptions.Add (ErrorHelper.CreateWarning (4189, $"The class '{@class.Type.FullName}' will not be registered it has been removed from the {App.Platform} SDK.")); continue; @@ -2741,9 +2742,9 @@ public void Rewrite () var rewriter = new Rewriter (map_dict, GetAssemblies (), LinkContext); var result = rewriter.Process (); if (!string.IsNullOrEmpty (result)) { - Driver.Log (5, $"Not redirecting class handles because {result}"); + App.Log (5, $"Not redirecting class handles because {result}"); } - ErrorHelper.ThrowIfErrors (exceptions); + ErrorHelper.ThrowIfErrors (App, exceptions); } #endif } @@ -3200,7 +3201,7 @@ void Specialize (AutoIndentStringBuilder sb, out string initialization_method) sb.WriteLine (map.ToString ()); sb.WriteLine (map_init.ToString ()); - ErrorHelper.ThrowIfErrors (exceptions); + ErrorHelper.ThrowIfErrors (App, exceptions); } bool TryGetIntPtrBoolCtor (TypeDefinition type, List exceptions, [NotNullWhen (true)] out MethodDefinition? ctor) @@ -4399,11 +4400,11 @@ void SpecializePrepareReturnValue (AutoIndentStringBuilder sb, ObjCMethod method var token = "INVALID_TOKEN_REF"; if (App.Optimizations.OptimizeBlockLiteralSetupBlock == true) { if (type.Is ("System", "Delegate") || type.Is ("System", "MulticastDelegate")) { - ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4173, method.Method, Errors.MT4173, type.FullName, descriptiveMethodName)); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (App, 4173, method.Method, Errors.MT4173, type.FullName, descriptiveMethodName)); } else { var delegateMethod = type.Resolve ().GetMethods ().FirstOrDefault ((v) => v.Name == "Invoke"); if (delegateMethod is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4173, method.Method, Errors.MT4173_A, type.FullName, descriptiveMethodName)); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (App, 4173, method.Method, Errors.MT4173_A, type.FullName, descriptiveMethodName)); } else { signature = "\"" + ComputeSignature (method.DeclaringType.Type, null, method, isBlockSignature: true) + "\""; } @@ -4688,7 +4689,7 @@ public bool TryFindMethod (MethodDefinition method, [NotNullWhen (true)] out Obj // One common variation is that the IDE will add the BlockProxy attribute found in base methods when the user overrides those methods, // which unfortunately doesn't compile (because the type passed to the BlockProxy attribute is internal), and then // the user just modifies the attribute to something that compiles. - ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4175, method, $"{(string.IsNullOrEmpty (param.Name) ? $"Parameter #{param.Index + 1}" : $"The parameter '{param.Name}'")} in the method '{GetTypeFullName (method.DeclaringType)}.{GetDescriptiveMethodName (method)}' has an invalid BlockProxy attribute (the type passed to the attribute does not have a 'Create' method).")); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (App, 4175, method, $"{(string.IsNullOrEmpty (param.Name) ? $"Parameter #{param.Index + 1}" : $"The parameter '{param.Name}'")} in the method '{GetTypeFullName (method.DeclaringType)}.{GetDescriptiveMethodName (method)}' has an invalid BlockProxy attribute (the type passed to the attribute does not have a 'Create' method).")); // Returning null will make the caller look for the attribute in the base implementation. } return createMethod; @@ -4965,7 +4966,7 @@ void GenerateConversionToManaged (TypeReference inputType, TypeReference outputT func = GetNSStringToSmartEnumFunc (underlyingManagedType, inputType, outputType, descriptiveMethodName, managedClassExpression, out nativeTypeName); if (!IsSmartEnum (underlyingManagedType, out var _, out var getValueMethod)) { // method linked away!? this should already be verified - ErrorHelper.Show (ErrorHelper.CreateWarning (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); token = "INVALID_TOKEN_REF"; } else if (TryCreateTokenReference (getValueMethod, TokenType.Method, out var get_value_method_token_ref, out _)) { token = $"0x{get_value_method_token_ref:X} /* {getValueMethod.FullName} */"; @@ -5061,7 +5062,7 @@ void GenerateConversionToNative (TypeReference inputType, TypeReference outputTy func = GetSmartEnumToNSStringFunc (underlyingManagedType, inputType, outputType, descriptiveMethodName, classVariableName); if (!IsSmartEnum (underlyingManagedType, out var getConstantMethod, out var _)) { // method linked away!? this should already be verified - ErrorHelper.Show (ErrorHelper.CreateWarning (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); token = "INVALID_TOKEN_REF"; } else if (TryCreateTokenReference (getConstantMethod, TokenType.Method, out var get_constant_method_token_ref, out _)) { token = $"0x{get_constant_method_token_ref:X} /* {getConstantMethod.FullName} */"; @@ -5339,7 +5340,7 @@ string TryGeneratePInvokeWrapper (PInvokeWrapperGenerator state, MethodDefinitio sb.WriteLine ("}"); sb.WriteLine (); } else { - // Console.WriteLine ("Signature already processed: {0} for {1}.{2}", signature.ToString (), method.DeclaringType.FullName, method.Name); + // App.Log ("Signature already processed: {0} for {1}.{2}", signature.ToString (), method.DeclaringType.FullName, method.Name); } return wrapperName; @@ -5382,7 +5383,7 @@ public void Register (PlatformResolver? resolver, IEnumerable exceptions) } #endif // !LEGACY_TOOLS - [DllImport (Constants.libSystemLibrary, SetLastError = true)] + [DllImport ("libc", SetLastError = true)] static extern string realpath (string path, IntPtr zero); - public static string GetRealPath (string path, bool warnIfNoSuchPathExists = true) + public static string GetRealPath (IToolLog log, string path, bool warnIfNoSuchPathExists = true) { // For some reason realpath doesn't always like filenames only, and will randomly fail. // Prepend the current directory if there's no directory specified. @@ -80,7 +80,7 @@ public static string GetRealPath (string path, bool warnIfNoSuchPathExists = tru var errno = Marshal.GetLastWin32Error (); if (warnIfNoSuchPathExists || (errno != 2)) - ErrorHelper.Warning (54, Errors.MT0054, path, FileCopier.strerror (errno), errno); + ErrorHelper.Warning (log, 54, Errors.MT0054, path, FileCopier.strerror (errno), errno); return path; } @@ -135,7 +135,7 @@ public void ComputeLinkerFlags () sb.AppendLine ("}"); sb.AppendLine (); - Driver.WriteIfDifferent (reference_m, sb.ToString (), true); + Driver.WriteIfDifferent (App, reference_m, sb.ToString (), true); return reference_m; } @@ -193,7 +193,7 @@ public void GenerateMain (StringBuilder sb, ApplePlatform platform, Abi abi, str throw ErrorHelper.CreateError (71, Errors.MX0071, platform, App.ProductName); } } - Driver.WriteIfDifferent (main_source, sb.ToString (), true); + Driver.WriteIfDifferent (App, main_source, sb.ToString (), true); } catch (ProductException) { throw; } catch (Exception e) { @@ -317,7 +317,7 @@ void GenerateMainImpl (StringWriter sw, Abi abi) sw.WriteLine ("\txamarin_executable_name = \"{0}\";", assembly_name); if (app.XamarinRuntime == XamarinRuntime.MonoVM) sw.WriteLine ("\tmono_use_llvm = {0};", enable_llvm ? "TRUE" : "FALSE"); - sw.WriteLine ("\txamarin_log_level = {0};", Driver.Verbosity.ToString (CultureInfo.InvariantCulture)); + sw.WriteLine ("\txamarin_log_level = {0};", Verbosity.ToString (CultureInfo.InvariantCulture)); sw.WriteLine ("\txamarin_arch_name = \"{0}\";", abi.AsArchString ()); if (!app.IsDefaultMarshalManagedExceptionMode) sw.WriteLine ("\txamarin_marshal_managed_exception_mode = MarshalManagedExceptionMode{0};", app.MarshalManagedExceptions); diff --git a/tools/common/cache.cs b/tools/common/cache.cs index a89b6db7753b..1a7e607f1630 100644 --- a/tools/common/cache.cs +++ b/tools/common/cache.cs @@ -33,77 +33,69 @@ public bool IsCacheTemporary { } // see --cache=DIR - public string Location { - get { - if (cache_dir is null) { - do { - cache_dir = Path.Combine (Path.GetTempPath (), NAME + ".cache", Path.GetRandomFileName ()); - if (File.Exists (cache_dir) || Directory.Exists (cache_dir)) - continue; - Directory.CreateDirectory (cache_dir); - break; - } while (true); - - cache_dir = Application.GetRealPath (cache_dir); - - temporary_cache = true; - if (!Directory.Exists (cache_dir)) - Directory.CreateDirectory (cache_dir); -#if DEBUG - Console.WriteLine ("Cache defaults to {0}", cache_dir); -#endif - } - return cache_dir; - } - set { - cache_dir = value; + public string GetLocation (IToolLog log) + { + if (cache_dir is null) { + do { + cache_dir = Path.Combine (Path.GetTempPath (), NAME + ".cache", Path.GetRandomFileName ()); + if (File.Exists (cache_dir) || Directory.Exists (cache_dir)) + continue; + Directory.CreateDirectory (cache_dir); + break; + } while (true); + + cache_dir = Application.GetRealPath (log, cache_dir); + + temporary_cache = true; if (!Directory.Exists (cache_dir)) Directory.CreateDirectory (cache_dir); - cache_dir = Application.GetRealPath (Path.GetFullPath (cache_dir)); +#if DEBUG + log.Log ("Cache defaults to {0}", cache_dir); +#endif } + return cache_dir; + } + + public void SetLocation (IToolLog log, string value) + { + cache_dir = value; + if (!Directory.Exists (cache_dir)) + Directory.CreateDirectory (cache_dir); + cache_dir = Application.GetRealPath (log, Path.GetFullPath (cache_dir)); } - public void Clean () + public void Clean (IToolLog log) { + var location = GetLocation (log); #if DEBUG - Console.WriteLine ("Cache.Clean: {0}", Location); + log.Log ("Cache.Clean: {0}", location); #endif - Directory.Delete (Location, true); - Directory.CreateDirectory (Location); + Directory.Delete (location, true); + Directory.CreateDirectory (location); } - public static bool CompareFiles (string a, string b, bool ignore_cache = false) + public static bool CompareFiles (IToolLog log, string a, string b) { - if (Driver.Force && !ignore_cache) { - Driver.Log (6, "Files {0} and {1} are considered different because -f was passed to " + NAME + ".", a, b); - return false; - } - if (!File.Exists (b)) { - Driver.Log (6, "Files {0} and {1} are considered different because the latter doesn't exist.", a, b); + log.Log (6, "Files {0} and {1} are considered different because the latter doesn't exist.", a, b); return false; } using (var astream = new FileStream (a, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var bstream = new FileStream (b, FileMode.Open, FileAccess.Read, FileShare.Read)) { bool rv; - Driver.Log (6, "Comparing files {0} and {1}...", a, b); - rv = CompareStreams (astream, bstream, ignore_cache); - Driver.Log (6, " > {0}", rv ? "Identical" : "Different"); + log.Log (6, "Comparing files {0} and {1}...", a, b); + rv = CompareStreams (log, astream, bstream); + log.Log (6, " > {0}", rv ? "Identical" : "Different"); return rv; } } } - public unsafe static bool CompareStreams (Stream astream, Stream bstream, bool ignore_cache = false) + public unsafe static bool CompareStreams (IToolLog log, Stream astream, Stream bstream) { - if (Driver.Force && !ignore_cache) { - Driver.Log (6, " > streams are considered different because -f was passed to " + NAME + "."); - return false; - } - if (astream.Length != bstream.Length) { - Driver.Log (6, " > streams are considered different because their lengths do not match."); + log.Log (6, " > streams are considered different because their lengths do not match."); return false; } @@ -151,20 +143,20 @@ void CollectArgumentsForCache (IList args, int firstArgument, StringBuil public bool IsCacheValid (Application app) { var name = "arguments"; - var pcache = Path.Combine (Location, name); + var pcache = Path.Combine (GetLocation (app), name); if (!File.Exists (pcache)) { - Driver.Log (3, "A full rebuild will be performed because the cache is either incomplete or entirely missing."); + app.Log (3, "A full rebuild will be performed because the cache is either incomplete or entirely missing."); return false; } else if (GetArgumentsForCacheData (app) != File.ReadAllText (pcache)) { - Driver.Log (3, "A full rebuild will be performed because the arguments to " + NAME + " has changed with regards to the cached data."); + app.Log (3, "A full rebuild will be performed because the arguments to " + NAME + " has changed with regards to the cached data."); return false; } // Check if mtouch/mmp has been modified. var executable = System.Reflection.Assembly.GetExecutingAssembly ().Location; - if (!Application.IsUptodate (executable, pcache)) { - Driver.Log (3, "A full rebuild will be performed because " + NAME + " has been modified."); + if (!Application.IsUptodate (app, executable, pcache)) { + app.Log (3, "A full rebuild will be performed because " + NAME + " has been modified."); return false; } @@ -174,7 +166,7 @@ public bool IsCacheValid (Application app) public bool VerifyCache (Application app) { if (!IsCacheValid (app)) { - Clean (); + Clean (app); return false; } @@ -184,54 +176,7 @@ public bool VerifyCache (Application app) public void ValidateCache (Application app) { var name = "arguments"; - var pcache = Path.Combine (Location, name); + var pcache = Path.Combine (GetLocation (app), name); File.WriteAllText (pcache, GetArgumentsForCacheData (app)); } - -#if false - static public void ComputeDependencies (IEnumerable assemblies, MonoTouchResolver resolver) - { - // note: Parallel.ForEach (with lock to add on 'digests') turns out (much) slower - // (linksdk.app with 20 assemblies) - // likely because it's faster (using commoncrypto) than it seems - foreach (string a in assemblies) { - string key = Path.GetFileNameWithoutExtension (a); - using (Stream fs = File.OpenRead (a)) { - string digest = ComputeDigest (fs, 140); - digests.Add (key, digest); - } - } - - Dictionary> dependencies = new Dictionary> (); - foreach (string a in assemblies) { - HashSet references; - AssemblyDefinition ad = resolver.Load (a); - foreach (AssemblyNameReference ar in ad.MainModule.AssemblyReferences) { - if (!dependencies.TryGetValue (ar.Name, out references)) { - references = new HashSet (); - dependencies.Add (ar.Name, references); - } - references.Add (ad.Name.Name); - } - } -#if DEBUG - foreach (var kvp in dependencies) { - Console.WriteLine ("The following assemblies depends on {0}", kvp.Key); - foreach (var s in kvp.Value) - Console.WriteLine ("\t{0}", s); - } -#endif - // if a dependency has changed everything that depends on it must be cleaned - foreach (var kvp in dependencies) { - string cname = kvp.Key + ".*.cache." + GetDigestForAssembly (kvp.Key) + ".o"; - var files = Directory.GetFiles (Location, cname); - if (files.Length != 0) - continue; - - Clean (kvp.Key + "*"); - foreach (var deps in kvp.Value) - Clean (deps + "*"); - } - } -#endif } diff --git a/tools/common/create-makefile-fragment.sh b/tools/common/create-makefile-fragment.sh index 076245d65ca2..d436c538b039 100755 --- a/tools/common/create-makefile-fragment.sh +++ b/tools/common/create-makefile-fragment.sh @@ -33,13 +33,15 @@ fi PROJECT_FILE="$1" PROJECT=$(basename -s .csproj "$PROJECT_FILE") PROJECT_DIR=$(dirname "$PROJECT_FILE") -FRAGMENT_PATH="$2" +FINAL_FRAGMENT_PATH="$2" REFERENCES_PATH=$(pwd)/$PROJECT-references.txt -if test -z "$FRAGMENT_PATH"; then - FRAGMENT_PATH=$PROJECT_FILE.inc +if test -z "$FINAL_FRAGMENT_PATH"; then + FINAL_FRAGMENT_PATH=$PROJECT_FILE.inc fi +FRAGMENT_PATH="$FINAL_FRAGMENT_PATH.$$.tmp" + BUILD_EXECUTABLE="dotnet build" if ! dotnet --version >& /dev/null; then @@ -59,6 +61,7 @@ fi function upon_exit () { rm -f "$PROJECT_DIR/ProjectInspector.csproj" + rm -f "$FRAGMENT_PATH" } trap upon_exit EXIT cp ProjectInspector.csproj "$PROJECT_DIR" @@ -89,6 +92,7 @@ function delete_tmpproj if test -n "$TMPPROJ"; then rm -f "$TMPPROJ" fi + rm -f "$FRAGMENT_PATH" } trap delete_tmpproj EXIT trap delete_tmpproj ERR @@ -138,5 +142,7 @@ if test -z "$ABSOLUTE_PATHS"; then sed "${SED_INPLACE_FLAGS[@]}" "s@$PROJECT_DIR/@@" "$FRAGMENT_PATH" fi +mv "$FRAGMENT_PATH" "$FINAL_FRAGMENT_PATH" + # Cleanup rm -f "${INPUT_PATHS[@]}" diff --git a/tools/common/error.cs b/tools/common/error.cs index d61c1f80f6eb..626a112453e5 100644 --- a/tools/common/error.cs +++ b/tools/common/error.cs @@ -9,8 +9,6 @@ namespace Xamarin.Bundler { public class ProductException : Exception { - public static string Prefix => ErrorHelper.Prefix; - public ProductException (int code, string message) : this (code, false, message) { @@ -49,22 +47,37 @@ public ProductException (int code, bool error, Exception? innerException, string public int Code { get; private set; } - public bool Error { get; private set; } + bool Warning { get; set; } + + public bool IsError (IToolLog? log) + { + if (!Warning) + return true; + if (log is null) + return false; + return ErrorHelper.GetWarningLevel (log, Code) == ErrorHelper.WarningLevel.Error; + } void SetValues (int code, bool error) { Code = code; - Error = error || ErrorHelper.GetWarningLevel (code) == ErrorHelper.WarningLevel.Error; + Warning = !error; } // http://blogs.msdn.com/b/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx public override string ToString () + { + return ToString (null); + } + + // http://blogs.msdn.com/b/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx + public string ToString (IToolLog? log) { var sb = new StringBuilder (); if (!String.IsNullOrEmpty (FileName)) sb.Append (FileName).Append ('(').Append (LineNumber).Append ("): "); - sb.Append (Error ? "error" : "warning").Append (' ').Append (Prefix).Append (Code.ToString ("0000: ")).Append (Message); + sb.Append (IsError (log) ? "error" : "warning").Append (' ').Append (ErrorHelper.GetPrefix (log)).Append (Code.ToString ("0000: ")).Append (Message); return sb.ToString (); } diff --git a/tools/devops/automation/build-pipeline.yml b/tools/devops/automation/build-pipeline.yml index d3e3f8b93895..09f588d9d0c7 100644 --- a/tools/devops/automation/build-pipeline.yml +++ b/tools/devops/automation/build-pipeline.yml @@ -45,7 +45,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main - repository: CustomPipelineTemplates type: git @@ -132,6 +132,7 @@ extends: forceInsertion: ${{ parameters.forceInsertion }} pushNugets: ${{ parameters.pushNugets }} pushNugetsToMaestro: ${{ parameters.pushNugetsToMaestro }} + useACES: true # flip to false to opt CI out of ACES; see templates/variables/common.yml - template: localization/v1.yml@yaml-templates parameters: diff --git a/tools/devops/automation/build-pull-request.yml b/tools/devops/automation/build-pull-request.yml index b6e7f76620cf..cc30c3acf9a0 100644 --- a/tools/devops/automation/build-pull-request.yml +++ b/tools/devops/automation/build-pull-request.yml @@ -36,7 +36,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main - repository: CustomPipelineTemplates type: git @@ -113,3 +113,4 @@ extends: forceInsertion: ${{ parameters.forceInsertion }} pushNugets: false pushNugetsToMaestro: false + useACES: false # flip to true to opt PR into ACES; see templates/variables/common.yml diff --git a/tools/devops/automation/publish-pr-html-results.yml b/tools/devops/automation/publish-pr-html-results.yml index c1b7f08c1b2b..254babc35993 100644 --- a/tools/devops/automation/publish-pr-html-results.yml +++ b/tools/devops/automation/publish-pr-html-results.yml @@ -14,7 +14,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main # we need all stages to be completed, else we do not have the test results, this trigger is just for CI, because we have # but because we have device issues, and it needs to be gree to trigger, we will deal with it later diff --git a/tools/devops/automation/run-ci-api-diff.yml b/tools/devops/automation/run-ci-api-diff.yml index 8ccd511ab0c3..caf428a30870 100644 --- a/tools/devops/automation/run-ci-api-diff.yml +++ b/tools/devops/automation/run-ci-api-diff.yml @@ -17,3 +17,4 @@ extends: parameters: isPR: false pool: $(CIBuildPool) + useACES: true # flip to false to opt CI api-diff out of ACES; see templates/variables/common.yml diff --git a/tools/devops/automation/run-nightly-codeql.yml b/tools/devops/automation/run-nightly-codeql.yml index 1e4144a6028e..f5375ab46ea2 100644 --- a/tools/devops/automation/run-nightly-codeql.yml +++ b/tools/devops/automation/run-nightly-codeql.yml @@ -21,7 +21,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main variables: - template: /tools/devops/automation/templates/variables/common.yml diff --git a/tools/devops/automation/run-post-ci-build-tests.yml b/tools/devops/automation/run-post-ci-build-tests.yml index af8677d8b4e6..f09d70d3e7ba 100644 --- a/tools/devops/automation/run-post-ci-build-tests.yml +++ b/tools/devops/automation/run-post-ci-build-tests.yml @@ -17,3 +17,4 @@ extends: template: templates/pipelines/run-tests-pipeline.yml parameters: isPR: false + useACES: true # flip to false to opt CI simulator tests out of ACES; see templates/variables/common.yml diff --git a/tools/devops/automation/run-post-pr-build-tests.yml b/tools/devops/automation/run-post-pr-build-tests.yml index b83f2d8e95c3..81be17692d32 100644 --- a/tools/devops/automation/run-post-pr-build-tests.yml +++ b/tools/devops/automation/run-post-pr-build-tests.yml @@ -27,3 +27,4 @@ extends: parameters: isPR: true buildPackages: true + useACES: false # flip to true to opt PR simulator tests into ACES; see templates/variables/common.yml diff --git a/tools/devops/automation/run-pr-api-diff.yml b/tools/devops/automation/run-pr-api-diff.yml index 07401bdf077c..03f693b4b5ea 100644 --- a/tools/devops/automation/run-pr-api-diff.yml +++ b/tools/devops/automation/run-pr-api-diff.yml @@ -26,3 +26,4 @@ extends: parameters: isPR: true pool: $(PRBuildPool) + useACES: false # flip to true to opt PR api-diff into ACES; see templates/variables/common.yml diff --git a/tools/devops/automation/scripts/GitHub.psm1 b/tools/devops/automation/scripts/GitHub.psm1 index 82436b73540d..c4b001ee52d1 100644 --- a/tools/devops/automation/scripts/GitHub.psm1 +++ b/tools/devops/automation/scripts/GitHub.psm1 @@ -306,7 +306,7 @@ class GitHubComments { return $true } else { # we might have gotten here because of the trigger type. This means that we are in a PR BUT - # we did not get the PR ids, but those can be found in the diff evirtoment vars + # we did not get the PR ids, but those can be found in the diff environment vars if ($Env:BUILD_REASON -eq "PullRequest") { # set the PR ids to the PR we have in the VSTS env vars $this.PRIds = @($Env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER) @@ -1118,6 +1118,13 @@ function Get-GitHubPRsForHash { Write-Host "Getting related PR ids for commit $Hash" $prs = [System.Collections.ArrayList]@() + + if ($Env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER) { + Write-Host "Found PR in environment: $Env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER" + $prs.Add($Env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER) > $null + return $prs + } + if ($Env:IS_PR -eq "false") { Write-Host "This isn't a PR, IS_PR=false" return $prs diff --git a/tools/devops/automation/templates/api-diff-stage.yml b/tools/devops/automation/templates/api-diff-stage.yml index a81ac79c8bda..e13e9957a7c5 100644 --- a/tools/devops/automation/templates/api-diff-stage.yml +++ b/tools/devops/automation/templates/api-diff-stage.yml @@ -24,6 +24,9 @@ parameters: - name: macOSName type: string +- name: useACES + type: boolean + default: false stages: @@ -69,3 +72,4 @@ stages: gitHubToken: $(Github.Token) xqaCertPass: $(xqa--certificates--password) pool: ${{ parameters.pool }} + useACES: ${{ parameters.useACES }} diff --git a/tools/devops/automation/templates/build/api-diff-stage.yml b/tools/devops/automation/templates/build/api-diff-stage.yml index 03cc9d7f34d9..edac9d79ca91 100644 --- a/tools/devops/automation/templates/build/api-diff-stage.yml +++ b/tools/devops/automation/templates/build/api-diff-stage.yml @@ -34,6 +34,10 @@ parameters: - name: macOSName type: string +- name: useACES + type: boolean + default: false + jobs: # Detect changes - job: api_diff @@ -44,13 +48,19 @@ jobs: # set the branch variable name, this is required by jenkins and we have a lot of scripts that depend on it BRANCH_NAME: $[ replace(variables['Build.SourceBranch'], 'refs/heads/', '') ] XHARNESS_LABELS: $[ stageDependencies.configure_build.configure.outputs['labels.xharness_labels'] ] - pool: - name: ${{ parameters.pool }} - demands: - - Agent.OS -equals Darwin - - Agent.OSVersion -gtVersion $(minimumMacOSVersion) - - macOS.Name -equals ${{ parameters.macOSName }} - - XcodeChannel -equals ${{ parameters.xcodeChannel }} + ${{ if parameters.useACES }}: + pool: + name: $(CIBuildPoolACES) + demands: + - ImageOverride -equals $(CIBuildPoolACESImage) + ${{ else }}: + pool: + name: ${{ parameters.pool }} + demands: + - Agent.OS -equals Darwin + - Agent.OSVersion -gtVersion $(minimumMacOSVersion) + - macOS.Name -equals ${{ parameters.macOSName }} + - XcodeChannel -equals ${{ parameters.xcodeChannel }} workspace: clean: all diff --git a/tools/devops/automation/templates/build/build-mac-tests-stage.yml b/tools/devops/automation/templates/build/build-mac-tests-stage.yml index 0622c8741b5d..be7ea2efb3b1 100644 --- a/tools/devops/automation/templates/build/build-mac-tests-stage.yml +++ b/tools/devops/automation/templates/build/build-mac-tests-stage.yml @@ -34,6 +34,10 @@ parameters: - name: macOSName type: string +- name: useACES + type: boolean + default: false + jobs: # This job builds the macOS tests. @@ -49,14 +53,21 @@ jobs: BRANCH_NAME: $[ replace(variables['Build.SourceBranch'], 'refs/heads/', '') ] RUN_MAC_TESTS: $[ stageDependencies.configure_build.configure.outputs['decisions.RUN_MAC_TESTS'] ] condition: ne(stageDependencies.configure_build.configure.outputs['decisions.RUN_MAC_TESTS'],'') - pool: - os: macOS - name: ${{ parameters.pool }} - demands: - - Agent.OS -equals Darwin - - Agent.OSVersion -gtVersion $(minimumMacOSVersion) - - macOS.Name -equals ${{ parameters.macOSName }} - - XcodeChannel -equals ${{ parameters.xcodeChannel }} + ${{ if parameters.useACES }}: + pool: + os: macOS + name: $(CIBuildPoolACES) + demands: + - ImageOverride -equals $(CIBuildPoolACESImage) + ${{ else }}: + pool: + os: macOS + name: ${{ parameters.pool }} + demands: + - Agent.OS -equals Darwin + - Agent.OSVersion -gtVersion $(minimumMacOSVersion) + - macOS.Name -equals ${{ parameters.macOSName }} + - XcodeChannel -equals ${{ parameters.xcodeChannel }} steps: - template: build-mac-tests.yml diff --git a/tools/devops/automation/templates/build/build-stage.yml b/tools/devops/automation/templates/build/build-stage.yml index c03d3abe9a37..3bd8bc1f799b 100644 --- a/tools/devops/automation/templates/build/build-stage.yml +++ b/tools/devops/automation/templates/build/build-stage.yml @@ -38,6 +38,10 @@ parameters: - name: use1ES type: boolean + - name: useACES + type: boolean + default: false + jobs: # This job performs the build of the nuget pkgs and the framework pkgs. There are two interesting dependencies in this job: - job: build @@ -66,14 +70,21 @@ jobs: BRANCH_NAME: $[ replace(variables['Build.SourceBranch'], 'refs/heads/', '') ] XHARNESS_LABELS: $[ stageDependencies.configure_build.configure.outputs['labels.xharness_labels'] ] RUN_MAC_TESTS: $[ stageDependencies.configure_build.configure.outputs['decisions.RUN_MAC_TESTS'] ] - pool: - os: macOS - name: ${{ parameters.pool }} - demands: - - Agent.OS -equals Darwin - - Agent.OSVersion -gtVersion $(minimumMacOSVersion) - - macOS.Name -equals ${{ parameters.macOSName }} - - XcodeChannel -equals ${{ parameters.xcodeChannel }} + ${{ if parameters.useACES }}: + pool: + os: macOS + name: $(CIBuildPoolACES) + demands: + - ImageOverride -equals $(CIBuildPoolACESImage) + ${{ else }}: + pool: + os: macOS + name: ${{ parameters.pool }} + demands: + - Agent.OS -equals Darwin + - Agent.OSVersion -gtVersion $(minimumMacOSVersion) + - macOS.Name -equals ${{ parameters.macOSName }} + - XcodeChannel -equals ${{ parameters.xcodeChannel }} steps: - template: build-pkgs.yml diff --git a/tools/devops/automation/templates/build/build.yml b/tools/devops/automation/templates/build/build.yml index ae746a2d4776..1eff352e19b6 100644 --- a/tools/devops/automation/templates/build/build.yml +++ b/tools/devops/automation/templates/build/build.yml @@ -82,6 +82,17 @@ steps: HostedMacKeychainPassword: ${{ parameters.keyringPass }} - bash: | + set -eo pipefail + set -x + + XCODE_PATH=$(xcode-select -p 2>/dev/null || true) + if [[ "$XCODE_PATH" != */Contents/Developer || ! -d "$XCODE_PATH" ]]; then + echo "xcode-select does not point to an Xcode developer directory: '$XCODE_PATH'" + exit 1 + fi + export XCODE_DEVELOPER_ROOT="$XCODE_PATH" + export DEVELOPER_DIR="$XCODE_PATH" + make -C $(Build.SourcesDirectory)/$(BUILD_REPOSITORY_TITLE)/tools/devops provisioning displayName: 'Generate provisionator files.' @@ -93,8 +104,18 @@ steps: retryCount: ${{ parameters.retryCount }} # mono does give issues sometimes to download, we will retry - bash: | + set -eo pipefail set -x - set -e + + XCODE_PATH=$(xcode-select -p 2>/dev/null || true) + if [[ "$XCODE_PATH" != */Contents/Developer || ! -d "$XCODE_PATH" ]]; then + echo "xcode-select does not point to an Xcode developer directory: '$XCODE_PATH'" + exit 1 + fi + export XCODE_DEVELOPER_ROOT="$XCODE_PATH" + export DEVELOPER_DIR="$XCODE_PATH" + xcrun -k + ARGS=() ARGS+=(--ignore-all) ARGS+=(--provision-xcode-components) @@ -135,7 +156,17 @@ steps: displayName: "Configure install extra args" timeoutInMinutes: 5 - - bash: $(System.DefaultWorkingDirectory)/$(BUILD_REPOSITORY_TITLE)/configure + - bash: | + set -eo pipefail + set -x + + ARGS=() + XCODE_PATH=$(xcode-select -p 2>/dev/null || true) + if [[ -n "$XCODE_PATH" && -d "$XCODE_PATH" ]]; then + ARGS+=("--xcode=$XCODE_PATH") + fi + + ./configure "${ARGS[@]}" env: ${{ if eq(parameters.isPR, true) }}: IsPR: 'True' diff --git a/tools/devops/automation/templates/common/provision.yml b/tools/devops/automation/templates/common/provision.yml index 6424ffd2103d..b60e12e2fb84 100644 --- a/tools/devops/automation/templates/common/provision.yml +++ b/tools/devops/automation/templates/common/provision.yml @@ -35,6 +35,7 @@ steps: - task: AzureCLI@2 displayName: 'Generate BosStorageMirror SAS tokens' condition: and(succeeded(), ${{ parameters.enabled }}) + retryCountOnTaskFailure: 3 inputs: azureSubscription: 'Xamarin - RelEng (BosStorageMirror-Contributor-MI)' scriptType: 'bash' diff --git a/tools/devops/automation/templates/main-stage.yml b/tools/devops/automation/templates/main-stage.yml index c06cfb6e6828..671be873a5d1 100644 --- a/tools/devops/automation/templates/main-stage.yml +++ b/tools/devops/automation/templates/main-stage.yml @@ -56,6 +56,10 @@ parameters: type: string default: '' + - name: useACES + type: boolean + default: false + stages: - stage: configure_build @@ -103,6 +107,7 @@ stages: xqaCertPass: $(xqa--certificates--password) pool: ${{ parameters.pool }} use1ES: true + useACES: ${{ parameters.useACES }} # .NET Release Prep and VS Insertion Stages, only execute them when the build comes from an official branch and is not a schedule build from OneLoc # setting the stage at this level makes the graph of the UI look better, else the lines overlap and is not clear. diff --git a/tools/devops/automation/templates/pipelines/api-diff-pipeline.yml b/tools/devops/automation/templates/pipelines/api-diff-pipeline.yml index 5b81d42282de..f8fe235e2bb9 100644 --- a/tools/devops/automation/templates/pipelines/api-diff-pipeline.yml +++ b/tools/devops/automation/templates/pipelines/api-diff-pipeline.yml @@ -22,6 +22,10 @@ parameters: type: boolean default: false +- name: useACES + type: boolean + default: false + resources: repositories: - repository: self @@ -31,7 +35,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main variables: - template: ../variables/common.yml @@ -49,3 +53,4 @@ stages: isPR: ${{ parameters.isPR }} provisionatorChannel: ${{ parameters.provisionatorChannel }} pool: ${{ parameters.pool }} + useACES: ${{ parameters.useACES }} diff --git a/tools/devops/automation/templates/pipelines/build-pipeline.yml b/tools/devops/automation/templates/pipelines/build-pipeline.yml index 0d7af904d237..ebd3ee2f4ae7 100644 --- a/tools/devops/automation/templates/pipelines/build-pipeline.yml +++ b/tools/devops/automation/templates/pipelines/build-pipeline.yml @@ -59,7 +59,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main variables: - ${{ if eq(parameters.isPR, false) }}: diff --git a/tools/devops/automation/templates/pipelines/run-api-scan.yml b/tools/devops/automation/templates/pipelines/run-api-scan.yml index 116c6fcbeb61..44fd63925e64 100644 --- a/tools/devops/automation/templates/pipelines/run-api-scan.yml +++ b/tools/devops/automation/templates/pipelines/run-api-scan.yml @@ -25,7 +25,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main - repository: release-scripts type: github diff --git a/tools/devops/automation/templates/pipelines/run-tests-pipeline.yml b/tools/devops/automation/templates/pipelines/run-tests-pipeline.yml index a3ef20748f63..3da391226489 100644 --- a/tools/devops/automation/templates/pipelines/run-tests-pipeline.yml +++ b/tools/devops/automation/templates/pipelines/run-tests-pipeline.yml @@ -36,6 +36,11 @@ parameters: type: boolean default: false + - name: useACES + displayName: Use ACES shared pool for simulator tests + type: boolean + default: false + resources: repositories: - repository: self @@ -45,7 +50,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main variables: - template: ../variables/common.yml @@ -62,3 +67,4 @@ stages: runTests: ${{ parameters.runTests }} runWindowsIntegration: ${{ parameters.runWindowsIntegration }} buildPackages: ${{ parameters.buildPackages }} + useACES: ${{ parameters.useACES }} diff --git a/tools/devops/automation/templates/tests-stage.yml b/tools/devops/automation/templates/tests-stage.yml index b1d242b21e13..94a378b6bafd 100644 --- a/tools/devops/automation/templates/tests-stage.yml +++ b/tools/devops/automation/templates/tests-stage.yml @@ -95,6 +95,10 @@ parameters: type: boolean default: false +- name: useACES + type: boolean + default: false + stages: - template: ./build/linux-build-verification.yml @@ -204,6 +208,7 @@ stages: xqaCertPass: $(xqa--certificates--password) condition: ${{ parameters.runTests }} postPipeline: ${{ not(parameters.buildPackages) }} + useACES: ${{ parameters.useACES }} - template: ./tests/publish-results.yml parameters: @@ -252,6 +257,7 @@ stages: gitHubToken: $(Github.Token) xqaCertPass: $(xqa--certificates--password) pool: $(PRBuildPool) + useACES: ${{ parameters.useACES }} - ${{ each config in parameters.macTestsConfigurations }}: - template: ./mac/stage.yml diff --git a/tools/devops/automation/templates/tests/build.yml b/tools/devops/automation/templates/tests/build.yml index 1eacbac94c70..4e071cd06d33 100644 --- a/tools/devops/automation/templates/tests/build.yml +++ b/tools/devops/automation/templates/tests/build.yml @@ -91,14 +91,19 @@ steps: # if we got to this point, it means that we do have at least 20 Gb to run the test, should # be more than enough, else the above script would have stopped the pipeline - bash: | + set -eo pipefail set -x - set -e cd "$BUILD_REPOSITORY_TITLE" + ARGS=() TEST_PLATFORM=$(echo "${{ parameters.testPlatform }}" | tr '[:upper:]' '[:lower:]') if test -n "$TEST_PLATFORM"; then ARGS+=("--disable-all-platforms") ARGS+=("--enable-$TEST_PLATFORM") fi + XCODE_PATH=$(xcode-select -p 2>/dev/null || true) + if [[ -n "$XCODE_PATH" && -d "$XCODE_PATH" ]]; then + ARGS+=("--xcode=$XCODE_PATH") + fi ./configure "${ARGS[@]}" displayName: 'Enable Xamarin and configure platforms' timeoutInMinutes: 1 @@ -208,6 +213,7 @@ steps: provisioning_script: $(System.DefaultWorkingDirectory)/$(BUILD_REPOSITORY_TITLE)/tools/devops/build-provisioning.csx displayName: 'Provisionator dependencies' provisionatorChannel: $(PROVISIONATOR_CHANNEL) + retryCount: 3 - bash: | set -x diff --git a/tools/devops/automation/templates/tests/run-tests.yml b/tools/devops/automation/templates/tests/run-tests.yml index 188474aa28ea..483f3afbb30c 100644 --- a/tools/devops/automation/templates/tests/run-tests.yml +++ b/tools/devops/automation/templates/tests/run-tests.yml @@ -172,6 +172,22 @@ steps: continueOnError: true condition: succeededOrFailed() +# Upload updated expected app size files if the app size tests produced any. +- bash: | + if [ -d "$(Build.ArtifactStagingDirectory)/updated-expected-sizes" ]; then + echo "##vso[task.setvariable variable=HAS_UPDATED_EXPECTED_SIZES]true" + fi + displayName: 'Check for updated expected app size files' + condition: succeededOrFailed() + +- task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: Updated expected app size files' + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)/updated-expected-sizes' + artifactName: '${{ parameters.uploadPrefix }}updated-expected-sizes-${{ parameters.testPrefix }}-$(System.JobAttempt)' + continueOnError: true + condition: and(succeededOrFailed(), eq(variables['HAS_UPDATED_EXPECTED_SIZES'], 'true')) + - pwsh: | $summaryName = "TestSummary-${{ parameters.testPrefix }}.md" $summaryPath = "$Env:SYSTEM_DEFAULTWORKINGDIRECTORY/$(BUILD_REPOSITORY_TITLE)/tests/TestSummary.md" diff --git a/tools/devops/automation/templates/tests/stage.yml b/tools/devops/automation/templates/tests/stage.yml index 7301307f3f1f..cbe4c4c73881 100644 --- a/tools/devops/automation/templates/tests/stage.yml +++ b/tools/devops/automation/templates/tests/stage.yml @@ -66,6 +66,10 @@ parameters: type: boolean default: false +- name: useACES + type: boolean + default: false + stages: - stage: ${{ parameters.stageName }} displayName: ${{ parameters.displayName }} @@ -89,17 +93,29 @@ stages: BRANCH_NAME: $[ replace(variables['Build.SourceBranch'], 'refs/heads/', '') ] XHARNESS_LABELS: $[ stageDependencies.configure_build.configure.outputs['labels.xharness_labels'] ] DOTNET_PLATFORMS: $[ stageDependencies.configure_build.configure.outputs['configure_platforms.DOTNET_PLATFORMS'] ] - pool: - name: ${{ parameters.testPool }} - demands: - - Agent.OS -equals Darwin - - macOS.Name -equals ${{ parameters.macOSName }} - - macOS.Architecture -equals arm64 - - XcodeChannel -equals ${{ parameters.XcodeChannel }} - - ${{ each demand in parameters.extraBotDemands }}: - - demand - workspace: - clean: all + # The ACES pool is a virtual-machine pool; expose VM_VENDOR so tests + # gated by TestRuntime.AssertNotVirtualMachine get ignored there. + ${{ if parameters.useACES }}: + VM_VENDOR: ACES + ${{ if parameters.useACES }}: + pool: + name: $(CIBuildPoolACES) + demands: + - ImageOverride -equals $(CIBuildPoolACESImage) + workspace: + clean: all + ${{ else }}: + pool: + name: ${{ parameters.testPool }} + demands: + - Agent.OS -equals Darwin + - macOS.Name -equals ${{ parameters.macOSName }} + - macOS.Architecture -equals arm64 + - XcodeChannel -equals ${{ parameters.XcodeChannel }} + - ${{ each demand in parameters.extraBotDemands }}: + - demand + workspace: + clean: all strategy: matrix: $[ stageDependencies.configure_build.configure.outputs['test_matrix.SIMULATOR_TEST_MATRIX'] ] condition: ne(stageDependencies.configure_build.configure.outputs['labels.skip_all_tests'], 'True') diff --git a/tools/devops/automation/templates/variables/common.yml b/tools/devops/automation/templates/variables/common.yml index c596f2b28938..db4b945f053a 100644 --- a/tools/devops/automation/templates/variables/common.yml +++ b/tools/devops/automation/templates/variables/common.yml @@ -45,6 +45,46 @@ variables: - name: CIBuildPoolUrl value: 'https://devdiv.visualstudio.com/_settings/agentpools?poolId=367&view=agents' +# ACES shared pool wiring. +# +# The infrastructure for routing build / api-diff / simulator-test jobs onto +# the ACES shared pool ($(CIBuildPoolACES), image $(CIBuildPoolACESImage)) +# instead of the traditional Redmond Mac build pools ($(CIBuildPool) / +# $(PRBuildPool)) is plumbed through the `useACES` template parameter, which +# flows from each entry pipeline down through main-stage.yml / +# build-stage.yml, api-diff-stage.yml and tests/stage.yml. When `useACES` is +# true, those job-level templates emit: +# pool: +# name: $(CIBuildPoolACES) +# demands: ImageOverride -equals $(CIBuildPoolACESImage) +# Otherwise they emit the original pool + Darwin / macOS.Name / XcodeChannel +# demands. +# +# The switch MUST be a literal in the entry pipeline. Azure Pipelines only +# resolves `${{ }}` expressions at template-expansion time, and variables +# brought in via `- template:` (like this file) are not visible at that +# point — they are runtime-only. So there is no working "single global +# variable" we can read here; the literal lives in each entry pipeline: +# +# CI (uses CIBuildPool / ACES): +# - build-pipeline.yml -> useACES: true +# - run-ci-api-diff.yml -> useACES: true +# - run-post-ci-build-tests.yml -> useACES: true +# PR (uses PRBuildPool): +# - build-pull-request.yml -> useACES: false +# - run-pr-api-diff.yml -> useACES: false +# - run-post-pr-build-tests.yml -> useACES: false +# +# Flip the literal in the three files on the side you want to move (e.g. when +# the ACES pool is unavailable, or when you need an Xcode/macOS beta that is +# only present on the traditional pools) and queue a new run. +- name: CIBuildPoolACES + value: 'AcesShared' +- name: CIBuildPoolACESUrl + value: 'https://dev.azure.com/devdiv/DevDiv/_settings/agentqueues?queueId=8259&view=jobs' +- name: CIBuildPoolACESImage + value: 'ACES_VM_SharedPool_Tahoe' + # override the default build revision - name: BUILD_REVISION value: azure-devops-$(Build.SourceVersion) diff --git a/tools/devops/automation/vs-insertion.yml b/tools/devops/automation/vs-insertion.yml index 90eef300b8a1..f98208720aed 100644 --- a/tools/devops/automation/vs-insertion.yml +++ b/tools/devops/automation/vs-insertion.yml @@ -12,7 +12,7 @@ resources: - repository: yaml-templates type: git name: xamarin.yaml-templates - ref: e30b445c2ffcbebe75efdd69546d7196a20c5a43 + ref: refs/heads/main # we need all stages to be completed, else we do not have the test results, this trigger is just for CI, because we have # but because we have device issues, and it needs to be gree to trigger, we will deal with it later diff --git a/tools/dotnet-linker/AppBundleRewriter.cs b/tools/dotnet-linker/AppBundleRewriter.cs index 5013997108d1..1b3908f009ea 100644 --- a/tools/dotnet-linker/AppBundleRewriter.cs +++ b/tools/dotnet-linker/AppBundleRewriter.cs @@ -70,6 +70,7 @@ public AssemblyDefinition SystemConsoleAssembly { Dictionary> type_map = new (); Dictionary method_map = new (); Dictionary field_map = new (); + Dictionary created_types = new (); public AppBundleRewriter (LinkerConfiguration configuration) { @@ -1450,6 +1451,7 @@ public void ClearCurrentAssembly () type_map.Clear (); method_map.Clear (); field_map.Clear (); + created_types.Clear (); } public CustomAttribute CreateAttribute (MethodReference constructor) @@ -1676,5 +1678,53 @@ static bool DebugAttributes { return debug_attributes.Value; } } + + public TypeDefinition GetOrCreateType (ModuleDefinition module, string @namespace, string @typename, out bool created) + { + created = false; + + var fullName = @namespace + "." + typename; + if (!created_types.TryGetValue (fullName, out var cachedTypeDefinition)) { + cachedTypeDefinition = module.Types.FirstOrDefault (t => t.Namespace == @namespace && t.Name == typename); + if (cachedTypeDefinition is null) { + cachedTypeDefinition = new TypeDefinition (@namespace, typename, TypeAttributes.Public | TypeAttributes.Sealed, module.TypeSystem.Object); + module.Types.Add (cachedTypeDefinition); + created = true; + } + created_types [fullName] = cachedTypeDefinition; + } + + return cachedTypeDefinition; + } + + public MethodDefinition CreateInternalPInvoke (ModuleDefinition module, string @namespace, string @typename, string methodName, out bool created) + { + var cachedTypeDefinition = GetOrCreateType (module, @namespace, @typename, out _); + var nativeMethod = methodName; + var rv = cachedTypeDefinition.Methods.FirstOrDefault (m => m.Name == methodName); + if (rv is not null) { + created = false; + return rv; // already exists, no need to create it again + } + + // [DllImport ("__Internal")] + // static extern IntPtr {methodName} (); + + rv = new MethodDefinition (methodName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PInvokeImpl, System_IntPtr); + rv.IsPreserveSig = true; + + var mod = module.ModuleReferences.FirstOrDefault (mr => mr.Name == "__Internal"); + if (mod is null) { + mod = new ModuleReference ("__Internal"); + module.ModuleReferences.Add (mod); + } + rv.PInvokeInfo = new PInvokeInfo (PInvokeAttributes.CharSetNotSpec | PInvokeAttributes.CallConvCdecl, nativeMethod, mod); + + cachedTypeDefinition.Methods.Add (rv); + + created = true; + + return rv; + } } } diff --git a/tools/dotnet-linker/BackingFieldDelayHandler.cs b/tools/dotnet-linker/BackingFieldDelayHandler.cs index be9b46adf828..9a61786f7c0d 100644 --- a/tools/dotnet-linker/BackingFieldDelayHandler.cs +++ b/tools/dotnet-linker/BackingFieldDelayHandler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Linker; @@ -38,7 +39,7 @@ public override void Initialize (LinkContext context, MarkContext markContext) } // cache `Dispose` body of optimization NSObject subclasses - static Dictionary dispose = new (); + static ConditionalWeakTable> disposes = new (); protected override void Process (MethodDefinition method) { @@ -54,7 +55,7 @@ protected override void Process (MethodDefinition method) return; // keep original for later (if needed) - dispose.Add (method, method.Body); + disposes.GetOrCreateValue (LinkContext).Add (method, method.Body); // setting body to null will only cause it to be reloaded again // same if we don't get a new IL processor @@ -68,6 +69,10 @@ protected override void Process (MethodDefinition method) public static void ReapplyDisposedFields (DerivedLinkContext context, string operation) { // note: all methods in the dictionary are marked (since they were added from an IMarkHandler) + if (!disposes.TryGetValue (context, out var dispose)) + return; + + var app = context.App; foreach ((var method, var body) in dispose) { foreach (var ins in body.Instructions) { switch (ins.OpCode.OperandType) { @@ -79,9 +84,9 @@ public static void ReapplyDisposedFields (DerivedLinkContext context, string ope var store_field = ins; var load_null = ins.Previous; var load_this = ins.Previous.Previous; - if (OptimizeGeneratedCodeHandler.ValidateInstruction (method, store_field, operation, Code.Stfld) && - OptimizeGeneratedCodeHandler.ValidateInstruction (method, load_null, operation, Code.Ldnull) && - OptimizeGeneratedCodeHandler.ValidateInstruction (method, load_this, operation, Code.Ldarg_0)) { + if (OptimizeGeneratedCodeHandler.ValidateInstruction (app, method, store_field, operation, Code.Stfld) && + OptimizeGeneratedCodeHandler.ValidateInstruction (app, method, load_null, operation, Code.Ldnull) && + OptimizeGeneratedCodeHandler.ValidateInstruction (app, method, load_this, operation, Code.Ldarg_0)) { store_field.OpCode = OpCodes.Nop; load_null.OpCode = OpCodes.Nop; load_this.OpCode = OpCodes.Nop; diff --git a/tools/dotnet-linker/DotNetResolver.cs b/tools/dotnet-linker/DotNetResolver.cs index 37e04bb9e1f9..f71c2ec5b4cb 100644 --- a/tools/dotnet-linker/DotNetResolver.cs +++ b/tools/dotnet-linker/DotNetResolver.cs @@ -8,6 +8,10 @@ namespace Xamarin.Linker { public class DotNetResolver : CoreResolver { + public DotNetResolver (Application app) + { + } + public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters) { throw new NotImplementedException ($"Unable to resolve the assembly reference {name}"); diff --git a/tools/dotnet-linker/PreserveSmartEnumConversionsStep.cs b/tools/dotnet-linker/PreserveSmartEnumConversionsStep.cs index 75ebca8360dd..7dae7ba20e13 100644 --- a/tools/dotnet-linker/PreserveSmartEnumConversionsStep.cs +++ b/tools/dotnet-linker/PreserveSmartEnumConversionsStep.cs @@ -94,6 +94,7 @@ class PreserveSmartEnumConversion { Dictionary> cache = new (); public DerivedLinkContext LinkContext { get; private set; } + public Application App => LinkContext.App; Func, bool, MethodDefinition? [], bool> preserve { get; set; } @@ -122,14 +123,14 @@ public bool ProcessAttributeProvider (ICustomAttributeProvider provider, params continue; if (ca.ConstructorArguments.Count != 1) { - ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 4124, provider, Errors.MT4124_E, provider.AsString (), ca.ConstructorArguments.Count)); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (LinkContext.App, 4124, provider, Errors.MT4124_E, provider.AsString (), ca.ConstructorArguments.Count)); continue; } var managedType = ca.ConstructorArguments [0].Value as TypeReference; var managedEnumType = managedType?.GetElementType ().Resolve (); if (managedEnumType is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 4124, provider, Errors.MT4124_H, provider.AsString (), managedType?.FullName ?? "(null)")); + ErrorHelper.Show (App, ErrorHelper.CreateWarning (LinkContext.App, 4124, provider, Errors.MT4124_H, provider.AsString (), managedType?.FullName ?? "(null)")); continue; } @@ -155,7 +156,7 @@ public bool ProcessAttributeProvider (ICustomAttributeProvider provider, params break; } if (extensionType is null) { - Driver.Log (1, $"Could not find a smart extension type for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); + App.Log (1, $"Could not find a smart extension type for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); continue; } @@ -184,12 +185,12 @@ public bool ProcessAttributeProvider (ICustomAttributeProvider provider, params } if (getConstant is null) { - Driver.Log (1, $"Could not find the GetConstant method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); + App.Log (1, $"Could not find the GetConstant method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); continue; } if (getValue is null) { - Driver.Log (1, $"Could not find the GetValue method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); + App.Log (1, $"Could not find the GetValue method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); continue; } diff --git a/tools/dotnet-linker/SetupStep.cs b/tools/dotnet-linker/SetupStep.cs index 3d1ecf296cf3..a6fb4461aef7 100644 --- a/tools/dotnet-linker/SetupStep.cs +++ b/tools/dotnet-linker/SetupStep.cs @@ -22,7 +22,6 @@ public class SetupStep : ConfigurationAwareStep { protected override void TryProcess () { Configuration.Write (); - ErrorHelper.Platform = Configuration.Platform; Directory.CreateDirectory (Configuration.ItemsDirectory); Directory.CreateDirectory (Configuration.CacheDirectory); } diff --git a/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs b/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs index 56423d905bff..7c5eb5ca3775 100644 --- a/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs +++ b/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs @@ -136,7 +136,7 @@ Exception [] CollectExceptions (Exception e, Func createExcept // If we're only reporting warnings, then don't add the step-specific exception at all. if (CollectProductExceptions (e, out var productExceptions)) { // don't add inner exception - if (productExceptions.Any (v => v.Error)) { + if (productExceptions.Any (v => v.IsError (App))) { var ex = createException (); // instead return an aggregate exception with the original exception and all the ProductExceptions we're reporting. productExceptions.Add (ex); diff --git a/tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs b/tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs index 4eda1e9f18f3..25153aca76fa 100644 --- a/tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs +++ b/tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs @@ -34,6 +34,8 @@ public virtual void Initialize (LinkContext context) protected Profile Profile => Configuration.Profile; + protected Application App => Configuration.Application; + public void ProcessAssembly (AssemblyDefinition assembly) { try { diff --git a/tools/dotnet-linker/Steps/InlineClassGetHandleStep.cs b/tools/dotnet-linker/Steps/InlineClassGetHandleStep.cs new file mode 100644 index 000000000000..11e8dd1996b8 --- /dev/null +++ b/tools/dotnet-linker/Steps/InlineClassGetHandleStep.cs @@ -0,0 +1,271 @@ +using System.Linq; +using System.Text; + +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Linker; +using Mono.Tuner; + +using Xamarin.Bundler; +using Xamarin.Utils; + +#nullable enable + +namespace Xamarin.Linker.Steps; + +// See docs/code/class-handles.md for an overview of class handle handling. + +// Find all the references to Objective-C classes for each assembly. +// * If an assembly is trimmed, we replace calls to (inline) Class.GetHandle with a P/Invoke that fetches the class in question. +// * If an assembly is not trimmed, we do not inline Class.GetHandle, but we keep a list of all the Objective-C classes that are used, so that we can tell the native linker about them so they're not linked away by the native linker. +// +// The sticky problem is that we can't inspect the managed output from NativeAOT, which means +// we can't list the Objective-C classes NativeAOT-compiled assemblies using. To get around this +// problem, we convert calls to Class.GetHandle to a P/Invoke which fetches the native Objective-C +// class handle directly - because we _can_ list the P/Invoke calls from NativeAOT-compiled code. +// +// For non-trimmed assemblies, we don't need to do this, because we know nothing from the assembly +// will be trimmed away. This has the added advantage of being Hot Reload compatible, because we +// can't modify assemblies when we're doing Hot Reload. + +public class InlineClassGetHandleStep : AssemblyModifierStep { + + protected override string Name { get; } = "Inline Class GetHandle"; + protected override int ErrorCode { get; } = 2262; + + bool strictMode; + bool? inlining_enabled; + + Dictionary objectiveCTypeMap = new (); + + public const string PInvokePrefix = "xamarin_Class_GetHandle_"; + public const string PInvokeSuffix = "_Native"; + + protected override void TryProcess () + { + strictMode = Configuration.InlineClassGetHandle == InlineClassGetHandleMode.Strict; + + if (strictMode && Configuration.Application.Registrar == Bundler.RegistrarMode.Dynamic) { + Report (ErrorHelper.CreateError (Configuration.Application, 2262, null, Errors.MX2262)); + } + + objectiveCTypeMap = DerivedLinkContext.StaticRegistrar.Types.ToDictionary (v => v.Value.ExportedName, v => v.Value); + + if (!string.IsNullOrEmpty (Configuration.TypeMapFilePath)) { + var sb = new StringBuilder (); + foreach (var info in objectiveCTypeMap.Values.OrderBy (v => v.ExportedName)) { + var td = info.Type.Resolve (); + if (td is null) + continue; + var introduced = DerivedLinkContext.StaticRegistrar.GetSdkIntroducedVersion (td, out _); + Frameworks.TryGetFramework (App, td, out string? framework); + sb.AppendLine ($"Class={info.ExportedName}|Framework={framework}|Introduced={introduced}|IsWrapper={info.IsWrapper}|IsStubClass={info.IsStubClass}"); + } + Driver.WriteIfDifferent (App, Configuration.TypeMapFilePath, sb.ToString ()); + } + + base.TryProcess (); + } + + protected override bool IsActiveFor (AssemblyDefinition assembly) + { + if (!Configuration.Profile.IsOrReferencesProductAssembly (assembly)) + return false; + + // we have to process both trimmed and non-trimmed assemblies. + + return true; + } + + protected override bool ModifyAssembly (AssemblyDefinition assembly) + { + inlining_enabled = Annotations.GetAction (assembly) == AssemblyAction.Link; + var modified = base.ModifyAssembly (assembly); + inlining_enabled = null; + return modified; + } + + protected override bool ProcessType (TypeDefinition type) + { + var modified = false; + + if (inlining_enabled == true) { + modified |= ProcessMethods (type); + } else { + if (ListExportedSymbols.TryGetRequiredObjectiveCType (DerivedLinkContext, type, out var exportedName)) { + DerivedLinkContext.RequiredSymbols.AddObjectiveCClass (exportedName).AddMember (type); + } + } + return modified; + } + + MethodDefinition GetOrCreatePInvokeMethod (MethodDefinition callingMethod, string objectiveCClassName) + { + // [DllImport ("__Internal")] + // static extern IntPtr xamarin_Class_GetClassHandle_{objectiveCClassName}_Native (); + + return abr.CreateInternalPInvoke (callingMethod.Module, "ObjCRuntime", "Class", $"{PInvokePrefix}{objectiveCClassName}{PInvokeSuffix}", out _); + } + + protected override bool ProcessMethod (MethodDefinition method) + { + var modified = false; + + if (!method.HasBody) + return modified; + + if (method.DeclaringType.Name == "Class" && method.DeclaringType.Namespace == "ObjCRuntime") + return modified; // don't process the Class methods themselves + + bool isOurOwnCode () + { + // Don't show warnings for a few places in our own code where we call Class.GetHandle in un-inlinable ways. + switch (method.DeclaringType.Namespace) { + case "Registrar": + switch (method.DeclaringType.Name) { + case "DynamicRegistrar": + switch (method.Name) { + case "OnReloadType": + case "OnRegisterType": + return true; + } + break; + } + break; + } + return false; + } + + foreach (var instr in method.Body.Instructions) { + if (instr.Operand is not MethodReference mr) + continue; + if (mr.DeclaringType.Name != "Class" || mr.DeclaringType.Namespace != "ObjCRuntime") + continue; + if (mr.Name != "GetHandle" && mr.Name != "GetHandleIntrinsic") + continue; + if (mr.Parameters.Count != 1) + continue; + if (!mr.Parameters [0].ParameterType.Is ("System", "String")) + continue; + if (!mr.ReturnType.Is ("ObjCRuntime", "NativeHandle")) + continue; + + var ldstr = instr.Previous; + if (ldstr.OpCode != OpCodes.Ldstr) { + if (!isOurOwnCode ()) + App.Log (3, "Unknown or unsupported pattern in call to Class.GetHandle in '{0}': {1}. The call will not be inlined.", FormatMethod (method), ldstr); + continue; + } + if (ldstr.Operand is not string objectiveCClassName) { + if (!isOurOwnCode ()) + App.Log (3, "Unknown or unsupported pattern in call to Class.GetHandle in '{0}': {1}. The call will not be inlined.", FormatMethod (method), ldstr.Operand); + continue; + } + + if (!objectiveCTypeMap.TryGetValue (objectiveCClassName, out var objCType)) { + App.Log (3, "Could not find a managed type for the Objective-C type '{1}' in the call to Class.GetHandle in '{0}', assuming the Objective-C type is available in the simulator.", FormatMethod (method), objectiveCClassName); + } + + if (!strictMode) { + if (objCType is not null && objCType.Type == method.DeclaringType) { + // This is a call to Class.GetHandle for the same class that it's being called from, this is OK. + } else if (ListExportedSymbols.TryGetRequiredObjectiveCType (DerivedLinkContext, method.DeclaringType, out var exportedName)) { + if (exportedName != objectiveCClassName) { + App.Log (3, "The call to Class.GetHandle in '{0}' is trying to get the handle for the Objective-C class '{1}', but the declaring type's exported name is '{2}', not '{1}'. Since we're in compat mode, we're assuming the class should not be preserved.", FormatMethod (method), objectiveCClassName, exportedName); + continue; + } + } else { + if (App.StaticRegistrar.GetCategoryAttribute (method.DeclaringType) is not null) + App.Log (3, "The call to Class.GetHandle in '{0}' is trying to get the handle for the Objective-C class '{1}', but we couldn't determine whether this class should be statically preserved or not. Since we're in compat mode, we're assuming the class should not be statically preserved.", FormatMethod (method), objectiveCClassName); + continue; + } + } + + // Check if the Objective-C class is listed as a ReferenceNativeSymbol with Ignore mode, and if so, don't inline the call to Class.GetHandle (because the native symbol won't be available at link time) + var existingSymbol = DerivedLinkContext.RequiredSymbols.Find (Symbol.ObjectiveCPrefix + objectiveCClassName); + if (existingSymbol is not null && existingSymbol.Type == SymbolType.ObjectiveCClass && existingSymbol.Mode == SymbolMode.Ignore) { + App.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the class is listed as a ReferenceNativeSymbol with Ignore mode.", objectiveCClassName, FormatMethod (method)); + continue; + } + + if (objCType is not null) { + if (DerivedLinkContext.App.IsSimulatorBuild) { + if (DerivedLinkContext.HasAvailabilityAttributesShowingUnavailableInSimulator (objCType.Type.Resolve (), method)) { + App.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the type is marked with an attribute indicating it's not available in the simulator.", objectiveCClassName, FormatMethod (method)); + continue; + } + } + + if (IsUnsupported (objCType.Type.Resolve ())) { + App.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the type is marked with an [UnsupportedOSPlatform] attribute.", objectiveCClassName, FormatMethod (method)); + continue; + } + + if (objCType.Methods is null && DerivedLinkContext.StaticRegistrar.IsPlatformType (objCType.Type) && !objCType.IsProtocol && !objCType.IsCategory && objCType.IsModel) { + // The static registrar skips generating code for this type, so we shouldn't inline calls to Class.GetHandle for it, because the P/Invoke we generate won't be able to find the native symbol for it. + continue; + } + + if (Frameworks.TryGetFramework (App, objCType.Type.Resolve (), out Framework? framework) && framework.IsFrameworkUnavailable (App)) { + App.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the framework {2} is unavailable.", objectiveCClassName, FormatMethod (method), framework.Name); + continue; + } + + if (objCType.Type.Is ("UIKit", "UITitlebar")) { + // UITitlebar is a weird special case, the class exists in the headers, and it's documented online, but it's not possible to link with it (not even in an Xcode project, it's not in any .tbd files). + continue; + } + + if (objCType.Type.Namespace == "BrowserEngineKit" || objCType.Type.Namespace == "BrowserEngineCore") { + // Most apps do not use BrowserEngineKit, and linking with it when an app is not supposed to will prevent it from getting approved in the App Store. + // So we treat these frameworks specially, where we don't link with these two frameworks by default, *even if they're detected as used*, + // which means we shouldn't inline Class.GetHandle calls for any classes in these frameworks, since native linking will fail. + continue; + } + } + + ldstr.OpCode = OpCodes.Call; + ldstr.Operand = GetOrCreatePInvokeMethod (method, objectiveCClassName); + + instr.OpCode = OpCodes.Call; + instr.Operand = abr.NativeObject_op_Implicit_NativeHandle; + + modified = true; + } + + return modified; + } + + bool IsUnsupported (TypeDefinition? type) + { + if (type is null) + return false; + + if (!type.HasCustomAttributes) + return false; + + foreach (var ca in type.CustomAttributes) { + if (!ca.AttributeType.Is ("System.Runtime.Versioning", "UnsupportedOSPlatformAttribute")) + continue; + + if (!DerivedLinkContext.StaticRegistrar.GetDotNetAvailabilityAttribute (ca, App.Platform, out var sdkVersion, out _)) + continue; + + if (sdkVersion is null) + return true; // if there's no version, then it's always unavailable + + return sdkVersion <= App.SdkVersion; + } + + return false; + } + + static string FormatMethod (MethodReference method) + { + var rv = method.FullName; + var idx = rv.IndexOf (' '); + if (idx > 0) + rv = rv.Substring (idx + 1); + return rv; + } +} diff --git a/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs b/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs index d6b214986d02..95913f88ead9 100644 --- a/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs +++ b/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs @@ -28,6 +28,9 @@ public class InlineDlfcnMethodsStep : AssemblyModifierStep { bool strictMode; + public const string PInvokePrefix = "xamarin_Dlfcn_"; + public const string PInvokeSuffix = "_Native"; + protected override void TryProcess () { strictMode = Configuration.InlineDlfcnMethods == InlineDlfcnMethodsMode.Strict; @@ -40,7 +43,7 @@ protected override bool ProcessType (TypeDefinition type) var modified = false; if (type.HasMethods) { if (Frameworks.TryGetFramework (App, type, out Framework? framework) && framework.IsFrameworkUnavailable (App)) { - Driver.Log (3, $"Type {type.FullName} appears to be part of the '{framework.Name}' framework, which is not available in the current SDK. Skipping inlining Dlfcn calls for this type."); + App.Log (3, $"Type {type.FullName} appears to be part of the '{framework.Name}' framework, which is not available in the current SDK. Skipping inlining Dlfcn calls for this type."); return modified; } @@ -99,18 +102,15 @@ TypeDefinition GetDlfcnType (ModuleDefinition module, string @namespace, string? { var frameworkOverride = !string.IsNullOrEmpty (fieldLibraryName) ? fieldLibraryName : current_framework; var ns = string.IsNullOrEmpty (frameworkOverride) ? @namespace : frameworkOverride; - var dlfcn = module.Types.FirstOrDefault (t => t.Namespace == ns && t.Name == "Dlfcn"); - if (dlfcn is null) { - dlfcn = new TypeDefinition (ns, "Dlfcn", TypeAttributes.NotPublic | TypeAttributes.Sealed, module.TypeSystem.Object); - module.Types.Add (dlfcn); - + var rv = abr.GetOrCreateType (module, ns, "Dlfcn", out var created); + if (created) { if (!string.IsNullOrEmpty (frameworkOverride)) { - var attrib = new CustomAttribute (abr.ObjectiveCFrameworkAttribute_ctor_String); + var attrib = abr.CreateAttribute (abr.ObjectiveCFrameworkAttribute_ctor_String); attrib.ConstructorArguments.Add (new CustomAttributeArgument (abr.System_String, frameworkOverride)); - dlfcn.CustomAttributes.Add (attrib); + rv.CustomAttributes.Add (attrib); } } - return dlfcn; + return rv; } void AddField (string assemblyName, string symbolName) @@ -124,30 +124,13 @@ void AddField (string assemblyName, string symbolName) MethodDefinition GetOrCreatePInvokeMethod (MethodDefinition callingMethod, string symbolName) { - var dlfcn = GetDlfcnType (callingMethod); - var methodName = $"xamarin_Dlfcn_{symbolName}_Native"; - var nativeMethod = methodName; - var rv = dlfcn.Methods.FirstOrDefault (m => m.Name == methodName); - if (rv is not null) - return rv; // already exists, no need to create it again - // [DllImport ("__Internal")] // static extern IntPtr xamarin_Dlfcn_{symbolName}_Native (); - rv = new MethodDefinition (methodName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PInvokeImpl, abr.System_IntPtr); - rv.IsPreserveSig = true; - - var mod = callingMethod.Module.ModuleReferences.FirstOrDefault (mr => mr.Name == "__Internal"); - if (mod is null) { - mod = new ModuleReference ("__Internal"); - callingMethod.Module.ModuleReferences.Add (mod); - } - rv.PInvokeInfo = new PInvokeInfo (PInvokeAttributes.CharSetNotSpec | PInvokeAttributes.CallConvCdecl, nativeMethod, mod); - - dlfcn.Methods.Add (rv); - - AddField (callingMethod.Module.Assembly.Name.Name, symbolName); - + var methodName = $"{PInvokePrefix}{symbolName}{PInvokeSuffix}"; + var rv = abr.CreateInternalPInvoke (callingMethod.Module, callingMethod.DeclaringType.Namespace, "Dlfcn", methodName, out var created); + if (created) + AddField (callingMethod.Module.Assembly.Name.Name, symbolName); return rv; } @@ -542,11 +525,11 @@ protected override bool ProcessMethod (MethodDefinition method) if (DerivedLinkContext.App.IsSimulatorBuild) { // if the method or its declaring type aren't available in the simulator, and we're building for the simulator, then don't inline. if (DerivedLinkContext.HasAvailabilityAttributesShowingUnavailableInSimulator (method, method)) { - Driver.Log (3, $"Method {method.FullName} is not available in the simulator. Skipping inlining Dlfcn calls for this method."); + App.Log (3, $"Method {method.FullName} is not available in the simulator. Skipping inlining Dlfcn calls for this method."); return modified; } if (DerivedLinkContext.HasAvailabilityAttributesShowingUnavailableInSimulator (method.DeclaringType, method)) { - Driver.Log (3, $"Type {method.DeclaringType.FullName} is not available in the simulator. Skipping inlining Dlfcn calls for this type."); + App.Log (3, $"Type {method.DeclaringType.FullName} is not available in the simulator. Skipping inlining Dlfcn calls for this type."); return modified; } } diff --git a/tools/dotnet-linker/Steps/ManagedRegistrarLookupTablesStep.cs b/tools/dotnet-linker/Steps/ManagedRegistrarLookupTablesStep.cs index a0d764222e29..68bbe468e009 100644 --- a/tools/dotnet-linker/Steps/ManagedRegistrarLookupTablesStep.cs +++ b/tools/dotnet-linker/Steps/ManagedRegistrarLookupTablesStep.cs @@ -330,7 +330,7 @@ void GenerateConstructNSObject (TypeDefinition registrarType) foreach (var type in types) { var ctorRef = FindNSObjectConstructor (type); if (ctorRef is null) { - Driver.Log (9, $"Cannot include {type.FullName} in ConstructNSObject because it doesn't have a suitable constructor"); + App.Log (9, $"Cannot include {type.FullName} in ConstructNSObject because it doesn't have a suitable constructor"); continue; } @@ -652,7 +652,7 @@ void GenerateLookupUnmanagedFunction (TypeDefinition registrar_type, IList 0) { // All the methods in a given assembly will have consecutive IDs (but might not start at 0). if (trampolineInfos.First ().Id + trampolineInfos.Count - 1 != trampolineInfos.Last ().Id) diff --git a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs index cfc23620e1d7..70c4cc72a7bf 100644 --- a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs +++ b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs @@ -1315,7 +1315,7 @@ void GenerateConversionToNative (MethodDefinition method, ILProcessor il, TypeRe } else if (underlyingNativeType.Is ("Foundation", "NSString")) { if (!StaticRegistrar.IsSmartEnum (underlyingManagedType, out var getConstantMethod, out var getValueMethod)) { // method linked away!? this should already be verified - ErrorHelper.Show (ErrorHelper.CreateError (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); + ErrorHelper.Show (App, ErrorHelper.CreateError (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); return; } diff --git a/tools/dotnet-linker/Steps/TrimmableRegistrarStep.cs b/tools/dotnet-linker/Steps/TrimmableRegistrarStep.cs index cf3f544bc5b6..e494cec5a972 100644 --- a/tools/dotnet-linker/Steps/TrimmableRegistrarStep.cs +++ b/tools/dotnet-linker/Steps/TrimmableRegistrarStep.cs @@ -47,7 +47,7 @@ AssemblyDefinition CreateTypeMapRootAssembly (ModuleParameters moduleParameters, AssemblyDefinition rootTypeMapAssembly; // .NET 10 doesn't support a separate root type map assembly, so we have to add these attributes to the entry assembly instead. - var useEntryAssemblyAsRootTypeMapAssembly = Driver.TargetFramework.Version.Major <= 10; + var useEntryAssemblyAsRootTypeMapAssembly = App.TargetFramework.Version.Major <= 10; if (useEntryAssemblyAsRootTypeMapAssembly) { rootTypeMapAssembly = Configuration.EntryAssembly; diff --git a/tools/dotnet-linker/dotnet-linker.csproj b/tools/dotnet-linker/dotnet-linker.csproj index 853bba62528f..c3ff1f126681 100644 --- a/tools/dotnet-linker/dotnet-linker.csproj +++ b/tools/dotnet-linker/dotnet-linker.csproj @@ -71,6 +71,9 @@ external/tools/common/FileUtils.cs + + external/tools/common/IToolLog.cs + external/tools/common/LinkMode.cs diff --git a/tools/linker/CoreOptimizeGeneratedCode.cs b/tools/linker/CoreOptimizeGeneratedCode.cs index 85cf938052a0..c33d231aeb66 100644 --- a/tools/linker/CoreOptimizeGeneratedCode.cs +++ b/tools/linker/CoreOptimizeGeneratedCode.cs @@ -67,28 +67,33 @@ static protected void Nop (Instruction ins) ins.Operand = null; } - internal static bool ValidateInstruction (MethodDefinition caller, Instruction ins, string operation, Code expected) + internal static bool ValidateInstruction (OptimizeGeneratedCodeData data, MethodDefinition caller, Instruction ins, string operation, Code expected) + { + return ValidateInstruction (data.App, caller, ins, operation, expected); + } + + internal static bool ValidateInstruction (IToolLog log, MethodDefinition caller, Instruction ins, string operation, Code expected) { if (ins.OpCode.Code != expected) { - Driver.Log (1, "Could not {0} in {1} at offset {2}, expected {3} got {4}", operation, caller, ins.Offset, expected, ins); + log.Log (1, "Could not {0} in {1} at offset {2}, expected {3} got {4}", operation, caller, ins.Offset, expected, ins); return false; } return true; } - internal static bool ValidateInstruction (MethodDefinition caller, Instruction ins, string operation, params Code [] expected) + internal static bool ValidateInstruction (OptimizeGeneratedCodeData data, MethodDefinition caller, Instruction ins, string operation, params Code [] expected) { foreach (var code in expected) { if (ins.OpCode.Code == code) return true; } - Driver.Log (1, "Could not {0} in {1} at offset {2}, expected any of [{3}] got {4}", operation, caller, ins.Offset, string.Join (", ", expected), ins); + data.App.Log (1, "Could not {0} in {1} at offset {2}, expected any of [{3}] got {4}", operation, caller, ins.Offset, string.Join (", ", expected), ins); return false; } - static int? GetConstantValue (Instruction? ins) + static int? GetConstantValue (OptimizeGeneratedCodeData data, Instruction? ins) { if (ins is null) return null; @@ -159,13 +164,13 @@ internal static bool ValidateInstruction (MethodDefinition caller, Instruction i #endif default: #if DEBUG - Driver.Log (9, "Unknown conditional instruction: {0}", ins); + data.App.Log (9, "Unknown conditional instruction: {0}", ins); #endif return null; } } - static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic.Collection instructions, bool [] reachable, int start, int end) + static bool MarkInstructions (OptimizeGeneratedCodeData data, MethodDefinition method, Mono.Collections.Generic.Collection instructions, bool [] reachable, int start, int end) { if (reachable [start]) return true; // We've already marked this section of code @@ -178,7 +183,7 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. case FlowControl.Branch: // Unconditional branch, we continue marking from the instruction that we branch to. var br_target = (Instruction) ins.Operand; - return MarkInstructions (method, instructions, reachable, instructions.IndexOf (br_target), instructions.Count); + return MarkInstructions (data, method, instructions, reachable, instructions.IndexOf (br_target), instructions.Count); case FlowControl.Cond_Branch: // Conditional instruction, we need to check if we can calculate a constant value for the condition var cond_target = ins.Operand as Instruction; @@ -190,26 +195,26 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. // FIXME: calculate the potential constant branch (currently there are no optimizable methods where the switch condition is constant, so this is not needed for now) var targets = ins.Operand as Instruction []; if (targets is null) { - Driver.Log (4, "Can't optimize {0} because of unknown target of branch instruction {1} {2}", method, ins, ins.Operand); + data.App.Log (4, "Can't optimize {0} because of unknown target of branch instruction {1} {2}", method, ins, ins.Operand); return false; } foreach (var target in targets) { // not constant, continue marking both this code sequence and the branched sequence - if (!MarkInstructions (method, instructions, reachable, instructions.IndexOf (target), end)) + if (!MarkInstructions (data, method, instructions, reachable, instructions.IndexOf (target), end)) return false; } - return MarkInstructions (method, instructions, reachable, instructions.IndexOf (ins.Next), end); + return MarkInstructions (data, method, instructions, reachable, instructions.IndexOf (ins.Next), end); } if (cond_target is null) { - Driver.Log (4, "Can't optimize {0} because of unknown target of branch instruction {1} {2}", method, ins, ins.Operand); + data.App.Log (4, "Can't optimize {0} because of unknown target of branch instruction {1} {2}", method, ins, ins.Operand); return false; } switch (ins.OpCode.Code) { case Code.Brtrue: case Code.Brtrue_S: { - var v = GetConstantValue (ins.Previous); + var v = GetConstantValue (data, ins.Previous); if (v.HasValue) branch = v.Value != 0; cond_instruction_count = 2; @@ -217,7 +222,7 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. } case Code.Brfalse: case Code.Brfalse_S: { - var v = GetConstantValue (ins.Previous); + var v = GetConstantValue (data, ins.Previous); if (v.HasValue) branch = v.Value == 0; cond_instruction_count = 2; @@ -225,8 +230,8 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. } case Code.Beq: case Code.Beq_S: { - var x1 = GetConstantValue (ins.Previous?.Previous); - var x2 = GetConstantValue (ins.Previous); + var x1 = GetConstantValue (data, ins.Previous?.Previous); + var x2 = GetConstantValue (data, ins.Previous); if (x1.HasValue && x2.HasValue) branch = x1.Value == x2.Value; cond_instruction_count = 3; @@ -234,8 +239,8 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. } case Code.Bne_Un: case Code.Bne_Un_S: { - var x1 = GetConstantValue (ins.Previous?.Previous); - var x2 = GetConstantValue (ins.Previous); + var x1 = GetConstantValue (data, ins.Previous?.Previous); + var x2 = GetConstantValue (data, ins.Previous); if (x1.HasValue && x2.HasValue) branch = x1.Value != x2.Value; cond_instruction_count = 3; @@ -245,8 +250,8 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: { - var x1 = GetConstantValue (ins.Previous?.Previous); - var x2 = GetConstantValue (ins.Previous); + var x1 = GetConstantValue (data, ins.Previous?.Previous); + var x2 = GetConstantValue (data, ins.Previous); if (x1.HasValue && x2.HasValue) branch = x1.Value <= x2.Value; cond_instruction_count = 3; @@ -256,8 +261,8 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: { - var x1 = GetConstantValue (ins.Previous?.Previous); - var x2 = GetConstantValue (ins.Previous); + var x1 = GetConstantValue (data, ins.Previous?.Previous); + var x2 = GetConstantValue (data, ins.Previous); if (x1.HasValue && x2.HasValue) branch = x1.Value < x2.Value; cond_instruction_count = 3; @@ -267,8 +272,8 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: { - var x1 = GetConstantValue (ins.Previous?.Previous); - var x2 = GetConstantValue (ins.Previous); + var x1 = GetConstantValue (data, ins.Previous?.Previous); + var x2 = GetConstantValue (data, ins.Previous); if (x1.HasValue && x2.HasValue) branch = x1.Value >= x2.Value; cond_instruction_count = 3; @@ -278,15 +283,15 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: { - var x1 = GetConstantValue (ins.Previous?.Previous); - var x2 = GetConstantValue (ins.Previous); + var x1 = GetConstantValue (data, ins.Previous?.Previous); + var x2 = GetConstantValue (data, ins.Previous); if (x1.HasValue && x2.HasValue) branch = x1.Value > x2.Value; cond_instruction_count = 3; break; } default: - Driver.Log ("Can't optimize {0} because of unknown branch instruction: {1}", method, ins); + data.App.Log ("Can't optimize {0} because of unknown branch instruction: {1}", method, ins); break; } @@ -294,13 +299,13 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. // Make sure nothing else in the method branches into the middle of our supposedly constant condition, // bypassing our constant calculation. Note that it's not a bad to branch to the _first_ instruction in // the sequence (thus the +2 here), just into the middle of it. - if (AnyBranchTo (instructions, instructions [i - cond_instruction_count + 2], ins)) + if (AnyBranchTo (data, instructions, instructions [i - cond_instruction_count + 2], ins)) branch = null; } if (!branch.HasValue) { // not constant, continue marking both this code sequence and the branched sequence - if (!MarkInstructions (method, instructions, reachable, instructions.IndexOf (cond_target), end)) + if (!MarkInstructions (data, method, instructions, reachable, instructions.IndexOf (cond_target), end)) return false; } else { // we can remove the branch (and the code that loads the condition), so we mark those instructions as dead. @@ -310,7 +315,7 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. // Now continue marking according to whether we branched or not if (branch.Value) { // branch always taken - return MarkInstructions (method, instructions, reachable, instructions.IndexOf (cond_target), end); + return MarkInstructions (data, method, instructions, reachable, instructions.IndexOf (cond_target), end); } else { // branch never taken // continue looping @@ -329,7 +334,7 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. case FlowControl.Meta: case FlowControl.Phi: default: - Driver.Log (4, "Can't optimize {0} because of unknown flow control for: {1}", method, ins); + data.App.Log (4, "Can't optimize {0} because of unknown flow control for: {1}", method, ins); return false; } } @@ -338,10 +343,10 @@ static bool MarkInstructions (MethodDefinition method, Mono.Collections.Generic. } // Check if there are any branches in the instructions that branch to anywhere between 'first' and 'last' instructions (both inclusive). - static bool AnyBranchTo (Mono.Collections.Generic.Collection instructions, Instruction first, Instruction last) + static bool AnyBranchTo (OptimizeGeneratedCodeData data, Mono.Collections.Generic.Collection instructions, Instruction first, Instruction last) { if (first.Offset > last.Offset) { - Driver.Log ($"Broken assumption: {first} is after {last}"); + data.App.Log ($"Broken assumption: {first} is after {last}"); return true; // This is the safe thing to do, since it will prevent inlining } @@ -373,7 +378,7 @@ static bool EliminateDeadCode (OptimizeGeneratedCodeData data, MethodDefinition // marking all reachable instructions. Any non-reachable instructions at the end // can be removed. - if (!MarkInstructions (caller, instructions, reachable, 0, instructions.Count)) + if (!MarkInstructions (data, caller, instructions, reachable, 0, instructions.Count)) return modified; // Handle exception handlers specially, they do not follow normal code flow. @@ -407,19 +412,19 @@ static bool EliminateDeadCode (OptimizeGeneratedCodeData data, MethodDefinition } } if (!allNops) { - if (!MarkInstructions (caller, instructions, reachable, instructions.IndexOf (eh.HandlerStart), instructions.IndexOf (eh.HandlerEnd))) + if (!MarkInstructions (data, caller, instructions, reachable, instructions.IndexOf (eh.HandlerStart), instructions.IndexOf (eh.HandlerEnd))) return modified; } break; case ExceptionHandlerType.Finally: // finally clauses are always executed, even if the protected region is empty - if (!MarkInstructions (caller, instructions, reachable, instructions.IndexOf (eh.HandlerStart), instructions.IndexOf (eh.HandlerEnd))) + if (!MarkInstructions (data, caller, instructions, reachable, instructions.IndexOf (eh.HandlerStart), instructions.IndexOf (eh.HandlerEnd))) return modified; break; case ExceptionHandlerType.Fault: case ExceptionHandlerType.Filter: // FIXME: and until fixed, exit gracefully without doing anything - Driver.Log (4, "Unhandled exception handler: {0}, skipping dead code elimination for {1}", eh.HandlerType, caller); + data.App.Log (4, "Unhandled exception handler: {0}, skipping dead code elimination for {1}", eh.HandlerType, caller); return modified; } } @@ -475,7 +480,7 @@ static bool EliminateDeadCode (OptimizeGeneratedCodeData data, MethodDefinition case FlowControl.Cond_Branch: var target = (Instruction) ins.Operand; if (target.Offset > last_reachable_offset) { - Driver.Log (4, "Can't optimize {0} because of branching beyond last instruction alive: {1}", caller, ins); + data.App.Log (4, "Can't optimize {0} because of branching beyond last instruction alive: {1}", caller, ins); return modified; } break; @@ -483,13 +488,13 @@ static bool EliminateDeadCode (OptimizeGeneratedCodeData data, MethodDefinition } } #if false - Console.WriteLine ($"{caller.FullName}:"); + data.App.Log ($"{caller.FullName}:"); for (int i = 0; i < reachable.Length; i++) { - Console.WriteLine ($"{(reachable [i] ? " " : "- ")} {instructions [i]}"); + data.App.Log ($"{(reachable [i] ? " " : "- ")} {instructions [i]}"); if (!reachable [i]) Nop (instructions [i]); } - Console.WriteLine (); + data.App.Log (""); #endif // Exterminate, exterminate, exterminate @@ -648,7 +653,7 @@ static bool ProcessEnsureUIThread (OptimizeGeneratedCodeData data, MethodDefinit // Verify a few assumptions before doing anything const string operation = "remove calls to [NS|UI]Application::EnsureUIThread"; - if (!ValidateInstruction (caller, ins, operation, Code.Call)) + if (!ValidateInstruction (data, caller, ins, operation, Code.Call)) return false; // This is simple: just remove the call @@ -680,10 +685,10 @@ static bool ProcessIsDirectBinding (OptimizeGeneratedCodeData data, MethodDefini return false; // Verify a few assumptions before doing anything - if (!ValidateInstruction (caller, ins.Previous, operation, Code.Ldarg_0)) + if (!ValidateInstruction (data, caller, ins.Previous, operation, Code.Ldarg_0)) return false; - if (!ValidateInstruction (caller, ins, operation, Code.Call)) + if (!ValidateInstruction (data, caller, ins, operation, Code.Call)) return false; // Clearing the branch succeeded, so clear the condition too @@ -742,10 +747,10 @@ static bool ProcessSetupBlock (OptimizeGeneratedCodeData data, MethodDefinition prev = prev.Previous; // Skip any nops. if (prev.OpCode.StackBehaviourPush != StackBehaviour.Push1) { //todo: localize mmp error 2106 - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106, caller, ins.Offset, mr.Name, prev)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106, caller, ins.Offset, mr.Name, prev)); return false; } else if (prev.OpCode.StackBehaviourPop != StackBehaviour.Pop0) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106, caller, ins.Offset, mr.Name, prev)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106, caller, ins.Offset, mr.Name, prev)); return false; } @@ -756,22 +761,22 @@ static bool ProcessSetupBlock (OptimizeGeneratedCodeData data, MethodDefinition // Then find the type of the previous instruction (the first argument to SetupBlock[Unsafe]) var trampolineDelegateType = GetPushedType (caller, loadTrampolineInstruction); if (trampolineDelegateType is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106_A, caller, ins.Offset, mr.Name, loadTrampolineInstruction)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106_A, caller, ins.Offset, mr.Name, loadTrampolineInstruction)); return false; } if (trampolineDelegateType.Is ("System", "Delegate") || trampolineDelegateType.Is ("System", "MulticastDelegate")) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106_B, caller, trampolineDelegateType.FullName, mr.Name)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106_B, caller, trampolineDelegateType.FullName, mr.Name)); return false; } if (!data.LinkContext.App.StaticRegistrar.TryComputeBlockSignature (caller, trampolineDelegateType, out var exception, out signature)) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, exception, caller, ins, Errors.MM2106_D, caller, ins.Offset, exception.Message)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, exception, caller, ins, Errors.MM2106_D, caller, ins.Offset, exception.Message)); return false; } } catch (Exception e) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, e, caller, ins, Errors.MM2106_D, caller, ins.Offset, e.Message)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, e, caller, ins, Errors.MM2106_D, caller, ins.Offset, e.Message)); return false; } @@ -854,34 +859,34 @@ static bool ProcessBlockLiteralConstructor (OptimizeGeneratedCodeData data, Meth // Verify 'ldstr ...' var loadString = GetPreviousSkippingNops (ins); if (loadString.OpCode != OpCodes.Ldstr) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadString)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadString)); return false; } // Verify 'call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)' var callGetTypeFromHandle = GetPreviousSkippingNops (loadString); if (callGetTypeFromHandle.OpCode != OpCodes.Call || !(callGetTypeFromHandle.Operand is MethodReference methodOperand) || methodOperand.Name != "GetTypeFromHandle" || !methodOperand.DeclaringType.Is ("System", "Type")) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, callGetTypeFromHandle)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, callGetTypeFromHandle)); return false; } // Verify 'ldtoken ...' var loadType = GetPreviousSkippingNops (callGetTypeFromHandle); if (loadType.OpCode != OpCodes.Ldtoken) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadType)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadType)); return false; } // Then find the type of the previous instruction var trampolineContainerTypeReference = loadType.Operand as TypeReference; if (trampolineContainerTypeReference is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadType.Operand)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadType.Operand)); return false; } var trampolineContainerType = trampolineContainerTypeReference.Resolve (); if (trampolineContainerType is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, trampolineContainerTypeReference)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, trampolineContainerTypeReference)); return false; } @@ -889,15 +894,15 @@ static bool ProcessBlockLiteralConstructor (OptimizeGeneratedCodeData data, Meth var trampolineMethodName = (string) loadString.Operand; var trampolineMethods = trampolineContainerType.Methods.Where (v => v.Name == trampolineMethodName).ToArray (); if (!trampolineMethods.Any ()) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_E1 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because no method named '{3}' was found in the type '{4}'. */, caller, ins.Offset, mr.Name, trampolineMethodName, trampolineContainerType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_E1 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because no method named '{3}' was found in the type '{4}'. */, caller, ins.Offset, mr.Name, trampolineMethodName, trampolineContainerType.FullName)); return false; } else if (trampolineMethods.Count () > 1) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_E2 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because more than one method named '{3}' was found in the type '{4}'. */, caller, ins.Offset, mr.Name, trampolineMethodName, trampolineContainerType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_E2 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because more than one method named '{3}' was found in the type '{4}'. */, caller, ins.Offset, mr.Name, trampolineMethodName, trampolineContainerType.FullName)); return false; } var trampolineMethod = trampolineMethods [0]; if (!trampolineMethod.HasParameters || trampolineMethod.Parameters.Count < 1) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_F /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' must have at least one parameter. */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_F /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' must have at least one parameter. */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName)); return false; } @@ -908,18 +913,18 @@ static bool ProcessBlockLiteralConstructor (OptimizeGeneratedCodeData data, Meth } else if (firstParameterType is PointerType ptrType) { var ptrTargetType = ptrType.ElementType; if (!(ptrTargetType.Is ("System", "Void") || ptrTargetType.Is ("ObjCRuntime", "BlockLiteral"))) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_G /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName, firstParameterType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_G /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName, firstParameterType.FullName)); return false; } // ok } else { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_G /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName, firstParameterType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_G /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName, firstParameterType.FullName)); return false; } // Check that the method has [UnmanagedCallersOnly] if (!trampolineMethod.HasCustomAttributes || !trampolineMethod.CustomAttributes.Any (v => v.AttributeType.Is ("System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute"))) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_H /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute. */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MX2106_H /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute. */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName)); return false; } @@ -933,7 +938,7 @@ static bool ProcessBlockLiteralConstructor (OptimizeGeneratedCodeData data, Meth } if (userMethod is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106_D, caller, ins.Offset, "Could not find delegate invoke method")); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, caller, ins, Errors.MM2106_D, caller, ins.Offset, "Could not find delegate invoke method")); return false; } @@ -945,7 +950,7 @@ static bool ProcessBlockLiteralConstructor (OptimizeGeneratedCodeData data, Meth sequenceStart = loadType; } catch (Exception e) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2106, e, caller, ins, Errors.MM2106_D, caller, ins.Offset, e.Message)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2106, e, caller, ins, Errors.MM2106_D, caller, ins.Offset, e.Message)); return false; } @@ -963,7 +968,7 @@ static bool ProcessBlockLiteralConstructor (OptimizeGeneratedCodeData data, Meth // Change the call to call the ctor with the string signature parameter instead ins.Operand = GetBlockLiteralConstructor (data, caller, ins); - Driver.Log (4, "Optimized call to BlockLiteral..ctor in {0} at offset {1} with signature {2}", caller, ins.Offset, signature); + data.App.Log (4, "Optimized call to BlockLiteral..ctor in {0} at offset {1} with signature {2}", caller, ins.Offset, signature); instructionsAddedOrRemoved = instructionDiff; return true; } @@ -1004,7 +1009,7 @@ static bool ProcessIsARM64CallingConvention (OptimizeGeneratedCodeData data, Met if (fr is null || !fr.DeclaringType.Is (Namespaces.ObjCRuntime, "Runtime")) return false; - if (!ValidateInstruction (caller, ins, operation, Code.Ldsfld)) + if (!ValidateInstruction (data, caller, ins, operation, Code.Ldsfld)) return false; // We're fine, inline the Runtime.IsARM64CallingConvention value @@ -1027,7 +1032,7 @@ static bool ProcessRuntimeArch (OptimizeGeneratedCodeData data, MethodDefinition return false; // Verify a few assumptions before doing anything - if (!ValidateInstruction (caller, ins, operation, Code.Ldsfld)) + if (!ValidateInstruction (data, caller, ins, operation, Code.Ldsfld)) return false; // We're fine, inline the Runtime.Arch condition @@ -1153,52 +1158,52 @@ static bool ProcessProtocolInterfaceStaticConstructor (OptimizeGeneratedCodeData return false; if (data.Optimizations.RegisterProtocols != true) { - Driver.Log (4, "Did not optimize static constructor in the protocol interface {0}: the 'register-protocols' optimization is disabled.", method.DeclaringType.FullName); + data.App.Log (4, "Did not optimize static constructor in the protocol interface {0}: the 'register-protocols' optimization is disabled.", method.DeclaringType.FullName); return false; } if (!method.DeclaringType.HasCustomAttributes || !method.DeclaringType.CustomAttributes.Any (v => v.AttributeType.Is ("Foundation", "ProtocolAttribute"))) { - Driver.Log (4, "Did not optimize static constructor in the protocol interface {0}: no Protocol attribute found.", method.DeclaringType.FullName); + data.App.Log (4, "Did not optimize static constructor in the protocol interface {0}: no Protocol attribute found.", method.DeclaringType.FullName); return false; } var ins = SkipNops (method.Body.Instructions.First ()); if (ins is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName)); return false; } else if (ins.OpCode != OpCodes.Ldnull) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); return false; } ins = SkipNops (ins.Next); if (ins is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName)); return false; } var callGCKeepAlive = ins; if (callGCKeepAlive.OpCode != OpCodes.Call || !(callGCKeepAlive.Operand is MethodReference methodOperand) || methodOperand.Name != "KeepAlive" || !methodOperand.DeclaringType.Is ("System", "GC")) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); return false; } ins = SkipNops (ins.Next); if (ins is null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_A /* Could not optimize the static constructor in the interface {0} because it did not have the expected instruction sequence (found end of method too soon). */, method.DeclaringType.FullName)); return false; } else if (ins.OpCode != OpCodes.Ret) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); return false; } ins = SkipNops (ins.Next); if (ins is not null) { - ErrorHelper.Show (ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); + ErrorHelper.Show (data.App, ErrorHelper.CreateWarning (data.LinkContext.App, 2112, method, ins, Errors.MX2112_B /* Could not optimize the static constructor in the interface {0} because it had an unexpected instruction {1} at offset {2}. */, method.DeclaringType.FullName, ins.OpCode, ins.Offset)); return false; } // We can just remove the entire method, however that confuses the linker later on, so just empty it out and remove all the attributes. - Driver.Log (4, "Optimized static constructor in the protocol interface {0} (static constructor was cleared and custom attributes removed)", method.DeclaringType.FullName); + data.App.Log (4, "Optimized static constructor in the protocol interface {0} (static constructor was cleared and custom attributes removed)", method.DeclaringType.FullName); method.Body.Instructions.Clear (); method.Body.Instructions.Add (Instruction.Create (OpCodes.Ret)); @@ -1234,6 +1239,8 @@ public class OptimizeGeneratedCodeData { public MethodDefinition? SetupBlockImplDefinition; public MethodDefinition? BlockCtorDefinition; public bool? InlineIsArm64CallingConvention; + + public Application App => LinkContext.App; } } diff --git a/tools/linker/CoreTypeMapStep.cs b/tools/linker/CoreTypeMapStep.cs index 76fd37c49770..c180cf3b43fc 100644 --- a/tools/linker/CoreTypeMapStep.cs +++ b/tools/linker/CoreTypeMapStep.cs @@ -167,7 +167,7 @@ bool IsWrapperType (TypeDefinition type) // Cache the results of the IsCIFilter check in a dictionary. It makes this method slightly faster // (total time spent in IsCIFilter when linking monotouch-test went from 11 ms to 3ms). - static Dictionary ci_filter_types = new Dictionary (); + Dictionary ci_filter_types = new Dictionary (); bool IsCIFilter (TypeReference type) { if (type is null) diff --git a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs index eda79a994f73..bb2193ab35ad 100644 --- a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs +++ b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs @@ -18,7 +18,6 @@ namespace Xamarin.Linker.Steps { public class ListExportedSymbols : BaseStep { PInvokeWrapperGenerator? state; - bool is_product_assembly; PInvokeWrapperGenerator? State { get { @@ -80,8 +79,6 @@ protected override void ProcessAssembly (AssemblyDefinition assembly) if (!hasSymbols) return; - is_product_assembly = Configuration.Profile.IsProductAssembly (assembly); - var modified = false; foreach (var type in assembly.MainModule.Types) modified |= ProcessType (type); @@ -114,40 +111,41 @@ bool ProcessType (TypeDefinition type) void AddRequiredObjectiveCType (TypeDefinition type) { + if (TryGetRequiredObjectiveCType (DerivedLinkContext, type, out var exportedName)) + DerivedLinkContext.RequiredSymbols.AddObjectiveCClass (exportedName).AddMember (type); + } + + // Returns true if the specified type represents an Objective-C class that should be referenced as a required symbol, so that the native linker doesn't link it away. + public static bool TryGetRequiredObjectiveCType (DerivedLinkContext derivedLinkContext, TypeDefinition type, [NotNullWhen (true)] out string? exportedName) + { + exportedName = null; + // The product assembly only has one type we may need to keep: XamarinSwiftFunctions - if (is_product_assembly) { + if (derivedLinkContext.LinkerConfiguration.Profile.IsProductAssembly (type.Module.Assembly)) { switch (type.Name) { case "XamarinSwiftFunctions": break; default: - return; + return false; } } - var staticRegistrar = DerivedLinkContext.StaticRegistrar; + var staticRegistrar = derivedLinkContext.StaticRegistrar; if (staticRegistrar is null) - return; + return false; - var registerAttribute = staticRegistrar.GetRegisterAttribute (type); - if (registerAttribute is null) - return; + if (!staticRegistrar.TryGetExportedTypeName (type, out exportedName)) + return false; - if (!registerAttribute.IsWrapper) - return; - - if (staticRegistrar.HasProtocolAttribute (type)) - return; - - if (DerivedLinkContext.App.RequireLinkWithAttributeForObjectiveCClassSearch) { + if (derivedLinkContext.App.RequireLinkWithAttributeForObjectiveCClassSearch) { var has_linkwith_attributes = false; - if (DerivedLinkContext.App.Assemblies.TryGetValue (type.Module.Assembly, out var asm)) + if (derivedLinkContext.App.Assemblies.TryGetValue (type.Module.Assembly, out var asm)) has_linkwith_attributes = asm.HasLinkWithAttributes; if (!has_linkwith_attributes) - return; + return false; } - var exportedName = staticRegistrar.GetExportedTypeName (type, registerAttribute); - DerivedLinkContext.RequiredSymbols.AddObjectiveCClass (exportedName).AddMember (type); + return true; } bool ProcessMethod (MethodDefinition method) @@ -191,25 +189,30 @@ bool ProcessMethod (MethodDefinition method) switch (pinfo.Module.Name) { case "__Internal": - // For NativeAOT builds, don't add inlined dlfcn P/Invoke wrappers as - // required symbols: only the surviving ones will have native code generated, - // so force-referencing all of them causes linker errors for symbols that - // NativeAOT trimmed away. For non-NativeAOT builds, the wrappers are resolved - // via dlsym and need the -u flags to be exported from the binary. - if (Configuration.InlineDlfcnMethodsEnabled && Configuration.Application.XamarinRuntime == XamarinRuntime.NativeAOT && pinfo.EntryPoint.StartsWith ("xamarin_Dlfcn_", StringComparison.Ordinal)) - break; - Driver.Log (4, "Adding native reference to {0} in {1} because it's referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); + if (Configuration.Application.XamarinRuntime == XamarinRuntime.NativeAOT) { + // For NativeAOT builds, don't add inlined dlfcn P/Invoke wrappers as + // required symbols: only the surviving ones will have native code generated, + // so force-referencing all of them causes linker errors for symbols that + // NativeAOT trimmed away. For non-NativeAOT builds, the wrappers are resolved + // via dlsym and need the -u flags to be exported from the binary. + if (Configuration.InlineDlfcnMethodsEnabled && pinfo.EntryPoint.StartsWith (InlineDlfcnMethodsStep.PInvokePrefix, StringComparison.Ordinal)) + break; + // Same goes for inlined Class.GetHandle calls. + if (Configuration.InlineClassGetHandle != InlineClassGetHandleMode.Disabled && pinfo.EntryPoint.StartsWith (InlineClassGetHandleStep.PInvokePrefix, StringComparison.Ordinal)) + break; + } + DerivedLinkContext.App.Log (4, "Adding native reference to {0} in {1} because it's referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); DerivedLinkContext.RequiredSymbols.AddFunction (pinfo.EntryPoint).AddMember (method); break; default: if (!addPInvokeSymbol) - Driver.Log (4, "Did not add native reference to {0} in {1} referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); + DerivedLinkContext.App.Log (4, "Did not add native reference to {0} in {1} referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); break; } if (addPInvokeSymbol) { - Driver.Log (4, "Adding native reference to {0} in {1} because it's referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); + DerivedLinkContext.App.Log (4, "Adding native reference to {0} in {1} because it's referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); DerivedLinkContext.RequireMonoNative = true; if (DerivedLinkContext.App.Platform != ApplePlatform.MacOSX && DerivedLinkContext.App.LibMonoNativeLinkMode == AssemblyBuildTarget.StaticObject) { diff --git a/tools/linker/RegistrarRemovalTrackingStep.cs b/tools/linker/RegistrarRemovalTrackingStep.cs index f88452f3ccd0..b2cd10bc170c 100644 --- a/tools/linker/RegistrarRemovalTrackingStep.cs +++ b/tools/linker/RegistrarRemovalTrackingStep.cs @@ -153,7 +153,7 @@ bool RequiresDynamicRegistrar (AssemblyDefinition assembly, bool warnIfRequired) void Warn (AssemblyDefinition assembly, MemberReference mr) { - ErrorHelper.Warning (WarnCode, Errors.MM2107, assembly.Name.Name, mr.DeclaringType.FullName, mr.Name, string.Join (", ", ((MethodReference) mr).Parameters.Select ((v) => v.ParameterType.FullName))); + ErrorHelper.Warning (App, WarnCode, Errors.MM2107, assembly.Name.Name, mr.DeclaringType.FullName, mr.Name, string.Join (", ", ((MethodReference) mr).Parameters.Select ((v) => v.ParameterType.FullName))); } protected override void TryEndProcess () @@ -164,7 +164,7 @@ protected override void TryEndProcess () Optimizations.RemoveDynamicRegistrar = !dynamic_registration_support_required; } - Driver.Log (4, "Optimization dynamic registrar removal: {0}", Optimizations.RemoveDynamicRegistrar.Value ? "enabled" : "disabled"); + App.Log (4, "Optimization dynamic registrar removal: {0}", Optimizations.RemoveDynamicRegistrar.Value ? "enabled" : "disabled"); if (Optimizations.RemoveDynamicRegistrar.Value) { // ILLink will optimize `Runtime.Initialize` based on `DynamicRegistrationSupported` returning a constant (`true`) diff --git a/tools/mtouch/AssemblyResolver.cs b/tools/mtouch/AssemblyResolver.cs index f63d6ebebbe7..3b2f94d2d865 100644 --- a/tools/mtouch/AssemblyResolver.cs +++ b/tools/mtouch/AssemblyResolver.cs @@ -22,14 +22,10 @@ #nullable enable namespace MonoTouch.Tuner { - - public partial class MonoTouchManifestResolver : MonoTouchResolver { - } - // recent cecil removed some overloads - https://github.com/mono/cecil/commit/42db79cc16f1cbe8dbab558904e188352dba2b41 public static class AssemblyResolverRocks { - static ReaderParameters defaults = new ReaderParameters (); + static readonly ReaderParameters defaults = new ReaderParameters (); public static AssemblyDefinition Resolve (this IAssemblyResolver self, string fullName) { @@ -41,6 +37,12 @@ public static AssemblyDefinition Resolve (this IAssemblyResolver self, string fu } public class MonoTouchResolver : CoreResolver { + Application app; + + public MonoTouchResolver (Application app) + { + this.app = app; + } public IEnumerable GetAssemblies () { @@ -63,29 +65,29 @@ public void Add (AssemblyDefinition assembly) if (FrameworkDirectory is not null) { var facadeDir = Path.Combine (FrameworkDirectory, "Facades"); - assembly = SearchDirectory (aname, facadeDir); + assembly = SearchDirectory (app, aname, facadeDir); if (assembly is not null) return assembly; } if (ArchDirectory is not null) { - assembly = SearchDirectory (aname, ArchDirectory); + assembly = SearchDirectory (app, aname, ArchDirectory); if (assembly is not null) return assembly; } if (FrameworkDirectory is not null) { - assembly = SearchDirectory (aname, FrameworkDirectory); + assembly = SearchDirectory (app, aname, FrameworkDirectory); if (assembly is not null) return assembly; } if (RootDirectory is not null) { - assembly = SearchDirectory (aname, RootDirectory); + assembly = SearchDirectory (app, aname, RootDirectory); if (assembly is not null) return assembly; - assembly = SearchDirectory (aname, RootDirectory, ".exe"); + assembly = SearchDirectory (app, aname, RootDirectory, ".exe"); if (assembly is not null) return assembly; } diff --git a/tools/mtouch/Errors.designer.cs b/tools/mtouch/Errors.designer.cs index ee92d9580d81..7c3f1861b4ab 100644 --- a/tools/mtouch/Errors.designer.cs +++ b/tools/mtouch/Errors.designer.cs @@ -3596,6 +3596,15 @@ public static string MX2261 { } } + /// + /// Looks up a localized string similar to The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar.. + /// + public static string MX2262 { + get { + return ResourceManager.GetString("MX2262", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not {0} the assembly '{1}'. /// diff --git a/tools/mtouch/Errors.resx b/tools/mtouch/Errors.resx index 987d7c75e479..cc89125d1ff1 100644 --- a/tools/mtouch/Errors.resx +++ b/tools/mtouch/Errors.resx @@ -1131,6 +1131,12 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + + + + diff --git a/tools/mtouch/Makefile b/tools/mtouch/Makefile index 0ad70dd239a7..d48cc4bd1eaf 100644 --- a/tools/mtouch/Makefile +++ b/tools/mtouch/Makefile @@ -35,18 +35,21 @@ $(abspath Constants.cs): Constants.cs.in Makefile $(TOP)/Make.config.inc # define RunRegistrar .libs/Microsoft.$(9).registrar.$(10)%m .libs/Microsoft.$(9).registrar.$(10)%h: $(TOP)/src/build/dotnet/$(1)/$(3)/Microsoft.$(9).dll $(LOCAL_MTOUCH) | .libs - $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --sdkroot $$(XCODE_DEVELOPER_ROOT) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) + $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --xcode-version $$(XCODE_VERSION) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) $$(Q) touch $$(basename $$@).m $$(basename $$@).h .libs/Microsoft.$(9).registrar.$(10).a: .libs/Microsoft.$(9).registrar.$(10).m .libs/Microsoft.$(9).registrar.$(10).h | .libs $$(Q_CC) $$(CLANG) -DDEBUG -g -gdwarf-2 $(6) -stdlib=libc++ -std=c++14 -x objective-c++ -o $$@ -c $$< -Wall -Wno-unguarded-availability-new -I$(TOP)/runtime .libs/Microsoft.$(9).registrar.coreclr.$(10)%m .libs/Microsoft.$(9).registrar.coreclr.$(10)%h: $(TOP)/src/build/dotnet/$(1)/$(3)/Microsoft.$(9).dll $(LOCAL_MTOUCH) | .libs - $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --sdkroot $$(XCODE_DEVELOPER_ROOT) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) --xamarin-runtime CoreCLR + $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --xcode-version $$(XCODE_VERSION) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) --xamarin-runtime CoreCLR $$(Q) touch $$(basename $$@).m $$(basename $$@).h .libs/Microsoft.$(9).registrar.coreclr.$(10).a: .libs/Microsoft.$(9).registrar.coreclr.$(10).m .libs/Microsoft.$(9).registrar.$(10).h | .libs $$(Q_CC) $$(CLANG) -DDEBUG -g -gdwarf-2 $(6) -stdlib=libc++ -std=c++14 -x objective-c++ -o $$@ -c $$< -Wall -Wno-unguarded-availability-new -I$(TOP)/runtime + +no-xcode-build:: .libs/Microsoft.$(9).registrar.$(10).m .libs/Microsoft.$(9).registrar.$(10).h +no-xcode-build:: .libs/Microsoft.$(9).registrar.coreclr.$(10).m .libs/Microsoft.$(9).registrar.$(10).h endef $(eval $(call RunRegistrar,ios,x86_64,64,$(IOS_SDK_VERSION),iOS,$(iossimulator-x64_CFLAGS),,,iOS,iossimulator-x64)) $(eval $(call RunRegistrar,ios,arm64,64,$(IOS_SDK_VERSION),iOS,$(iossimulator-arm64_CFLAGS),,,iOS,iossimulator-arm64)) @@ -86,12 +89,15 @@ endef $(foreach platform,$(DOTNET_PLATFORMS_MTOUCH),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(eval $(call InstallRegistrar,$(platform),$(rid))))) -ifndef NO_XCODE +ifdef NO_XCODE +dotnet:: no-xcode-build +else dotnet: $(TARGETS_DOTNET) -install-local:: $(TARGETS_DOTNET) -all-local:: $(TARGETS_DOTNET) endif +install-local:: dotnet +all-local:: dotnet + clean-local:: rm -Rf bin obj diff --git a/tools/mtouch/mtouch.cs b/tools/mtouch/mtouch.cs index 21349adc0aaf..42ae6901f1a0 100644 --- a/tools/mtouch/mtouch.cs +++ b/tools/mtouch/mtouch.cs @@ -22,8 +22,6 @@ static int Main2 (string [] args) var os = new OptionSet (); ParseOptions (app, os, args); - ValidateXcode (app, false, false); - app.InitializeCommon (); app.RunRegistrar (); diff --git a/tools/mtouch/mtouch.csproj b/tools/mtouch/mtouch.csproj index a11f77fcc353..d9ba0a1ea76e 100644 --- a/tools/mtouch/mtouch.csproj +++ b/tools/mtouch/mtouch.csproj @@ -171,6 +171,9 @@ external/tools/common/XamarinRuntime.cs + + external/tools/common/IToolLog.cs + diff --git a/tools/nunit3-console-3.10.0 b/tools/nunit3-console-3.10.0 deleted file mode 100755 index 8ddf8c438192..000000000000 --- a/tools/nunit3-console-3.10.0 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -eu - -# This makes it so that stack traces have source code location -if test -z "${MONO_ENV_OPTIONS:-}"; then - export MONO_ENV_OPTIONS=--debug -fi - -TOP="$(cd "$(dirname "$0")/.." && pwd)" - -exec mono --debug "$TOP"/packages/nunit.consolerunner/3.10.0/tools/nunit3-console.exe "$@" diff --git a/tools/nunit3-console-3.11.1 b/tools/nunit3-console-3.11.1 deleted file mode 100755 index 9c9a4238b79c..000000000000 --- a/tools/nunit3-console-3.11.1 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -eu - -# This makes it so that stack traces have source code location -if test -z "${MONO_ENV_OPTIONS:-}"; then - export MONO_ENV_OPTIONS=--debug -fi - -TOP="$(cd "$(dirname "$0")/.." && pwd)" - -exec mono --debug "$TOP"/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe "$@" diff --git a/tools/nunit3-console-3.12.0 b/tools/nunit3-console-3.12.0 deleted file mode 100755 index 70cee8a5e84f..000000000000 --- a/tools/nunit3-console-3.12.0 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -eu - -# This makes it so that stack traces have source code location -if test -z "${MONO_ENV_OPTIONS:-}"; then - export MONO_ENV_OPTIONS=--debug -fi - -TOP="$(cd "$(dirname "$0")/.." && pwd)" - -exec mono --debug "$TOP"/packages/nunit.consolerunner/3.12.0/tools/nunit3-console.exe "$@" diff --git a/tools/nunit3-console-3.9.0 b/tools/nunit3-console-3.9.0 deleted file mode 100755 index 627c4900965a..000000000000 --- a/tools/nunit3-console-3.9.0 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -eu - -# This makes it so that stack traces have source code location -if test -z "${MONO_ENV_OPTIONS:-}"; then - export MONO_ENV_OPTIONS=--debug -fi - -TOP="$(cd "$(dirname "$0")/.." && pwd)" - -exec mono --debug "$TOP"/packages/nunit.consolerunner/3.9.0/tools/nunit3-console.exe "$@" diff --git a/tools/sharpie/Makefile b/tools/sharpie/Makefile index 56e53de56372..a2c79f4e8727 100644 --- a/tools/sharpie/Makefile +++ b/tools/sharpie/Makefile @@ -21,7 +21,7 @@ SHARPIE_BIND_TOOL_NUPKG_NAME=Sharpie.Bind.Tool.$(SHARPIE_BIND_TOOL_NUGET_VERSION SHARPIE_BIND_TOOL_NUPKG=Sharpie.Bind.Tool/bin/Release/$(SHARPIE_BIND_TOOL_NUPKG_NAME) pack: $(SHARPIE_BIND_TOOL_NUPKG) -$(SHARPIE_BIND_TOOL_NUPKG): $(Sharpie.Bind_dependencies) +$(SHARPIE_BIND_TOOL_NUPKG): $(Sharpie.Bind_dependencies) | $(SHARPIE_BIND_TOOL_DEBUG) $(Q_BUILD) $(DOTNET) pack Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj "/p:Version=$(SHARPIE_VERSION)" "/p:CurrentBranch=$(CURRENT_BRANCH)" "/p:CurrentHash=$(CURRENT_HASH_LONG)" $(DOTNET_PACK_VERBOSITY) -bl:$@.binlog all-local:: $(DOTNET_NUPKG_DIR)/$(SHARPIE_BIND_TOOL_NUPKG_NAME) diff --git a/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj b/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj index 0e75b9029de6..47aecdf36349 100644 --- a/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj +++ b/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj @@ -32,6 +32,9 @@ Icon.png https://github.com/dotnet/macios true + + + NU5123;$(NoWarn)