diff --git a/.pipelines/DSC-Official.yml b/.pipelines/DSC-Official.yml
index 60870a794..2f18aecd3 100644
--- a/.pipelines/DSC-Official.yml
+++ b/.pipelines/DSC-Official.yml
@@ -236,13 +236,17 @@ extends:
ob_restore_phase: true
- pwsh: |
apt update
- apt -y install musl-tools
+ apt -y install musl-tools rpm dpkg build-essential
$header = "Bearer $(AzToken)"
$env:CARGO_REGISTRIES_POWERSHELL_TOKEN = $header
$env:CARGO_REGISTRIES_POWERSHELL_CREDENTIAL_PROVIDER = 'cargo:token'
./build.ps1 -Release -Architecture x86_64-unknown-linux-musl
./build.ps1 -PackageType tgz -Architecture x86_64-unknown-linux-musl -Release
+ ./build.ps1 -PackageType rpm -Architecture x86_64-unknown-linux-musl -Release
+ ./build.ps1 -PackageType deb -Architecture x86_64-unknown-linux-musl -Release
Copy-Item ./bin/*.tar.gz "$(ob_outputDirectory)"
+ Copy-Item ./bin/*.rpm "$(ob_outputDirectory)"
+ Copy-Item ./bin/*.deb "$(ob_outputDirectory)"
displayName: 'Build x86_64-unknown-linux-musl'
condition: succeeded()
@@ -289,6 +293,9 @@ extends:
#apt -y install gcc-multilib
apt -y install libssl-dev
apt -y install pkg-config
+ apt -y install rpm
+ apt -y install dpkg
+ apt -y install build-essential
msrustup default stable-aarch64-unknown-linux-musl
if ((openssl version -d) -match 'OPENSSLDIR: "(?
.*?)"') {
$env:OPENSSL_LIB_DIR = $matches['dir']
@@ -298,7 +305,11 @@ extends:
$env:CARGO_REGISTRIES_POWERSHELL_CREDENTIAL_PROVIDER = 'cargo:token'
./build.ps1 -Release -Architecture aarch64-unknown-linux-musl
./build.ps1 -PackageType tgz -Architecture aarch64-unknown-linux-musl -Release
+ ./build.ps1 -PackageType rpm -Architecture aarch64-unknown-linux-musl -Release
+ ./build.ps1 -PackageType deb -Architecture aarch64-unknown-linux-musl -Release
Copy-Item ./bin/*.tar.gz "$(ob_outputDirectory)"
+ Copy-Item ./bin/*.rpm "$(ob_outputDirectory)"
+ Copy-Item ./bin/*.deb "$(ob_outputDirectory)"
displayName: 'Build aarch64-unknown-linux-musl'
condition: succeeded()
@@ -370,11 +381,17 @@ extends:
- download: current
artifact: drop_BuildAndSign_BuildLinuxArm64Musl
- patterns: '*.tar.gz'
+ patterns: |
+ *.tar.gz
+ *.rpm
+ *.deb
- download: current
artifact: drop_BuildAndSign_BuildLinuxMusl
- patterns: '*.tar.gz'
+ patterns: |
+ *.tar.gz
+ *.rpm
+ *.deb
- download: current
artifact: release ## this includes artifacts for macOS
@@ -385,7 +402,7 @@ extends:
patterns: '*.msixbundle'
- pwsh: |
- Get-ChildItem "$(Pipeline.Workspace)" -Recurse -Include '*.zip', '*.tar.gz', '*.msixbundle' | ForEach-Object {
+ Get-ChildItem "$(Pipeline.Workspace)" -Recurse -Include '*.zip', '*.tar.gz', '*.msixbundle', '*.rpm', '*.deb' | ForEach-Object {
Write-Host "Found artifact: $($_.FullName)"
}
displayName: List downloaded artifacts
@@ -398,7 +415,7 @@ extends:
Write-Verbose -Verbose "Starting to copy"
- Get-ChildItem "$(Pipeline.Workspace)" -Recurse -Include '*.zip', '*.tar.gz', '*.msixbundle' | ForEach-Object {
+ Get-ChildItem "$(Pipeline.Workspace)" -Recurse -Include '*.zip', '*.tar.gz', '*.msixbundle', '*.rpm', '*.deb' | ForEach-Object {
Copy-Item -Path $_.FullName -Destination $outputDir -Force -Verbose
}
@@ -448,7 +465,7 @@ extends:
script: |
Write-Verbose -Verbose "Release version: $(PackageVersion)"
- $artifacts = Get-ChildItem "$(Pipeline.Workspace)" -Recurse -Include '*.zip', '*.tar.gz', '*.msixbundle'
+ $artifacts = Get-ChildItem "$(Pipeline.Workspace)" -Recurse -Include '*.zip', '*.tar.gz', '*.msixbundle', '*.rpm', '*.deb'
$artifacts | ForEach-Object {
Write-Verbose -Verbose "Found artifact: $($_.FullName)"
@@ -489,6 +506,8 @@ extends:
$(GitHubReleaseDirectory)\*.zip
$(GitHubReleaseDirectory)\*.tar.gz
$(GitHubReleaseDirectory)\*.msixbundle
+ $(GitHubReleaseDirectory)\*.rpm
+ $(GitHubReleaseDirectory)\*.deb
addChangeLog: false
tagSource: 'userSpecifiedTag'
tag: '$(GitHubReleaseVersion)'
diff --git a/build.ps1 b/build.ps1
index f92f6571f..cf94a1ac9 100755
--- a/build.ps1
+++ b/build.ps1
@@ -9,7 +9,7 @@ param(
$architecture = 'current',
[switch]$Clippy,
[switch]$SkipBuild,
- [ValidateSet('msix','msix-private','msixbundle','tgz','zip')]
+ [ValidateSet('msix','msix-private','msixbundle','tgz','zip','rpm','deb')]
$packageType,
[switch]$Test,
[switch]$GetPackageVersion,
@@ -857,6 +857,176 @@ if ($packageType -eq 'msixbundle') {
}
Write-Host -ForegroundColor Green "`ntar.gz file is created at $tarFile"
+} elseif ($packageType -eq 'rpm') {
+ if (!$IsLinux) {
+ throw "RPM package creation is only supported on Linux"
+ }
+
+ # Check if rpmbuild is available
+ if ($null -eq (Get-Command rpmbuild -ErrorAction Ignore)) {
+ throw "rpmbuild not found. Please install rpm-build package (e.g., 'sudo apt install rpm build-essential' or 'sudo dnf install rpm-build')"
+ }
+
+ $rpmTarget = Join-Path $PSScriptRoot 'bin' $architecture 'rpm'
+ if (Test-Path $rpmTarget) {
+ Remove-Item $rpmTarget -Recurse -ErrorAction Stop -Force
+ }
+
+ New-Item -ItemType Directory $rpmTarget > $null
+
+ # Create RPM build directories
+ $rpmBuildRoot = Join-Path $rpmTarget 'rpmbuild'
+ $rpmDirs = @('BUILD', 'RPMS', 'SOURCES', 'SPECS', 'SRPMS')
+ foreach ($dir in $rpmDirs) {
+ New-Item -ItemType Directory -Path (Join-Path $rpmBuildRoot $dir) -Force > $null
+ }
+
+ # Create a staging directory for the files
+ $stagingDir = Join-Path $rpmBuildRoot 'SOURCES' 'dsc_files'
+ New-Item -ItemType Directory $stagingDir > $null
+
+ $filesForPackage = $filesForLinuxPackage
+
+ foreach ($file in $filesForPackage) {
+ if ((Get-Item "$target\$file") -is [System.IO.DirectoryInfo]) {
+ Copy-Item "$target\$file" "$stagingDir\$file" -Recurse -ErrorAction Stop
+ } else {
+ Copy-Item "$target\$file" $stagingDir -ErrorAction Stop
+ }
+ }
+
+ # Determine RPM architecture
+ $rpmArch = if ($architecture -eq 'current') {
+ # Detect current system architecture
+ $currentArch = uname -m
+ if ($currentArch -eq 'x86_64') {
+ 'x86_64'
+ } elseif ($currentArch -eq 'aarch64') {
+ 'aarch64'
+ } else {
+ throw "Unsupported current architecture for RPM: $currentArch"
+ }
+ } elseif ($architecture -eq 'aarch64-unknown-linux-musl' -or $architecture -eq 'aarch64-unknown-linux-gnu') {
+ 'aarch64'
+ } elseif ($architecture -eq 'x86_64-unknown-linux-musl' -or $architecture -eq 'x86_64-unknown-linux-gnu') {
+ 'x86_64'
+ } else {
+ throw "Unsupported architecture for RPM: $architecture"
+ }
+
+ # Read the spec template and replace placeholders
+ $specTemplate = Get-Content "$PSScriptRoot/packaging/rpm/dsc.spec" -Raw
+ $specContent = $specTemplate.Replace('VERSION_PLACEHOLDER', $productVersion.Replace('-','~')).Replace('ARCH_PLACEHOLDER', $rpmArch)
+ $specFile = Join-Path $rpmBuildRoot 'SPECS' 'dsc.spec'
+ Set-Content -Path $specFile -Value $specContent
+
+ Write-Verbose -Verbose "Building RPM package"
+ $rpmPackageName = "dsc-$productVersion-1.$rpmArch.rpm"
+
+ # Build the RPM
+ rpmbuild -v -bb --define "_topdir $rpmBuildRoot" --buildroot "$rpmBuildRoot/BUILDROOT" $specFile 2>&1 > $rpmTarget/rpmbuild.log
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error (Get-Content $rpmTarget/rpmbuild.log -Raw)
+ throw "Failed to create RPM package"
+ }
+
+ # Copy the RPM to the bin directory
+ $builtRpm = Get-ChildItem -Path (Join-Path $rpmBuildRoot 'RPMS') -Recurse -Filter '*.rpm' | Select-Object -First 1
+ if ($null -eq $builtRpm) {
+ throw "RPM package was not created"
+ }
+
+ $finalRpmPath = Join-Path $PSScriptRoot 'bin' $builtRpm.Name
+ Copy-Item $builtRpm.FullName $finalRpmPath -Force
+
+ Write-Host -ForegroundColor Green "`nRPM package is created at $finalRpmPath"
+} elseif ($packageType -eq 'deb') {
+ if (!$IsLinux) {
+ throw "DEB package creation is only supported on Linux"
+ }
+
+ # Check if dpkg-deb is available
+ if ($null -eq (Get-Command dpkg-deb -ErrorAction Ignore)) {
+ throw "dpkg-deb not found. Please install dpkg package (e.g., 'sudo apt install dpkg' or 'sudo dnf install dpkg')"
+ }
+
+ $debTarget = Join-Path $PSScriptRoot 'bin' $architecture 'deb'
+ if (Test-Path $debTarget) {
+ Remove-Item $debTarget -Recurse -ErrorAction Stop -Force
+ }
+
+ New-Item -ItemType Directory $debTarget > $null
+
+ # Create DEB package structure
+ $debBuildRoot = Join-Path $debTarget 'dsc'
+ $debDirs = @('DEBIAN', 'opt/dsc', 'usr/bin')
+ foreach ($dir in $debDirs) {
+ New-Item -ItemType Directory -Path (Join-Path $debBuildRoot $dir) -Force > $null
+ }
+
+ # Copy files to the package directory
+ $filesForPackage = $filesForLinuxPackage
+ $stagingDir = Join-Path $debBuildRoot 'opt' 'dsc'
+
+ foreach ($file in $filesForPackage) {
+ if ((Get-Item "$target\$file") -is [System.IO.DirectoryInfo]) {
+ Copy-Item "$target\$file" "$stagingDir\$file" -Recurse -ErrorAction Stop
+ } else {
+ Copy-Item "$target\$file" $stagingDir -ErrorAction Stop
+ }
+ }
+
+ # Create symlink in usr/bin
+ $symlinkPath = Join-Path $debBuildRoot 'usr' 'bin' 'dsc'
+ New-Item -ItemType SymbolicLink -Path $symlinkPath -Target '/opt/dsc/dsc' -Force > $null
+
+ # Determine DEB architecture
+ $debArch = if ($architecture -eq 'current') {
+ # Detect current system architecture
+ $currentArch = uname -m
+ if ($currentArch -eq 'x86_64') {
+ 'amd64'
+ } elseif ($currentArch -eq 'aarch64') {
+ 'arm64'
+ } else {
+ throw "Unsupported current architecture for DEB: $currentArch"
+ }
+ } elseif ($architecture -eq 'aarch64-unknown-linux-musl' -or $architecture -eq 'aarch64-unknown-linux-gnu') {
+ 'arm64'
+ } elseif ($architecture -eq 'x86_64-unknown-linux-musl' -or $architecture -eq 'x86_64-unknown-linux-gnu') {
+ 'amd64'
+ } else {
+ throw "Unsupported architecture for DEB: $architecture"
+ }
+
+ # Read the control template and replace placeholders
+ $controlTemplate = Get-Content "$PSScriptRoot/packaging/deb/control" -Raw
+ $controlContent = $controlTemplate.Replace('VERSION_PLACEHOLDER', $productVersion).Replace('ARCH_PLACEHOLDER', $debArch)
+ $controlFile = Join-Path $debBuildRoot 'DEBIAN' 'control'
+ Set-Content -Path $controlFile -Value $controlContent
+
+ Write-Verbose -Verbose "Building DEB package"
+ $debPackageName = "dsc_$productVersion-1_$debArch.deb"
+
+ # Build the DEB
+ dpkg-deb --build $debBuildRoot 2>&1 > $debTarget/debbuild.log
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error (Get-Content $debTarget/debbuild.log -Raw)
+ throw "Failed to create DEB package"
+ }
+
+ # Move the DEB to the bin directory with the correct name
+ $builtDeb = "$debBuildRoot.deb"
+ if (!(Test-Path $builtDeb)) {
+ throw "DEB package was not created"
+ }
+
+ $finalDebPath = Join-Path $PSScriptRoot 'bin' $debPackageName
+ Move-Item $builtDeb $finalDebPath -Force
+
+ Write-Host -ForegroundColor Green "`nDEB package is created at $finalDebPath"
}
$env:RUST_BACKTRACE=1
diff --git a/packaging/deb/control b/packaging/deb/control
new file mode 100644
index 000000000..fd36329bc
--- /dev/null
+++ b/packaging/deb/control
@@ -0,0 +1,12 @@
+Package: dsc
+Version: VERSION_PLACEHOLDER
+Section: utils
+Priority: optional
+Architecture: ARCH_PLACEHOLDER
+Maintainer: Microsoft Corporation
+Homepage: https://github.com/PowerShell/DSC
+Description: DesiredStateConfiguration v3
+ DSCv3 is the latest iteration of Microsoft's Desired State Configuration
+ platform. DSCv3 is an open source command line application that abstracts
+ the management of software components declaratively and idempotently.
+ DSCv3 runs on Linux, macOS, and Windows without any external dependencies.
diff --git a/packaging/rpm/dsc.spec b/packaging/rpm/dsc.spec
new file mode 100644
index 000000000..06fde7bc7
--- /dev/null
+++ b/packaging/rpm/dsc.spec
@@ -0,0 +1,38 @@
+Name: dsc
+Version: VERSION_PLACEHOLDER
+Release: 1
+Summary: DesiredStateConfiguration v3
+License: MIT
+URL: https://github.com/PowerShell/DSC
+BuildArch: ARCH_PLACEHOLDER
+
+%description
+DSCv3 is the latest iteration of Microsoft's Desired State Configuration platform.
+DSCv3 is an open source command line application that abstracts the management of
+software components declaratively and idempotently. DSCv3 runs on Linux, macOS,
+and Windows without any external dependencies.
+
+%prep
+# No prep needed - files are already built
+
+%build
+# No build needed - binary is already compiled
+
+%install
+# Create installation directories
+mkdir -p $RPM_BUILD_ROOT/opt/dsc
+mkdir -p $RPM_BUILD_ROOT/usr/bin
+
+# Copy all files from the source directory
+cp -r $RPM_SOURCE_DIR/dsc_files/* $RPM_BUILD_ROOT/opt/dsc/
+
+# Create symlink to make dsc available in PATH
+ln -s /opt/dsc/dsc $RPM_BUILD_ROOT/usr/bin/dsc
+
+%files
+/opt/dsc/*
+/usr/bin/dsc
+
+%changelog
+* Wed Oct 22 2025 Microsoft Corporation
+- Initial RPM package release