Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0954f89
feat: Add CMake FetchContent support to updater
vaind Sep 18, 2025
891ea75
fix: Complete CMake FetchContent implementation
vaind Sep 18, 2025
9566917
docs: Fix CMake examples to be more logical
vaind Sep 18, 2025
ca1444d
docs: Refactor path input description into cleaner sublist
vaind Sep 18, 2025
c676be0
fix: cleanup CMake file handling in update-dependency script
vaind Sep 18, 2025
e11ac81
fix: ensure newline at end of file in Update-CMakeFile function
vaind Sep 18, 2025
0cea893
refactor: Use cross-platform temp directory approach
vaind Sep 18, 2025
e0b5a39
security: Fix ancestry validation to fail safely
vaind Sep 18, 2025
b9c8c4f
refactor: Simplify GIT_TAG line replacement logic
vaind Sep 18, 2025
8c0107a
fix: Add proper error handling for git ls-remote commands
vaind Sep 18, 2025
f058514
test: Add missing hash-to-hash update test case
vaind Sep 18, 2025
2f572cc
refactor: Inline test data and group related test cases
vaind Sep 19, 2025
b419603
refactor: Improve test structure with shared data and individual cases
vaind Sep 19, 2025
6888e3f
refactor: Reorganize test hierarchy for better clarity
vaind Sep 19, 2025
814a5c5
test: Use exact hash instead of regex pattern in assertion
vaind Sep 19, 2025
6b48177
test: Use exact hash in integration test assertion
vaind Sep 19, 2025
d7e850f
test: Use exact version in remaining integration test assertions
vaind Sep 19, 2025
132845a
revert: Use generic patterns in integration tests without version con…
vaind Sep 19, 2025
cd95e70
docs: Add changelog entry for CMake FetchContent support
vaind Sep 19, 2025
df907ad
Add parameter validation to CMake helper functions
vaind Sep 19, 2025
58cef75
Add dependency name validation in update-dependency.ps1
vaind Sep 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions updater/scripts/cmake-functions.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# CMake FetchContent helper functions for update-dependency.ps1

function Parse-CMakeFetchContent($filePath, $depName) {
$content = Get-Content $filePath -Raw

if ($depName) {
$pattern = "FetchContent_Declare\s*\(\s*$depName\s+([^)]+)\)"
} else {
# Find all FetchContent_Declare blocks
$allMatches = [regex]::Matches($content, "FetchContent_Declare\s*\(\s*([a-zA-Z0-9_-]+)", 'Singleline')
if ($allMatches.Count -eq 1) {
$depName = $allMatches[0].Groups[1].Value
$pattern = "FetchContent_Declare\s*\(\s*$depName\s+([^)]+)\)"
} else {
throw "Multiple FetchContent declarations found. Use #DepName syntax."
}
}

$match = [regex]::Match($content, $pattern, 'Singleline,IgnoreCase')
if (-not $match.Success) {
throw "FetchContent_Declare for '$depName' not found in $filePath"
}
$block = $match.Groups[1].Value

# Look for GIT_REPOSITORY and GIT_TAG patterns specifically
# Exclude matches that are in comments (lines starting with #)
$repoMatch = [regex]::Match($block, '(?m)^\s*GIT_REPOSITORY\s+(\S+)')
$tagMatch = [regex]::Match($block, '(?m)^\s*GIT_TAG\s+(\S+)')

$repo = if ($repoMatch.Success) { $repoMatch.Groups[1].Value } else { "" }
$tag = if ($tagMatch.Success) { $tagMatch.Groups[1].Value } else { "" }

if ([string]::IsNullOrEmpty($repo) -or [string]::IsNullOrEmpty($tag)) {
throw "Could not parse GIT_REPOSITORY or GIT_TAG from FetchContent_Declare block"
}

return @{ GitRepository = $repo; GitTag = $tag; DepName = $depName }
}

function Find-TagForHash($repo, $hash) {
try {
$refs = git ls-remote --tags $repo
foreach ($ref in $refs) {
$commit, $tagRef = $ref -split '\s+', 2
if ($commit -eq $hash) {
return $tagRef -replace '^refs/tags/', ''
}
}
return $null
}
catch {
Write-Host "Warning: Could not resolve hash $hash to tag name: $_"
return $null
}
}

