Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create msi for windows #2819

Draft
wants to merge 72 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
bd0722b
creating azcopy msi installer
dphulkar-msft Oct 4, 2024
f2651b0
Create windows msi
dphulkar-msft Oct 4, 2024
b5df7db
Create windows msi
dphulkar-msft Oct 4, 2024
07e5f5e
Create windows msi
dphulkar-msft Oct 7, 2024
e84a248
Create windows msi
dphulkar-msft Oct 7, 2024
9173779
Create windows msi
dphulkar-msft Oct 7, 2024
e134d48
Create windows msi
dphulkar-msft Oct 7, 2024
0b49218
Create windows msi
dphulkar-msft Oct 7, 2024
8371f1a
Create windows msi
dphulkar-msft Oct 7, 2024
28ff617
Create windows msi
dphulkar-msft Oct 7, 2024
24b4c27
Create windows msi
dphulkar-msft Oct 7, 2024
28672eb
Create windows msi
dphulkar-msft Oct 7, 2024
333d8a4
Create windows msi
dphulkar-msft Oct 7, 2024
f53f39a
Create windows msi
dphulkar-msft Oct 7, 2024
8b8290a
Create windows msi
dphulkar-msft Oct 7, 2024
d17c4dc
Create windows msi
dphulkar-msft Oct 7, 2024
04f31a7
Create windows msi
dphulkar-msft Oct 7, 2024
78d9287
Create windows msi
dphulkar-msft Oct 7, 2024
07890ab
Create windows msi
dphulkar-msft Oct 7, 2024
bfded4a
Create windows msi
dphulkar-msft Oct 7, 2024
5da3c02
Create windows msi
dphulkar-msft Oct 7, 2024
f552be5
Create windows msi
dphulkar-msft Oct 7, 2024
5783cc2
Create windows msi
dphulkar-msft Oct 7, 2024
d4d1cd4
Create windows msi
dphulkar-msft Oct 7, 2024
1f4fbda
Create windows msi
dphulkar-msft Oct 7, 2024
8500d18
Create windows msi
dphulkar-msft Oct 7, 2024
599fe81
Create windows msi
dphulkar-msft Oct 8, 2024
2b59069
Create windows msi
dphulkar-msft Oct 8, 2024
560acbc
Create windows msi
dphulkar-msft Oct 8, 2024
fa836d6
Create windows msi
dphulkar-msft Oct 8, 2024
6a63cab
Create windows msi
dphulkar-msft Oct 8, 2024
56d0cdf
Create windows msi
dphulkar-msft Oct 8, 2024
ebf5389
Merge branch 'main' of https://github.com/Azure/azure-storage-azcopy …
dphulkar-msft Oct 24, 2024
f50f469
Merge branch 'main' of https://github.com/Azure/azure-storage-azcopy …
dphulkar-msft Nov 4, 2024
85ee524
create windows msi
dphulkar-msft Nov 4, 2024
1a3104c
create windows msi
dphulkar-msft Nov 4, 2024
de165d7
create windows msi
dphulkar-msft Nov 4, 2024
5941470
create windows msi
dphulkar-msft Nov 4, 2024
d57b439
create windows msi
dphulkar-msft Nov 4, 2024
49ed85a
create windows msi
dphulkar-msft Nov 4, 2024
f04a07d
Merge branch 'main' of https://github.com/Azure/azure-storage-azcopy …
dphulkar-msft Nov 7, 2024
0de3c25
create windows msi
dphulkar-msft Nov 7, 2024
c9062e5
create windows msi
dphulkar-msft Nov 7, 2024
bb953ad
Merge branch 'main' of https://github.com/Azure/azure-storage-azcopy …
dphulkar-msft Nov 19, 2024
a1277c9
create msi
dphulkar-msft Nov 19, 2024
f8851ed
create msi
dphulkar-msft Nov 19, 2024
802e04a
create msi
dphulkar-msft Nov 19, 2024
56f968d
create msi
dphulkar-msft Nov 19, 2024
a18d80d
create msi
dphulkar-msft Nov 25, 2024
63f694c
create msi
dphulkar-msft Nov 25, 2024
2b1eb4d
create msi
dphulkar-msft Nov 26, 2024
2ccdf7e
winget package
dphulkar-msft Dec 13, 2024
3d49d5f
create windows msi
dphulkar-msft Jan 7, 2025
1029314
create windows msi
dphulkar-msft Jan 9, 2025
1ff705e
create windows msi
dphulkar-msft Jan 9, 2025
883dcdf
create windows msi
dphulkar-msft Jan 9, 2025
3a4e456
create windows msi
dphulkar-msft Jan 9, 2025
0ba2759
create windows msi
dphulkar-msft Jan 9, 2025
e306726
create windows msi
dphulkar-msft Jan 9, 2025
dc4ec40
create windows msi
dphulkar-msft Jan 21, 2025
f720ad7
create windows msi
dphulkar-msft Jan 21, 2025
f375431
create windows msi
dphulkar-msft Jan 21, 2025
37232f2
create windows msi
dphulkar-msft Jan 21, 2025
c1b6df2
create windows msi
dphulkar-msft Jan 21, 2025
3cc6762
create windows msi
dphulkar-msft Jan 22, 2025
59e6891
Merge branch 'main' of https://github.com/Azure/azure-storage-azcopy …
dphulkar-msft Jan 22, 2025
05fb17c
create windows msi
dphulkar-msft Jan 22, 2025
adc6d36
Add msi to signing step
dphulkar-msft Jan 22, 2025
42e75bc
display azcopy version after msi installation
dphulkar-msft Jan 22, 2025
12812a9
Add support for windows arm64 msi
dphulkar-msft Jan 22, 2025
4e77ea2
Fixed check for spelling errors failure
dphulkar-msft Jan 22, 2025
aafdfbb
Fixed check for spelling errors failure
dphulkar-msft Jan 22, 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
22 changes: 22 additions & 0 deletions azcopy.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="azcopy" Language="1033" Version="10.28.0" Manufacturer="Microsoft" UpgradeCode="abeee33a-0cca-4060-89d7-0687f7374f7a">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

