/// <summary> /// /// </summary> /// <param name="settings"></param> /// <param name="asset"></param> /// <param name="destinationDir"></param> /// <param name="type"></param> /// <param name="streams"></param> /// <returns></returns> private static bool LockAllContents(ZombieSettings settings, AssetObject asset, string destinationDir, LocationType type, out Dictionary <string, FileStream> streams) { streams = new Dictionary <string, FileStream>(); var dir = FileUtils.GetZombieDownloadsDirectory(); string filePath; if (type == LocationType.Trash) { filePath = Path.Combine(dir, Path.GetFileNameWithoutExtension(asset.Name) + "_old" + Path.GetExtension(asset.Name)); if (!File.Exists(filePath)) { if (!GitHubUtils.DownloadAssets(settings, asset.Url, filePath)) { return(false); } } } else { filePath = Path.Combine(dir, asset.Name); } try { using (var zip = ZipFile.Open(filePath, ZipArchiveMode.Read)) { foreach (var file in zip.Entries) { var completeFileName = Path.Combine(destinationDir, file.FullName); if (file.Name == string.Empty || !Directory.Exists(Path.GetDirectoryName(completeFileName)) || !File.Exists(completeFileName)) { continue; } var fs = new FileStream(completeFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); streams.Add(completeFileName, fs); } } } catch (Exception e) { _logger.Fatal(e.Message); return(false); } return(true); }
private void OnShowContents() { IsContentVisible = !IsContentVisible; if (Contents.Any()) { return; } var dir = Path.Combine(Directory.GetCurrentDirectory(), "downloads"); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } try { var filePath = Path.Combine(dir, Asset.Name); // download GitHubUtils.DownloadAssets(App.Settings, Asset.Url, filePath); // verify if (!File.Exists(filePath)) { StatusBarManager.StatusLabel.Text = "Could not retrieve contents of the Asset!"; return; } using (var zip = ZipFile.Open(filePath, ZipArchiveMode.Read)) { foreach (var asset in zip.Entries) { Contents.Add(new AssetViewModel(new AssetObject { Name = asset.Name }) { IsContent = true }); } } } catch (Exception e) { Console.WriteLine(e); throw; } }
/// <summary> /// /// </summary> /// <param name="settings"></param> public async void GetLatestRelease(ZombieSettings settings) { if (string.IsNullOrEmpty(settings?.AccessToken) || string.IsNullOrEmpty(settings.Address)) { UpdateUI("Connection failed!", ConnectionResult.Failure); return; } var response = await GetLatestReleaseFromGitHub(settings); if (response.StatusCode != HttpStatusCode.OK) { UpdateUI("Connection failed!", ConnectionResult.Failure); return; } var release = response.Data; var currentVersion = Properties.Settings.Default["CurrentVersion"].ToString(); if (!release.Assets.Any() || new Version(release.TagName).CompareTo(new Version(currentVersion)) <= 0) { UpdateUI("Your release is up to date!", ConnectionResult.UpToDate, release); return; } var dir = FileUtils.GetZombieDownloadsDirectory(); var downloaded = 0; foreach (var asset in release.Assets) { var filePath = Path.Combine(dir, asset.Name); if (GitHubUtils.DownloadAssets(settings, asset.Url, filePath)) { downloaded++; } } if (downloaded != release.Assets.Count) { UpdateUI("Failed to download assets!", ConnectionResult.Failure); return; } // (Konrad) Let's get updated settings, they might be local, or remote. // We need latest settings since there might be changes to the target locations. ZombieSettings newSettings; if (File.Exists(settings.SettingsLocation)) { if (!SettingsUtils.TryGetStoredSettings(settings.SettingsLocation, out newSettings)) { UpdateUI("Could not get latest local Zombie Settings!", ConnectionResult.Failure); return; } } else { if (!SettingsUtils.TryGetRemoteSettings(settings.SettingsLocation, out newSettings)) { UpdateUI("Could not get latest remote Zombie Settings!", ConnectionResult.Failure); return; } } // (Konrad) Let's make sure that we own the files that we are trying to override var fileStreams = new Dictionary <string, FileStream>(); foreach (var loc in newSettings.DestinationAssets) { foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (LockAllContents(settings, asset, loc.DirectoryPath, out var zippedStreams)) { fileStreams = fileStreams.Concat(zippedStreams).GroupBy(x => x.Key) .ToDictionary(x => x.Key, x => x.First().Value); continue; } UpdateUI("Could not get access to all ZIP contents!", ConnectionResult.Failure); return; } var to = Path.Combine(FilePathUtils.CreateUserSpecificPath(loc.DirectoryPath), asset.Name); try { var fs = new FileStream(to, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); fileStreams.Add(to, fs); } catch (Exception e) { UpdateUI(e.Message, ConnectionResult.Failure); return; } } } // (Konrad) Move assets to target locations foreach (var loc in newSettings.DestinationAssets) { foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (ExtractToDirectory(asset, loc.DirectoryPath, fileStreams)) { continue; } UpdateUI("Could not override existing ZIP contents!", ConnectionResult.Failure); return; } var from = Path.Combine(dir, asset.Name); var to = Path.Combine(FilePathUtils.CreateUserSpecificPath(loc.DirectoryPath), asset.Name); // make sure that file is not locked var stream = fileStreams[to]; stream?.Close(); if (FileUtils.Copy(@from, @to)) { continue; } UpdateUI("Could not override existing file!", ConnectionResult.Failure); return; } } // (Konrad) Remove temporary assets if (!FileUtils.DeleteDirectory(dir)) { UpdateUI("Could not remove temporary download assets!", ConnectionResult.Failure); return; } // (Konrad) Update UI and save current version Properties.Settings.Default.CurrentVersion = release.TagName; Properties.Settings.Default.Save(); _logger.Info("Successfully updated to version: " + release.TagName); Messenger.Default.Send(new UpdateStatus { Status = "Successfully updated to version: " + release.TagName }); Messenger.Default.Send(new ReleaseDownloaded { Release = release, Result = ConnectionResult.Success }); }
/// <summary> /// Method that retrieves the latest release from GitHub. /// </summary> /// <param name="settings">Zombie Settings to be used to retrieve latest Release.</param> public static async void GetLatestRelease(ZombieSettings settings) { if (IsProcessRunning("Revit")) { _logger.Error("Update failed. Revit is running."); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is running."); return; } if (string.IsNullOrWhiteSpace(settings?.AccessToken) || string.IsNullOrWhiteSpace(settings.Address)) { var a = string.IsNullOrWhiteSpace(settings.Address) ? "Not found" : "Exists"; _logger.Error($"Connection failed! Address: {a}"); return; } var segments = GitHubUtils.ParseUrl(settings.Address); var client = new GitHubClient(new ProductHeaderValue("Zombie")); var tokenAuth = new Credentials(settings.AccessToken); client.Credentials = tokenAuth; Release release; try { release = await client.Repository.Release.GetLatest(segments["owner"], segments["repo"]); var currentVersion = RegistryUtils.GetZombieVersion(); if (!release.Assets.Any() || new Version(release.TagName).CompareTo(new Version(currentVersion)) <= 0) { PublishGuiUpdate(Program.Settings, Status.UpToDate, "Your release is up to date! Version: " + currentVersion); return; } } catch (Exception e) { _logger.Fatal("Failed to retrieve Release from GitHub. " + e.Message); return; } // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update in progress. Please do not launch Revit."); var dir = FileUtils.GetZombieDownloadsDirectory(); var downloaded = 0; foreach (var asset in release.Assets) { var filePath = Path.Combine(dir, asset.Name); if (GitHubUtils.DownloadAssets(settings, asset.Url, filePath)) { downloaded++; } } if (downloaded != release.Assets.Count) { _logger.Error("Failed to download assets!"); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Check your internet connection and try again."); return; } // (Konrad) Let's get updated settings, they might be local, or remote. // We need latest settings since there might be changes to the target locations. ZombieSettings newSettings; if (File.Exists(settings.SettingsLocation)) { if (!SettingsUtils.TryGetStoredSettings(settings.SettingsLocation, out newSettings)) { _logger.Error("Could not get latest local Zombie Settings!"); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Zombie Settings not found."); return; } } else { if (!SettingsUtils.TryGetRemoteSettings(settings.SettingsLocation, out newSettings)) { _logger.Error("Could not get latest remote Zombie Settings!"); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Zombie Settings not found."); return; } } // (Konrad) Let's make sure that we own the files that we are trying to override var fileStreams = new Dictionary <string, FileStream>(); foreach (var loc in newSettings.DestinationAssets.OrderByDescending(x => (int)x.LocationType)) { foreach (var asset in loc.Assets) { if (asset.IsArchive()) { // (Konrad) Use old settings if (LockAllContents(loc.LocationType == LocationType.Trash ? settings : newSettings, asset, loc.DirectoryPath, loc.LocationType, out var zippedStreams)) { fileStreams = fileStreams .Concat(zippedStreams) .GroupBy(x => x.Key) .ToDictionary(x => x.Key, x => x.First().Value); continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } if (loc.LocationType != LocationType.Trash) { // (Konrad) Make sure that destination folder exists. if (!Directory.Exists(loc.DirectoryPath)) { FileUtils.CreateDirectory(loc.DirectoryPath); } } var to = Path.Combine(loc.DirectoryPath, asset.Name); if (!File.Exists(to)) { continue; } try { var fs = new FileStream(to, FileMode.Open, FileAccess.ReadWrite, FileShare.None); fileStreams.Add(to, fs); } catch (Exception e) { _logger.Fatal(e.Message); ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed...due to unknown reasons. Sorry about that."); return; } } } // (Konrad) Move assets to target locations. // We sort the locations list so that Trash (3) is first. // This should make sure that we delete first, then move. // Could be important with Zipped contents and overriding. foreach (var loc in newSettings.DestinationAssets.OrderByDescending(x => (int)x.LocationType)) { if (loc.LocationType == LocationType.Trash) { // (Konrad) Let's remove these files. foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (DeleteZipContents(asset, loc.DirectoryPath, fileStreams)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } var to = Path.Combine(loc.DirectoryPath, asset.Name); if (fileStreams.ContainsKey(to)) { // make sure that file is not locked var stream = fileStreams[to]; stream?.Close(); } if (FileUtils.DeleteFile(to)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } } else { // (Konrad) Let's copy these files. foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (ExtractToDirectory(asset, loc.DirectoryPath, fileStreams)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } var from = Path.Combine(dir, asset.Name); var to = Path.Combine(loc.DirectoryPath, asset.Name); if (fileStreams.ContainsKey(to)) { // make sure that file is not locked var stream = fileStreams[to]; stream?.Close(); } // (Konrad) Make sure that directory exists. if (!Directory.Exists(Path.GetDirectoryName(to))) { FileUtils.CreateDirectory(Path.GetDirectoryName(to)); } if (FileUtils.Copy(from, to)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } } } // (Konrad) Remove temporary assets if (!FileUtils.DeleteDirectory(dir)) { // (Konrad) Cleanup failed but we can continue. _logger.Error("Could not remove temporary download assets!"); } // (Konrad) This is important! ReleaseStreams(fileStreams); // (Konrad) We need to store the current version for comparison on next update RegistryUtils.SetZombieVersion(release.TagName); // (Konrad) Settings need to be updated with the latest one just downloaded newSettings.LatestRelease = new ReleaseObject(release); if (!newSettings.StoreSettings) { newSettings.AccessToken = Program.Settings.AccessToken; newSettings.SettingsLocation = Program.Settings.SettingsLocation; } Program.Settings = newSettings; // (Konrad) Publish to any open GUIs PublishGuiUpdate(newSettings, Status.Succeeded, "Successfully updated to Version: " + release.TagName); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update succeeded. Go ahead and launch Revit to see what's new."); }