function Update-CMakeFile($filePath, $depName, $newValue) {
$content = Get-Content $filePath -Raw
$fetchContent = Parse-CMakeFetchContent $filePath $depName
$originalValue = $fetchContent.GitTag
$repo = $fetchContent.GitRepository
$wasHash = $originalValue -match '^[a-f0-9]{40}$'

if ($wasHash) {
# Convert tag to hash and add comment
$newHashRefs = git ls-remote $repo "refs/tags/$newValue"
if (-not $newHashRefs) {
throw "Tag $newValue not found in repository $repo"
}
$newHash = ($newHashRefs -split '\s+')[0]
$replacement = "$newHash # $newValue"

# Validate ancestry: ensure old hash is reachable from new tag
# Note: Skipping ancestry check for now as it requires local repository
# TODO: Implement proper ancestry validation for remote repositories
Write-Host "Warning: Skipping ancestry validation for hash update from $originalValue to $newValue"
} else {
$replacement = $newValue
}

# Update GIT_TAG value, preserving formatting
$pattern = "(FetchContent_Declare\s*\(\s*$depName\s+[^)]*GIT_TAG\s+)\S+([^#\r\n]*).*?(\s*[^)]*\))"
$newContent = [regex]::Replace($content, $pattern, "`${1}$replacement`${3}", 'Singleline')

if ($newContent -eq $content) {
throw "Failed to update GIT_TAG in $filePath - pattern may not have matched"
}

$newContent | Out-File $filePath -NoNewline

# Verify the update worked
$verifyContent = Parse-CMakeFetchContent $filePath $depName
$expectedValue = $wasHash ? $newHash : $newValue
if ($verifyContent.GitTag -notmatch [regex]::Escape($expectedValue)) {
throw "Update verification failed - read-after-write did not match expected value"
}
}
46 changes: 45 additions & 1 deletion updater/scripts/update-dependency.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ param(
# * `get-version` - return the currently specified dependency version
# * `get-repo` - return the repository url (e.g. https://github.com/getsentry/dependency)
# * `set-version` - update the dependency version (passed as another string argument after this one)
# - a CMake file (.cmake) with FetchContent_Declare statements:
# * Use `path/to/file.cmake#DepName` to specify dependency name
# * Or just `path/to/file.cmake` if file contains single FetchContent_Declare
[Parameter(Mandatory = $true)][string] $Path,
# RegEx pattern that will be matched against available versions when picking the latest one
[string] $Pattern = '',
Expand All @@ -16,6 +19,19 @@ param(
Set-StrictMode -Version latest
. "$PSScriptRoot/common.ps1"

# Parse CMake file with dependency name
$cmakeFile = $null
$cmakeDep = $null
if ($Path -match '^(.+\.cmake)#(.+)$') {
$cmakeFile = $Matches[1]
$cmakeDep = $Matches[2]
$Path = $cmakeFile # Set Path to file for existing logic
} elseif ($Path -match '\.cmake$') {
$cmakeFile = $Path
$cmakeDep = $null # Will auto-detect
}
$isCMakeFile = $cmakeFile -ne $null

if (-not (Test-Path $Path ))
{
throw "Dependency $Path doesn't exit";
Expand All @@ -41,7 +57,32 @@ if (-not $isSubmodule)
$isScript = $Path -match '\.(ps1|sh)$'
function DependencyConfig ([Parameter(Mandatory = $true)][string] $action, [string] $value = $null)
{
if ($isScript)
if ($isCMakeFile) {
# CMake file handling
switch ($action) {
'get-version' {
$fetchContent = Parse-CMakeFetchContent $cmakeFile $cmakeDep
$currentValue = $fetchContent.GitTag
if ($currentValue -match '^[a-f0-9]{40}$') {
# Try to resolve hash to tag for version comparison
$repo = $fetchContent.GitRepository
$tagForHash = Find-TagForHash $repo $currentValue
return $tagForHash ?? $currentValue
}
return $currentValue
}
'get-repo' {
return (Parse-CMakeFetchContent $cmakeFile $cmakeDep).GitRepository
}
'set-version' {
Update-CMakeFile $cmakeFile $cmakeDep $value
}
Default {
throw "Unknown action $action"
}
}
}
elseif ($isScript)
{
if (Get-Command 'chmod' -ErrorAction SilentlyContinue)
{
Expand Down Expand Up @@ -99,6 +140,9 @@ if (-not $isSubmodule)
}
}
}

# Load CMake helper functions
. "$PSScriptRoot/cmake-functions.ps1"
}

if ("$Tag" -eq '')
Expand Down
14 changes: 14 additions & 0 deletions updater/tests/testdata/cmake/complex-formatting.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
include(FetchContent)

FetchContent_Declare(sentry-native
GIT_REPOSITORY
https://github.com/getsentry/sentry-native
GIT_TAG
v0.9.1 # Current stable version
GIT_SHALLOW
FALSE
GIT_SUBMODULES
"external/breakpad"
)

FetchContent_MakeAvailable(sentry-native)
11 changes: 11 additions & 0 deletions updater/tests/testdata/cmake/hash-dependency.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include(FetchContent)

FetchContent_Declare(
sentry-native
GIT_REPOSITORY https://github.com/getsentry/sentry-native
GIT_TAG a64d5bd8ee130f2cda196b6fa7d9b65bfa6d32e2 # 0.9.1
GIT_SHALLOW FALSE
GIT_SUBMODULES "external/breakpad"
)

FetchContent_MakeAvailable(sentry-native)
8 changes: 8 additions & 0 deletions updater/tests/testdata/cmake/malformed.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include(FetchContent)

FetchContent_Declare(
sentry-native
GIT_REPOSITORY https://github.com/getsentry/sentry-native
# Missing GIT_TAG
GIT_SHALLOW FALSE
)
8 changes: 8 additions & 0 deletions updater/tests/testdata/cmake/missing-repository.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include(FetchContent)

FetchContent_Declare(
sentry-native
# Missing GIT_REPOSITORY
GIT_TAG v0.9.1
GIT_SHALLOW FALSE
)
17 changes: 17 additions & 0 deletions updater/tests/testdata/cmake/multiple-dependencies.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include(FetchContent)

FetchContent_Declare(
sentry-native
GIT_REPOSITORY https://github.com/getsentry/sentry-native
GIT_TAG v0.9.1
GIT_SHALLOW FALSE
)

FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest
GIT_TAG v1.14.0
EXCLUDE_FROM_ALL
)

FetchContent_MakeAvailable(sentry-native googletest)
11 changes: 11 additions & 0 deletions updater/tests/testdata/cmake/single-dependency.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include(FetchContent)

FetchContent_Declare(
sentry-native
GIT_REPOSITORY https://github.com/getsentry/sentry-native
GIT_TAG v0.9.1
GIT_SHALLOW FALSE
GIT_SUBMODULES "external/breakpad"
)

FetchContent_MakeAvailable(sentry-native)
Loading
Loading