mirror of
https://github.com/actions/runner.git
synced 2025-12-20 06:29:53 +00:00
GitHub Actions Runner
This commit is contained in:
113
src/Sdk/DTPipelines/Pipelines/ContextData/ArrayContextData.cs
Normal file
113
src/Sdk/DTPipelines/Pipelines/ContextData/ArrayContextData.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[DataContract]
|
||||
[JsonObject]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public sealed class ArrayContextData : PipelineContextData, IEnumerable<PipelineContextData>, IReadOnlyArray
|
||||
{
|
||||
public ArrayContextData()
|
||||
: base(PipelineContextDataType.Array)
|
||||
{
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Int32 Count => m_items?.Count ?? 0;
|
||||
|
||||
public PipelineContextData this[Int32 index] => m_items[index];
|
||||
|
||||
Object IReadOnlyArray.this[Int32 index] => m_items[index];
|
||||
|
||||
public void Add(PipelineContextData item)
|
||||
{
|
||||
if (m_items == null)
|
||||
{
|
||||
m_items = new List<PipelineContextData>();
|
||||
}
|
||||
|
||||
m_items.Add(item);
|
||||
}
|
||||
|
||||
public override PipelineContextData Clone()
|
||||
{
|
||||
var result = new ArrayContextData();
|
||||
if (m_items?.Count > 0)
|
||||
{
|
||||
result.m_items = new List<PipelineContextData>(m_items.Count);
|
||||
foreach (var item in m_items)
|
||||
{
|
||||
result.m_items.Add(item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public override JToken ToJToken()
|
||||
{
|
||||
var result = new JArray();
|
||||
if (m_items?.Count > 0)
|
||||
{
|
||||
foreach (var item in m_items)
|
||||
{
|
||||
result.Add(item?.ToJToken() ?? JValue.CreateNull());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerator<PipelineContextData> GetEnumerator()
|
||||
{
|
||||
if (m_items?.Count > 0)
|
||||
{
|
||||
foreach (var item in m_items)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
if (m_items?.Count > 0)
|
||||
{
|
||||
foreach (var item in m_items)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IReadOnlyArray.GetEnumerator()
|
||||
{
|
||||
if (m_items?.Count > 0)
|
||||
{
|
||||
foreach (var item in m_items)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OnSerializing]
|
||||
private void OnSerializing(StreamingContext context)
|
||||
{
|
||||
if (m_items?.Count == 0)
|
||||
{
|
||||
m_items = null;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Name = "a", EmitDefaultValue = false)]
|
||||
private List<PipelineContextData> m_items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[DataContract]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public sealed class BooleanContextData : PipelineContextData, IBoolean
|
||||
{
|
||||
public BooleanContextData(Boolean value)
|
||||
: base(PipelineContextDataType.Boolean)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
public Boolean Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
}
|
||||
|
||||
public override PipelineContextData Clone()
|
||||
{
|
||||
return new BooleanContextData(m_value);
|
||||
}
|
||||
|
||||
public override JToken ToJToken()
|
||||
{
|
||||
return (JToken)m_value;
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return m_value ? "true" : "false";
|
||||
}
|
||||
|
||||
Boolean IBoolean.GetBoolean()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static implicit operator Boolean(BooleanContextData data)
|
||||
{
|
||||
return data.Value;
|
||||
}
|
||||
|
||||
public static implicit operator BooleanContextData(Boolean data)
|
||||
{
|
||||
return new BooleanContextData(data);
|
||||
}
|
||||
|
||||
[DataMember(Name = "b", EmitDefaultValue = false)]
|
||||
private Boolean m_value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[DataContract]
|
||||
[JsonObject]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class CaseSensitiveDictionaryContextData : PipelineContextData, IEnumerable<KeyValuePair<String, PipelineContextData>>, IReadOnlyObject
|
||||
{
|
||||
public CaseSensitiveDictionaryContextData()
|
||||
: base(PipelineContextDataType.CaseSensitiveDictionary)
|
||||
{
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Int32 Count => m_list?.Count ?? 0;
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<String> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return pair.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PipelineContextData> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return pair.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Object> IReadOnlyObject.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return pair.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<String, Int32> IndexLookup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_indexLookup == null)
|
||||
{
|
||||
m_indexLookup = new Dictionary<String, Int32>(StringComparer.Ordinal);
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
for (var i = 0; i < m_list.Count; i++)
|
||||
{
|
||||
var pair = m_list[i];
|
||||
m_indexLookup.Add(pair.Key, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_indexLookup;
|
||||
}
|
||||
}
|
||||
|
||||
private List<DictionaryContextDataPair> List
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list == null)
|
||||
{
|
||||
m_list = new List<DictionaryContextDataPair>();
|
||||
}
|
||||
|
||||
return m_list;
|
||||
}
|
||||
}
|
||||
|
||||
public PipelineContextData this[String key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var index = IndexLookup[key];
|
||||
return m_list[index].Value;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
// Existing
|
||||
if (IndexLookup.TryGetValue(key, out var index))
|
||||
{
|
||||
key = m_list[index].Key; // preserve casing
|
||||
m_list[index] = new DictionaryContextDataPair(key, value);
|
||||
}
|
||||
// New
|
||||
else
|
||||
{
|
||||
Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object IReadOnlyObject.this[String key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var index = IndexLookup[key];
|
||||
return m_list[index].Value;
|
||||
}
|
||||
}
|
||||
|
||||
internal KeyValuePair<String, PipelineContextData> this[Int32 index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var pair = m_list[index];
|
||||
return new KeyValuePair<String, PipelineContextData>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(IEnumerable<KeyValuePair<String, PipelineContextData>> pairs)
|
||||
{
|
||||
foreach (var pair in pairs)
|
||||
{
|
||||
Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(
|
||||
String key,
|
||||
PipelineContextData value)
|
||||
{
|
||||
IndexLookup.Add(key, m_list?.Count ?? 0);
|
||||
List.Add(new DictionaryContextDataPair(key, value));
|
||||
}
|
||||
|
||||
public override PipelineContextData Clone()
|
||||
{
|
||||
var result = new CaseSensitiveDictionaryContextData();
|
||||
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
result.m_list = new List<DictionaryContextDataPair>(m_list.Count);
|
||||
foreach (var item in m_list)
|
||||
{
|
||||
result.m_list.Add(new DictionaryContextDataPair(item.Key, item.Value?.Clone()));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override JToken ToJToken()
|
||||
{
|
||||
var json = new JObject();
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var item in m_list)
|
||||
{
|
||||
json.Add(item.Key, item.Value?.ToJToken() ?? JValue.CreateNull());
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public Boolean ContainsKey(String key)
|
||||
{
|
||||
return TryGetValue(key, out _);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<String, PipelineContextData>> GetEnumerator()
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return new KeyValuePair<String, PipelineContextData>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return new KeyValuePair<String, PipelineContextData>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IReadOnlyObject.GetEnumerator()
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return new KeyValuePair<String, Object>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean TryGetValue(
|
||||
String key,
|
||||
out PipelineContextData value)
|
||||
{
|
||||
if (m_list?.Count > 0 &&
|
||||
IndexLookup.TryGetValue(key, out var index))
|
||||
{
|
||||
value = m_list[index].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean IReadOnlyObject.TryGetValue(
|
||||
String key,
|
||||
out Object value)
|
||||
{
|
||||
if (TryGetValue(key, out PipelineContextData data))
|
||||
{
|
||||
value = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
[OnSerializing]
|
||||
private void OnSerializing(StreamingContext context)
|
||||
{
|
||||
if (m_list?.Count == 0)
|
||||
{
|
||||
m_list = null;
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
private sealed class DictionaryContextDataPair
|
||||
{
|
||||
public DictionaryContextDataPair(
|
||||
String key,
|
||||
PipelineContextData value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember(Name = "k")]
|
||||
public readonly String Key;
|
||||
|
||||
[DataMember(Name = "v")]
|
||||
public readonly PipelineContextData Value;
|
||||
}
|
||||
|
||||
private Dictionary<String, Int32> m_indexLookup;
|
||||
|
||||
[DataMember(Name = "d", EmitDefaultValue = false)]
|
||||
private List<DictionaryContextDataPair> m_list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[DataContract]
|
||||
[JsonObject]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class DictionaryContextData : PipelineContextData, IEnumerable<KeyValuePair<String, PipelineContextData>>, IReadOnlyObject
|
||||
{
|
||||
public DictionaryContextData()
|
||||
: base(PipelineContextDataType.Dictionary)
|
||||
{
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Int32 Count => m_list?.Count ?? 0;
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<String> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return pair.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PipelineContextData> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return pair.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Object> IReadOnlyObject.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return pair.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<String, Int32> IndexLookup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_indexLookup == null)
|
||||
{
|
||||
m_indexLookup = new Dictionary<String, Int32>(StringComparer.OrdinalIgnoreCase);
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
for (var i = 0; i < m_list.Count; i++)
|
||||
{
|
||||
var pair = m_list[i];
|
||||
m_indexLookup.Add(pair.Key, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_indexLookup;
|
||||
}
|
||||
}
|
||||
|
||||
private List<DictionaryContextDataPair> List
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_list == null)
|
||||
{
|
||||
m_list = new List<DictionaryContextDataPair>();
|
||||
}
|
||||
|
||||
return m_list;
|
||||
}
|
||||
}
|
||||
|
||||
public PipelineContextData this[String key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var index = IndexLookup[key];
|
||||
return m_list[index].Value;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
// Existing
|
||||
if (IndexLookup.TryGetValue(key, out var index))
|
||||
{
|
||||
key = m_list[index].Key; // preserve casing
|
||||
m_list[index] = new DictionaryContextDataPair(key, value);
|
||||
}
|
||||
// New
|
||||
else
|
||||
{
|
||||
Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object IReadOnlyObject.this[String key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var index = IndexLookup[key];
|
||||
return m_list[index].Value;
|
||||
}
|
||||
}
|
||||
|
||||
internal KeyValuePair<String, PipelineContextData> this[Int32 index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var pair = m_list[index];
|
||||
return new KeyValuePair<String, PipelineContextData>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(IEnumerable<KeyValuePair<String, PipelineContextData>> pairs)
|
||||
{
|
||||
foreach (var pair in pairs)
|
||||
{
|
||||
Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(
|
||||
String key,
|
||||
PipelineContextData value)
|
||||
{
|
||||
IndexLookup.Add(key, m_list?.Count ?? 0);
|
||||
List.Add(new DictionaryContextDataPair(key, value));
|
||||
}
|
||||
|
||||
public override PipelineContextData Clone()
|
||||
{
|
||||
var result = new DictionaryContextData();
|
||||
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
result.m_list = new List<DictionaryContextDataPair>(m_list.Count);
|
||||
foreach (var item in m_list)
|
||||
{
|
||||
result.m_list.Add(new DictionaryContextDataPair(item.Key, item.Value?.Clone()));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override JToken ToJToken()
|
||||
{
|
||||
var json = new JObject();
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var item in m_list)
|
||||
{
|
||||
json.Add(item.Key, item.Value?.ToJToken() ?? JValue.CreateNull());
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public Boolean ContainsKey(String key)
|
||||
{
|
||||
return TryGetValue(key, out _);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<String, PipelineContextData>> GetEnumerator()
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return new KeyValuePair<String, PipelineContextData>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return new KeyValuePair<String, PipelineContextData>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IReadOnlyObject.GetEnumerator()
|
||||
{
|
||||
if (m_list?.Count > 0)
|
||||
{
|
||||
foreach (var pair in m_list)
|
||||
{
|
||||
yield return new KeyValuePair<String, Object>(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean TryGetValue(
|
||||
String key,
|
||||
out PipelineContextData value)
|
||||
{
|
||||
if (m_list?.Count > 0 &&
|
||||
IndexLookup.TryGetValue(key, out var index))
|
||||
{
|
||||
value = m_list[index].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean IReadOnlyObject.TryGetValue(
|
||||
String key,
|
||||
out Object value)
|
||||
{
|
||||
if (TryGetValue(key, out PipelineContextData data))
|
||||
{
|
||||
value = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
[OnSerializing]
|
||||
private void OnSerializing(StreamingContext context)
|
||||
{
|
||||
if (m_list?.Count == 0)
|
||||
{
|
||||
m_list = null;
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
private sealed class DictionaryContextDataPair
|
||||
{
|
||||
public DictionaryContextDataPair(
|
||||
String key,
|
||||
PipelineContextData value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember(Name = "k")]
|
||||
public readonly String Key;
|
||||
|
||||
[DataMember(Name = "v")]
|
||||
public readonly PipelineContextData Value;
|
||||
}
|
||||
|
||||
private Dictionary<String, Int32> m_indexLookup;
|
||||
|
||||
[DataMember(Name = "d", EmitDefaultValue = false)]
|
||||
private List<DictionaryContextDataPair> m_list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static class JTokenExtensions
|
||||
{
|
||||
public static PipelineContextData ToPipelineContextData(this JToken value)
|
||||
{
|
||||
return value.ToPipelineContextData(1, 100);
|
||||
}
|
||||
|
||||
public static PipelineContextData ToPipelineContextData(
|
||||
this JToken value,
|
||||
Int32 depth,
|
||||
Int32 maxDepth)
|
||||
{
|
||||
if (depth < maxDepth)
|
||||
{
|
||||
if (value.Type == JTokenType.String)
|
||||
{
|
||||
return new StringContextData((String)value);
|
||||
}
|
||||
else if (value.Type == JTokenType.Boolean)
|
||||
{
|
||||
return new BooleanContextData((Boolean)value);
|
||||
}
|
||||
else if (value.Type == JTokenType.Float || value.Type == JTokenType.Integer)
|
||||
{
|
||||
return new NumberContextData((Double)value);
|
||||
}
|
||||
else if (value.Type == JTokenType.Object)
|
||||
{
|
||||
var subContext = new DictionaryContextData();
|
||||
var obj = (JObject)value;
|
||||
foreach (var property in obj.Properties())
|
||||
{
|
||||
subContext[property.Name] = ToPipelineContextData(property.Value, depth + 1, maxDepth);
|
||||
}
|
||||
return subContext;
|
||||
}
|
||||
else if (value.Type == JTokenType.Array)
|
||||
{
|
||||
var arrayContext = new ArrayContextData();
|
||||
var arr = (JArray)value;
|
||||
foreach (var element in arr)
|
||||
{
|
||||
arrayContext.Add(ToPipelineContextData(element, depth + 1, maxDepth));
|
||||
}
|
||||
return arrayContext;
|
||||
}
|
||||
else if (value.Type == JTokenType.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't understand the type or have reached our max, return as string
|
||||
return new StringContextData(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[DataContract]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public sealed class NumberContextData : PipelineContextData, INumber
|
||||
{
|
||||
public NumberContextData(Double value)
|
||||
: base(PipelineContextDataType.Number)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
public Double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
}
|
||||
|
||||
public override PipelineContextData Clone()
|
||||
{
|
||||
return new NumberContextData(m_value);
|
||||
}
|
||||
|
||||
public override JToken ToJToken()
|
||||
{
|
||||
if (Double.IsNaN(m_value) || m_value == Double.PositiveInfinity || m_value == Double.NegativeInfinity)
|
||||
{
|
||||
return (JToken)m_value;
|
||||
}
|
||||
|
||||
var floored = Math.Floor(m_value);
|
||||
if (m_value == floored && m_value <= (Double)Int32.MaxValue && m_value >= (Double)Int32.MinValue)
|
||||
{
|
||||
Int32 flooredInt = (Int32)floored;
|
||||
return (JToken)flooredInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (JToken)m_value;
|
||||
}
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return m_value.ToString("G15", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
Double INumber.GetNumber()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static implicit operator Double(NumberContextData data)
|
||||
{
|
||||
return data.Value;
|
||||
}
|
||||
|
||||
public static implicit operator NumberContextData(Double data)
|
||||
{
|
||||
return new NumberContextData(data);
|
||||
}
|
||||
|
||||
[DataMember(Name = "n", EmitDefaultValue = false)]
|
||||
private Double m_value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all template tokens
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
[JsonConverter(typeof(PipelineContextDataJsonConverter))]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public abstract class PipelineContextData
|
||||
{
|
||||
protected PipelineContextData(Int32 type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
[DataMember(Name = "t", EmitDefaultValue = false)]
|
||||
internal Int32 Type { get; }
|
||||
|
||||
public abstract PipelineContextData Clone();
|
||||
|
||||
public abstract JToken ToJToken();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static class PipelineContextDataExtensions
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static ArrayContextData AssertArray(
|
||||
this PipelineContextData value,
|
||||
String objectDescription)
|
||||
{
|
||||
if (value is ArrayContextData array)
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unexpected type '{value?.GetType().Name}' encountered while reading '{objectDescription}'. The type '{nameof(ArrayContextData)}' was expected.");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static DictionaryContextData AssertDictionary(
|
||||
this PipelineContextData value,
|
||||
String objectDescription)
|
||||
{
|
||||
if (value is DictionaryContextData dictionary)
|
||||
{
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unexpected type '{value?.GetType().Name}' encountered while reading '{objectDescription}'. The type '{nameof(DictionaryContextData)}' was expected.");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static StringContextData AssertString(
|
||||
this PipelineContextData value,
|
||||
String objectDescription)
|
||||
{
|
||||
if (value is StringContextData str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unexpected type '{value?.GetType().Name}' encountered while reading '{objectDescription}'. The type '{nameof(StringContextData)}' was expected.");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static BooleanContextData AssertBoolean(
|
||||
this PipelineContextData value,
|
||||
String objectDescription)
|
||||
{
|
||||
if (value is BooleanContextData boolValue)
|
||||
{
|
||||
return boolValue;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unexpected type '{value?.GetType().Name}' encountered while reading '{objectDescription}'. The type '{nameof(BooleanContextData)}' was expected.");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static NumberContextData AssertNumber(
|
||||
this PipelineContextData value,
|
||||
String objectDescription)
|
||||
{
|
||||
if (value is NumberContextData num)
|
||||
{
|
||||
return num;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unexpected type '{value?.GetType().Name}' encountered while reading '{objectDescription}'. The type '{nameof(NumberContextData)}' was expected.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all context data objects (depth first)
|
||||
/// </summary>
|
||||
internal static IEnumerable<PipelineContextData> Traverse(this PipelineContextData value)
|
||||
{
|
||||
return Traverse(value, omitKeys: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all context data objects (depth first)
|
||||
/// </summary>
|
||||
internal static IEnumerable<PipelineContextData> Traverse(
|
||||
this PipelineContextData value,
|
||||
Boolean omitKeys)
|
||||
{
|
||||
yield return value;
|
||||
|
||||
if (value is ArrayContextData || value is DictionaryContextData)
|
||||
{
|
||||
var state = new TraversalState(null, value);
|
||||
while (state != null)
|
||||
{
|
||||
if (state.MoveNext(omitKeys))
|
||||
{
|
||||
value = state.Current;
|
||||
yield return value;
|
||||
|
||||
if (value is ArrayContextData || value is DictionaryContextData)
|
||||
{
|
||||
state = new TraversalState(state, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state = state.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static JToken ToJToken(this PipelineContextData value)
|
||||
{
|
||||
JToken result;
|
||||
|
||||
if (value is StringContextData str)
|
||||
{
|
||||
result = str.Value ?? String.Empty;
|
||||
}
|
||||
else if (value is BooleanContextData booleanValue)
|
||||
{
|
||||
result = booleanValue.Value;
|
||||
}
|
||||
else if (value is NumberContextData num)
|
||||
{
|
||||
result = num.Value;
|
||||
}
|
||||
else if (value is ArrayContextData array)
|
||||
{
|
||||
var jarray = new JArray();
|
||||
|
||||
foreach (var item in array)
|
||||
{
|
||||
jarray.Add(item.ToJToken()); // Recurse
|
||||
}
|
||||
|
||||
result = jarray;
|
||||
}
|
||||
else if (value is DictionaryContextData dictionary)
|
||||
{
|
||||
var jobject = new JObject();
|
||||
|
||||
foreach (var pair in dictionary)
|
||||
{
|
||||
var key = pair.Key ?? String.Empty;
|
||||
var value2 = pair.Value.ToJToken(); // Recurse
|
||||
|
||||
if (value2 != null)
|
||||
{
|
||||
jobject[key] = value2;
|
||||
}
|
||||
}
|
||||
|
||||
result = jobject;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Internal error reading the template. Expected a string, an array, or a dictionary");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static TemplateToken ToTemplateToken(this PipelineContextData data)
|
||||
{
|
||||
if (data is null)
|
||||
{
|
||||
return new NullToken(null, null, null);
|
||||
}
|
||||
|
||||
switch (data.Type)
|
||||
{
|
||||
case PipelineContextDataType.Dictionary:
|
||||
var dictionary = data.AssertDictionary("dictionary");
|
||||
var mapping = new MappingToken(null, null, null);
|
||||
if (dictionary.Count > 0)
|
||||
{
|
||||
foreach (var pair in dictionary)
|
||||
{
|
||||
var key = new StringToken(null, null, null, pair.Key);
|
||||
var value = pair.Value.ToTemplateToken();
|
||||
mapping.Add(key, value);
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
|
||||
case PipelineContextDataType.Array:
|
||||
var array = data.AssertArray("array");
|
||||
var sequence = new SequenceToken(null, null, null);
|
||||
if (array.Count > 0)
|
||||
{
|
||||
foreach (var item in array)
|
||||
{
|
||||
sequence.Add(item.ToTemplateToken());
|
||||
}
|
||||
}
|
||||
return sequence;
|
||||
|
||||
case PipelineContextDataType.String:
|
||||
var stringData = data as StringContextData;
|
||||
return new StringToken(null, null, null, stringData.Value);
|
||||
|
||||
case PipelineContextDataType.Boolean:
|
||||
var booleanData = data as BooleanContextData;
|
||||
return new BooleanToken(null, null, null, booleanData.Value);
|
||||
|
||||
case PipelineContextDataType.Number:
|
||||
var numberData = data as NumberContextData;
|
||||
return new NumberToken(null, null, null, numberData.Value);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Unexpected {nameof(PipelineContextDataType)} type '{data.Type}'");
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TraversalState
|
||||
{
|
||||
public TraversalState(
|
||||
TraversalState parent,
|
||||
PipelineContextData data)
|
||||
{
|
||||
Parent = parent;
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
public Boolean MoveNext(Boolean omitKeys)
|
||||
{
|
||||
switch (m_data.Type)
|
||||
{
|
||||
case PipelineContextDataType.Array:
|
||||
var array = m_data.AssertArray("array");
|
||||
if (++m_index < array.Count)
|
||||
{
|
||||
Current = array[m_index];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Current = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
case PipelineContextDataType.Dictionary:
|
||||
var dictionary = m_data.AssertDictionary("dictionary");
|
||||
|
||||
// Return the value
|
||||
if (m_isKey)
|
||||
{
|
||||
m_isKey = false;
|
||||
Current = dictionary[m_index].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (++m_index < dictionary.Count)
|
||||
{
|
||||
// Skip the key, return the value
|
||||
if (omitKeys)
|
||||
{
|
||||
m_isKey = false;
|
||||
Current = dictionary[m_index].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the key
|
||||
m_isKey = true;
|
||||
Current = new StringContextData(dictionary[m_index].Key);
|
||||
return true;
|
||||
}
|
||||
|
||||
Current = null;
|
||||
return false;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Unexpected {nameof(PipelineContextData)} type '{m_data.Type}'");
|
||||
}
|
||||
}
|
||||
|
||||
private PipelineContextData m_data;
|
||||
private Int32 m_index = -1;
|
||||
private Boolean m_isKey;
|
||||
public PipelineContextData Current;
|
||||
public TraversalState Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using GitHub.Services.WebApi;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
/// <summary>
|
||||
/// JSON serializer for ContextData objects
|
||||
/// </summary>
|
||||
internal sealed class PipelineContextDataJsonConverter : VssSecureJsonConverter
|
||||
{
|
||||
public override Boolean CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override Boolean CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(PipelineContextData).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
|
||||
}
|
||||
|
||||
public override Object ReadJson(
|
||||
JsonReader reader,
|
||||
Type objectType,
|
||||
Object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
return new StringContextData(reader.Value.ToString());
|
||||
|
||||
case JsonToken.Boolean:
|
||||
return new BooleanContextData((Boolean)reader.Value);
|
||||
|
||||
case JsonToken.Float:
|
||||
return new NumberContextData((Double)reader.Value);
|
||||
|
||||
case JsonToken.Integer:
|
||||
return new NumberContextData((Double)(Int64)reader.Value);
|
||||
|
||||
case JsonToken.StartObject:
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
Int32? type = null;
|
||||
JObject value = JObject.Load(reader);
|
||||
if (!value.TryGetValue("t", StringComparison.OrdinalIgnoreCase, out JToken typeValue))
|
||||
{
|
||||
type = PipelineContextDataType.String;
|
||||
}
|
||||
else if (typeValue.Type == JTokenType.Integer)
|
||||
{
|
||||
type = (Int32)typeValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return existingValue;
|
||||
}
|
||||
|
||||
Object newValue = null;
|
||||
switch (type)
|
||||
{
|
||||
case PipelineContextDataType.String:
|
||||
newValue = new StringContextData(null);
|
||||
break;
|
||||
|
||||
case PipelineContextDataType.Array:
|
||||
newValue = new ArrayContextData();
|
||||
break;
|
||||
|
||||
case PipelineContextDataType.Dictionary:
|
||||
newValue = new DictionaryContextData();
|
||||
break;
|
||||
|
||||
case PipelineContextDataType.Boolean:
|
||||
newValue = new BooleanContextData(false);
|
||||
break;
|
||||
|
||||
case PipelineContextDataType.Number:
|
||||
newValue = new NumberContextData(0);
|
||||
break;
|
||||
|
||||
case PipelineContextDataType.CaseSensitiveDictionary:
|
||||
newValue = new CaseSensitiveDictionaryContextData();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Unexpected {nameof(PipelineContextDataType)} '{type}'");
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
using (JsonReader objectReader = value.CreateReader())
|
||||
{
|
||||
serializer.Populate(objectReader, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public override void WriteJson(
|
||||
JsonWriter writer,
|
||||
Object value,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
base.WriteJson(writer, value, serializer);
|
||||
if (Object.ReferenceEquals(value, null))
|
||||
{
|
||||
writer.WriteNull();
|
||||
}
|
||||
else if (value is StringContextData stringData)
|
||||
{
|
||||
writer.WriteValue(stringData.Value);
|
||||
}
|
||||
else if (value is BooleanContextData boolData)
|
||||
{
|
||||
writer.WriteValue(boolData.Value);
|
||||
}
|
||||
else if (value is NumberContextData numberData)
|
||||
{
|
||||
writer.WriteValue(numberData.Value);
|
||||
}
|
||||
else if (value is ArrayContextData arrayData)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("t");
|
||||
writer.WriteValue(PipelineContextDataType.Array);
|
||||
if (arrayData.Count > 0)
|
||||
{
|
||||
writer.WritePropertyName("a");
|
||||
writer.WriteStartArray();
|
||||
foreach (var item in arrayData)
|
||||
{
|
||||
serializer.Serialize(writer, item);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
else if (value is DictionaryContextData dictionaryData)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("t");
|
||||
writer.WriteValue(PipelineContextDataType.Dictionary);
|
||||
if (dictionaryData.Count > 0)
|
||||
{
|
||||
writer.WritePropertyName("d");
|
||||
writer.WriteStartArray();
|
||||
foreach (var pair in dictionaryData)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("k");
|
||||
writer.WriteValue(pair.Key);
|
||||
writer.WritePropertyName("v");
|
||||
serializer.Serialize(writer, pair.Value);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
else if (value is CaseSensitiveDictionaryContextData caseSensitiveDictionaryData)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("t");
|
||||
writer.WriteValue(PipelineContextDataType.CaseSensitiveDictionary);
|
||||
if (caseSensitiveDictionaryData.Count > 0)
|
||||
{
|
||||
writer.WritePropertyName("d");
|
||||
writer.WriteStartArray();
|
||||
foreach (var pair in caseSensitiveDictionaryData)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("k");
|
||||
writer.WriteValue(pair.Key);
|
||||
writer.WritePropertyName("v");
|
||||
serializer.Serialize(writer, pair.Value);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"Unexpected type '{value.GetType().Name}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
internal static class PipelineContextDataType
|
||||
{
|
||||
internal const Int32 String = 0;
|
||||
|
||||
internal const Int32 Array = 1;
|
||||
|
||||
internal const Int32 Dictionary = 2;
|
||||
|
||||
internal const Int32 Boolean = 3;
|
||||
|
||||
internal const Int32 Number = 4;
|
||||
|
||||
internal const Int32 CaseSensitiveDictionary = 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||
using GitHub.Services.WebApi.Internal;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[DataContract]
|
||||
[ClientIgnore]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public sealed class StringContextData : PipelineContextData, IString
|
||||
{
|
||||
public StringContextData(String value)
|
||||
: base(PipelineContextDataType.String)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
public String Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_value == null)
|
||||
{
|
||||
m_value = String.Empty;
|
||||
}
|
||||
|
||||
return m_value;
|
||||
}
|
||||
}
|
||||
|
||||
public override PipelineContextData Clone()
|
||||
{
|
||||
return new StringContextData(m_value);
|
||||
}
|
||||
|
||||
public override JToken ToJToken()
|
||||
{
|
||||
return (JToken)m_value;
|
||||
}
|
||||
|
||||
String IString.GetString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static implicit operator String(StringContextData data)
|
||||
{
|
||||
return data.Value;
|
||||
}
|
||||
|
||||
public static implicit operator StringContextData(String data)
|
||||
{
|
||||
return new StringContextData(data);
|
||||
}
|
||||
|
||||
[OnSerializing]
|
||||
private void OnSerializing(StreamingContext context)
|
||||
{
|
||||
if (m_value?.Length == 0)
|
||||
{
|
||||
m_value = null;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Name = "s", EmitDefaultValue = false)]
|
||||
private String m_value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GitHub.DistributedTask.ObjectTemplating;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
internal static class TemplateMemoryExtensions
|
||||
{
|
||||
internal static void AddBytes(
|
||||
this TemplateMemory memory,
|
||||
PipelineContextData value,
|
||||
Boolean traverse)
|
||||
{
|
||||
var bytes = CalculateBytes(memory, value, traverse);
|
||||
memory.AddBytes(bytes);
|
||||
}
|
||||
|
||||
internal static Int32 CalculateBytes(
|
||||
this TemplateMemory memory,
|
||||
PipelineContextData value,
|
||||
Boolean traverse)
|
||||
{
|
||||
var enumerable = traverse ? value.Traverse() : new[] { value } as IEnumerable<PipelineContextData>;
|
||||
var result = 0;
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
// This measurement doesn't have to be perfect
|
||||
// https://codeblog.jonskeet.uk/2011/04/05/of-memory-and-strings/
|
||||
switch (item?.Type)
|
||||
{
|
||||
case PipelineContextDataType.String:
|
||||
var str = item.AssertString("string").Value;
|
||||
checked
|
||||
{
|
||||
result += TemplateMemory.MinObjectSize + TemplateMemory.StringBaseOverhead + ((str?.Length ?? 0) * sizeof(Char));
|
||||
}
|
||||
break;
|
||||
|
||||
case PipelineContextDataType.Array:
|
||||
case PipelineContextDataType.Dictionary:
|
||||
case PipelineContextDataType.Boolean:
|
||||
case PipelineContextDataType.Number:
|
||||
// Min object size is good enough. Allows for base + a few fields.
|
||||
checked
|
||||
{
|
||||
result += TemplateMemory.MinObjectSize;
|
||||
}
|
||||
break;
|
||||
|
||||
case null:
|
||||
checked
|
||||
{
|
||||
result += IntPtr.Size;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Unexpected pipeline context data type '{item.Type}'");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
|
||||
namespace GitHub.DistributedTask.Pipelines.ContextData
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static class TemplateTokenExtensions
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static StringContextData ToContextData(this LiteralToken literal)
|
||||
{
|
||||
var token = literal as TemplateToken;
|
||||
var contextData = token.ToContextData();
|
||||
return contextData.AssertString("converted literal token");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static ArrayContextData ToContextData(this SequenceToken sequence)
|
||||
{
|
||||
var token = sequence as TemplateToken;
|
||||
var contextData = token.ToContextData();
|
||||
return contextData.AssertArray("converted sequence token");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static PipelineContextData ToContextData(this TemplateToken token)
|
||||
{
|
||||
switch (token.Type)
|
||||
{
|
||||
case TokenType.Mapping:
|
||||
var mapping = token as MappingToken;
|
||||
var dictionary = new DictionaryContextData();
|
||||
if (mapping.Count > 0)
|
||||
{
|
||||
foreach (var pair in mapping)
|
||||
{
|
||||
var keyLiteral = pair.Key.AssertString("dictionary context data key");
|
||||
var key = keyLiteral.Value;
|
||||
var value = pair.Value.ToContextData();
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
}
|
||||
return dictionary;
|
||||
|
||||
case TokenType.Sequence:
|
||||
var sequence = token as SequenceToken;
|
||||
var array = new ArrayContextData();
|
||||
if (sequence.Count > 0)
|
||||
{
|
||||
foreach (var item in sequence)
|
||||
{
|
||||
array.Add(item.ToContextData());
|
||||
}
|
||||
}
|
||||
return array;
|
||||
|
||||
case TokenType.Null:
|
||||
return null;
|
||||
|
||||
case TokenType.Boolean:
|
||||
var boolean = token as BooleanToken;
|
||||
return new BooleanContextData(boolean.Value);
|
||||
|
||||
case TokenType.Number:
|
||||
var number = token as NumberToken;
|
||||
return new NumberContextData(number.Value);
|
||||
|
||||
case TokenType.String:
|
||||
var stringToken = token as StringToken;
|
||||
return new StringContextData(stringToken.Value);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Unexpected {nameof(TemplateToken)} type '{token.Type}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user