/// <summary> /// Called when the CLI invokes this command. /// </summary> /// <param name="IpcClient">Interprocess communication pipe to the application that invoked this command.</param> internal void Run(CommandIPC IpcClient) { VirtualPath = VirtualFileSystem.Normalize(VirtualPath); if (!Directory.Exists(LocalPath)) { IpcClient.Respond("FAILED: Path does not exists: {0}"); return; } if (!Program.NetClient.IsConnected) { IpcClient.Respond("FAILED: No connection to server."); return; } if (!Program.NetClient.Permissions.HasPermission(UserPermissionType.Write, "", false, true)) { IpcClient.Respond("FAILED: Permission denied to manage builds."); return; } PublishBuildTask Publisher = new PublishBuildTask(); BuildPublishingState OldPublisherState = BuildPublishingState.Unknown; int OldPublisherProgress = 0; Publisher.Start(VirtualPath, LocalPath); Program.PumpLoop( () => { if (!Program.NetClient.IsConnected) { IpcClient.Respond("FAILED: Lost connection to server."); return(true); } if (Publisher != null && (Publisher.State != OldPublisherState || (int)Publisher.Progress != OldPublisherProgress)) { OldPublisherState = Publisher.State; OldPublisherProgress = (int)Publisher.Progress; switch (Publisher.State) { case BuildPublishingState.CopyingFiles: { IpcClient.Respond(string.Format("Copying files to storage: {0}%", OldPublisherProgress)); break; } case BuildPublishingState.ScanningFiles: { IpcClient.Respond(string.Format("Scanning local files: {0}%", OldPublisherProgress)); break; } case BuildPublishingState.UploadingManifest: { IpcClient.Respond("Uploading manfiest to server."); break; } case BuildPublishingState.FailedVirtualPathAlreadyExists: { IpcClient.Respond(string.Format("FAILED: Build already exists at path '{0}'.", VirtualPath)); return(true); } case BuildPublishingState.PermissionDenied: { IpcClient.Respond(string.Format("FAILED: Permission denied to path '{0}'.", VirtualPath)); return(true); } case BuildPublishingState.FailedGuidAlreadyExists: { IpcClient.Respond("FAILED: Manifest with same GUID already exists."); return(true); } case BuildPublishingState.Success: { Publisher.Commit(); Publisher = null; IpcClient.Respond("SUCCESS: Build added successfully."); return(true); } case BuildPublishingState.Failed: default: { IpcClient.Respond("FAILED: Undefined reason."); return(true); } } } return(false); } ); }
/// <summary> /// </summary> /// <param name="Name"></param> /// <param name="VirtualPath"></param> /// <param name="LocalPath"></param> public void Start(string VirtualPath, string InLocalPath) { LocalPath = InLocalPath; State = BuildPublishingState.ScanningFiles; Task.Run( () => { try { Guid NewManifestId = Guid.NewGuid(); // Don't allow downloading of this manifest until we have fully committed it. Program.ManifestDownloadManager.BlockDownload(NewManifestId); // Calculate max size of all files in folder to publish. string[] Files = Directory.GetFiles(LocalPath, "*", SearchOption.AllDirectories); long TotalSize = 0; for (int i = 0; i < Files.Length; i++) { TotalSize += new FileInfo(Files[i]).Length; } // Allocate appropriate folder to store build in. if (!Program.StorageManager.AllocateSpace(TotalSize, NewManifestId, out StoragePath)) { Logger.Log(LogLevel.Error, LogCategory.Main, "Failed to allocate space, storage folders likely at capacity."); Program.ManifestDownloadManager.UnblockDownload(NewManifestId); State = BuildPublishingState.Failed; return; } // Recreated directory. if (Directory.Exists(StoragePath)) { FileUtils.DeleteDirectory(StoragePath); } Directory.CreateDirectory(StoragePath); // Copy each file over to the storage folder. State = BuildPublishingState.CopyingFiles; for (int i = 0; i < Files.Length; i++) { string Src = Files[i]; string RelativePath = Files[i].Substring(LocalPath.Length).TrimStart('/', '\\'); string Dst = Path.Combine(StoragePath, RelativePath); string DstDir = Path.GetDirectoryName(Dst); if (!Directory.Exists(DstDir)) { Directory.CreateDirectory(DstDir); } Progress = i / (float)Files.Length * 50.0f; CurrentFile = Src; File.Copy(Src, Dst); } // Build manifest from directory. Manifest = BuildManifest.BuildFromDirectory( NewManifestId, StoragePath, VirtualPath, Program.IOQueue, (InFile, InProgress) => { Progress = 50.0f + InProgress * 0.5f; if (InFile.Length > 0) { CurrentFile = InFile; } } ); ManualResetEvent PublishCompleteEvent = new ManualResetEvent(false); ManifestPublishResultRecievedHandler PublishHandler = (ManifestId, Result) => { if (ManifestId == Manifest.Guid) { switch (Result) { case PublishManifestResult.Success: { break; } case PublishManifestResult.VirtualPathAlreadyExists: { State = BuildPublishingState.FailedVirtualPathAlreadyExists; break; } case PublishManifestResult.PermissionDenied: { State = BuildPublishingState.PermissionDenied; break; } case PublishManifestResult.GuidAlreadyExists: { State = BuildPublishingState.FailedGuidAlreadyExists; break; } case PublishManifestResult.Failed: default: { State = BuildPublishingState.Failed; break; } } PublishCompleteEvent.Set(); } }; Program.NetClient.OnManifestPublishResultRecieved += PublishHandler; // Submit to the server. State = BuildPublishingState.UploadingManifest; if (!Program.NetClient.PublishManifest(Manifest)) { State = BuildPublishingState.Failed; Program.ManifestDownloadManager.UnblockDownload(NewManifestId); return; } // Wait for complete delegate. PublishCompleteEvent.WaitOne(); Program.NetClient.OnManifestPublishResultRecieved -= PublishHandler; // Abort here if publishing failed. if (State != BuildPublishingState.UploadingManifest) { Program.ManifestDownloadManager.UnblockDownload(NewManifestId); return; } State = BuildPublishingState.Success; Progress = 100; } catch (Exception ex) { Logger.Log(LogLevel.Error, LogCategory.Main, "Manifest publishing failed with exception: {0}", ex.Message); State = BuildPublishingState.Failed; } } ); }