Skip to content

Commit bb10d2d

Browse files
publish async again...
1 parent 85daf5e commit bb10d2d

File tree

3 files changed

+152
-29
lines changed

3 files changed

+152
-29
lines changed

build/Build.cs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,21 @@ async Task PublishCalamariProjects(List<Project> projects)
272272
.Distinct(t => new { t.Project?.Name, t.Architecture, t.Framework });
273273

274274
var packagesToPublish = crossPlatformPackages.Concat(netFxPackages).ToArray();
275+
276+
var publishTasks = packagesToPublish
277+
.Select(package => PublishPackageAsync(package))
278+
.ToList();
275279

276-
packagesToPublish.ForEach(PublishPackage);
280+
var outputPaths = await Task.WhenAll(publishTasks);
281+
282+
var signTasks = outputPaths
283+
.Where(output => output != null && !output.ToString().Contains("Tests"))
284+
.Select(output => Task.Run(() => SignDirectory(output!)))
285+
.ToList();
286+
287+
await Task.WhenAll(signTasks);
288+
289+
277290
await Task.WhenAll(SignDirectoriesTasks);
278291

279292
StageLegacyCalamariAssemblies(packagesToPublish);
@@ -282,11 +295,39 @@ async Task PublishCalamariProjects(List<Project> projects)
282295
await Task.WhenAll(ProjectCompressionTasks);
283296
}
284297

