mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-06-12 06:16:26 +00:00
Added offline build mode for local build script (#806)
This commit is contained in:
parent
0ea63a16c0
commit
e4fa1cd72a
@ -7,73 +7,90 @@ namespace Build.Commands;
|
|||||||
|
|
||||||
public static class Pdfium
|
public static class Pdfium
|
||||||
{
|
{
|
||||||
public static async Task InstallAsync(RID rid, string version)
|
public static async Task InstallAsync(RID rid, string version, bool offline)
|
||||||
{
|
{
|
||||||
Console.Write($"- Installing Pdfium {version} for {rid.ToUserFriendlyName()} ...");
|
Console.Write($"- Installing Pdfium {version} for {rid.ToUserFriendlyName()} ...");
|
||||||
|
|
||||||
var cwd = Environment.GetRustRuntimeDirectory();
|
var cwd = Environment.GetRustRuntimeDirectory();
|
||||||
var pdfiumTmpDownloadPath = Path.GetTempFileName();
|
|
||||||
var pdfiumTmpExtractPath = Directory.CreateTempSubdirectory();
|
|
||||||
var pdfiumUrl = GetPdfiumDownloadUrl(rid, version);
|
var pdfiumUrl = GetPdfiumDownloadUrl(rid, version);
|
||||||
|
var library = GetLibraryPath(rid);
|
||||||
|
var pdfiumLibTargetPath = Path.Join(cwd, "resources", "libraries", library.Filename);
|
||||||
|
|
||||||
//
|
if (offline)
|
||||||
// Download the file:
|
|
||||||
//
|
|
||||||
Console.Write(" downloading ...");
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
{
|
||||||
var response = await client.GetAsync(pdfiumUrl);
|
if (File.Exists(pdfiumLibTargetPath))
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
{
|
||||||
Console.WriteLine($" failed to download Pdfium {version} for {rid.ToUserFriendlyName()} from {pdfiumUrl}");
|
Console.WriteLine(" offline mode enabled and library already exists, skipping download");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await using var fileStream = File.Create(pdfiumTmpDownloadPath);
|
Console.WriteLine($" failed because offline mode is enabled and '{pdfiumLibTargetPath}' does not exist");
|
||||||
await response.Content.CopyToAsync(fileStream);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Extract the downloaded file:
|
|
||||||
//
|
|
||||||
Console.Write(" extracting ...");
|
|
||||||
await using(var tgzStream = File.Open(pdfiumTmpDownloadPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
||||||
{
|
|
||||||
await using var uncompressedStream = new GZipStream(tgzStream, CompressionMode.Decompress);
|
|
||||||
await TarFile.ExtractToDirectoryAsync(uncompressedStream, pdfiumTmpExtractPath.FullName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copy the library to the target directory:
|
|
||||||
//
|
|
||||||
Console.Write(" deploying ...");
|
|
||||||
var library = GetLibraryPath(rid);
|
|
||||||
if (string.IsNullOrWhiteSpace(library.Path))
|
if (string.IsNullOrWhiteSpace(library.Path))
|
||||||
{
|
{
|
||||||
Console.WriteLine($" failed to find the library path for {rid.ToUserFriendlyName()}");
|
Console.WriteLine($" failed to find the library path for {rid.ToUserFriendlyName()}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pdfiumLibSourcePath = Path.Join(pdfiumTmpExtractPath.FullName, library.Path);
|
var pdfiumLibTargetDirectory = Path.Join(cwd, "resources", "libraries");
|
||||||
var pdfiumLibTargetPath = Path.Join(cwd, "resources", "libraries", library.Filename);
|
var pdfiumLibTmpTargetPath = Path.Join(pdfiumLibTargetDirectory, $"{library.Filename}.{Guid.NewGuid():N}.tmp");
|
||||||
if (!File.Exists(pdfiumLibSourcePath))
|
var pdfiumLibArchivePath = library.Path.Replace('\\', '/');
|
||||||
|
|
||||||
|
//
|
||||||
|
// Download the file:
|
||||||
|
//
|
||||||
|
Console.Write(" downloading ...");
|
||||||
|
using var client = new HttpClient();
|
||||||
|
using var response = await client.GetAsync(pdfiumUrl, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Console.WriteLine($" failed to find the library file '{pdfiumLibSourcePath}'");
|
Console.WriteLine($" failed to download Pdfium {version} for {rid.ToUserFriendlyName()} from {pdfiumUrl}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.Join(cwd, "resources", "libraries"));
|
|
||||||
if (File.Exists(pdfiumLibTargetPath))
|
|
||||||
File.Delete(pdfiumLibTargetPath);
|
|
||||||
|
|
||||||
File.Copy(pdfiumLibSourcePath, pdfiumLibTargetPath);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cleanup:
|
// Extract the library from the downloaded file:
|
||||||
//
|
//
|
||||||
Console.Write(" cleaning up ...");
|
Console.Write(" extracting ...");
|
||||||
File.Delete(pdfiumTmpDownloadPath);
|
Directory.CreateDirectory(pdfiumLibTargetDirectory);
|
||||||
Directory.Delete(pdfiumTmpExtractPath.FullName, true);
|
|
||||||
|
var foundLibrary = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var downloadStream = await response.Content.ReadAsStreamAsync();
|
||||||
|
await using var uncompressedStream = new GZipStream(downloadStream, CompressionMode.Decompress);
|
||||||
|
await using var tarReader = new TarReader(uncompressedStream, false);
|
||||||
|
|
||||||
|
while (await tarReader.GetNextEntryAsync(false) is { } entry)
|
||||||
|
{
|
||||||
|
if (!string.Equals(entry.Name.Replace('\\', '/'), pdfiumLibArchivePath, StringComparison.Ordinal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entry.DataStream == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
await using var fileStream = File.Create(pdfiumLibTmpTargetPath);
|
||||||
|
await entry.DataStream.CopyToAsync(fileStream);
|
||||||
|
foundLibrary = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundLibrary)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" failed to find the library file '{pdfiumLibArchivePath}' in the Pdfium archive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write(" deploying ...");
|
||||||
|
File.Move(pdfiumLibTmpTargetPath, pdfiumLibTargetPath, true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (File.Exists(pdfiumLibTmpTargetPath))
|
||||||
|
File.Delete(pdfiumLibTmpTargetPath);
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine(" done.");
|
Console.WriteLine(" done.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,8 @@ public sealed partial class UpdateMetadataCommands
|
|||||||
[Command("release", Description = "Prepare & build the next release")]
|
[Command("release", Description = "Prepare & build the next release")]
|
||||||
public async Task Release(
|
public async Task Release(
|
||||||
[Option("action", ['a'], Description = "The release action: patch, minor, or major")] PrepareAction action = PrepareAction.NONE,
|
[Option("action", ['a'], Description = "The release action: patch, minor, or major")] PrepareAction action = PrepareAction.NONE,
|
||||||
[Option("version", ['v'], Description = "Set a specific version directly, e.g., 26.1.2")] string? version = null)
|
[Option("version", ['v'], Description = "Set a specific version directly, e.g., 26.1.2")] string? version = null,
|
||||||
|
[Option("offline", Description = "Skip downloads and use locally available build dependencies")] bool offline = false)
|
||||||
{
|
{
|
||||||
if(!Environment.IsWorkingDirectoryValid())
|
if(!Environment.IsWorkingDirectoryValid())
|
||||||
return;
|
return;
|
||||||
@ -42,7 +43,7 @@ public sealed partial class UpdateMetadataCommands
|
|||||||
|
|
||||||
// Build once to allow the Rust compiler to read the changed metadata
|
// Build once to allow the Rust compiler to read the changed metadata
|
||||||
// and to update all .NET artifacts:
|
// and to update all .NET artifacts:
|
||||||
await this.Build();
|
await this.Build(offline);
|
||||||
|
|
||||||
// Now, we update the web assets (which may were updated by the first build):
|
// Now, we update the web assets (which may were updated by the first build):
|
||||||
new UpdateWebAssetsCommand().UpdateWebAssets();
|
new UpdateWebAssetsCommand().UpdateWebAssets();
|
||||||
@ -53,7 +54,7 @@ public sealed partial class UpdateMetadataCommands
|
|||||||
|
|
||||||
// Build the final release, where Rust knows the updated metadata, the .NET
|
// Build the final release, where Rust knows the updated metadata, the .NET
|
||||||
// artifacts are already in place, and .NET knows the updated web assets, etc.:
|
// artifacts are already in place, and .NET knows the updated web assets, etc.:
|
||||||
await this.Build();
|
await this.Build(offline);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("update-versions", Description = "The command will update the package versions in the metadata file")]
|
[Command("update-versions", Description = "The command will update the package versions in the metadata file")]
|
||||||
@ -136,7 +137,8 @@ public sealed partial class UpdateMetadataCommands
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Command("build", Description = "Build MindWork AI Studio")]
|
[Command("build", Description = "Build MindWork AI Studio")]
|
||||||
public async Task Build()
|
public async Task Build(
|
||||||
|
[Option("offline", Description = "Skip downloads and use locally available build dependencies")] bool offline = false)
|
||||||
{
|
{
|
||||||
if(!Environment.IsWorkingDirectoryValid())
|
if(!Environment.IsWorkingDirectoryValid())
|
||||||
return;
|
return;
|
||||||
@ -153,7 +155,7 @@ public sealed partial class UpdateMetadataCommands
|
|||||||
await this.UpdateVectorStoreVersion();
|
await this.UpdateVectorStoreVersion();
|
||||||
|
|
||||||
var pdfiumVersion = await this.ReadPdfiumVersion();
|
var pdfiumVersion = await this.ReadPdfiumVersion();
|
||||||
await Pdfium.InstallAsync(rid, pdfiumVersion);
|
await Pdfium.InstallAsync(rid, pdfiumVersion, Environment.IsOfflineBuildRequested(offline));
|
||||||
|
|
||||||
Console.Write($"- Start .NET build for {rid.ToUserFriendlyName()} ...");
|
Console.Write($"- Start .NET build for {rid.ToUserFriendlyName()} ...");
|
||||||
await this.ReadCommandOutput(pathApp, "dotnet", $"clean --configuration release --runtime {rid.AsMicrosoftRid()}");
|
await this.ReadCommandOutput(pathApp, "dotnet", $"clean --configuration release --runtime {rid.AsMicrosoftRid()}");
|
||||||
|
|||||||
@ -7,6 +7,7 @@ namespace Build.Tools;
|
|||||||
public static class Environment
|
public static class Environment
|
||||||
{
|
{
|
||||||
public const string DOTNET_VERSION = "net9.0";
|
public const string DOTNET_VERSION = "net9.0";
|
||||||
|
public const string BUILD_OFFLINE_ENVIRONMENT_VARIABLE = "AI_STUDIO_BUILD_OFFLINE";
|
||||||
public static readonly Encoding UTF8_NO_BOM = new UTF8Encoding(false);
|
public static readonly Encoding UTF8_NO_BOM = new UTF8Encoding(false);
|
||||||
|
|
||||||
private static readonly Dictionary<RID, string> ALL_RIDS = Enum.GetValues<RID>().Select(rid => new KeyValuePair<RID, string>(rid, rid.AsMicrosoftRid())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
private static readonly Dictionary<RID, string> ALL_RIDS = Enum.GetValues<RID>().Select(rid => new KeyValuePair<RID, string>(rid, rid.AsMicrosoftRid())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||||
@ -47,6 +48,19 @@ public static class Environment
|
|||||||
return Path.GetFullPath(directory);
|
return Path.GetFullPath(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsOfflineBuildRequested(bool offlineOption)
|
||||||
|
{
|
||||||
|
if (offlineOption)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var environmentValue = global::System.Environment.GetEnvironmentVariable(BUILD_OFFLINE_ENVIRONMENT_VARIABLE);
|
||||||
|
return environmentValue?.Trim().ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"1" or "true" or "yes" or "on" => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static string? GetOS()
|
public static string? GetOS()
|
||||||
{
|
{
|
||||||
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user