/// <summary> /// Attempts to parse a version string and outputs the equivalent RantPackageVersion. /// </summary> /// <param name="version">The version string to parse.</param> /// <param name="result">The parsing result, if successful.</param> /// <returns></returns> public static bool TryParse(string version, out RantPackageVersion result) { const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite; result = null; if (Util.IsNullOrWhiteSpace(version)) { return(false); } var parts = version.Split('.'); if (parts.Length > 3) { return(false); } var v = new RantPackageVersion(); if (!int.TryParse(parts[0], styles, CultureInfo.InvariantCulture, out v._major) || v._major < 0) { return(false); } if (parts.Length < 2) { return(true); } if (!int.TryParse(parts[1], styles, CultureInfo.InvariantCulture, out v._minor) || v._minor < 0) { return(false); } if (parts.Length < 3) { return(true); } return(int.TryParse(parts[2], styles, CultureInfo.InvariantCulture, out v._revision) && v._revision >= 0); }
/// <summary> /// Checks if the specified version is compatible with the current dependency. /// </summary> /// <param name="version">The version to check.</param> /// <returns></returns> public bool CheckVersion(RantPackageVersion version) { if (version == null) { throw new ArgumentNullException(nameof(version)); } return(AllowNewer ? version >= Version : version == Version); }
/// <summary> /// Initializes a new RantPackageDependency object. /// </summary> /// <param name="id">The ID of the package.</param> /// <param name="version">The targeted version of the package.</param> public RantPackageDependency(string id, RantPackageVersion version) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (version == null) { throw new ArgumentNullException(nameof(version)); } ID = id; Version = version; }
/// <summary> /// Attempts to resolve a depdendency to the appropriate package. /// </summary> /// <param name="depdendency">The depdendency to resolve.</param> /// <param name="package">The package loaded from the depdendency.</param> /// <returns></returns> public virtual bool TryResolvePackage(RantPackageDependency depdendency, out RantPackage package) { package = null; string path = Path.Combine(Environment.CurrentDirectory, $"{depdendency.ID}.rantpkg"); if (!File.Exists(path)) { RantPackageVersion version; // Fallback to name with version appended #if UNITY path = Directory.GetFiles(Environment.CurrentDirectory, $"{depdendency.ID}*.rantpkg", SearchOption.AllDirectories).FirstOrDefault(p => #else path = Directory.EnumerateFiles(Environment.CurrentDirectory, "*.rantpkg", SearchOption.AllDirectories) .FirstOrDefault(p => #endif { var match = FallbackRegex.Match(Path.GetFileNameWithoutExtension(p)); if (!match.Success) { return(false); } version = RantPackageVersion.Parse(match.Groups["version"].Value); return(depdendency.AllowNewer && version >= depdendency.Version || depdendency.Version == version); }); if (path == null) { return(false); } } try { var pkg = RantPackage.Load(path); if (pkg.ID != depdendency.ID) { return(false); } if (depdendency.AllowNewer && pkg.Version >= depdendency.Version || pkg.Version == depdendency.Version) { package = pkg; return(true); } return(false); } catch { return(false); } }
/// <summary> /// Attempts to parse a version string and returns the equivalent RantPackageVersion. /// </summary> /// <param name="version">The version string to parse.</param> /// <returns></returns> public static RantPackageVersion Parse(string version) { const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite; if (Util.IsNullOrWhiteSpace(version)) { throw new ArgumentException("Version cannot be empty.", nameof(version)); } var parts = version.Split('.'); if (parts.Length > 3) { throw new FormatException("Version cannot be composed of more than 3 parts."); } var v = new RantPackageVersion(); if (!int.TryParse(parts[0], styles, CultureInfo.InvariantCulture, out v._major) || v._major < 0) { throw new FormatException("Major version must be a valid, non-negative integer."); } if (parts.Length < 2) { return(v); } if (!int.TryParse(parts[1], styles, CultureInfo.InvariantCulture, out v._minor) || v._minor < 0) { throw new FormatException("Minor version must be a valid, non-negative integer."); } if (parts.Length < 3) { return(v); } if (!int.TryParse(parts[2], styles, CultureInfo.InvariantCulture, out v._revision) || v._revision < 0) { throw new FormatException("Revision number must be a valid, non-negative integer."); } return(v); }
/// <summary> /// Loads a package from the specified stream and returns it as a RantPackage object. /// </summary> /// <param name="source">The stream to load the package data from.</param> /// <returns></returns> public static RantPackage Load(Stream source) { using (var reader = new EasyReader(source)) { var magic = Encoding.ASCII.GetString(reader.ReadBytes(4)); if (magic == OLD_MAGIC) { return(LoadOldPackage(reader)); } if (magic != MAGIC) { throw new InvalidDataException("File is corrupt."); } var package = new RantPackage(); var version = reader.ReadUInt32(); if (version != PACKAGE_VERSION) { throw new InvalidDataException("Invalid package version: " + version); } var compress = reader.ReadBoolean(); var size = reader.ReadInt32(); var data = reader.ReadBytes(size); if (compress) { data = EasyCompressor.Decompress(data); } var doc = BsonDocument.Read(data); var info = doc["info"]; if (info == null) { throw new InvalidDataException("Metadata is missing from package."); } package.Title = info["title"]; package.ID = info["id"]; package.Version = RantPackageVersion.Parse(info["version"]); package.Description = info["description"]; package.Authors = (string[])info["authors"]; package.Tags = (string[])info["tags"]; var deps = info["dependencies"]; if (deps != null && deps.IsArray) { for (int i = 0; i < deps.Count; i++) { var dep = deps[i]; var depId = dep["id"].Value; var depVersion = dep["version"].Value; bool depAllowNewer = (bool)dep["allow-newer"].Value; package.AddDependency(new RantPackageDependency(depId.ToString(), depVersion.ToString()) { AllowNewer = depAllowNewer }); } } var patterns = doc["patterns"]; if (patterns != null) { var names = patterns.Keys; foreach (string name in names) { package.AddPattern(new RantPattern(name, RantPatternOrigin.File, patterns[name])); } } var tables = doc["tables"]; if (tables != null) { var names = tables.Keys; foreach (string name in names) { var table = tables[name]; string tableName = table["name"]; string[] tableSubs = (string[])table["subs"]; string[] hiddenClasses = (string[])table["hidden"]; var entries = new List <RantDictionaryEntry>(); var entryList = table["entries"]; for (var i = 0; i < entryList.Count; i++) { var loadedEntry = entryList[i]; int weight = 1; if (loadedEntry.HasKey("weight")) { weight = (int)loadedEntry["weight"].Value; } string[] requiredClasses = (string[])loadedEntry["classes"]; string[] optionalClasses = (string[])loadedEntry["optional_classes"]; var terms = new List <RantDictionaryTerm>(); var termList = loadedEntry["terms"]; for (var j = 0; j < termList.Count; j++) { var t = new RantDictionaryTerm(termList[j]["value"], termList[j]["pron"]); terms.Add(t); } var entry = new RantDictionaryEntry( terms.ToArray(), requiredClasses.Concat(optionalClasses.Select(x => x + "?")), weight ); entries.Add(entry); } var rantTable = new RantDictionaryTable( tableName, tableSubs, entries, hiddenClasses ); package.AddTable(rantTable); } } return(package); } }