Skip to content

Commit

Permalink
Allow builds that potentially aren't 100% deployed to work.
Browse files Browse the repository at this point in the history
There's some weird issue with sitetest2's build completion checks, so I'm trying to work around it now until they provide a proper fix.
  • Loading branch information
MaximumADHD committed Feb 12, 2021
1 parent 5686326 commit 2d35944
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 43 deletions.
7 changes: 6 additions & 1 deletion ProjectSrc/Bootstrapper/History/StudioDeployLogs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace RobloxStudioModManager
{
public class StudioDeployLogs
{
private const string LogPattern = "New (Studio6?4?) (version-[a-f\\d]+) at (\\d+/\\d+/\\d+ \\d+:\\d+:\\d+ [A,P]M), file version: (\\d+), (\\d+), (\\d+), (\\d+)...Done!";
private const string LogPattern = "New (Studio6?4?) (version-[a-f\\d]+) at (\\d+/\\d+/\\d+ \\d+:\\d+:\\d+ [A,P]M), file version: (\\d+), (\\d+), (\\d+), (\\d+)...";
private const int EarliestChangelist = 338804; // The earliest acceptable changelist of Roblox Studio, with explicit 64-bit versions declared via DeployHistory.txt

public string Branch { get; private set; }
Expand Down Expand Up @@ -96,6 +96,11 @@ private void UpdateLogs(string deployHistory, int maxVersion)

if (timespan.TotalDays > 90)
continue;

// Unverified builds might need a moment.

if (timespan.TotalMinutes < 5)
continue;

HashSet<DeployLog> targetList;

Expand Down
220 changes: 186 additions & 34 deletions ProjectSrc/Bootstrapper/StudioBootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Windows.Forms;

using Microsoft.Win32;
using System.Threading;

namespace RobloxStudioModManager
{
Expand Down Expand Up @@ -307,9 +308,7 @@ public static List<Process> GetRunningStudioProcesses()

private void deleteUnusedFiles()
{
var taskQueue = new List<Task>();
string studioDir = GetLocalStudioDirectory();

setStatus("Deleting unused files...");

if (newManifestEntries != null)
Expand Down Expand Up @@ -503,14 +502,11 @@ private static string fixFilePath(string pkgName, string filePath)
return filePath.Replace('/', '\\');
}

private async Task installPackage(HashSet<string> writtenFiles, Package package)
private bool shouldFetchPackage(Package package)
{
string pkgName = package.Name;
var pkgInfo = pkgRegistry.GetSubKey(pkgName);

string studioDir = GetLocalStudioDirectory();
string downloads = getDirectory(studioDir, "downloads");

string oldSig = pkgInfo.GetString("Signature");
string newSig = package.Signature;

Expand All @@ -522,32 +518,87 @@ private async Task installPackage(HashSet<string> writtenFiles, Package package)
MaxProgress += fileCount;
Progress += fileCount;

return;
return false;
}

string zipFileUrl = $"https://s3.amazonaws.com/setup.{Branch}.com/{buildVersion}-{pkgName}";
string zipExtractPath = Path.Combine(downloads, package.Name);
return true;
}

private async Task<bool> packageExists(Package package)
{
try
{
echo($"Verifying availability of: {package.Name}");

string pkgName = package.Name;
var zipFileUrl = new Uri($"https://s3.amazonaws.com/setup.{Branch}.com/{buildVersion}-{pkgName}");

var request = WebRequest.Create(zipFileUrl) as HttpWebRequest;
request.Headers.Set("UserAgent", UserAgent);
request.Method = "HEAD";

echo($"Installing package {zipFileUrl}");
MaxProgress++;
var response = await request
.GetResponseAsync()
.ConfigureAwait(false)
as HttpWebResponse;

var statusCode = response.StatusCode;
response.Close();

return (statusCode == HttpStatusCode.OK);
}
catch
{
return false;
}
}

private async Task<byte[]> installPackage(Package package)
{
byte[] result = null;
string pkgName = package.Name;
string zipFileUrl = $"https://s3.amazonaws.com/setup.{Branch}.com/{buildVersion}-{pkgName}";

using (var localHttp = new WebClient())
{
localHttp.Headers.Set("UserAgent", UserAgent);
echo($"Installing package {zipFileUrl}");
MaxProgress++;

try
{
var getFile = localHttp.DownloadDataTaskAsync(zipFileUrl);
byte[] fileContents = await getFile.ConfigureAwait(false);

// If the size of the file we downloaded does not match the packed
// size specified in the manifest, then this file isn't valid.

// Download the zip file package.
byte[] fileContents = await localHttp
.DownloadDataTaskAsync(zipFileUrl)
.ConfigureAwait(false);
if (fileContents.Length != package.PackedSize)
throw new InvalidDataException($"{pkgName} expected packed size: {package.PackedSize} but got: {fileContents.Length}");

// If the size of the file we downloaded does not match the packed size specified
// in the manifest, then this file isn't valid.
Progress++;
result = fileContents;
}
catch (Exception e)
{
echo($"Error while fetching package {pkgName}:");
echo(e.Message);
}
}

if (fileContents.Length != package.PackedSize)
throw new InvalidDataException($"{package.Name} expected packed size: {package.PackedSize} but got: {fileContents.Length}");
return result;
}

Progress++;
}
private void extractPackage(HashSet<string> writtenFiles, Package package)
{
Contract.Requires(package.Data != null);
string pkgName = package.Name;

var pkgInfo = pkgRegistry.GetSubKey(pkgName);
string studioDir = GetLocalStudioDirectory();

string downloads = getDirectory(studioDir, "downloads");
string zipExtractPath = Path.Combine(downloads, pkgName);

using (var archive = ZipFile.OpenRead(zipExtractPath))
{
Expand All @@ -561,8 +612,8 @@ private async Task installPackage(HashSet<string> writtenFiles, Package package)
string localRootDir = null;
MaxProgress += numFiles;

if (knownRoots.ContainsKey(package.Name))
localRootDir = knownRoots[package.Name];
if (knownRoots.ContainsKey(pkgName))
localRootDir = knownRoots[pkgName];

foreach (ZipArchiveEntry entry in archive.Entries)
{
Expand Down Expand Up @@ -815,7 +866,7 @@ private async Task<bool> shutdownStudioProcesses()
return !cancelled;
}

public async Task Bootstrap(string targetVersion = "")
public async Task<bool> Bootstrap(string targetVersion = "")
{
setStatus("Checking for updates");
echo("Checking build installation...");
Expand All @@ -837,20 +888,23 @@ public async Task Bootstrap(string targetVersion = "")
if (!shouldInstall)
shouldInstall = (fastVersion != currentVersion);

if (!shouldInstall && !string.IsNullOrEmpty(targetVersion))
{
string versionOverload = versionRegistry.GetString("VersionOverload");
shouldInstall = (targetVersion != versionOverload);
}
string versionOverload = versionRegistry.GetString("VersionOverload");

if (targetVersion != versionOverload)
shouldInstall = true;

if (shouldInstall)
{
if (currentBranch != "roblox")
echo("Possible update detected, verifying...");

var getVersionInfo = GetCurrentVersionInfo(Branch, versionRegistry, fastVersion, targetVersion);
var getVersionInfo = GetCurrentVersionInfo(currentBranch, versionRegistry, fastVersion, targetVersion);
versionInfo = await getVersionInfo.ConfigureAwait(true);

if (targetVersion == versionOverload)
if (fastVersion != versionInfo.Guid)
shouldInstall = false;

buildVersion = versionInfo.Guid;
}
else
Expand All @@ -877,8 +931,8 @@ public async Task Bootstrap(string targetVersion = "")

setStatus($"Installing Version {versionId} of Roblox Studio...");

var taskQueue = new List<Task>();
var writtenFiles = new HashSet<string>();
var taskQueue = new List<Task>();

echo("Grabbing package manifest...");

Expand All @@ -905,12 +959,108 @@ public async Task Bootstrap(string targetVersion = "")
MaxProgress = 0;
ProgressBarStyle = ProgressBarStyle.Continuous;

foreach (var package in pkgManifest)
foreach (Package package in pkgManifest)
{
package.ShouldInstall = shouldFetchPackage(package);

if (!package.ShouldInstall)
{
package.Exists = true;
continue;
}

Task verify = Task.Run(async () =>
{
var doesExist = packageExists(package);
package.Exists = await doesExist.ConfigureAwait(false);
});

taskQueue.Add(verify);
}

await Task
.WhenAll(taskQueue)
.ConfigureAwait(true);

taskQueue.Clear();

foreach (Package package in pkgManifest)
{
Task installer = Task.Run(() => installPackage(writtenFiles, package));
if (!package.Exists)
{
setStatus("Installation Failed!");
echo($"ERROR WHILE INSTALLING: Package {package.Name} could not be fetched! Skipping installation for now.");

Progress = 1;
MaxProgress = 1;
ProgressBarStyle = ProgressBarStyle.Marquee;

var timeout = Task.Delay(2000);
await timeout.ConfigureAwait(false);

return false;
}

if (!package.ShouldInstall)
continue;

var installer = Task.Run(async () =>
{
bool success = true;
try
{
var install = installPackage(package);
package.Data = await install.ConfigureAwait(false);
extractPackage(writtenFiles, package);
}
catch
{
success = false;
}
return success;
});

taskQueue.Add(installer);
}

await Task
.WhenAll(taskQueue)
.ConfigureAwait(true);

foreach (var task in taskQueue)
{
bool passed = true;

if (task is Task<bool> boolTask)
if (!boolTask.Result)
passed = false;

if (task.IsFaulted)
passed = false;

if (!passed)
{
setStatus("Installation Failed!");
echo("One or more packages failed to install correctly! Skipping update for now...");

await Task
.Delay(500)
.ConfigureAwait(false);

return false;
}
}

taskQueue.Clear();

foreach (Package package in pkgManifest)
{
var extract = Task.Run(() => extractPackage(writtenFiles, package));
taskQueue.Add(extract);
}

await Task
.WhenAll(taskQueue)
.ConfigureAwait(true);
Expand All @@ -930,7 +1080,7 @@ await Task
string studioPath = GetLocalStudioPath();
string apiPath = Path.Combine(studioDir, "API-Dump.json");

Process dumpApi = Process.Start(studioPath, $"-API \"{apiPath}\"");
var dumpApi = Process.Start(studioPath, $"-API \"{apiPath}\"");
dumpApi.WaitForExit();
}

Expand Down Expand Up @@ -1011,6 +1161,8 @@ await ClassIconEditor
start.Dispose();
});
}

return true;
}
}
}
19 changes: 11 additions & 8 deletions ProjectSrc/Utility/Package.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RobloxStudioModManager
namespace RobloxStudioModManager
{
public struct Package
public class Package
{
public string Name { get; set; }
public string Signature { get; set; }
public int PackedSize { get; set; }
public int Size { get; set; }

public byte[] Data { get; set; }
public bool Exists { get; set; }
public bool ShouldInstall { get; set; }

public override string ToString()
{
return $"[{Signature}] {Name}";
}
}
}
Binary file modified RobloxStudioModManager.exe
Binary file not shown.

0 comments on commit 2d35944

Please sign in to comment.