/// <summary> /// Invoked before uploading to include a file with all the requirements. /// </summary> private void CreateManifest() { _files[Manifest.fileName] = null; string manifestPath = PathExtensions.Combine(directory, Manifest.fileName); Serialization.WriteJson(manifestPath, new Manifest(assetFileName, _files.Keys.ToArray(), _files.Values.ToArray(), requiredPlugins), true); }
/// <summary> /// Invoked after all files are downloaded to add data from manifest and ensure there are no orphan or missing files. /// </summary> /// <returns>True if manifest was loaded without error or manifest does not exist. False otherwise.</returns> public bool LoadManifest() { string manifestPath = PathExtensions.Combine(directory, Manifest.fileName); if (!File.Exists(manifestPath)) { Logger.WriteLine("WARNING: " + name.fullName + " has no manifest."); return(true); } Manifest manifest; Serialization.ReadJson(manifestPath, out manifest); assetFileName = manifest.assetFileName; requiredPlugins = manifest.requiredPlugins; if (manifest.files == null || manifest.files.Length == 0) { Logger.WriteLine("ERROR: Manifest for " + name.fullName + " has no files."); return(false); } bool error = false; HashSet <string> orphans = new HashSet <string>(_files.Keys); foreach (var f in manifest.FilesAndRequirements()) { if (!orphans.Remove(f.Key)) { Logger.WriteLine("ERROR: " + f.Key + " listed on manifest for " + name.fullName + " is missing"); error = true; } } foreach (string o in orphans) { Logger.WriteLine(o + " is not listed on manifest for " + name.fullName + ", deleting"); File.Delete(GetFullPath(o)); } if (error) { return(false); } Logger.WriteLine(name.fullName + " manifest loaded"); _files.Clear(); foreach (var f in manifest.FilesAndRequirements()) { _files.Add(f.Key, f.Value); } return(true); }
private Plugin AddLocallyCompiled(PluginBuilder builder) { PluginName name = new PluginName(builder.author, builder.repository); Plugin plugin; if (!_data.TryGetDownloaded(name, out plugin)) { plugin = new Plugin(_directory, new PluginConfig(name, true)); } else { plugin.EraseAllFiles(); } plugin.version = builder.version; Logger.WriteLine("plugin: " + name.fullName + ", compiled version: " + plugin.version); plugin.requiredPlugins = builder.requires; Directory.CreateDirectory(plugin.directory); foreach (var fileSource in builder.files) { string fileDestination = fileSource.targetFolder == null? PathExtensions.Combine(plugin.directory, Path.GetFileName(fileSource.source)) : PathExtensions.Combine(plugin.directory, fileSource.targetFolder, Path.GetFileName(fileSource.source)); if (!Path.GetFullPath(fileDestination).StartsWith(plugin.directory)) { throw new Exception(Path.GetFullPath(fileDestination) + " is outside of plugin's directory"); } Logger.WriteLine("Copy: " + fileSource.source + " to " + fileDestination); Directory.CreateDirectory(Path.GetDirectoryName(fileDestination)); File.Copy(fileSource.source, fileDestination, true); plugin.AddFile(fileDestination, fileSource.requires); } plugin.locallyCompiled = true; _data.AddConfig(plugin.config); _data.AddDownloaded(plugin); if (name.author == "Rynchodon" && name.repository == SeplRepo) { Robocopy(); } return(plugin); }
private GitChecks(PluginBuilder builder, string pathToGit) { this._builder = builder; this._pathToGit = pathToGit; foreach (string path in PathExtensions.PathsToRoot(builder.files.First().source)) { string gitDirectory = PathExtensions.Combine(path, ".git"); if (Directory.Exists(gitDirectory)) { _repoDirectory = path; break; } } }
/// <summary> /// Get the commit hash of local head. /// </summary> /// <returns>The commit hash of local head.</returns> private string LocalHead() { string headPath = PathExtensions.Combine(_repoDirectory, ".git", "HEAD"); string head; using (StreamReader reader = new StreamReader(headPath)) head = reader.ReadLine(); const string refstring = "ref: "; if (head.StartsWith(refstring)) { headPath = PathExtensions.Combine(_repoDirectory, ".git", head.Substring(refstring.Length)); using (StreamReader reader = new StreamReader(headPath)) head = reader.ReadLine(); } return(head); }
internal void Publish(Plugin plugin, PluginBuilder pluginBuilder) { if (!HasOAuthToken) { throw new ArgumentException("Need oAuthToken"); } CreateRelease release = new CreateRelease(plugin.version, pluginBuilder.release); string zipFileName; if (pluginBuilder.zipFileName != null) { zipFileName = Path.GetFileName(pluginBuilder.zipFileName); } else { zipFileName = plugin.name.repository; } if (!zipFileName.EndsWith(".zip")) { zipFileName = zipFileName + ".zip"; } string zipFilePath = PathExtensions.Combine(plugin.directory, zipFileName); try { plugin.Zip(zipFilePath); if (PublishRelease(release, zipFilePath)) { MessageBox.Show("Release posted"); } } finally { if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } } }
private string SearchForGit() { HashSet <string> searchLocations = new HashSet <string>(); foreach (string envPath in Environment.GetEnvironmentVariable("PATH").Split(';')) { if (string.IsNullOrWhiteSpace(envPath)) { Logger.WriteLine("empty string in PATH"); } else { searchLocations.Add(envPath); } } foreach (string envVar in new string[] { "ProgramFiles", "ProgramFiles(x86)", "ProgramW6432" }) { string path = Environment.GetEnvironmentVariable(envVar); if (string.IsNullOrWhiteSpace(path)) { Logger.WriteLine("No environment variable: " + envVar); } else { searchLocations.Add(PathExtensions.Combine(path, "Git", "bin")); searchLocations.Add(PathExtensions.Combine(path, "Git", "cmd")); } } foreach (string location in searchLocations) { string gitExe = PathExtensions.Combine(location, "git.exe"); if (File.Exists(gitExe)) { Logger.WriteLine("git @ " + gitExe); return(gitExe); } } return(null); }
/// <summary> /// Update PluginLoader.dll and PluginManager.exe from download folder using robocopy. /// </summary> private void Robocopy() { if (_instance != this || _startedRobocopy) { return; } _startedRobocopy = true; PluginName seplName = new PluginName("Rynchodon", SeplRepo); string seplDownloadPath = PathExtensions.Combine(_directory, "plugin", seplName.fullName); string license = PathExtensions.Combine(seplDownloadPath, "License.rtf"); if (File.Exists(license)) { File.Copy(license, PathExtensions.Combine(_directory, "License.rtf"), true); } string readme = PathExtensions.Combine(seplDownloadPath, "Readme.txt"); if (File.Exists(readme)) { File.Copy(readme, PathExtensions.Combine(_directory, "Readme.txt"), true); } Logger.WriteLine("starting robocopy"); string first = '"' + seplDownloadPath + "\" \""; string copyDll = first + _directory + "\" " + Dll + " /COPY:DATSO /W:1 /xx"; string copyExe = first + _directory + "\" " + Exe + " /COPY:DATSO /W:1 /xx"; Process robocopy = new Process(); robocopy.StartInfo.FileName = "cmd.exe"; robocopy.StartInfo.Arguments = "/C robocopy " + copyDll + " & robocopy " + copyExe; robocopy.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; robocopy.Start(); }
/// <summary> /// Download an update for a plugin. /// </summary> /// <returns>True iff the plugin was updated.</returns> internal bool Update(Plugin plugin) { Release[] releases = GetReleases(); if (releases == null) { // already complained about it in depth return(false); } int seVersion = Loader.GetCurrentSeVersion(); Release mostRecent = null; foreach (Release rel in releases) { if (rel.draft) { continue; } if (rel.prerelease && !plugin.config.downloadPrerelease) { continue; } // skip if release was compiled with a newer version of SE if (seVersion < rel.version.SeVersion) { continue; } if (mostRecent == null || mostRecent.version.CompareTo(rel.version) < 0) { mostRecent = rel; } } if (mostRecent == null) { Logger.WriteLine("ERROR: No available releases"); return(false); } Logger.WriteLine("Latest release version: " + mostRecent.version + ", Current version: " + plugin.version); int relative = mostRecent.version.CompareTo(plugin.version); if (relative == 0) { Logger.WriteLine("Up-to-date: " + plugin.version); return(false); } if (relative < 0) // current version is newer than latest release { if (plugin.locallyCompiled) { Logger.WriteLine("Keeping locally compiled version: " + plugin.version); return(false); } Logger.WriteLine("Roll back version: " + plugin.version + " to " + mostRecent.version); } if (mostRecent.assets == null || mostRecent.assets.Length == 0) { Logger.WriteLine("ERROR: Release has no assets"); return(false); } // warn if a locally compiled version is going to be replaced by a downloaded version if (plugin.locallyCompiled && MessageBox.Show("Plugin: " + plugin.name.fullName + "\nLocally compiled version: " + plugin.version + "\nLatest release version: " + mostRecent.version + "\n\nOverwrite locally compiled plugin?", "Warning", MessageBoxButtons.YesNo) == DialogResult.No) { Logger.WriteLine("Not overwriting locally compiled plugin"); return(false); } plugin.EraseAllFiles(); Logger.WriteLine("Downloading version: " + mostRecent.version); Directory.CreateDirectory(plugin.directory); string targetAssetName = plugin.assetFileName; if (targetAssetName != null) { bool found = false; foreach (Release.Asset asset in mostRecent.assets) { if (asset.name == targetAssetName) { Logger.WriteLine("Target asset: " + targetAssetName); found = true; break; } } if (!found) { targetAssetName = null; } } foreach (Release.Asset asset in mostRecent.assets) { // If an asset file name has been specified and it exists, only download that asset. Otherwise, download all assets. if (targetAssetName != null && asset.name != targetAssetName) { Logger.WriteLine("Not downloading: " + asset.name); continue; } Logger.WriteLine("Downloading asset: " + asset.name); HttpWebRequest request = WebRequest.CreateHttp(asset.browser_download_url); request.Accept = "application/octet-stream"; request.UserAgent = _userAgent; WebResponse response = request.GetResponse(); Stream responseStream = response.GetResponseStream(); string assetDestination = PathExtensions.Combine(plugin.directory, asset.name); if (!PathExtensions.IsInPath(assetDestination, plugin.directory)) { Logger.WriteLine("Access denied: " + assetDestination); continue; } if (asset.name.EndsWith(".zip")) { try { using (FileStream zipFile = new FileStream(assetDestination, FileMode.CreateNew)) responseStream.CopyTo(zipFile); Logger.WriteLine("Unpacking: " + asset.name); using (ZipArchive archive = ZipFile.OpenRead(assetDestination)) foreach (ZipArchiveEntry entry in archive.Entries) { string entryDestination = PathExtensions.Combine(plugin.directory, entry.FullName); if (!PathExtensions.IsInPath(entryDestination, plugin.directory)) { Logger.WriteLine("Access denied: " + entryDestination); continue; } Directory.CreateDirectory(Path.GetDirectoryName(entryDestination)); if (File.Exists(entryDestination)) { Logger.WriteLine("WARNING: File exists: " + entry.FullName + ", it will not be extracted from " + asset.name); } else { try { entry.ExtractToFile(entryDestination); Logger.WriteLine("Unpacked entry: " + entry.FullName); } catch (Exception ex) { Logger.WriteLine(ex.Message); Logger.WriteLine("Failed to unpack: " + entry.FullName); if (File.Exists(entryDestination)) { File.Delete(entryDestination); } continue; } plugin.AddFile(entryDestination); } } } finally { if (File.Exists(assetDestination)) { File.Delete(assetDestination); } } } else { if (File.Exists(assetDestination)) { Logger.WriteLine("WARNING: File exists: " + asset.name + ", it will not be downloaded"); } else { using (FileStream file = new FileStream(assetDestination, FileMode.CreateNew)) responseStream.CopyTo(file); plugin.AddFile(assetDestination); } } responseStream.Dispose(); response.Dispose(); } if (!plugin.LoadManifest()) { Logger.WriteLine("Failed to load manifest"); return(false); } plugin.version = mostRecent.version; plugin.locallyCompiled = false; return(true); }
private string GetFullPath(string relativePath) { return(PathExtensions.Combine(directory, relativePath)); }
public Plugin(string seplDirectory, PluginConfig config) { this.config = config; this.directory = PathExtensions.Combine(seplDirectory, "plugin", name.fullName); }
private string GetFilePath() { return(PathExtensions.Combine(_directory, fileName)); }