<Media Id="1" Cabinet="azcopy.cab" EmbedCab="yes" />

<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="azcopy">
<Component Id="azcopy.exe" Guid="abeee33a-0cca-4060-89d7-0687f7374f7a">
<File Id="azcopy.exe" Source="azcopy_executable_path" />
</Component>
</Directory>
</Directory>
</Directory>

<Feature Id="ProductFeature" Title="AzCopy" Level="1">
<ComponentRef Id="azcopy.exe" />
</Feature>
</Product>
</Wix>
2 changes: 1 addition & 1 deletion cmd/copyEnumeratorInit.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ func (cca *CookedCopyCmdArgs) initEnumerator(jobPartOrder common.CopyJobPartOrde
return NewCopyEnumerator(traverser, filters, processor, finalizer), nil
}

// This is condensed down into an individual function as we don't end up re-using the destination traverser at all.
// This is condensed down into an individual function as we don't end up reusing the destination traverser at all.
// This is just for the directory check.
func (cca *CookedCopyCmdArgs) isDestDirectory(dst common.ResourceString, ctx *context.Context) bool {
var err error
Expand Down
7 changes: 4 additions & 3 deletions cmd/zt_parseSize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
package cmd

import (
"testing"

"github.com/stretchr/testify/assert"
chk "gopkg.in/check.v1"
"testing"
)

type parseSizeSuite struct{}
Expand Down Expand Up @@ -55,7 +56,7 @@
_, err = ParseSizeString("123T", "foo-bar") // we don't support terabytes
a.Equal(expectedError, err.Error())

_, err = ParseSizeString("abcK", "foo-bar")
_, err = ParseSizeString("abck", "foo-bar")

Check failure on line 59 in cmd/zt_parseSize_test.go

View workflow job for this annotation

GitHub Actions / Check for spelling errors

abck ==> back, aback
a.Equal(expectedError, err.Error())

}
}
2 changes: 1 addition & 1 deletion common/version.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package common

const AzcopyVersion = "10.28.0-Preview"
const AzcopyVersion = "10.28.0"
const UserAgent = "AzCopy/" + AzcopyVersion
const S3ImportUserAgent = "S3Import " + UserAgent
const GCPImportUserAgent = "GCPImport " + UserAgent
Expand Down
7 changes: 4 additions & 3 deletions e2etest/newe2e_account_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

import (
"fmt"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
"github.com/google/uuid"
"strings"
)

// AccountRegistry is a set of accounts that are intended to be initialized when the tests start running.
// Suites and tests should not add to this pool.
// todo: long-term, support flexible static configuration of accounts.
var AccountRegistry = map[string]AccountResourceManager{} // For re-using accounts across testing
var AccountRegistry = map[string]AccountResourceManager{} // For reusing accounts across testing