298+
async Task<AbsolutePath?> PublishPackageAsync(CalamariPackageMetadata calamariPackageMetadata)
299+
{
300+
if (!OperatingSystem.IsWindows() && !calamariPackageMetadata.IsCrossPlatform)
301+
{
302+
Log.Warning($"Not publishing {calamariPackageMetadata.Framework}: can only publish netfx on a Windows OS");
303+
return null;
304+
}
305+
306+
Log.Information($"Publishing {calamariPackageMetadata.Project?.Name} for framework '{calamariPackageMetadata.Framework}' and arch '{calamariPackageMetadata.Architecture}'");
307+
308+
var project = calamariPackageMetadata.Project;
309+
var outputDirectory = PublishDirectory / project?.Name / (calamariPackageMetadata.IsCrossPlatform ? calamariPackageMetadata.Architecture : "netfx");
310+
311+
await Task.Run(() =>
312+
DotNetPublish(s =>
313+
s.SetConfiguration(Configuration)
314+
.SetProject(project)
315+
.SetFramework(calamariPackageMetadata.Framework)
316+
.SetRuntime(calamariPackageMetadata.Architecture)
317+
.EnableDisableParallel()
318+
.EnableSelfContained()
319+
.SetOutput(outputDirectory)));
320+
321+
File.Copy(RootDirectory / "global.json", outputDirectory / "global.json");
322+
323+
return outputDirectory;
324+
}
325+
285326
void PublishPackage(CalamariPackageMetadata calamariPackageMetadata)
286327
{
287328
if (!OperatingSystem.IsWindows() && !calamariPackageMetadata.IsCrossPlatform)
288329
{
289-
Log.Warning($"Not building {calamariPackageMetadata.Framework}: can only build netfx on a Windows OS");
330+
Log.Warning($"Not publishing {calamariPackageMetadata.Framework}: can only build netfx on a Windows OS");
290331
return;
291332
}
292333

@@ -300,6 +341,7 @@ void PublishPackage(CalamariPackageMetadata calamariPackageMetadata)
300341
.SetProject(project)
301342
.SetFramework(calamariPackageMetadata.Framework)
302343
.SetRuntime(calamariPackageMetadata.Architecture)
344+
.EnableDisableParallel()
303345
//explicitly mark all of these as self-contained (because they use a specific runtime)
304346
.EnableSelfContained()
305347
.SetOutput(outputDirectory)
@@ -597,16 +639,8 @@ void CompressCalamariProject(Project project)
597639

598640
async Task RunPackActions(List<Action> actions)
599641
{
600-
if (PackInParallel)
601-
{
602642
var tasks = actions.Select(Task.Run).ToList();
603643
await Task.WhenAll(tasks);
604-
}
605-
else
606-
{
607-
foreach (var action in actions)
608-
action();
609-
}
610644
}
611645

612646
AbsolutePath DoPublish(string project, string framework, string version, string? runtimeId = null)

source/Calamari.Common/Features/Scripting/Bash/Bootstrap.sh

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,24 @@ function log_environment_information
265265

266266
log_environment_information
267267

268+
function hex_to_bin_fd() {
269+
local hex="$1"
270+
local fd="$2"
271+
272+
# Process hex in reasonable chunks
273+
for ((i=0; i<${#hex}; i+=40)); do
274+
local chunk="${hex:$i:40}"
275+
local cmd="printf '"
276+
277+
for ((j=0; j<${#chunk}; j+=2)); do
278+
cmd+="\\x${chunk:$j:2}"
279+
done
280+
281+
cmd+="'"
282+
eval "$cmd" >&$fd
283+
done
284+
}
285+
268286
function decrypt_and_parse_variables {
269287
local encrypted="$1"
270288
local iv="$2"
@@ -287,7 +305,9 @@ function decrypt_and_parse_variables {
287305
local concatenated_hex
288306
concatenated_hex=$(printf "%s" "${hex_parts[@]}")
289307

290-
exec 3< <(echo -n "$concatenated_hex" | xxd -r -p)
308+
exec 3<> <(:)
309+
hex_to_bin_fd "$concatenated_hex" 3
310+
exec 3<&3
291311

292312
local idx
293313
for idx in "${!key_byte_lengths[@]}"; do

source/Calamari.Tests/Fixtures/Bash/BashFixture.cs

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using Calamari.Common.Features.Processes;
5+
using System.Diagnostics;
6+
using System.Linq;
57
using Calamari.Common.FeatureToggles;
68
using Calamari.Common.Plumbing;
79
using Calamari.Common.Plumbing.Variables;
810
using Calamari.Deployment;
911
using Calamari.Testing.Requirements;
1012
using Calamari.Tests.Helpers;
13+
using FluentAssertions;
1114
using NUnit.Framework;
1215

1316
namespace Calamari.Tests.Fixtures.Bash
@@ -34,7 +37,7 @@ public void ShouldPrintEncodedVariable(FeatureToggle? featureToggle)
3437
[RequiresBashDotExeIfOnWindows]
3538
public void ShouldPrintSensitiveVariable(FeatureToggle? featureToggle)
3639
{
37-
var (output, _) = RunScript("print-sensitive-variable.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
40+
var (output, _) = RunScript("print-sensitive-variable.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
3841

3942
Assert.Multiple(() =>
4043
{
@@ -48,7 +51,7 @@ public void ShouldPrintSensitiveVariable(FeatureToggle? featureToggle)
4851
[RequiresBashDotExeIfOnWindows]
4952
public void ShouldCreateArtifact(FeatureToggle? featureToggle)
5053
{
51-
var (output, _) = RunScript("create-artifact.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
54+
var (output, _) = RunScript("create-artifact.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
5255

5356
Assert.Multiple(() =>
5457
{
@@ -62,7 +65,7 @@ public void ShouldCreateArtifact(FeatureToggle? featureToggle)
6265
[RequiresBashDotExeIfOnWindows]
6366
public void ShouldUpdateProgress(FeatureToggle? featureToggle)
6467
{
65-
var (output, _) = RunScript("update-progress.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
68+
var (output, _) = RunScript("update-progress.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
6669

6770
Assert.Multiple(() =>
6871
{
@@ -160,7 +163,7 @@ public void ShouldConsumeParametersWithQuotes(FeatureToggle? featureToggle)
160163
{
161164
var (output, _) = RunScript("parameters.sh",
162165
new Dictionary<string, string>()
163-
{ [SpecialVariables.Action.Script.ScriptParameters] = "\"Para meter0\" 'Para meter1'" }.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
166+
{ [SpecialVariables.Action.Script.ScriptParameters] = "\"Para meter0\" 'Para meter1'" }.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
164167

165168
Assert.Multiple(() =>
166169
{
@@ -174,8 +177,10 @@ public void ShouldConsumeParametersWithQuotes(FeatureToggle? featureToggle)
174177
[RequiresBashDotExeIfOnWindows]
175178
public void ShouldNotReceiveParametersIfNoneProvided(FeatureToggle? featureToggle)
176179
{
177-
var (output, _) = RunScript("parameters.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }), sensitiveVariablesPassword:
178-
"5XETGOgqYR2bRhlfhDruEg==");
180+
var (output, _) = RunScript("parameters.sh",
181+
new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }),
182+
sensitiveVariablesPassword:
183+
"5XETGOgqYR2bRhlfhDruEg==");
179184

180185
Assert.Multiple(() =>
181186
{
@@ -197,7 +202,7 @@ public void ShouldCallHello(FeatureToggle? featureToggle)
197202
["Variable3"] = "GHI",
198203
["Foo_bar"] = "Hello",
199204
["Host"] = "Never",
200-
}.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
205+
}.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
201206

202207
Assert.Multiple(() =>
203208
{
@@ -213,8 +218,9 @@ public void ShouldCallHelloWithSensitiveVariable(FeatureToggle? featureToggle)
213218
{
214219
var (output, _) = RunScript("hello.sh",
215220
new Dictionary<string, string>()
216-
{ ["Name"] = "NameToEncrypt" }.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }), sensitiveVariablesPassword:
217-
"5XETGOgqYR2bRhlfhDruEg==");
221+
{ ["Name"] = "NameToEncrypt" }.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }),
222+
sensitiveVariablesPassword:
223+
"5XETGOgqYR2bRhlfhDruEg==");
218224

219225
Assert.Multiple(() =>
220226
{
@@ -230,7 +236,7 @@ public void ShouldCallHelloWithNullVariable(FeatureToggle? featureToggle)
230236
{
231237
var (output, _) = RunScript("hello.sh",
232238
new Dictionary<string, string>()
233-
{ ["Name"] = null }.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
239+
{ ["Name"] = null }.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
234240

235241
Assert.Multiple(() =>
236242
{
@@ -246,8 +252,9 @@ public void ShouldCallHelloWithNullSensitiveVariable(FeatureToggle? featureToggl
246252
{
247253
var (output, _) = RunScript("hello.sh",
248254
new Dictionary<string, string>()
249-
{ ["Name"] = null }.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }), sensitiveVariablesPassword:
250-
"5XETGOgqYR2bRhlfhDruEg==");
255+
{ ["Name"] = null }.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }),
256+
sensitiveVariablesPassword:
257+
"5XETGOgqYR2bRhlfhDruEg==");
251258

252259
Assert.Multiple(() =>
253260
{
@@ -262,7 +269,7 @@ public void ShouldCallHelloWithNullSensitiveVariable(FeatureToggle? featureToggl
262269
public void ShouldNotFailOnStdErr(FeatureToggle? featureToggle)
263270
{
264271
var (output, _) = RunScript("stderr.sh",
265-
new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
272+
new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
266273

267274
Assert.Multiple(() =>
268275
{
@@ -278,7 +285,7 @@ public void ShouldFailOnStdErrWithTreatScriptWarningsAsErrors(FeatureToggle? fea
278285
{
279286
var (output, _) = RunScript("stderr.sh",
280287
new Dictionary<string, string>()
281-
{ [SpecialVariables.Action.FailScriptOnErrorOutput] = "True" }.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
288+
{ [SpecialVariables.Action.FailScriptOnErrorOutput] = "True" }.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
282289

283290
Assert.Multiple(() =>
284291
{
@@ -294,7 +301,7 @@ public void ShouldNotFailOnStdErrFromServiceMessagesWithTreatScriptWarningsAsErr
294301
{
295302
var (output, _) = RunScript("hello.sh",
296303
new Dictionary<string, string>()
297-
{ [SpecialVariables.Action.FailScriptOnErrorOutput] = "True" }.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
304+
{ [SpecialVariables.Action.FailScriptOnErrorOutput] = "True" }.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
298305

299306
output.AssertSuccess();
300307
}
@@ -304,7 +311,7 @@ public void ShouldNotFailOnStdErrFromServiceMessagesWithTreatScriptWarningsAsErr
304311
[TestCase(null)]
305312
public void ShouldSupportStrictVariableUnset(FeatureToggle? featureToggle)
306313
{
307-
var (output, _) = RunScript("strict-mode.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
314+
var (output, _) = RunScript("strict-mode.sh", new Dictionary<string, string>().AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
308315

309316
Assert.Multiple(() =>
310317
{
@@ -313,7 +320,7 @@ public void ShouldSupportStrictVariableUnset(FeatureToggle? featureToggle)
313320
});
314321
}
315322

316-
static string specialCharacters => "! \" # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \\ ] ^ _ ` { | } ~ \n\u00b1 \u00d7 \u00f7 \u2211 \u220f \u2202 \u221e \u222b \u2248 \u2260 \u2264 \u2265 \u221a \u221b \u2206 \u2207 \u221d \n$ \u00a2 \u00a3 \u00a5 \u20ac \u20b9 \u20a9 \u20b1 \u20aa \u20bf \n• ‣ … ′ ″ ‘ ’ “ ” ‽ ¡ ¿ – — ― \n( ) [ ] { } ⟨ ⟩ « » ‘ ’ “ ” \n\u2190 \u2191 \u2192 \u2193 \u2194 \u2195 \u2196 \u2197 \u2198 \u2199 \u2b05 \u2b06 \u2b07 \u27a1 \u27f3 \nα β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω \n\u00a9 \u00ae \u2122 § ¶ † ‡ µ #\n";
323+
static string specialCharacters => "! \" # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \\ ] ^ _ ` { | } ~ \n\u00b1 \u00d7 \u00f7 \u2211 \u220f \u2202 \u221e \u222b \u2248 \u2260 \u2264 \u2265 \u221a \u221b \u2206 \u2207 \u221d \n$ \u00a2 \u00a3 \u00a5 \u20ac \u20b9 \u20a9 \u20b1 \u20aa \u20bf \n• ‣ … ′ ″ ‘ ’ “ ” ‽ ¡ ¿ – — ― \n( ) [ ] { } ⟨ ⟩ « » ‘ ’ “ ” \n\u2190 \u2191 \u2192 \u2193 \u2194 \u2195 \u2196 \u2197 \u2198 \u2199 \u2b05 \u2b06 \u2b07 \u27a1 \u27f3 \nα β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω \n\u00a9 \u00ae \u2122 § ¶ † ‡ µ #";
317324

318325
[TestCase(FeatureToggle.BashParametersArrayFeatureToggle)]
319326
[TestCase(null)]
@@ -336,8 +343,9 @@ public void ShouldBeAbleToEnumerateVariableValues(FeatureToggle? featureToggle)
336343
["VariableName \n 11"] = "Value \n 11",
337344
["VariableName.prop.anotherprop 12"] = "Value.prop.12",
338345
["VariableName`prop`anotherprop` 13"] = "Value`prop`13",
346+
["VariableName 14 😭🙈👀"] = "Value 14 😭🙈👀",
339347
[specialCharacters] = specialCharacters
340-
}.AddFeatureToggleToDictionary(new List<FeatureToggle?>{ featureToggle }));
348+
}.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
341349

342350
output.AssertSuccess();
343351
if (featureToggle == FeatureToggle.BashParametersArrayFeatureToggle)
@@ -366,9 +374,70 @@ public void ShouldBeAbleToEnumerateVariableValues(FeatureToggle? featureToggle)
366374

367375
output.AssertOutput("Key: VariableName.prop.anotherprop 12, Value: Value.prop.12");
368376
output.AssertOutput("Key: VariableName`prop`anotherprop` 13, Value: Value`prop`13");
377+
output.AssertOutput("Key: VariableName 14 😭🙈👀, Value: Value 14 😭🙈👀");
369378
output.AssertOutput($"Key: {specialCharacters}, Value: {specialCharacters}");
370379
}
371380
}
381+
[TestCase(FeatureToggle.BashParametersArrayFeatureToggle)]
382+
[TestCase(null)]
383+
[RequiresBashDotExeIfOnWindows]
384+
public void ShouldBeAbleToEnumerateLargeVariableSetsEfficiently(FeatureToggle? featureToggle)
385+
{
386+
// Create a dictionary with 10,000 variables with diverse characters
387+
var variables = new Dictionary<string, string>();
388+
var random = new Random(42); // Seed for reproducibility
389+
390+
// Generate 10,000 unique variables with diverse content
391+
for (int i = 0; i < 10000; i++)
392+
{
393+
string key = $"Key{i}_{Guid.NewGuid().ToString("N")}";
394+
string value = $"Value{i}_{Convert.ToBase64String(Guid.NewGuid().ToByteArray())}";
395+
396+
// Mix in some random Unicode characters
397+
if (random.Next(5) == 0)
398+
{
399+
key += (char)random.Next(0x1F600, 0x1F64F); // Emoji range
400+
value += Environment.NewLine + (char)random.Next(0x2600, 0x26FF); // Unicode symbols
401+
}
402+
403+
variables[key] = value;
404+
}
405+
406+
var sw = Stopwatch.StartNew();
407+
// Run the script with all these variables
408+
var (output, _) = RunScript("enumerate-variables.sh",
409+
variables.AddFeatureToggleToDictionary(new List<FeatureToggle?> { featureToggle }));
410+
sw.Stop();
411+
sw.Elapsed.TotalMilliseconds.Should().BeLessThan(2000);
412+
413+
output.AssertSuccess();
414+
if (featureToggle == FeatureToggle.BashParametersArrayFeatureToggle)
415+
{
416+
var fullOutput = string.Join(Environment.NewLine, output.CapturedOutput.Infos);
417+
if (fullOutput.Contains("Bash version 4.2 or later is required to use octopus_parameters"))
418+
{
419+
output.AssertOutput("Still ran this script");
420+
return;
421+
}
422+
423+
// Get all output lines that start with "Key: "
424+
var outputLines = output.CapturedOutput.Infos
425+
.Where(line => line.StartsWith("Key: "))
426+
.ToList();
427+
428+
// Verify count matches
429+
Assert.That(outputLines.Count, Is.EqualTo(variables.Count),
430+
"Not all variables were processed");
431+
432+
// For each variable, construct the expected output format and verify it exists
433+
foreach (var kvp in variables)
434+
{
435+
string expectedOutput = $"Key: {kvp.Key}, Value: {kvp.Value}";
436+
Assert.That(outputLines.Contains(expectedOutput),
437+
$"Expected output line not found: '{expectedOutput}'");
438+
}
439+
}
440+
}
372441
}
373442

374443
public static class AdditionalVariablesExtensions

0 commit comments

Comments
 (0)