GenerateToolingFeed/V4Format/V4FormatFeedEntryUpdater.cs (132 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using Newtonsoft.Json.Linq;
namespace GenerateToolingFeed.V4Format
{
internal class V4FormatFeedEntryUpdater : IFeedEntryUpdater
{
private readonly string _tag;
private readonly IDictionary<string, string> _dotnetToItemTemplates = new Dictionary<string, string>()
{
{ "net9-isolated", "Microsoft.Azure.Functions.Worker.ItemTemplates.NetCore" },
{ "net8", "Microsoft.Azure.WebJobs.ItemTemplates" },
{ "net8-isolated", "Microsoft.Azure.Functions.Worker.ItemTemplates.NetCore" },
{ "net7-isolated", "Microsoft.Azure.Functions.Worker.ItemTemplates.NetCore" },
{ "net6-isolated", "Microsoft.Azure.Functions.Worker.ItemTemplates.NetCore"},
{ "net6", "Microsoft.Azure.WebJobs.ItemTemplates" },
{ "net5-isolated", "Microsoft.Azure.Functions.Worker.ItemTemplates"},
{ "netcore3", "Microsoft.Azure.WebJobs.ItemTemplates" },
{ "netcore2", "Microsoft.Azure.WebJobs.ItemTemplates" },
{ "netframework", "Microsoft.Azure.WebJobs.ItemTemplates" },
{ "netfx-isolated", "Microsoft.Azure.Functions.Worker.ItemTemplates.NetFx" }
};
private readonly IDictionary<string, string> _dotnetToProjectTemplates = new Dictionary<string, string>()
{
{ "net9-isolated", "Microsoft.Azure.Functions.Worker.ProjectTemplates" },
{ "net8", "Microsoft.Azure.WebJobs.ProjectTemplates" },
{ "net8-isolated", "Microsoft.Azure.Functions.Worker.ProjectTemplates" },
{ "net7-isolated", "Microsoft.Azure.Functions.Worker.ProjectTemplates" },
{ "net6-isolated", "Microsoft.Azure.Functions.Worker.ProjectTemplates" },
{ "net6", "Microsoft.Azure.WebJobs.ProjectTemplates" },
{ "net5-isolated", "Microsoft.Azure.Functions.Worker.ProjectTemplates" },
{ "netcore3", "Microsoft.Azure.WebJobs.ProjectTemplates" },
{ "netcore2", "Microsoft.Azure.WebJobs.ProjectTemplates" },
{ "netframework", "Microsoft.Azure.WebJobs.ProjectTemplates" },
{ "netfx-isolated", "Microsoft.Azure.Functions.Worker.ProjectTemplates" }
};
private static readonly IDictionary<string, string> _linkSuffix = new Dictionary<string, string>()
{
{
"v0", "_inproc"
}
};
private static readonly IDictionary<string, List<string>> FilteredOSByTag = new Dictionary<string, List<string>>()
{
{ "v0", new List<string> {"Windows", "MacOs", "Linux" } },
{ "v4", new List<string> {"Windows", "MacOs", "Linux"} }
};
public V4FormatFeedEntryUpdater(string tag)
{
_tag = tag;
}
public JObject GetUpdatedFeedEntry(JObject feed, CoreToolsInfo coreToolsInfo)
{
V4FormatFeedEntry feedEntry = feed.ToObject<V4FormatFeedEntry>();
UpdateCoreToolsReferences(feedEntry.coreTools, coreToolsInfo);
UpdateDotnetTemplatesToLatest(feedEntry.workerRuntimes, coreToolsInfo.MajorVersion);
Helper.MergeObjectToJToken(feed, feedEntry);
return feed;
}
public void UpdateCoreToolsReferences(V4FormatCliEntry[] cliEntries, CoreToolsInfo coreToolsInfo)
{
foreach (var cliEntry in cliEntries)
{
var OperatingSystems = FilteredOSByTag[_tag];
// temporary change to get around the disk space issue on agents
if (OperatingSystems.Contains(cliEntry.OS, StringComparer.InvariantCultureIgnoreCase))
{
bool minified = Helper.ShouldBeMinified(cliEntry);
string zipFileName = GetZipFileName(cliEntry.OS, cliEntry.Architecture, coreToolsInfo, _tag, minified);
cliEntry.sha2 = GetShaFileContent(coreToolsInfo.ArtifactsDirectory, zipFileName);
cliEntry.downloadLink = GetDownloadLink(cliEntry.OS, cliEntry.Architecture, coreToolsInfo, _tag, minified);
}
}
}
private static string GetZipFileName(string os, string architecture, CoreToolsInfo coreToolsInfo, string tag, bool isMinified = false)
{
string rid = isMinified ? "min." : string.Empty;
rid += Helper.GetRuntimeIdentifier(false, os, architecture);
string linkSuffix = _linkSuffix.ContainsKey(tag) ? _linkSuffix[tag] : string.Empty;
string version = _linkSuffix.ContainsKey(tag) ? coreToolsInfo.InprocVersion : coreToolsInfo.Version;
return $"Azure.Functions.Cli.{rid}{linkSuffix}.{version}.zip";
}
private static string GetDownloadLink(string os, string architecture, CoreToolsInfo coreToolsInfo, string tag, bool isMinified = false)
{
string linkSuffix = _linkSuffix.ContainsKey(tag) ? _linkSuffix[tag] : string.Empty;
string version = _linkSuffix.ContainsKey(tag) ? coreToolsInfo.InprocVersion : coreToolsInfo.Version;
string rid = isMinified ? "min." : string.Empty;
rid += Helper.GetRuntimeIdentifier(false, os, architecture);
string containerName = $"{coreToolsInfo.MajorVersion}.0.{coreToolsInfo.BuildId}";
var url = $"https://cdn.functions.azure.com/public/{containerName}/Azure.Functions.Cli.{rid}{linkSuffix}.{version}.zip";
string bypassDownloadLinkValidation = Environment.GetEnvironmentVariable("bypassDownloadLinkValidation");
if (bypassDownloadLinkValidation != "1" && !Helper.IsValidDownloadLink(url))
{
throw new Exception($"{url} is not valid or no found. Cannot generate cli feed file");
}
return url;
}
public static string GetShaFileContent(string zipfilePath, string fileName)
{
string path = Path.Combine(zipfilePath, fileName);
string shaFilePath = $"{path}.sha2";
return File.ReadAllText(shaFilePath);
}
private void UpdateDotnetTemplatesToLatest(IDictionary<string, IDictionary<string, object>> workerRuntimes, int coreToolsMajor)
{
if (!workerRuntimes.TryGetValue("dotnet", out IDictionary<string, object> dotnetInfo))
{
throw new Exception("Could not find 'dotnet' worker runtime information in the feed.");
}
foreach (KeyValuePair<string, object> keyValInfo in dotnetInfo)
{
string dotnetEntryLabel = keyValInfo.Key;
JObject dotnetEntryToken = keyValInfo.Value as JObject;
V4FormatDotnetEntry dotnetEntry = dotnetEntryToken?.ToObject<V4FormatDotnetEntry>() ?? throw new Exception($"Cannot parse 'dotnet' object in the feed with label '{dotnetEntryLabel}'");
if (!_dotnetToItemTemplates.TryGetValue(dotnetEntryLabel, out string itemTemplates))
{
throw new Exception($"Cannot find the template package: Unidentified dotnet label '{dotnetEntryLabel}'.");
}
dotnetEntry.itemTemplates = Helper.GetTemplateUrl($"{itemTemplates}", coreToolsMajor);
if (!_dotnetToProjectTemplates.TryGetValue(dotnetEntryLabel, out string projecTemplate))
{
throw new Exception($"Cannot find the template package: Unidentified dotnet label '{dotnetEntryLabel}'.");
}
dotnetEntry.projectTemplates = Helper.GetTemplateUrl($"{projecTemplate}", coreToolsMajor);
Helper.MergeObjectToJToken(dotnetEntryToken, dotnetEntry);
}
}
}
}