diff --git a/.gitignore b/.gitignore index e25f63e6..5ef3e4cd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ Cargo.lock target bin/ .DS_Store +*.msix # Node.js generated files for tree-sitter build/ diff --git a/build.ps1 b/build.ps1 index a501c1a7..b25db9b2 100644 --- a/build.ps1 +++ b/build.ps1 @@ -6,6 +6,8 @@ param( [ValidateSet('current','aarch64-pc-windows-msvc','x86_64-pc-windows-msvc','aarch64-apple-darwin','x86_64-apple-darwin','aarch64-unknown-linux-gnu','aarch64-unknown-linux-musl','x86_64-unknown-linux-gnu','x86_64-unknown-linux-musl')] $architecture = 'current', [switch]$Clippy, + [switch]$SkipBuild, + [switch]$Msix, [switch]$Test, [switch]$GetPackageVersion, [switch]$SkipLinkCheck @@ -52,7 +54,7 @@ function Find-LinkExe { } } -if (!$SkipLinkCheck -and $IsWindows -and !(Get-Command 'link.exe' -ErrorAction Ignore)) { +if (!$SkipBuild -and !$SkipLinkCheck -and $IsWindows -and !(Get-Command 'link.exe' -ErrorAction Ignore)) { if (!(Test-Path $BuildToolsPath)) { Write-Verbose -Verbose "link.exe not found, installing C++ build tools" Invoke-WebRequest 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile 'temp:/vs_buildtools.exe' @@ -83,7 +85,6 @@ if (!$SkipLinkCheck -and $IsWindows -and !(Get-Command 'link.exe' -ErrorAction I #$env:PATH += ";$linkexe" } -## Create the output folder $configuration = $Release ? 'release' : 'debug' $flags = @($Release ? '-r' : $null) if ($architecture -eq 'current') { @@ -98,13 +99,14 @@ else { $target = Join-Path $PSScriptRoot 'bin' $architecture $configuration } -if (Test-Path $target) { - Remove-Item $target -Recurse -ErrorAction Stop -} -New-Item -ItemType Directory $target > $null +if (!$SkipBuild) { + if (Test-Path $target) { + Remove-Item $target -Recurse -ErrorAction Stop + } + New-Item -ItemType Directory $target > $null -# make sure dependencies are built first so clippy runs correctly -$windows_projects = @("pal", "ntreg", "ntstatuserror", "ntuserinfo", "registry") + # make sure dependencies are built first so clippy runs correctly + $windows_projects = @("pal", "ntreg", "ntstatuserror", "ntuserinfo", "registry") # projects are in dependency order $projects = @( @@ -125,74 +127,73 @@ $pedantic_unclean_projects = @("ntreg") $clippy_unclean_projects = @("tree-sitter-dscexpression") $skip_test_projects_on_windows = @("tree-sitter-dscexpression") -if ($IsWindows) { - $projects += $windows_projects -} + if ($IsWindows) { + $projects += $windows_projects + } -$failed = $false -foreach ($project in $projects) { - ## Build format_json - Write-Host -ForegroundColor Cyan "Building $project ... for $architecture" - try { - Push-Location "$PSScriptRoot/$project" -ErrorAction Stop + $failed = $false + foreach ($project in $projects) { + ## Build format_json + Write-Host -ForegroundColor Cyan "Building $project ... for $architecture" + try { + Push-Location "$PSScriptRoot/$project" -ErrorAction Stop - if ($project -eq 'tree-sitter-dscexpression') { - ./build.ps1 - } + if ($project -eq 'tree-sitter-dscexpression') { + ./build.ps1 + } - if (Test-Path "./Cargo.toml") - { - if ($Clippy) { - if ($clippy_unclean_projects -contains $project) { - Write-Verbose -Verbose "Skipping clippy for $project" - } - elseif ($pedantic_unclean_projects -contains $project) { - Write-Verbose -Verbose "Running clippy for $project" - cargo clippy @flags -- -Dwarnings + if (Test-Path "./Cargo.toml") + { + if ($Clippy) { + if ($clippy_unclean_projects -contains $project) { + Write-Verbose -Verbose "Skipping clippy for $project" + } + elseif ($pedantic_unclean_projects -contains $project) { + Write-Verbose -Verbose "Running clippy for $project" + cargo clippy @flags -- -Dwarnings + } + else { + Write-Verbose -Verbose "Running clippy with pedantic for $project" + cargo clippy @flags --% -- -Dwarnings -Dclippy::pedantic + } } else { - Write-Verbose -Verbose "Running clippy with pedantic for $project" - cargo clippy @flags --% -- -Dwarnings -Dclippy::pedantic + cargo build @flags } } - else { - cargo build @flags - } - } - if ($LASTEXITCODE -ne 0) { - $failed = $true - } + if ($LASTEXITCODE -ne 0) { + $failed = $true + } - $binary = Split-Path $project -Leaf + $binary = Split-Path $project -Leaf - if ($IsWindows) { - Copy-Item "$path/$binary.exe" $target -ErrorAction Ignore - } - else { - Copy-Item "$path/$binary" $target -ErrorAction Ignore - } + if ($IsWindows) { + Copy-Item "$path/$binary.exe" $target -ErrorAction Ignore + } + else { + Copy-Item "$path/$binary" $target -ErrorAction Ignore + } - if (Test-Path "./copy_files.txt") { - Get-Content "./copy_files.txt" | ForEach-Object { - Copy-Item $_ $target -Force -ErrorAction Ignore + if (Test-Path "./copy_files.txt") { + Get-Content "./copy_files.txt" | ForEach-Object { + Copy-Item $_ $target -Force -ErrorAction Ignore + } } - } - Copy-Item "*.dsc.resource.json" $target -Force -ErrorAction Ignore + Copy-Item "*.dsc.resource.json" $target -Force -ErrorAction Ignore - } finally { - Pop-Location + } finally { + Pop-Location + } } -} -if ($failed) { - Write-Host -ForegroundColor Red "Build failed" - exit 1 + if ($failed) { + Write-Host -ForegroundColor Red "Build failed" + exit 1 + } } -Copy-Item $PSScriptRoot/tools/add-path.ps1 $target -Force -ErrorAction Ignore - $relative = Resolve-Path $target -Relative if (!$Clippy) { Write-Host -ForegroundColor Green "`nEXE's are copied to $target ($relative)" @@ -221,7 +222,7 @@ if (!$Clippy) { if (!$found) { Write-Host -ForegroundCOlor Yellow "Adding $target to `$env:PATH" - $env:PATH += [System.IO.Path]::PathSeparator + $target + $env:PATH = $target + [System.IO.Path]::PathSeparator + $env:PATH } } @@ -293,4 +294,116 @@ if ($Test) { Invoke-Pester -ErrorAction Stop } +if ($Msix) { + if (!$IsWindows) { + throw "MSIX is only supported on Windows" + } + + if ($architecture -eq 'current') { + throw 'MSIX requires a specific architecture' + } + + $makeappx = Get-Command makeappx -CommandType Application -ErrorAction Ignore + if ($null -eq $makeappx) { + # try to find + if ($architecture -eq 'aarch64-pc-windows-msvc') { + $arch = 'arm64' + } + else { + $arch = 'x64' + } + + $makeappx = Get-ChildItem -Recurse -Path (Join-Path ${env:ProgramFiles(x86)} 'Windows Kits\10\bin\*\' $arch) -Filter makeappx.exe | Sort-Object FullName -Descending | Select-Object -First 1 + if ($null -eq $makeappx) { + throw "makeappx not found, please install Windows SDK" + } + } + + $makepri = Get-Item (Join-Path $makeappx.Directory "makepri.exe") -ErrorAction Stop + $displayName = "DesiredStateConfiguration" + $productVersion = ((Get-Content $PSScriptRoot/dsc/Cargo.toml) -match '^version\s*=\s*') -replace 'version\s*=\s*"(.*?)"', '$1' + $isPreview = $productVersion -like '*-*' + $productName = "DesiredStateConfiguration" + if ($isPreview) { + Write-Verbose -Verbose "Preview version detected" + $productName += "-Preview" + # save preview number + $previewNumber = $productVersion -replace '.*?-[a-z]+\.([0-9]+)', '$1' + # remove label from version + $productVersion = $productVersion.Split('-')[0] + # replace revision number with preview number + $productVersion = $productVersion -replace '(\d+)$', "$previewNumber.0" + $displayName += "-Preview" + } + Write-Verbose -Verbose "Product version is $productVersion" + $arch = if ($architecture -eq 'aarch64-pc-windows-msvc') { 'arm64' } else { 'x64' } + + # Appx manifest needs to be in root of source path, but the embedded version needs to be updated + # cp-459155 is 'CN=Microsoft Windows Store Publisher (Store EKU), O=Microsoft Corporation, L=Redmond, S=Washington, C=US' + # authenticodeFormer is 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' + $releasePublisher = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' + + $appxManifest = Get-Content "$PSScriptRoot\packaging\msix\AppxManifest.xml" -Raw + $appxManifest = $appxManifest.Replace('$VERSION$', $ProductVersion).Replace('$ARCH$', $Arch).Replace('$PRODUCTNAME$', $productName).Replace('$DISPLAYNAME$', $displayName).Replace('$PUBLISHER$', $releasePublisher) + $msixTarget = Join-Path $PSScriptRoot 'bin' $architecture 'msix' + if (Test-Path $msixTarget) { + Remove-Item $msixTarget -Recurse -ErrorAction Stop + } + + New-Item -ItemType Directory $msixTarget > $null + Set-Content -Path "$msixTarget\AppxManifest.xml" -Value $appxManifest -Force + + $filesForMsix = @( + 'dsc.exe', + 'assertion.dsc.resource.json', + 'group.dsc.resource.json', + 'parallel.dsc.resource.json', + 'powershellgroup.dsc.resource.json', + 'powershellgroup.resource.ps1', + 'wmigroup.dsc.resource.json.optout', + 'wmigroup.resource.ps1' + ) + + foreach ($file in $filesForMsix) { + Copy-Item "$target\$file" $msixTarget -ErrorAction Stop + } + + # Necessary image assets need to be in source assets folder + $assets = @( + 'Square150x150Logo' + 'Square64x64Logo' + 'Square44x44Logo' + 'Square44x44Logo.targetsize-48' + 'Square44x44Logo.targetsize-48_altform-unplated' + 'StoreLogo' + ) + + New-Item -ItemType Directory "$msixTarget\assets" > $null + foreach ($asset in $assets) { + Copy-Item "$PSScriptRoot\packaging\assets\$asset.png" "$msixTarget\assets" -ErrorAction Stop + } + + Write-Verbose "Creating priconfig.xml" -Verbose + & $makepri createconfig /o /cf (Join-Path $msixTarget "priconfig.xml") /dq en-US + if ($LASTEXITCODE -ne 0) { + throw "Failed to create priconfig.xml" + } + + Write-Verbose "Creating resources.pri" -Verbose + Push-Location $msixTarget + & $makepri new /v /o /pr $msixTarget /cf (Join-Path $msixTarget "priconfig.xml") + Pop-Location + if ($LASTEXITCODE -ne 0) { + throw "Failed to create resources.pri" + } + + Write-Verbose "Creating msix package" -Verbose + $packageName = "$productName-$productVersion-$arch" + & $makeappx pack /o /v /h SHA256 /d $msixTarget /p (Join-Path -Path (Get-Location) -ChildPath "$packageName.msix") + if ($LASTEXITCODE -ne 0) { + throw "Failed to create msix package" + } + Write-Verbose "Created $packageName.msix" -Verbose +} + $env:RUST_BACKTRACE=1 diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index b6066eab..ddd6194d 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -14,7 +14,7 @@ use std::fs::File; use std::io::BufReader; use std::path::Path; use std::time::Duration; -use tracing::{debug, error, warn}; +use tracing::{debug, error, trace, warn}; pub struct CommandDiscovery { } @@ -28,6 +28,7 @@ impl CommandDiscovery { #[allow(clippy::too_many_lines)] fn search_for_resources(required_resource_types: &[String]) -> Result, DscError> { + debug!("Searching for resources: {:?}", required_resource_types); let return_all_resources = required_resource_types.len() == 1 && required_resource_types[0] == "*"; let multi_progress_bar = MultiProgress::new(); @@ -53,20 +54,37 @@ impl CommandDiscovery { let mut resources: BTreeMap = BTreeMap::new(); let mut adapter_resources: Vec = Vec::new(); let mut remaining_required_resource_types = required_resource_types.to_owned(); + let mut using_custom_path = false; + // try DSC_RESOURCE_PATH env var first otherwise use PATH - let path_env = match env::var_os("DSC_RESOURCE_PATH") { - Some(value) => value, - None => { - match env::var_os("PATH") { - Some(value) => value, - None => { - return Err(DscError::Operation("Failed to get PATH environment variable".to_string())); - } + let path_env = if let Some(value) = env::var_os("DSC_RESOURCE_PATH") { + debug!("Using DSC_RESOURCE_PATH: {:?}", value.to_string_lossy()); + using_custom_path = true; + value + } else { + trace!("DSC_RESOURCE_PATH not set, trying PATH"); + match env::var_os("PATH") { + Some(value) => { + debug!("Using PATH: {:?}", value.to_string_lossy()); + value + }, + None => { + return Err(DscError::Operation("Failed to get PATH environment variable".to_string())); } } }; - for path in env::split_paths(&path_env) { + let mut paths = env::split_paths(&path_env).collect::>(); + + // add exe home to start of path + if !using_custom_path { + if let Some(exe_home) = env::current_exe()?.parent() { + debug!("Adding exe home to path: {}", exe_home.to_string_lossy()); + paths.insert(0, exe_home.to_path_buf()); + } + } + + for path in paths { if path.exists() && path.is_dir() { for entry in path.read_dir().unwrap() { let entry = entry.unwrap(); diff --git a/packaging/assets/Square150x150Logo.png b/packaging/assets/Square150x150Logo.png new file mode 100644 index 00000000..16da3eed Binary files /dev/null and b/packaging/assets/Square150x150Logo.png differ diff --git a/packaging/assets/Square44x44Logo.png b/packaging/assets/Square44x44Logo.png new file mode 100644 index 00000000..22a36917 Binary files /dev/null and b/packaging/assets/Square44x44Logo.png differ diff --git a/packaging/assets/Square44x44Logo.targetsize-48.png b/packaging/assets/Square44x44Logo.targetsize-48.png new file mode 100644 index 00000000..22a36917 Binary files /dev/null and b/packaging/assets/Square44x44Logo.targetsize-48.png differ diff --git a/packaging/assets/Square44x44Logo.targetsize-48_altform-unplated.png b/packaging/assets/Square44x44Logo.targetsize-48_altform-unplated.png new file mode 100644 index 00000000..22a36917 Binary files /dev/null and b/packaging/assets/Square44x44Logo.targetsize-48_altform-unplated.png differ diff --git a/packaging/assets/Square64x64Logo.png b/packaging/assets/Square64x64Logo.png new file mode 100644 index 00000000..8f2f3713 Binary files /dev/null and b/packaging/assets/Square64x64Logo.png differ diff --git a/packaging/assets/StoreLogo.png b/packaging/assets/StoreLogo.png new file mode 100644 index 00000000..8f2f3713 Binary files /dev/null and b/packaging/assets/StoreLogo.png differ diff --git a/packaging/msix/AppxManifest.xml b/packaging/msix/AppxManifest.xml new file mode 100644 index 00000000..37f7f541 --- /dev/null +++ b/packaging/msix/AppxManifest.xml @@ -0,0 +1,51 @@ + + + + + + + + $DISPLAYNAME$ + Microsoft Corporation + assets\Square64x64Logo.png + disabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/add-path.ps1 b/tools/add-path.ps1 deleted file mode 100644 index d0ff2406..00000000 --- a/tools/add-path.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# This script will add the script directory to the PATH environment variable -# for the current user. This is useful for development purposes. - -$pathSeparator = [System.IO.Path]::PathSeparator -$paths = $env:PATH.Split($pathSeparator) -if ($paths -notcontains $PSScriptRoot) { - $env:PATH = "$PSScriptRoot" + $pathSeparator + $env:PATH - Write-Host -ForegroundColor Green "Added $PSScriptRoot to `$env:PATH" -} - -# Invoke completer script for PowerShell -$completer = dsc completer powershell | Out-String -Invoke-Expression $completer -Write-Host -ForegroundColor Green "Added PowerShell completer"