-Moved CMSIS-PAck specific version parsing out of SemanticVersion classes to keep SemanticVersion clean and conformant, while still handling the lrelaxed parsing needs of CMSIS

- refactored more of the XSD generated classes
- Added Support to the SemanticVersion Grammar and parser to handle superset of valid syntax. All Valid Semantic versions parse, and a number of officially invalid ones do. This allows re-use of the primary parsing with other variants that have more lax syntax constraints.
- Added VersionQualifier to handle special cases of optional leading character in some forms of relaxed syntax
This commit is contained in:
Steve Maillet 2016-04-07 22:00:44 -07:00
Родитель 0f64195066
Коммит 1bf0a6ea05
20 изменённых файлов: 273 добавлений и 295 удалений

Просмотреть файл

@ -48,6 +48,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xml" />
@ -75,7 +76,7 @@
<Compile Include="PackDescription\DebugConfig.cs" />
<Compile Include="PackDescription\DebugInterface.cs" />
<Compile Include="PackDescription\DebugPort.cs" />
<Compile Include="PackDescription\DebugType.cs" />
<Compile Include="PackDescription\Debug.cs" />
<Compile Include="PackDescription\DebugVarsType.cs" />
<Compile Include="PackDescription\DescriptionType.cs" />
<Compile Include="PackDescription\DeviceFeatureType.cs" />
@ -123,6 +124,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RepositoryPackage.cs" />
<Compile Include="RepositoryUpdateEventArgs.cs" />
<Compile Include="VersionParser.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

Просмотреть файл

@ -43,7 +43,7 @@ namespace CMSIS.Pack.PackDescription
get { return ApiVersion.ToString(); }
set
{
ApiVersion = SemanticVersion.Parse( value );
ApiVersion = VersionParser.Parse( value );
}
}

Просмотреть файл

@ -22,8 +22,7 @@ namespace CMSIS.Pack.PackDescription
get { return Version.ToString( ); }
set
{
// NOTE: Gracefully handle some real-world PDSC files with simple versions
Version = SemanticVersion.Parse( value, ParseOptions.PatchOptional );
Version = VersionParser.Parse( value );
}
}

Просмотреть файл

@ -43,8 +43,7 @@ namespace CMSIS.Pack.PackDescription
get { return Version.ToString( ); }
set
{
// NOTE: Gracefully handle some real-world PDSC files with simple versions
Version = SemanticVersion.Parse( value, ParseOptions.PatchOptional );
Version = VersionParser.Parse( value );
}
}

Просмотреть файл

@ -39,7 +39,7 @@ namespace CMSIS.Pack.PackDescription
public string RawCversionString
{
get { return Version.ToString(); }
set { Version = SemanticVersion.Parse( value ); }
set { Version = VersionParser.Parse( value ); }
}
[XmlIgnore]
@ -51,7 +51,7 @@ namespace CMSIS.Pack.PackDescription
public string RawCapiversionString
{
get { return ApiVersion.ToString(); }
set { ApiVersion = SemanticVersion.Parse( value ); }
set { ApiVersion = VersionParser.Parse( value ); }
}
[XmlIgnore]

Просмотреть файл