func GetAccount(a Asserter, AccountName string) AccountResourceManager {
targetAccount, ok := AccountRegistry[AccountName]
Expand Down Expand Up @@ -111,8 +112,8 @@
EAccountType.PremiumBlockBlobs(), EAccountType.PremiumHNSEnabled(), EAccountType.HierarchicalNamespaceEnabled():
azureAcct, ok := arm.(*AzureAccountResourceManager)
a.Assert("account manager must be azure account", Equal{}, ok, true)

e2etest/newe2e_task_runazcopy.go:115

Check failure on line 115 in e2etest/newe2e_account_registry.go

View workflow job for this annotation

GitHub Actions / lint (1.22.7, ubuntu-latest)

syntax error: unexpected go, expected name or (

Check failure on line 115 in e2etest/newe2e_account_registry.go

View workflow job for this annotation

GitHub Actions / lint (1.22.7, ubuntu-latest)

expected selector or type assertion, found 'go' (typecheck)
armAcct := azureAcct.ManagementClient()

Check failure on line 116 in e2etest/newe2e_account_registry.go

View workflow job for this annotation

GitHub Actions / lint (1.22.7, ubuntu-latest)

syntax error: unexpected ) at end of statement (typecheck)
a.Assert("cannot delete an account that does not have a management client associated", Not{IsNil{}}, armAcct)

a.NoError("delete account", armAcct.Delete())
Expand All @@ -127,7 +128,7 @@
PremiumPageBlobAcct string = "PremiumPageBlob"
)

func AccountRegistryInitHook(a Asserter) {

Check failure on line 131 in e2etest/newe2e_account_registry.go

View workflow job for this annotation

GitHub Actions / lint (1.22.7, ubuntu-latest)

expected '(', found AccountRegistryInitHook (typecheck)
if GlobalConfig.StaticResources() {
acctInfo := GlobalConfig.E2EAuthConfig.StaticStgAcctInfo

Expand All @@ -154,7 +155,7 @@
}
}

func AccountRegistryCleanupHook(a Asserter) {

Check failure on line 158 in e2etest/newe2e_account_registry.go

View workflow job for this annotation

GitHub Actions / lint (1.22.7, ubuntu-latest)

expected '(', found AccountRegistryCleanupHook (typecheck)
if GlobalConfig.StaticResources() {
return // no need to attempt cleanup
}
Expand All @@ -165,4 +166,4 @@
a.Assert("Delete account", NoError{}, managementClient.Delete())
}
}
}

Check failure on line 169 in e2etest/newe2e_account_registry.go

View workflow job for this annotation

GitHub Actions / lint (1.22.7, ubuntu-latest)

expected '}', found 'EOF' (typecheck)
2 changes: 1 addition & 1 deletion e2etest/newe2e_task_runazcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ type AzCopyCommand struct {
}

