-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Add file commands for save-state and set-output #2118
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
0bb298b
Add save-state file command
rentziass 7490f6e
Add set-output file command
rentziass 0ac3c43
Add support for heredoc syntax to save-state file command
rentziass f5dc44d
Add support for heredoc syntax to set-output file command
rentziass f7652c9
Fix copy pasta mistakes in tests
rentziass 55d63f1
Refactor reading env files
rentziass 67d66d7
Move try/catch into EnvfileKeyValuePairs
rentziass File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,74 +140,10 @@ public sealed class SetEnvFileCommand : RunnerService, IFileCommandExtension | |
|
||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container) | ||
{ | ||
try | ||
{ | ||
var text = File.ReadAllText(filePath) ?? string.Empty; | ||
var index = 0; | ||
var line = ReadLine(text, ref index); | ||
while (line != null) | ||
{ | ||
if (!string.IsNullOrEmpty(line)) | ||
{ | ||
var equalsIndex = line.IndexOf("=", StringComparison.Ordinal); | ||
var heredocIndex = line.IndexOf("<<", StringComparison.Ordinal); | ||
|
||
// Normal style NAME=VALUE | ||
if (equalsIndex >= 0 && (heredocIndex < 0 || equalsIndex < heredocIndex)) | ||
{ | ||
var split = line.Split(new[] { '=' }, 2, StringSplitOptions.None); | ||
if (string.IsNullOrEmpty(line)) | ||
{ | ||
throw new Exception($"Invalid environment variable format '{line}'. Environment variable name must not be empty"); | ||
} | ||
SetEnvironmentVariable(context, split[0], split[1]); | ||
} | ||
// Heredoc style NAME<<EOF | ||
else if (heredocIndex >= 0 && (equalsIndex < 0 || heredocIndex < equalsIndex)) | ||
{ | ||
var split = line.Split(new[] { "<<" }, 2, StringSplitOptions.None); | ||
if (string.IsNullOrEmpty(split[0]) || string.IsNullOrEmpty(split[1])) | ||
{ | ||
throw new Exception($"Invalid environment variable format '{line}'. Environment variable name must not be empty and delimiter must not be empty"); | ||
} | ||
var name = split[0]; | ||
var delimiter = split[1]; | ||
var startIndex = index; // Start index of the value (inclusive) | ||
var endIndex = index; // End index of the value (exclusive) | ||
var tempLine = ReadLine(text, ref index, out var newline); | ||
while (!string.Equals(tempLine, delimiter, StringComparison.Ordinal)) | ||
{ | ||
if (tempLine == null) | ||
{ | ||
throw new Exception($"Invalid environment variable value. Matching delimiter not found '{delimiter}'"); | ||
} | ||
if (newline == null) | ||
{ | ||
throw new Exception($"Invalid environment variable value. EOF marker missing new line."); | ||
} | ||
endIndex = index - newline.Length; | ||
tempLine = ReadLine(text, ref index, out newline); | ||
} | ||
|
||
var value = endIndex > startIndex ? text.Substring(startIndex, endIndex - startIndex) : string.Empty; | ||
SetEnvironmentVariable(context, name, value); | ||
} | ||
else | ||
{ | ||
throw new Exception($"Invalid environment variable format '{line}'"); | ||
} | ||
} | ||
|
||
line = ReadLine(text, ref index); | ||
} | ||
} | ||
catch (DirectoryNotFoundException) | ||
var pairs = new EnvFileKeyValuePairs(context, filePath); | ||
foreach (var pair in pairs) | ||
{ | ||
context.Debug($"Environment variables file does not exist '{filePath}'"); | ||
} | ||
catch (FileNotFoundException) | ||
{ | ||
context.Debug($"Environment variables file does not exist '{filePath}'"); | ||
SetEnvironmentVariable(context, pair.Key, pair.Value); | ||
} | ||
} | ||
|
||
|
@@ -220,48 +156,6 @@ private static void SetEnvironmentVariable( | |
context.SetEnvContext(name, value); | ||
context.Debug($"{name}='{value}'"); | ||
} | ||
|
||
private static string ReadLine( | ||
string text, | ||
ref int index) | ||
{ | ||
return ReadLine(text, ref index, out _); | ||
} | ||
|
||
private static string ReadLine( | ||
string text, | ||
ref int index, | ||
out string newline) | ||
{ | ||
if (index >= text.Length) | ||
{ | ||
newline = null; | ||
return null; | ||
} | ||
|
||
var originalIndex = index; | ||
var lfIndex = text.IndexOf("\n", index, StringComparison.Ordinal); | ||
if (lfIndex < 0) | ||
{ | ||
index = text.Length; | ||
newline = null; | ||
return text.Substring(originalIndex); | ||
} | ||
|
||
#if OS_WINDOWS | ||
var crLFIndex = text.IndexOf("\r\n", index, StringComparison.Ordinal); | ||
if (crLFIndex >= 0 && crLFIndex < lfIndex) | ||
{ | ||
index = crLFIndex + 2; // Skip over CRLF | ||
newline = "\r\n"; | ||
return text.Substring(originalIndex, crLFIndex - originalIndex); | ||
} | ||
#endif | ||
|
||
index = lfIndex + 1; // Skip over LF | ||
newline = "\n"; | ||
return text.Substring(originalIndex, lfIndex - originalIndex); | ||
} | ||
} | ||
|
||
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension | ||
|
@@ -325,4 +219,200 @@ public void ProcessCommand(IExecutionContext context, string filePath, Container | |
} | ||
} | ||
} | ||
|
||
public sealed class SaveStateFileCommand : RunnerService, IFileCommandExtension | ||
{ | ||
public string ContextName => "state"; | ||
public string FilePrefix => "save_state_"; | ||
|
||
public Type ExtensionType => typeof(IFileCommandExtension); | ||
|
||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container) | ||
{ | ||
var pairs = new EnvFileKeyValuePairs(context, filePath); | ||
foreach (var pair in pairs) | ||
{ | ||
// Embedded steps (composite) keep track of the state at the root level | ||
if (context.IsEmbedded) | ||
{ | ||
var id = context.EmbeddedId; | ||
if (!context.Root.EmbeddedIntraActionState.ContainsKey(id)) | ||
{ | ||
context.Root.EmbeddedIntraActionState[id] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); | ||
} | ||
context.Root.EmbeddedIntraActionState[id][pair.Key] = pair.Value; | ||
} | ||
// Otherwise modify the ExecutionContext | ||
else | ||
{ | ||
context.IntraActionState[pair.Key] = pair.Value; | ||
} | ||
|
||
context.Debug($"Save intra-action state {pair.Key} = {pair.Value}"); | ||
} | ||
} | ||
} | ||
|
||
public sealed class SetOutputFileCommand : RunnerService, IFileCommandExtension | ||
{ | ||
public string ContextName => "output"; | ||
public string FilePrefix => "set_output_"; | ||
|
||
public Type ExtensionType => typeof(IFileCommandExtension); | ||
|
||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container) | ||
{ | ||
var pairs = new EnvFileKeyValuePairs(context, filePath); | ||
foreach (var pair in pairs) | ||
{ | ||
context.SetOutput(pair.Key, pair.Value, out var reference); | ||
context.Debug($"Set output {pair.Key} = {pair.Value}"); | ||
} | ||
} | ||
} | ||
|
||
public sealed class EnvFileKeyValuePairs: IEnumerable<KeyValuePair<string, string>> | ||
{ | ||
private IExecutionContext _context; | ||
private string _filePath; | ||
|
||
public EnvFileKeyValuePairs(IExecutionContext context, string filePath) | ||
{ | ||
_context = context; | ||
_filePath = filePath; | ||
} | ||
|
||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() | ||
{ | ||
var text = string.Empty; | ||
try | ||
{ | ||
text = File.ReadAllText(_filePath) ?? string.Empty; | ||
} | ||
catch (DirectoryNotFoundException) | ||
{ | ||
_context.Debug($"File does not exist '{_filePath}'"); | ||
yield break; | ||
} | ||
catch (FileNotFoundException) | ||
{ | ||
_context.Debug($"File does not exist '{_filePath}'"); | ||
yield break; | ||
} | ||
|
||
var index = 0; | ||
var line = ReadLine(text, ref index); | ||
while (line != null) | ||
{ | ||
if (!string.IsNullOrEmpty(line)) | ||
{ | ||
var key = string.Empty; | ||
var output = string.Empty; | ||
|
||
var equalsIndex = line.IndexOf("=", StringComparison.Ordinal); | ||
var heredocIndex = line.IndexOf("<<", StringComparison.Ordinal); | ||
|
||
// Normal style NAME=VALUE | ||
if (equalsIndex >= 0 && (heredocIndex < 0 || equalsIndex < heredocIndex)) | ||
{ | ||
var split = line.Split(new[] { '=' }, 2, StringSplitOptions.None); | ||
if (string.IsNullOrEmpty(line)) | ||
{ | ||
throw new Exception($"Invalid format '{line}'. Name must not be empty"); | ||
} | ||
|
||
key = split[0]; | ||
output = split[1]; | ||
} | ||
|
||
// Heredoc style NAME<<EOF | ||
else if (heredocIndex >= 0 && (equalsIndex < 0 || heredocIndex < equalsIndex)) | ||
{ | ||
var split = line.Split(new[] { "<<" }, 2, StringSplitOptions.None); | ||
if (string.IsNullOrEmpty(split[0]) || string.IsNullOrEmpty(split[1])) | ||
{ | ||
throw new Exception($"Invalid format '{line}'. Name must not be empty and delimiter must not be empty"); | ||
} | ||
key = split[0]; | ||
var delimiter = split[1]; | ||
var startIndex = index; // Start index of the value (inclusive) | ||
var endIndex = index; // End index of the value (exclusive) | ||
var tempLine = ReadLine(text, ref index, out var newline); | ||
while (!string.Equals(tempLine, delimiter, StringComparison.Ordinal)) | ||
{ | ||
if (tempLine == null) | ||
{ | ||
throw new Exception($"Invalid value. Matching delimiter not found '{delimiter}'"); | ||
} | ||
if (newline == null) | ||
{ | ||
throw new Exception($"Invalid value. EOF marker missing new line."); | ||
} | ||
endIndex = index - newline.Length; | ||
tempLine = ReadLine(text, ref index, out newline); | ||
} | ||
|
||
output = endIndex > startIndex ? text.Substring(startIndex, endIndex - startIndex) : string.Empty; | ||
} | ||
else | ||
{ | ||
throw new Exception($"Invalid format '{line}'"); | ||
} | ||
|
||
yield return new KeyValuePair<string, string>(key, output); | ||
} | ||
|
||
line = ReadLine(text, ref index); | ||
} | ||
} | ||
|
||
System.Collections.IEnumerator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a typo? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is sorry? I can't find this comment in the diff view 😕
thboop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
System.Collections.IEnumerable.GetEnumerator() | ||
{ | ||
// Invoke IEnumerator<KeyValuePair<string, string>> GetEnumerator() above. | ||
return GetEnumerator(); | ||
} | ||
|
||
private static string ReadLine( | ||
string text, | ||
ref int index) | ||
{ | ||
return ReadLine(text, ref index, out _); | ||
} | ||
|
||
private static string ReadLine( | ||
string text, | ||
ref int index, | ||
out string newline) | ||
{ | ||
if (index >= text.Length) | ||
{ | ||
newline = null; | ||
return null; | ||
} | ||
|
||
var originalIndex = index; | ||
var lfIndex = text.IndexOf("\n", index, StringComparison.Ordinal); | ||
if (lfIndex < 0) | ||
{ | ||
index = text.Length; | ||
newline = null; | ||
return text.Substring(originalIndex); | ||
} | ||
|
||
#if OS_WINDOWS | ||
var crLFIndex = text.IndexOf("\r\n", index, StringComparison.Ordinal); | ||
if (crLFIndex >= 0 && crLFIndex < lfIndex) | ||
{ | ||
index = crLFIndex + 2; // Skip over CRLF | ||
newline = "\r\n"; | ||
return text.Substring(originalIndex, crLFIndex - originalIndex); | ||
} | ||
#endif | ||
|
||
index = lfIndex + 1; // Skip over LF | ||
newline = "\n"; | ||
return text.Substring(originalIndex, lfIndex - originalIndex); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a copy paste with the key/output yields added and the error messages updated right? I wasn't able to find other changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, that is correct :)