@ -0,0 +1,43 @@
using System;
using System.ComponentModel;
using System.Xml;
using System.Xml.Serialization;
using Sprache;
namespace CMSIS.Pack.PackDescription
{
[Serializable( )]
public class Debug
{
/// <remarks/>
[XmlElement( "datapatch")]
public DebugDataPatch[] Datapatch { get; set; }
/// <remarks/>
[XmlAttribute( "__dp", Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
[DefaultValue( 0 )]
public uint DebugPortId { get; set; } = 0;
/// <remarks/>
[XmlAttribute( "__ap", Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
[DefaultValue( 0 )]
public uint AccessPortIndex { get; set; } = 0;
/// <remarks/>
[XmlAttribute( "svd", Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
public string SvdFile { get; set; }
/// <remarks/>
[XmlAttribute( "Pname", Form = System.Xml.Schema.XmlSchemaForm.Qualified )]
public string ProcessorName
{
get { return ProcessorName_; }
set { ProcessorName_ = Parsers.RestrictedString.Parse( value ); }
}
private string ProcessorName_;
/// <remarks/>
[XmlAnyAttribute( )]
public XmlAttribute[ ] AnyAttr { get; set; }
}
}

Просмотреть файл

@ -1,111 +0,0 @@
using System;
using System.Xml;
using System.Xml.Serialization;
using Sprache;
namespace CMSIS.Pack.PackDescription
{
[Serializable( )]
public class DebugType {
private DebugDataPatch[] datapatchField;
private uint @__dpField;
private bool @__dpFieldSpecified;
private uint @__apField;
private bool @__apFieldSpecified;
private string svdField;
private XmlAttribute[] anyAttrField;
/// <remarks/>
[XmlElement( "datapatch")]
public DebugDataPatch[] datapatch {
get {
return datapatchField;
}
set {
datapatchField = value;
}
}
/// <remarks/>
[XmlAttribute( Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
public uint @__dp {
get {
return @__dpField;
}
set {
@__dpField = value;
}
}
/// <remarks/>
[XmlIgnore( )]
public bool @__dpSpecified {
get {
return @__dpFieldSpecified;
}
set {
@__dpFieldSpecified = value;
}
}
/// <remarks/>
[XmlAttribute( Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
public uint @__ap {
get {
return @__apField;
}
set {
@__apField = value;
}
}
/// <remarks/>
[XmlIgnore( )]
public bool @__apSpecified {
get {
return @__apFieldSpecified;
}
set {
@__apFieldSpecified = value;
}
}
/// <remarks/>
[XmlAttribute( Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
public string svd {
get {
return svdField;
}
set {
svdField = value;
}
}
/// <remarks/>
[XmlAttribute( "Pname", Form = System.Xml.Schema.XmlSchemaForm.Qualified )]
public string ProcessorName
{
get { return ProcessorName_; }
set { ProcessorName_ = Parsers.RestrictedString.Parse( value ); }
}
private string ProcessorName_;
/// <remarks/>
[XmlAnyAttribute( )]
public XmlAttribute[ ] AnyAttr {
get {
return anyAttrField;
}
set {
anyAttrField = value;
}
}
}
}

Просмотреть файл

@ -1,43 +1,32 @@
using System;
using System.Xml;
using System.Xml.Serialization;
using SemVer.NET;
using Sprache;
namespace CMSIS.Pack.PackDescription
{
[Serializable( )]
public class DebugVarsType {
private string configfileField;
private string versionField;
private XmlAttribute[] anyAttrField;
private string valueField;
public class DebugVarsType
{
/// <remarks/>
[XmlAttribute( Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
public string configfile {
get {
return configfileField;
}
set {
configfileField = value;
}
}
/// <remarks/>
[XmlAttribute( Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
public string version {
get {
return versionField;
}
set {
versionField = value;
[XmlAttribute( "configfile", Form=System.Xml.Schema.XmlSchemaForm.Qualified )]
public string ConfigFile { get; set; }
[XmlAttribute( "version", Form = System.Xml.Schema.XmlSchemaForm.Qualified )]
[System.ComponentModel.EditorBrowsable( System.ComponentModel.EditorBrowsableState.Never )]
public string RawVersionString
{
get { return Version.ToString( ); }
set
{
Version = VersionParser.Parse( value );
}
}
[XmlIgnore]
public SemanticVersion Version { get; set; }
/// <remarks/>
[XmlAttribute( "Pname", Form = System.Xml.Schema.XmlSchemaForm.Qualified )]
public string ProcessorName
@ -49,24 +38,10 @@ namespace CMSIS.Pack.PackDescription
/// <remarks/>
[XmlAnyAttribute( )]
public XmlAttribute[ ] AnyAttr {
get {
return anyAttrField;
}
set {
anyAttrField = value;
}
}
public XmlAttribute[ ] AnyAttr { get; set; }
/// <remarks/>
[XmlText( )]
public string Value {
get {
return valueField;
}
set {
valueField = value;
}
}
public string Value { get; set; }
}
}

Просмотреть файл

@ -27,7 +27,7 @@ namespace CMSIS.Pack.PackDescription
private DebugPort[] debugportField;
private DebugType[] debugField;
private Debug[] debugField;
private TraceType[] traceField;
@ -150,7 +150,7 @@ namespace CMSIS.Pack.PackDescription
/// <remarks/>
[XmlElement( "debug")]
public DebugType[] debug {
public Debug[] debug {
get {
return debugField;
}

Просмотреть файл

@ -28,7 +28,7 @@ namespace CMSIS.Pack.PackDescription
private DebugPort[] debugportField;
private DebugType[] debugField;
private Debug[] debugField;
private TraceType[] traceField;
@ -149,7 +149,7 @@ namespace CMSIS.Pack.PackDescription
/// <remarks/>
[XmlElement( "debug")]
public DebugType[] debug {
public Debug[] debug {
get {
return debugField;
}

Просмотреть файл

@ -28,7 +28,7 @@ namespace CMSIS.Pack.PackDescription
private DebugPort[] debugportField;
private DebugType[] debugField;
private Debug[] debugField;
private TraceType[] traceField;
@ -155,7 +155,7 @@ namespace CMSIS.Pack.PackDescription
/// <remarks/>
[XmlElement( "debug")]
public DebugType[] debug {
public Debug[] debug {
get {
return debugField;
}

Просмотреть файл

@ -17,7 +17,7 @@ namespace CMSIS.Pack.PackDescription
get { return Version.ToString( ); }
set
{
Version = SemanticVersion.Parse( value );
Version = VersionParser.Parse( value );
}
}

Просмотреть файл

@ -28,7 +28,7 @@ namespace CMSIS.Pack.PackDescription
private DebugPort[] debugportField;
private DebugType[] debugField;
private Debug[] debugField;
private TraceType[] traceField;
@ -151,7 +151,7 @@ namespace CMSIS.Pack.PackDescription
/// <remarks/>
[XmlElement( "debug")]
public DebugType[] debug {
public Debug[] debug {
get {
return debugField;
}

Просмотреть файл

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using SemVer.NET;
using Sprache;
namespace CMSIS.Pack
{
// CMSIS-Pack uses a relaxed syntax for semantic versions.
// Deviations from the official spec are:
// 1) Trailing 0s on Minor and Patch are ignored
// 2) Patch is optional, if not present a default of 0 is assumed
// 3) The hyphen prerelease delimiter is optional if the first
// character of the prerelease identifier is a letter
//
// This utility class provides for relaxed parsing to generate
// a full SemanticVersion that, when converted back to a string
// will conform to the SemanticVersion 2.0.0 specs. Thus, this
// class serves to normalize the nonstandard versions into the
// standard form.
internal class VersionParser
{
internal static SemanticVersion Parse( string version)
{
var parts = Grammar.SemanticVersion.Parse( version );
// handle case #2
var patch = string.IsNullOrWhiteSpace( parts.Patch ) ? "0" : parts.Patch;
// handle case #1
patch = patch.Length > 1 ? patch.TrimEnd('0') : patch;
var minor = parts.Minor.Length > 1 ? parts.Minor.TrimEnd('0') : parts.Minor;
if( parts.LeadingV.HasValue )
throw new FormatException( "Leading 'v' characters not supported in CMSIS-PACK Versions" );
return new SemanticVersion( BigInteger.Parse( parts.Major )
, BigInteger.Parse( minor )
, BigInteger.Parse( patch )
, GetPrereleaseQualifiers( parts.Prerelease )
, parts.BuildMetadata?.Identifiers ?? Enumerable.Empty<string>( )
);
}
private static IEnumerable<string> GetPrereleaseQualifiers( VersionQualifier qualifier )
{
if( qualifier == null )
yield break;
var firstIdentifier = qualifier.Identifiers.FirstOrDefault( );
if( firstIdentifier == null )
yield break;
// handles case #3
if( char.IsLetter( qualifier.LeadingChar ) )
firstIdentifier = $"{qualifier.LeadingChar}{firstIdentifier}";
yield return firstIdentifier;
foreach( var identifier in qualifier.Identifiers.Skip( 1 ) )
yield return identifier;
}
}
}

Просмотреть файл

@ -70,6 +70,10 @@ namespace SemVer.NET
public static Parser<string> BuildNumber = NumericIdentifier.Text();
/// <summary>Parser monad to parse a semantic version string into a <see cref="ParseResult"/></summary>
/// <remarks>
/// This parser allows for a number of variations of SemanticVersions in the wild by parsing a
/// superset of SemanticVersion
/// </remarks>
public static Parser<ParseResult> SemanticVersion
= from leadingV in LeadingV.Optional()
from major in BuildNumber
@ -79,20 +83,21 @@ namespace SemVer.NET
from patchValue in BuildNumber
select patchValue
).Optional()
from preRelease in ( from start in StartPreRelease
from preRelease in ( from start in StartPreRelease.Or( Letter )
from preRelIds in DotSeparatedReleaseIdentifiers
select preRelIds
select new VersionQualifier( start, preRelIds )
).Optional()
from buildMetadata in ( from start in StartBuild
from buildIds in DotSeparatedBuildIdentifiers
select buildIds
select new VersionQualifier( start, buildIds )
).Optional()
select new ParseResult( leadingV.IsDefined ? new char?( leadingV.Get() ) : null
, major
, minor
, patch.GetOrElse( string.Empty )
, preRelease.GetOrElse( Enumerable.Empty<string>( ) )
, buildMetadata.GetOrElse( Enumerable.Empty<string>( ) )
, preRelease.GetOrDefault( )
, buildMetadata.GetOrDefault( )
);
}
}

Просмотреть файл

@ -3,6 +3,19 @@ using System.Collections.Generic;
namespace SemVer.NET
{
/// <summary>Parse result of a Version Prerelease or build qualifier</summary>
public class VersionQualifier
{
public VersionQualifier( char leadingChar, IEnumerable<string> identifiers)
{
LeadingChar = leadingChar;
Identifiers = identifiers;
}
public char LeadingChar { get; }
public IEnumerable<string> Identifiers { get; }
}
/// <summary>Contains the results of parsing a Semantic version string</summary>
/// <remarks>
/// <para>In order to support variations on Semantic versions as well as gracefully
@ -27,8 +40,8 @@ namespace SemVer.NET
, string major
, string minor
, string patch
, IEnumerable<string> prereleaseParts
, IEnumerable<string> buildParts
, VersionQualifier prereleaseParts
, VersionQualifier buildParts
)
{
if( major == null )
@ -40,12 +53,6 @@ namespace SemVer.NET
if( patch == null )
throw new ArgumentNullException( nameof( patch ) );
if( prereleaseParts == null )
throw new ArgumentNullException( nameof( prereleaseParts ) );
if( buildParts == null )
throw new ArgumentNullException( nameof( buildParts ) );
LeadingV = leadingV;
Major = major;
Minor = minor;
@ -83,9 +90,9 @@ namespace SemVer.NET
public string Patch { get; }
/// <summary>Gets a collection of prerelease identifier strings</summary>
public IEnumerable<string> Prerelease { get; }
public VersionQualifier Prerelease { get; }
/// <summary>Gets a collection of the build metadata identifier strings</summary>
public IEnumerable<string> BuildMetadata { get; }
public VersionQualifier BuildMetadata { get; }
}
}

Просмотреть файл

@ -37,6 +37,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup>
<Compile Include="Grammar.cs" />

Просмотреть файл

@ -2,36 +2,21 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Text;
using Sprache;
namespace SemVer.NET
{
/// <summary>Option flags for parsing a semantic version string</summary>
[Flags]
public enum ParseOptions
{
/// <summary>No special handling, parsing proceeds according to Semantic Version Specification</summary>
None = 0,
/// <summary>Patch build number is optional, and if not present in the string a default of "0" is assumed</summary>
PatchOptional = 1,
/// <summary>Allow a leading 'v' or 'V' as a common convention for version numbers</summary>
AllowLeadingV = 2,
}
// TODO: Add additional Comparer<SemanticVersion> implementation to handle build metadata in precedence
// see: https://github.com/mojombo/semver/issues/200
//
/// <summary>Version structure for versions based on Semantic Versioning v2.0 as defined by https://github.com/mojombo/semver/blob/master/semver.md </summary>
/// <summary>Version structure for versions based on SemanticVersion 2.0.0</summary>
/// <remarks>
/// <para>This class implements creating, parsing, and comparing semantic version values. In
/// addition to the standard support, this class includes an additional optional optimization
/// where parsing a version string can assume a default patch value of 0 if none is specified.
/// According to the formal Semantic Versioning v2.0 spec. the patch value is required, however
/// some real world applications allow the looser definition.</para>
/// <para>Technically the Major, Minor, and Patch numbers have no length limits, thus this uses</para>
/// This class implements creating, parsing, and comparing semantic version values.
/// <note type="note">
/// Technically, the Major, Minor, and Patch numbers have no length limits, thus this
/// class uses <see cref="BigInteger"/> as the type for each of the numeric parts.
/// </note>
/// </remarks>
/// <seealso cref="https://github.com/mojombo/semver/blob/master/semver.md"/>
public struct SemanticVersion
: IComparable
, IComparable<SemanticVersion>
@ -43,7 +28,7 @@ namespace SemVer.NET
/// <param name="patch">Patch version number</param>
/// <param name="preReleaseParts">Array of individual prerelease parts (not including the separating '.')</param>
/// <param name="metadataParts">Array of individual Build Metadata parts (not including the separating '.')</param>
public SemanticVersion( int major, int minor, int patch, IEnumerable<string> preReleaseParts, IEnumerable<string> metadataParts )
public SemanticVersion( BigInteger major, BigInteger minor, BigInteger patch, IEnumerable<string> preReleaseParts, IEnumerable<string> metadataParts )
{
if( major < 0 )
throw new ArgumentOutOfRangeException( nameof( major ) );
@ -57,15 +42,18 @@ namespace SemVer.NET
Major = major;
Minor = minor;
Patch = patch;
PreReleaseParts_ = ( preReleaseParts ?? Enumerable.Empty<string>() ).ToArray();
BuildMetadata_ = ( metadataParts ?? Enumerable.Empty<string>() ).ToArray();
var prereleaseList = preReleaseParts?.ToList().AsReadOnly() ?? EmptyStringList;
var buildMetadataList = metadataParts?.ToList().AsReadOnly() ?? EmptyStringList;
// Validate each part conforms to an "identifier" as defined by the spec
if( !ValidatePrereleaseIdentifierParts( PreReleaseParts_ ) )
if( !ValidatePrereleaseIdentifierParts( prereleaseList ) )
throw new ArgumentException( "Invalid identifier for prerelease part", nameof( preReleaseParts ) );
if( !ValidateBuildIdentifierParts( BuildMetadata_ ) )
if( !ValidateBuildIdentifierParts( buildMetadataList ) )
throw new ArgumentException( "Invalid identifier for build metadata part", nameof( metadataParts ) );
PreReleaseParts_ = prereleaseList;
BuildMetadata_ = buildMetadataList;
HashCode = null;
}
@ -94,13 +82,13 @@ namespace SemVer.NET
public bool IsValid => Major >= 0 && Minor >= 0 && Patch >= 0;
/// <summary>Major version number</summary>
public int Major { get; }
public BigInteger Major { get; }
/// <summary>Minor version number</summary>
public int Minor { get; }
public BigInteger Minor { get; }
/// <summary>Patch version number</summary>
public int Patch { get; }
public BigInteger Patch { get; }
/// <summary>List of identifier parts forming the prerelease value</summary>
/// <remarks>
@ -108,8 +96,8 @@ namespace SemVer.NET
/// value can consist of multiple parts separated by a '.', this list contains the
/// individual parts without the leading '-' or separating '.'.
/// </remarks>
public IReadOnlyList<string> PreReleaseParts => Array.AsReadOnly( PreReleaseParts_ ?? EmptyStringArray );
private readonly string[ ] PreReleaseParts_;
public IReadOnlyList<string> PreReleaseParts => PreReleaseParts_ ?? EmptyStringList;
private IReadOnlyList<string> PreReleaseParts_;
/// <summary>List of identifier parts forming the build Metadata value</summary>
/// <remarks>
@ -117,8 +105,8 @@ namespace SemVer.NET
/// value can consist of multiple parts separated by a '.', this list contains
/// the individual parts without the leading '+' or separating '.'.
/// </remarks>
public IReadOnlyList<string> BuildMetadata => Array.AsReadOnly( BuildMetadata_ ?? EmptyStringArray );
private readonly string[ ] BuildMetadata_;
public IReadOnlyList<string> BuildMetadata => BuildMetadata_ ?? EmptyStringList;
private IReadOnlyList<string> BuildMetadata_;
/// <inheritdoc/>
public override int GetHashCode( )
@ -239,13 +227,13 @@ namespace SemVer.NET
public string ToString( bool includeBuildMetadata )
{
var bldr = new StringBuilder( string.Format( CultureInfo.InvariantCulture, "{0}.{1}.{2}", Major, Minor, Patch ) );
if( PreReleaseParts.Count > 0 )
if( ( PreReleaseParts?.Count ?? 0 ) > 0 )
{
bldr.Append( '-' );
bldr.Append( string.Join( ".", PreReleaseParts ) );
}
if( BuildMetadata.Count > 0 && includeBuildMetadata )
if( ( BuildMetadata?.Count ?? 0 ) > 0 && includeBuildMetadata )
{
bldr.Append( '+' );
bldr.Append( string.Join( ".", BuildMetadata ) );
@ -257,22 +245,23 @@ namespace SemVer.NET
/// <summary>Parse a semantic version string into it's component parts</summary>
/// <param name="versionString">String containing the version to parse</param>
/// <returns>Parsed version details</returns>
public static SemanticVersion Parse( string versionString ) => Parse( versionString, ParseOptions.None );
/// <summary>Parse a semantic version string into it's component parts</summary>
/// <param name="versionString">String containing the version to parse</param>
/// <param name="patchOptional">Flag indicating non-standard optional default (0) for the patch if not present</param>
/// <returns>Parsed version details</returns>
/// <remarks>
/// This overload of Parse allows for a non-standard version where the Patch value
/// defaults to 0 if not present, instead of triggering an exception.
/// </remarks>
public static SemanticVersion Parse( string versionString, ParseOptions options )
public static SemanticVersion Parse( string versionString )
{
try
{
var parts = Grammar.SemanticVersion.Parse( versionString );
return new SemanticVersion( parts, options );
if( string.IsNullOrWhiteSpace( parts.Patch ) )
throw new FormatException( "Patch component of Semantic Version is required" );
if( parts.LeadingV.HasValue )
throw new FormatException( "Leading 'v' characters not supported in strict SemanticVersion" );
return new SemanticVersion( BigInteger.Parse( parts.Major )
, BigInteger.Parse( parts.Minor )
, BigInteger.Parse( parts.Patch )
, parts.Prerelease?.Identifiers ?? Enumerable.Empty<string>()
, parts.BuildMetadata?.Identifiers ?? Enumerable.Empty<string>( )
);
}
catch( ParseException ex )
{
@ -280,25 +269,41 @@ namespace SemVer.NET
}
}
/// <summary>Attempts to parse a version string into a new SemanticVersion instance</summary>
/// <param name="versionString">String to parse</param>
/// <param name="version">Version instance to construct</param>
/// <returns>true if the string is a valid semantic version string that was successfully parsed into <paramref name="version"/></returns>
public static bool TryParse( string versionString, out SemanticVersion version ) => TryParse( versionString, ParseOptions.None, out version );
/// <summary>Attempts to parse a version string into a new SemanticVersion instance</summary>
/// <param name="versionString">String to parse</param>
/// <param name="options">Options flags to control parsing variants and ambiguities in the spec</param>
/// <param name="version">Version instance to construct</param>
/// <returns>true if the string is a valid semantic version string that was successfully parsed into <paramref name="version"/></returns>
public static bool TryParse( string versionString, ParseOptions options, out SemanticVersion version )
public static bool TryParse( string versionString, out SemanticVersion version )
{
version = new SemanticVersion();
version = default( SemanticVersion );
var result = Grammar.SemanticVersion.TryParse( versionString );
if( !result.WasSuccessful )
return false;
version = new SemanticVersion( result.Value, options );
var parts = result.Value;
if( string.IsNullOrWhiteSpace( parts.Patch ) )
return false;
if( parts.LeadingV.HasValue )
return false;
BigInteger major,minor,patch;
if( !BigInteger.TryParse( parts.Major, out major ) )
return false;
if( !BigInteger.TryParse( parts.Minor, out minor ) )
return false;
if( !BigInteger.TryParse( parts.Patch, out patch ) )
return false;
version = new SemanticVersion( major
, minor
, patch
, parts.Prerelease?.Identifiers ?? Enumerable.Empty<string>( )
, parts.BuildMetadata?.Identifiers ?? Enumerable.Empty<string>( )
);
return true;
}
@ -334,7 +339,7 @@ namespace SemVer.NET
private int ComputeHashCode( ) => ToString( false ).GetHashCode( );
// this is intentionally not a read-only field
// This is intentionally not a read-only field
// its a private field and used like a C++ mutable.
// It caches the HashCode that's expensive to compute
// so it is only done once.
@ -343,21 +348,6 @@ namespace SemVer.NET
// When using the default constructor the prerelease and build meta arrays will be null
// The property accessors for those arrays will test for null and use this singleton empty
// array if null to prevent null reference issues.
static readonly string[] EmptyStringArray = new string [0];
private SemanticVersion( ParseResult parts, ParseOptions options )
: this( int.Parse( parts.Major )
, int.Parse( parts.Minor )
, string.IsNullOrWhiteSpace( parts.Patch ) ? 0 : int.Parse( parts.Patch )
, parts.Prerelease
, parts.BuildMetadata
)
{
if( !options.HasFlag( ParseOptions.PatchOptional ) && string.IsNullOrWhiteSpace( parts.Patch ) )
throw new FormatException( "Patch component of Semantic Version is required" );
if( !options.HasFlag( ParseOptions.AllowLeadingV ) && parts.LeadingV.HasValue )
throw new FormatException( "Leading 'v' characters not supported in SemanticVersion. Use ParseOptions.AllowLeadingV to enable this non-standard extension" );
}
static readonly IReadOnlyList<string> EmptyStringList = Enumerable.Empty<string>().ToList().AsReadOnly();
}
}

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using System.Numerics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SemVer.NET;
@ -126,39 +127,40 @@ namespace UnitTests
VerifyToStringReverseParse( ver );
}
[TestMethod]
public void StaticParseDefaultPatchTest()
{
var ver = SemanticVersion.Parse( "0.1-alpha.beta+foo-bar.baz", ParseOptions.PatchOptional );
Assert.AreEqual( 0, ver.Major );
Assert.AreEqual( 1, ver.Minor );
Assert.AreEqual( 0, ver.Patch );
Assert.IsTrue( ver.IsValid );
Assert.IsTrue( ver.IsDevelopment );
Assert.IsTrue( ver.IsPrerelease );
Assert.AreEqual( 2, ver.PreReleaseParts.Count );
Assert.AreEqual( "alpha", ver.PreReleaseParts[ 0 ] );
Assert.AreEqual( "beta", ver.PreReleaseParts[ 1 ] );
Assert.AreEqual( 2, ver.BuildMetadata.Count );
Assert.AreEqual( "foo-bar", ver.BuildMetadata[ 0 ] );
Assert.AreEqual( "baz", ver.BuildMetadata[ 1 ] );
Assert.AreEqual( "0.1.0-alpha.beta+foo-bar.baz", ver.ToString( ) );
VerifyToStringReverseParse( ver );
}
// TODO: move to CMSIS-Pack specific tests
//[TestMethod]
//public void StaticParseDefaultPatchTest()
//{
// var ver = SemanticVersion.Parse( "0.1-alpha.beta+foo-bar.baz", ParseOptions.PatchOptional );
// Assert.AreEqual( 0, ver.Major );
// Assert.AreEqual( 1, ver.Minor );
// Assert.AreEqual( 0, ver.Patch );
// Assert.IsTrue( ver.IsValid );
// Assert.IsTrue( ver.IsDevelopment );
// Assert.IsTrue( ver.IsPrerelease );
// Assert.AreEqual( 2, ver.PreReleaseParts.Count );
// Assert.AreEqual( "alpha", ver.PreReleaseParts[ 0 ] );
// Assert.AreEqual( "beta", ver.PreReleaseParts[ 1 ] );
// Assert.AreEqual( 2, ver.BuildMetadata.Count );
// Assert.AreEqual( "foo-bar", ver.BuildMetadata[ 0 ] );
// Assert.AreEqual( "baz", ver.BuildMetadata[ 1 ] );
// Assert.AreEqual( "0.1.0-alpha.beta+foo-bar.baz", ver.ToString( ) );
// VerifyToStringReverseParse( ver );
//}
[TestMethod]
public void StaticParseSimpleMajorMinorOnlyTest( )
{
var ver = SemanticVersion.Parse( "2.1", ParseOptions.PatchOptional );
Assert.AreEqual( 2, ver.Major );
Assert.AreEqual( 1, ver.Minor );
Assert.AreEqual( 0, ver.Patch );
Assert.IsTrue( ver.IsValid );
Assert.IsFalse( ver.IsDevelopment );
Assert.IsFalse( ver.IsPrerelease );
Assert.AreEqual( 0, ver.PreReleaseParts.Count );
VerifyToStringReverseParse( ver );
}
//[TestMethod]
//public void StaticParseSimpleMajorMinorOnlyTest( )
//{
// var ver = SemanticVersion.Parse( "2.1", ParseOptions.PatchOptional );
// Assert.AreEqual( 2, ver.Major );
// Assert.AreEqual( 1, ver.Minor );
// Assert.AreEqual( 0, ver.Patch );
// Assert.IsTrue( ver.IsValid );
// Assert.IsFalse( ver.IsDevelopment );
// Assert.IsFalse( ver.IsPrerelease );
// Assert.AreEqual( 0, ver.PreReleaseParts.Count );
// VerifyToStringReverseParse( ver );
//}
[TestMethod]
[ExpectedException( typeof( FormatException ))]
@ -170,7 +172,7 @@ namespace UnitTests
[TestMethod]
public void StaticParseNumericIdentifier()
{
var ver = SemanticVersion.Parse( "2.0.1-2.alpha", ParseOptions.PatchOptional );
var ver = SemanticVersion.Parse( "2.0.1-2.alpha" );
Assert.AreEqual( 2, ver.Major );
Assert.AreEqual( 0, ver.Minor );
Assert.AreEqual( 1, ver.Patch );

Просмотреть файл

@ -49,6 +49,7 @@
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Numerics" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">