Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
PackageVersion.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // Original code from http://nuget.codeplex.com class SemanticVersion
3 // Copyright 2010-2014 Outercurve Foundation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 using System;
14 using System.Text.RegularExpressions;
15 using SiliconStudio.Core;
16 using SiliconStudio.Core.Serialization;
17 using SiliconStudio.Core.Serialization.Serializers;
18 
19 namespace SiliconStudio.Assets
20 {
21  /// <summary>
22  /// A hybrid implementation of SemVer that supports semantic versioning as described at http://semver.org while not strictly enforcing it to
23  /// allow older 4-digit versioning schemes to continue working.
24  /// </summary>
25  [DataContract("PackageVersion")]
26  [DataSerializer(typeof(PackageVersionDataSerializer))]
27  public sealed class PackageVersion : IComparable, IComparable<PackageVersion>, IEquatable<PackageVersion>
28  {
29  private const RegexOptions Flags = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
30  private static readonly Regex SemanticVersionRegex = new Regex(@"^(?<Version>\d+(\s*\.\s*\d+){0,3})(?<Release>-[a-z][0-9a-z-]*)?$", Flags);
31  private static readonly Regex StrictSemanticVersionRegex = new Regex(@"^(?<Version>\d+(\.\d+){2})(?<Release>-[a-z][0-9a-z-]*)?$", Flags);
32  private readonly string originalString;
33 
34  /// <summary>
35  /// Initializes a new instance of the <see cref="PackageVersion"/> class.
36  /// </summary>
37  /// <param name="version">The version.</param>
38  public PackageVersion(string version)
39  : this(Parse(version))
40  {
41  // The constructor normalizes the version string so that it we do not need to normalize it every time we need to operate on it.
42  // The original string represents the original form in which the version is represented to be used when printing.
43  originalString = version;
44  }
45 
46  /// <summary>
47  /// Initializes a new instance of the <see cref="PackageVersion"/> class.
48  /// </summary>
49  /// <param name="major">The major.</param>
50  /// <param name="minor">The minor.</param>
51  /// <param name="build">The build.</param>
52  /// <param name="revision">The revision.</param>
53  public PackageVersion(int major, int minor, int build, int revision)
54  : this(new Version(major, minor, build, revision))
55  {
56  }
57 
58  /// <summary>
59  /// Initializes a new instance of the <see cref="PackageVersion"/> class.
60  /// </summary>
61  /// <param name="major">The major.</param>
62  /// <param name="minor">The minor.</param>
63  /// <param name="build">The build.</param>
64  /// <param name="specialVersion">The special version.</param>
65  public PackageVersion(int major, int minor, int build, string specialVersion)
66  : this(new Version(major, minor, build), specialVersion)
67  {
68  }
69 
70  /// <summary>
71  /// Initializes a new instance of the <see cref="PackageVersion"/> class.
72  /// </summary>
73  /// <param name="version">The version.</param>
74  public PackageVersion(Version version)
75  : this(version, String.Empty)
76  {
77  }
78 
79  /// <summary>
80  /// Initializes a new instance of the <see cref="PackageVersion"/> class.
81  /// </summary>
82  /// <param name="version">The version.</param>
83  /// <param name="specialVersion">The special version.</param>
84  public PackageVersion(Version version, string specialVersion)
85  : this(version, specialVersion, null)
86  {
87  }
88 
89  private PackageVersion(Version version, string specialVersion, string originalString)
90  {
91  if (version == null)
92  {
93  throw new ArgumentNullException("version");
94  }
95  Version = NormalizeVersionValue(version);
96  SpecialVersion = specialVersion ?? String.Empty;
97  this.originalString = String.IsNullOrEmpty(originalString) ? version.ToString() + (!String.IsNullOrEmpty(specialVersion) ? '-' + specialVersion : null) : originalString;
98  }
99 
100  internal PackageVersion(PackageVersion semVer)
101  {
102  originalString = semVer.ToString();
103  Version = semVer.Version;
104  SpecialVersion = semVer.SpecialVersion;
105  }
106 
107  /// <summary>
108  /// Gets the normalized version portion.
109  /// </summary>
110  public Version Version { get; private set; }
111 
112  /// <summary>
113  /// Gets the optional special version.
114  /// </summary>
115  public string SpecialVersion { get; private set; }
116 
118  {
119  if (!String.IsNullOrEmpty(originalString))
120  {
121  string original;
122 
123  // search the start of the SpecialVersion part, if any
124  int dashIndex = originalString.IndexOf('-');
125  if (dashIndex != -1)
126  {
127  // remove the SpecialVersion part
128  original = originalString.Substring(0, dashIndex);
129  }
130  else
131  {
132  original = originalString;
133  }
134 
135  return SplitAndPadVersionString(original);
136  }
137  else
138  {
139  return SplitAndPadVersionString(Version.ToString());
140  }
141  }
142 
143  private static string[] SplitAndPadVersionString(string version)
144  {
145  string[] a = version.Split('.');
146  if (a.Length == 4)
147  {
148  return a;
149  }
150  else
151  {
152  // if 'a' has less than 4 elements, we pad the '0' at the end
153  // to make it 4.
154  var b = new string[4] { "0", "0", "0", "0" };
155  Array.Copy(a, 0, b, 0, a.Length);
156  return b;
157  }
158  }
159 
160  /// <summary>
161  /// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version.
162  /// </summary>
163  public static PackageVersion Parse(string version)
164  {
165  if (String.IsNullOrEmpty(version))
166  {
167  throw new ArgumentNullException("version", "cannot be null or empty");
168  }
169 
170  PackageVersion semVer;
171  if (!TryParse(version, out semVer))
172  {
173  throw new ArgumentException(String.Format("Invalid version format [{0}]", version), "version");
174  }
175  return semVer;
176  }
177 
178  /// <summary>
179  /// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version.
180  /// </summary>
181  public static bool TryParse(string version, out PackageVersion value)
182  {
183  return TryParseInternal(version, SemanticVersionRegex, out value);
184  }
185 
186  /// <summary>
187  /// Parses a version string using strict semantic versioning rules that allows exactly 3 components and an optional special version.
188  /// </summary>
189  public static bool TryParseStrict(string version, out PackageVersion value)
190  {
191  return TryParseInternal(version, StrictSemanticVersionRegex, out value);
192  }
193 
194  private static bool TryParseInternal(string version, Regex regex, out PackageVersion semVer)
195  {
196  semVer = null;
197  if (String.IsNullOrEmpty(version))
198  {
199  return false;
200  }
201 
202  var match = regex.Match(version.Trim());
203  Version versionValue;
204  if (!match.Success || !Version.TryParse(match.Groups["Version"].Value, out versionValue))
205  {
206  // Support integer version numbers (i.e. 1 -> 1.0)
207  int versionNumber;
208  if (Int32.TryParse(version, out versionNumber) && versionNumber > 0)
209  {
210  semVer = new PackageVersion(new Version(versionNumber, 0));
211  return true;
212  }
213 
214  return false;
215  }
216 
217  semVer = new PackageVersion(NormalizeVersionValue(versionValue), match.Groups["Release"].Value.TrimStart('-'), version.Replace(" ", ""));
218  return true;
219  }
220 
221  /// <summary>
222  /// Attempts to parse the version token as a SemanticVersion.
223  /// </summary>
224  /// <returns>An instance of SemanticVersion if it parses correctly, null otherwise.</returns>
225  public static PackageVersion ParseOptionalVersion(string version)
226  {
227  PackageVersion semVer;
228  TryParse(version, out semVer);
229  return semVer;
230  }
231 
232  private static Version NormalizeVersionValue(Version version)
233  {
234  return new Version(version.Major,
235  version.Minor,
236  Math.Max(version.Build, 0),
237  Math.Max(version.Revision, 0));
238  }
239 
240  public int CompareTo(object obj)
241  {
242  if (Object.ReferenceEquals(obj, null))
243  {
244  return 1;
245  }
246  PackageVersion other = obj as PackageVersion;
247  if (other == null)
248  {
249  throw new ArgumentException("Object must be a SemanticVersion", "obj");
250  }
251  return CompareTo(other);
252  }
253 
254  public int CompareTo(PackageVersion other)
255  {
256  if (Object.ReferenceEquals(other, null))
257  {
258  return 1;
259  }
260 
261  int result = Version.CompareTo(other.Version);
262 
263  if (result != 0)
264  {
265  return result;
266  }
267 
268  bool empty = String.IsNullOrEmpty(SpecialVersion);
269  bool otherEmpty = String.IsNullOrEmpty(other.SpecialVersion);
270  if (empty && otherEmpty)
271  {
272  return 0;
273  }
274  else if (empty)
275  {
276  return 1;
277  }
278  else if (otherEmpty)
279  {
280  return -1;
281  }
282  return StringComparer.OrdinalIgnoreCase.Compare(SpecialVersion, other.SpecialVersion);
283  }
284 
285  public static bool operator ==(PackageVersion version1, PackageVersion version2)
286  {
287  if (Object.ReferenceEquals(version1, null))
288  {
289  return Object.ReferenceEquals(version2, null);
290  }
291  return version1.Equals(version2);
292  }
293 
294  public static bool operator !=(PackageVersion version1, PackageVersion version2)
295  {
296  return !(version1 == version2);
297  }
298 
299  public static bool operator <(PackageVersion version1, PackageVersion version2)
300  {
301  if (version1 == null)
302  {
303  throw new ArgumentNullException("version1");
304  }
305  return version1.CompareTo(version2) < 0;
306  }
307 
308  public static bool operator <=(PackageVersion version1, PackageVersion version2)
309  {
310  return (version1 == version2) || (version1 < version2);
311  }
312 
313  public static bool operator >(PackageVersion version1, PackageVersion version2)
314  {
315  if (version1 == null)
316  {
317  throw new ArgumentNullException("version1");
318  }
319  return version2 < version1;
320  }
321 
322  public static bool operator >=(PackageVersion version1, PackageVersion version2)
323  {
324  return (version1 == version2) || (version1 > version2);
325  }
326 
327  public override string ToString()
328  {
329  return originalString;
330  }
331 
332  public bool Equals(PackageVersion other)
333  {
334  return !Object.ReferenceEquals(null, other) &&
335  Version.Equals(other.Version) &&
336  SpecialVersion.Equals(other.SpecialVersion, StringComparison.OrdinalIgnoreCase);
337  }
338 
339  public override bool Equals(object obj)
340  {
341  PackageVersion semVer = obj as PackageVersion;
342  return !Object.ReferenceEquals(null, semVer) && Equals(semVer);
343  }
344 
345  public override int GetHashCode()
346  {
347  int hashCode = Version.GetHashCode();
348  if (SpecialVersion != null)
349  {
350  hashCode = hashCode*4567 + SpecialVersion.GetHashCode();
351  }
352 
353  return hashCode;
354  }
355 
356  internal class PackageVersionDataSerializer : DataSerializer<PackageVersion>
357  {
358  /// <inheritdoc/>
359  public override bool IsBlittable { get { return true; } }
360 
361  /// <inheritdoc/>
362  public override void Serialize(ref PackageVersion obj, ArchiveMode mode, SerializationStream stream)
363  {
364  if (mode == ArchiveMode.Deserialize)
365  {
366  string version = null;
367  stream.Serialize(ref version);
368  obj = PackageVersion.Parse(version);
369  }
370  else
371  {
372  string version = obj.ToString();
373  stream.Serialize(ref version);
374  }
375  }
376  }
377 
378  internal static PackageVersion FromSemanticVersion(NuGet.SemanticVersion semanticVersion)
379  {
380  if (semanticVersion == null)
381  {
382  return null;
383  }
384  return new PackageVersion(semanticVersion.ToString());
385  }
386  }
387 }
function b
function a
static PackageVersion ParseOptionalVersion(string version)
Attempts to parse the version token as a SemanticVersion.
PackageVersion(int major, int minor, int build, string specialVersion)
Initializes a new instance of the PackageVersion class.
Flags
Enumeration of the new Assimp's flags.
static bool TryParse(string version, out PackageVersion value)
Parses a version string using loose semantic versioning rules that allows 2-4 version components foll...
Base class for implementation of SerializationStream.
static bool TryParseStrict(string version, out PackageVersion value)
Parses a version string using strict semantic versioning rules that allows exactly 3 components and a...
PackageVersion(Version version, string specialVersion)
Initializes a new instance of the PackageVersion class.
Version Version
Gets the normalized version portion.
PackageVersion(string version)
Initializes a new instance of the PackageVersion class.
bool Equals(PackageVersion other)
PackageVersion(int major, int minor, int build, int revision)
Initializes a new instance of the PackageVersion class.
int CompareTo(PackageVersion other)
Describes how to serialize and deserialize an object without knowing its type. Used as a common base ...
ArchiveMode
Enumerates the different mode of serialization (either serialization or deserialization).
Definition: ArchiveMode.cs:8
PackageVersion(Version version)
Initializes a new instance of the PackageVersion class.
A hybrid implementation of SemVer that supports semantic versioning as described at http://semver...
static PackageVersion Parse(string version)
Parses a version string using loose semantic versioning rules that allows 2-4 version components foll...
override bool Equals(object obj)