type AzCopyEnvironment struct {
// `env:"XYZ"` is re-used but does not inherit the traits of config's env trait. Merely used for low-code mapping.
// `env:"XYZ"` is reused but does not inherit the traits of config's env trait. Merely used for low-code mapping.

LogLocation *string `env:"AZCOPY_LOG_LOCATION,defaultfunc:DefaultLogLoc"`
JobPlanLocation *string `env:"AZCOPY_JOB_PLAN_LOCATION,defaultfunc:DefaultPlanLoc"`
Expand Down
58 changes: 56 additions & 2 deletions release-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ stages:
variables:
- name: root_dir
value: '$(System.DefaultWorkingDirectory)'
- name: work_dir
value: '$(Build.SourcesDirectory)'

steps:
- task: GoTool@0
Expand Down Expand Up @@ -442,6 +444,45 @@ stages:
GOOS: windows
CGO_ENABLED: 0

- powershell: |
# Copy the azcopy executable to the working directory with a new name
Copy-Item -Path "$(Build.ArtifactStagingDirectory)\azcopy_windows_amd64.exe" -Destination "$(work_dir)\azcopy.exe" -Force

# Get AzCopy version
$azcopyVersionOutput = & "$(work_dir)\azcopy.exe" --version
Write-Host "Raw AzCopy version output: $azcopyVersionOutput"

# Extract the version using regex
if ($azcopyVersionOutput -match '(\d+\.\d+\.\d+)$') {
$azcopyVersion = $matches[1] # Access the first capture group
Write-Host "AzCopy version: $azcopyVersion"
} else {
Write-Host "Failed to extract AzCopy version. Raw output: $azcopyVersionOutput"
}

# Output the version to be captured as a pipeline variable
Write-Host "##vso[task.setvariable variable=azcopyVersion]$azcopyVersion"
displayName: 'Copy Windows Amd64 required files for packaging'

- template: setup/create_windows_msi.yml
parameters:
working_dir: $(work_dir)
build_dir: $(Build.ArtifactStagingDirectory)
azcopy_version: $(azcopyVersion)
azcopy_msi_name: 'azcopy_windows_amd64.msi'

- powershell: |
# Copy the azcopy executable to the working directory with a new name
Copy-Item -Path "$(Build.ArtifactStagingDirectory)\azcopy_windows_arm64.exe" -Destination "$(work_dir)\azcopy.exe" -Force
displayName: 'Copy Windows Arm64 required files for packaging'

- template: setup/create_windows_msi.yml
parameters:
working_dir: $(work_dir)
build_dir: $(Build.ArtifactStagingDirectory)
azcopy_version: $(azcopyVersion)
azcopy_msi_name: 'azcopy_windows_arm64.msi'

- task: PublishBuildArtifacts@1
inputs:
artifactName: 'azCopy-windows-temp'
Expand Down Expand Up @@ -785,11 +826,12 @@ stages:
parameters:
FolderPath: $(Build.ArtifactStagingDirectory)/azCopy-windows-temp
ESRP_AZCOPY_WIN_KEY_CODE: $(ESRP_AZCOPY_WIN_KEY_CODE)
Pattern: 'azcopy_windows*'
Pattern: '*.exe;*.msi'

- script: |
rm -rf azCopy-windows-temp/*.md
cp azCopy-windows-temp/* .
rm -rf *.msi
mv azCopy-windows-temp $(work_dir)
displayName: 'Add signed windows binary to staging directory'
workingDirectory: '$(Build.ArtifactStagingDirectory)'
Expand All @@ -799,6 +841,18 @@ stages:
inputs:
artifactName: 'azCopy-binaries'
displayName: 'Publish Signed Artifacts'

- script: |
rm -rf $(Build.ArtifactStagingDirectory)/*
mv $(work_dir)/azCopy-windows-temp/*.msi .
displayName: 'Add signed windows binary to staging directory'
workingDirectory: '$(Build.ArtifactStagingDirectory)'

# Push signed msi to artifact directory
- task: PublishBuildArtifacts@1
inputs:
artifactName: 'azCopy-windows-signed'
displayName: 'Publish Signed Artifacts'

# Validate signed images have md5sum changed
- script: |
Expand Down Expand Up @@ -2194,4 +2248,4 @@ stages:
exit 1
fi
workingDirectory: $(root_dir)
displayName: "Updating version number"
displayName: "Updating version number"
121 changes: 121 additions & 0 deletions setup/create_windows_msi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
parameters:
working_dir: ''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
working_dir: ''
- name: working_dir
type: string

nit. Similar changes for the other params,

build_dir: ''
azcopy_version: ''
azcopy_msi_name: ''

steps:
- powershell: |
# Check if Chocolatey is installed
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
Write-Host "Chocolatey is not installed. Installing Chocolatey..."
Set-ExecutionPolicy Bypass -Scope Process -Force;
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
} else {
Write-Host "Chocolatey is already installed."
}

# Install WiX Toolset using Chocolatey
Write-Host "Installing WiX Toolset via Chocolatey..."
choco install wixtoolset -y
Write-Host "WiX Toolset installation completed."
displayName: 'Install Chocolatey and WiX Toolset'

- powershell: |
# Script to create MSI in an Azure Pipeline

# Step 1: Set Variables
$workDir = "${{ parameters.working_dir }}"
$wixToolsPath = (where.exe candle.exe) -replace '\\candle.exe$', '' # Remove candle.exe from path
$wxsFilePath = "$workDir\azcopy.wxs"
$wixObjPath = "$workDir\azcopy.wixobj"
$outputMsi = "${{ parameters.build_dir }}\${{ parameters.azcopy_msi_name }}"

# Step 2: Update the fields in the .wxs file
Write-Host "Updating Uuid in .wxs file..."
$uuid = [guid]::NewGuid().Guid.ToString()

# Load the XML file with namespace handling
[xml]$wixXml = Get-Content $wxsFilePath

# Define the XML namespace manager
$namespaceManager = New-Object System.Xml.XmlNamespaceManager($wixXml.NameTable)
$namespaceManager.AddNamespace("wix", "http://schemas.microsoft.com/wix/2006/wi")

# Update fields using the namespace
$productNode = $wixXml.SelectSingleNode("//wix:Product", $namespaceManager)
$productNode.Name = "AzCopy v10"
$productNode.Version = "${{ parameters.azcopy_version }}"
$productNode.Manufacturer = "Updated Manufacturer"
$productNode.UpgradeCode = $uuid

# Locate the Component node using the namespace
$component = $wixXml.SelectSingleNode("//wix:Directory[@Id='INSTALLDIR']/wix:Component", $namespaceManager)

# Check if Component element exists
if ($component) {
# Check if Guid attribute exists and set it, or add it if missing
if ($component.Attributes["Guid"]) {
$component.Attributes["Guid"].Value = $uuid
} else {
$component.SetAttribute("Guid", $uuid)
}
Write-Host "Guid attribute updated successfully."
} else {
Write-Host "Component element not found in XML structure."
}

# Update the file source path
$file = $component.SelectSingleNode("wix:File", $namespaceManager)
$file.Source = "$workDir\azcopy.exe"

# Save the updated XML back to the file
$wixXml.Save($wxsFilePath)

# Print the updated content of the .wxs file
Write-Host "Updated content of the .wxs file:"
Get-Content $wxsFilePath

Write-Host "WiX XML file updated successfully."

# Step 3: Compile the .wxs file using Candle
Write-Host "Compiling .wxs file..."
& "$wixToolsPath\candle.exe" -out $wixObjPath $wxsFilePath

# Step 4: Link the .wixobj to create the MSI using Light
Write-Host "Linking to create MSI..."
& "$wixToolsPath\light.exe" -out $outputMsi $wixObjPath

Write-Host "MSI creation process completed!"

# Define the file path for the .wixpdb file
$filePath = "$outputMsi\*.wixpdb"

# Remove the azcopy.wixpdb file as it is not required.
# .wixpdb file is a debugging file generated by WiX Toolset.
# Check if the file exists
if (Test-Path -Path $filePath) {
# Remove the .wixpdb file if it exists
Remove-Item -Path $filePath -Force
Write-Host "The .wixpdb file has been deleted."
} else {
Write-Host "No .wixpdb file found to delete."
}

# Verify the file has been deleted
if (-not (Test-Path -Path $filePath)) {
Write-Host "File deletion confirmed."
} else {
Write-Host "File still exists."
}

# Step 5: Install the MSI and verify the installation
Write-Host "Installing the MSI for verification ..."
msiexec /i $outputMsi
if ($LASTEXITCODE -eq 0) {
Write-Host "Installation was successful."
} else {
Write-Host "Installation failed with exit code $LASTEXITCODE."
}
azcopy.exe --version
2 changes: 1 addition & 1 deletion setup/esrp_sign_windows.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
parameters:
FolderPath: ''
ESRP_AZCOPY_WIN_KEY_CODE: ''
Pattern: '*.exe'
Pattern: ''

steps:
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5
Expand Down
3 changes: 2 additions & 1 deletion ste/md5Comparer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package ste
import (
"bytes"
"errors"

"github.com/Azure/azure-storage-azcopy/v10/common"
)

Expand Down Expand Up @@ -64,7 +65,7 @@ func (c *md5Comparer) Check() error {
switch c.validationOption {
// This code would never be triggered anymore due to the early check that now occurs in xfer-remoteToLocal.go
case common.EHashValidationOption.FailIfDifferentOrMissing():
panic("Transfer should've pre-emptively failed with a missing MD5.")
panic("Transfer should've preemptively failed with a missing MD5.")
case common.EHashValidationOption.FailIfDifferent(),
common.EHashValidationOption.LogOnly():
c.logAsMissing()
Expand Down
5 changes: 3 additions & 2 deletions ste/pageRangeOptimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ package ste

import (
"context"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/pageblob"
"github.com/Azure/azure-storage-azcopy/v10/common"
"strings"
)

// isolate the logic to fetch page ranges for a page blob, and check whether a given range has data
// for two purposes:
// 1. capture the necessary info to do so, so that fetchPages can be invoked anywhere
// 2. open to extending the logic, which could be re-used for both download and s2s scenarios
// 2. open to extending the logic, which could be reused for both download and s2s scenarios
type pageRangeOptimizer struct {
srcPageBlobClient *pageblob.Client
ctx context.Context
Expand Down
Loading