Initial commit of basic pack library and test application to show contents and state of local repo

This commit is contained in:
Steve Maillet 2016-03-28 08:06:15 -07:00
Родитель 40f08cd399
Коммит bf578ca490
42 изменённых файлов: 3137 добавлений и 0 удалений

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

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{145D7231-C105-41BE-B646-5D400097C744}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CMSIS.Pack</RootNamespace>
<AssemblyName>CMSIS.Pack</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="Sprache, Version=2.0.0.0, Culture=neutral, PublicKeyToken=23dafc55df9bd3a3, processorArchitecture=MSIL">
<HintPath>..\packages\Sprache.JetBrains.2.0.0.44\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid1+MonoTouch1\Sprache.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileDownloadProgress.cs" />
<Compile Include="Interfaces.cs" />
<Compile Include="PackDescription\Api.cs" />
<Compile Include="PackDescription\Board.cs" />
<Compile Include="PackDescription\Component.cs" />
<Compile Include="PackDescription\Condition.cs" />
<Compile Include="PackDescription\DebugAccessSequence.cs" />
<Compile Include="PackDescription\DeviceFamily.cs" />
<Compile Include="PackDescription\Example.cs" />
<Compile Include="PackDescription\Generator.cs" />
<Compile Include="PackDescription\Keywords.cs" />
<Compile Include="PackDescription\Package.cs" />
<Compile Include="PackDescription\Parsers.cs" />
<Compile Include="PackDescription\Release.cs" />
<Compile Include="PackDescription\TaxonomyDescription.cs" />
<Compile Include="PackIndexEntry.cs" />
<Compile Include="PackIndex.cs" />
<Compile Include="PackInstallProgress.cs" />
<Compile Include="PackRepository.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RepositoryPackage.cs" />
<Compile Include="RepositoryUpdateEventArgs.cs" />
<Compile Include="SemanticVersion.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
-->
<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly);$(TargetFileName)" Outputs="$(OutputPath)$(_SGenDllName)" Condition="'$(GenerateSerializationAssemblies)'=='On'">
<SGen BuildAssemblyName="$(TargetFileName)" BuildAssemblyPath="$(OutputPath)" References="@(ReferencePath)" ShouldGenerateSerializer="true" UseProxyTypes="false" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" DelaySign="$(DelaySign)" ToolPath="$(TargetFrameworkSDKToolsDirectory)" Platform="$(Platform)">
<Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
</SGen>
</Target>
</Project>

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

@ -0,0 +1,34 @@
using System;
namespace CMSIS.Pack
{
/// <summary>Value type used to indicate the static state a file download</summary>
public struct FileDownloadProgress
{
public FileDownloadProgress( Uri source, TimeSpan elapsedTime, long sizeSoFar, long totalSize)
{
SourceUrl_ = source;
ElapsedTime_ = elapsedTime;
SizeSoFar_ = sizeSoFar;
TotalSize_ = totalSize;
}
public double PercentComplete
{
get { return 100.0 * (double)SizeSoFar/(double)TotalSize; }
}
public bool IsCompleted { get { return SizeSoFar_ == -1 || TotalSize_ == -1; } }
public Uri SourceUrl { get { return SourceUrl_; } }
private readonly Uri SourceUrl_;
public TimeSpan ElapsedTime { get { return ElapsedTime_; } }
private readonly TimeSpan ElapsedTime_;
public long SizeSoFar { get { return SizeSoFar_; } }
private readonly long SizeSoFar_;
public long TotalSize { get { return TotalSize_; } }
private readonly long TotalSize_;
}
}

115
CMSIS.Pack/Interfaces.cs Normal file
Просмотреть файл

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using CMSIS.Pack.PackDescription;
namespace CMSIS.Pack
{
public enum PackInstallState
{
AvailableForDownload,
Downloading,
Downloaded,
Installing,
Installed,
}
public interface IPackIndexEntry
{
/// <summary>File name of the compressed form of this pack</summary>
/// <remarks>
/// The file name is of the form: VENDOR.NAME.VERSION.pack
/// </remarks>
string PackName { get; }
/// <summary>Vendor name parsed out of the PackName from the index</summary>
string Vendor { get; }
/// <summary>Name of the pack parsed out of the Pack name from the index</summary>
string Name { get; }
/// <summary>Name of the PDSC file for this pack</summary>
/// <remarks>
/// The PDSC filename takes the form: VENDOR.NAME.pdsc
/// </remarks>
string PdscName { get; }
/// <summary>Full URL of the Package Description (PDSC) file for this pack</summary>
Uri PdscUrl { get; }
/// <summary>FULL URL of the Package file for this pack</summary>
Uri PackUrl { get; }
/// <summary>Base URI for this pack read from the index</summary>
Uri Url { get; }
/// <summary>Local path name for this pack relative to the root of a repository</summary>
/// <remarks>
/// The local path takes the form VENDOR\NAME\VERSION
/// </remarks>
string LocalPath { get; }
/// <summary>Version of the pack</summary>
SemanticVersion Version { get; }
/// <summary>Retrieves the contents of the Package Description file</summary>
/// <returns>string containing the XML content of the description</returns>
Task<string> GetPackageDescriptionDocumentAsync( );
/// <summary>Asynchronously download and parse the package description file for this pack</summary>
/// <returns>parsed package instance for the package description</returns>
Task<Package> GetPackageDescriptionAsync( );
}
public interface IRepositoryPackage
: IPackIndexEntry
{
PackInstallState InstallState { get; }
IRepository Repository { get; }
Task Download( IProgress<FileDownloadProgress> progressSink );
Task InstallPack( IProgress<PackInstallProgress> progressSink );
}
public enum RepositoryState
{
Idle,
DownloadingIndex,
DownloadingIndexPdsc,
DownloadingPackPdsc,
DownloadingPack,
InstallingPack,
UninstallingPack,
DeletingPack
}
/// <summary>Represents a remote repository and local store of the installed pack files</summary>
public interface IRepository
{
/// <summary>Location of the source of packs to download from</summary>
Uri SourceUri { get; }
/// <summary>Location of the locally installed packs that updates and new packs are installed into</summary>
string LocalPath { get; }
DateTime LastUpdatedTimeUTC { get; }
/// <summary>Full path to the local ".Web" folder containing the pack descriptions cached from the web source</summary>
string WebRoot { get; }
/// <summary>Full path </summary>
string DownloadRoot { get; }
IEnumerable<IRepositoryPackage> Packs { get; }
event EventHandler<RepositoryUpdateEventArgs> Updated;
Task UpdateLocalFromSource( );
Task LoadFromLocal( );
Task Download( IRepositoryPackage package, IProgress<FileDownloadProgress> progressSink );
Task InstallPack( IRepositoryPackage package, IProgress<PackInstallProgress> progressSink );
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Api
{
internal static Api ParseFrom( XElement arg )
{
return new Api();
}
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Board
{
internal static Board ParseFrom( XElement arg )
{
return new Board();
}
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Component
{
internal static Component ParseFrom( XElement arg )
{
return new Component();
}
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Condition
{
internal static Condition ParseFrom( XElement arg )
{
return new Condition();
}
}
}

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

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CMSIS.Pack.PackDescription
{
class DebugAccessSequence
{
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class DeviceFamily
{
internal static DeviceFamily ParseFrom( XElement arg )
{
return new DeviceFamily();
}
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Example
{
public static Example ParseFrom( XElement element )
{
return new Example();
}
}
}

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

@ -0,0 +1,12 @@
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Generator
{
internal static Generator ParseFrom( XElement arg )
{
return new Generator( );
}
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Keyword
{
internal static Keyword ParseFrom( XElement keyword )
{
return new Keyword();
}
}
}

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

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
// Unfortunately the officially published schema has circular group definitions
// that XSD.exe can't handle. Furthermore, some of the officially posted and
// "validated" PDSC files don't conform to the schema. In particular, they
// have the following issues:
// 1) They use DVendor attributes with values that don't match the case
// of the official schema XSD and documentation.
// 2) They have feature[@n] using a scaled integer notation (i.e. "512K")
// 3) Date values are occasionally missing leading 0 digits to match official
// XSD:date types. (i.e. "2015-12-1" should be "2015-12-01")
//
// This class and related classes work around these issues by Manually handling
// the deserialization and processing the offending nodes more liberally.
public class Package
{
public Package( )
{
Releases = new List<Release>();
Keywords = new List<Keyword>();
Generators = new List<Generator>();
Devices = new List<DeviceFamily>();
Boards = new List<Board>();
Taxonomy = new List<TaxonomyDescription>();
Apis = new List<Api>();
Conditions = new List<Condition>();
Examples = new List<Example>();
Components = new List<Component>();
}
public SemanticVersion SchemaVersion { get; set; }
public string Vendor { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Uri Url {get; set; }
public string SupportContact { get; set; }
public string License { get; set; }
public IList<Release> Releases { get; }
public IList<Keyword> Keywords { get; }
public IList<Generator> Generators { get; }
public IList<DeviceFamily> Devices { get; }
public IList<Board> Boards { get; }
public IList<TaxonomyDescription> Taxonomy { get; }
public IList<Api> Apis { get; }
public IList<Condition> Conditions { get; }
public IList<Example> Examples { get; }
public IList<Component> Components { get; }
public static async Task<Package> LoadFromAsync( string uri )
{
if( string.IsNullOrWhiteSpace( uri ) )
throw new ArgumentException("Path is null or empty", nameof( uri ) );
var doc = await Task.Run( ()=> XDocument.Load( uri ) );
return await ParseFromAsync( doc );
}
public static async Task<Package> ParseFromAsync( string xml )
{
var doc = await Task.Run( ( ) => XDocument.Parse( xml ) );
return await ParseFromAsync( doc );
}
public static Task<Package> ParseFromAsync( XDocument doc )
{
return Task.Run( ( ) =>
{
var retVal = new Package( );
var pkgElement = doc.Element( "package" );
retVal.Name = pkgElement.Element( "name" ).Value;
retVal.Vendor = pkgElement.Element( "vendor" ).Value;
retVal.Description = pkgElement.Element( "description" ).Value;
retVal.Url = new Uri( pkgElement.Element( "url" ).Value );
retVal.SupportContact = pkgElement.Element( "supportContact" )?.Value;
retVal.License = pkgElement.Element( "license" )?.Value;
ParseElements( pkgElement.Element( "releases" ), "release", retVal.Keywords, Keyword.ParseFrom );
ParseElements( pkgElement.Element( "keywords" ), "keyword", retVal.Keywords, Keyword.ParseFrom );
ParseElements( pkgElement.Element( "generators" ), "generator", retVal.Generators, Generator.ParseFrom );
ParseElements( pkgElement.Element( "devices" ), "family", retVal.Devices, DeviceFamily.ParseFrom );
ParseElements( pkgElement.Element( "boards" ), "board", retVal.Boards, Board.ParseFrom );
ParseElements( pkgElement.Element( "taxonomy" ), "description", retVal.Taxonomy, TaxonomyDescription.ParseFrom );
ParseElements( pkgElement.Element( "apis" ), "api", retVal.Apis, Api.ParseFrom );
ParseElements( pkgElement.Element( "conditions" ), "condition", retVal.Conditions, Condition.ParseFrom );
ParseElements( pkgElement.Element( "examples" ), "example", retVal.Conditions, Condition.ParseFrom );
// TODO: figure out plan to deal with multiple child element types in components element (component, bundle)
ParseElements( pkgElement.Element( "components" ), "component", retVal.Components, Component.ParseFrom );
return retVal;
} );
}
static void ParseElements<T>( XElement containerElement, XName descendantName, IList<T> list, Func<XElement,T> parser )
{
if( containerElement == null )
return;
foreach( var element in containerElement.Descendants( descendantName ) )
{
list.Add( parser( element ) );
}
}
}
}

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

@ -0,0 +1,47 @@
using System;
using System.Globalization;
using System.Linq;
using Sprache;
namespace CMSIS.Pack.PackDescription
{
internal static class Parsers
{
internal static bool IsIntegerScaleChar( char arg )
{
return arg == 'k'
|| arg == 'K'
|| arg == 'm'
|| arg == 'M';
}
internal static Parser<int> Integer( int minDigits, int maxDigitis )
{
return from value in Parse.Digit.Repeat( minDigits, maxDigitis ).Text( )
select int.Parse( value );
}
// Official W3C XSD specs require 2 digits for the month and day
// However, many PDSC files in the wild only have one, thus this
// parser handles the incorrectly formed dates
internal static Parser<DateTime> DateTime = from year in Integer( 4, 4 )
from sep in Parse.Char( '-' )
from month in Integer( 1, 2 )
from sep2 in Parse.Char( '-' )
from day in Integer( 1, 2 )
select new DateTime( year, month, day );
internal static Parser<double> Double = from value in Parse.Decimal
select double.Parse( value, CultureInfo.CurrentCulture );
internal static Parser<double> ScaledInteger = from value in Parse.Digit.AtLeastOnce( ).Text( )
from scale in ScaledIntMultiplier
select ( double )int.Parse( value ) * scale;
static Parser<int> ScaledIntMultiplier = Parse.Chars( 'k', 'K' ).Return( 1024 )
.Or( Parse.Chars( 'm', 'M' ).Return( 1024 * 1024 ) )
.Or( Parse.Return( 1 ) );
static Parser<double> NonConformantDecimal = ScaledInteger.Or( Double );
}
}

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

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class Release
{
public static Release ParseFrom( XElement release )
{
return new Release();
}
}
}

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

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CMSIS.Pack.PackDescription
{
public class TaxonomyDescription
{
internal static TaxonomyDescription ParseFrom( XElement arg )
{
return new TaxonomyDescription();
}
}
}

152
CMSIS.Pack/PackIndex.cs Normal file
Просмотреть файл

@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace CMSIS.Pack
{
/// <summary>Contains the contents of a CMSIS-Pack index</summary>
/// <remarks>
/// The source of the index content may be loaded from a file, a URL
/// or provided programatically to the constructor.
/// </remarks>
public class PackIndex
{
/// <summary>Default URI for the pack index</summary>
public const string DefaultIndexUriPath = "http://www.keil.com/pack/index.idx";
public PackIndex( )
{
}
public PackIndex( IEnumerable<IPackIndexEntry> packs )
{
Packs_.AddRange( packs );
}
/// <summary>Enumeration of the Packs listed in the Index</summary>
public IEnumerable<IPackIndexEntry> Packs { get { return Packs_.AsReadOnly( ); } }
private readonly List<IPackIndexEntry> Packs_ = new List<IPackIndexEntry>();
/// <summary>Download and parse the index file from the Default location <see cref="DefaultIndexUriPath"/></summary>
/// <returns>Task for the Asynchronous operation</returns>
public Task LoadAsync( )
{
return LoadAsync( new Uri( DefaultIndexUriPath ) );
}
public Task LoadAsync( IProgress<FileDownloadProgress> progressSink )
{
return LoadAsync( new Uri( DefaultIndexUriPath ), progressSink );
}
/// <summary>Download and parse the index asynchronously from a URL</summary>
/// <param name="indexUrl">URL of the index file to download</param>
/// <returns>Task for the Asynchronous operation</returns>
public async Task LoadAsync( Uri indexUrl )
{
using( var client = new HttpClient( ) )
{
var content = await client.GetStringAsync( indexUrl );
await ParseAsync( content );
}
}
/// <summary>Asynchronously read and parse the index from a file</summary>
/// <param name="filePath">Path of the file to load and parse</param>
/// <returns>Task for the Asynchronous operation</returns>
public async Task LoadAsync( string filePath )
{
if( string.IsNullOrWhiteSpace( filePath ) )
throw new ArgumentException( "Path cannot be null or empty", nameof( filePath ) );
if( !File.Exists( filePath ) )
throw new FileNotFoundException( filePath );
var content = await Task.Run( ()=>File.ReadAllText( filePath ) );
await ParseAsync( content );
}
public Task LoadAsync( Uri uri, IProgress<FileDownloadProgress> progressSink )
{
using( var webClient = new WebClient() )
{
var sw = new Stopwatch();
webClient.DownloadFileCompleted += ( s, e ) => progressSink.Report( new FileDownloadProgress( uri, sw.Elapsed, -1, -1 ) );
webClient.DownloadProgressChanged += ( s, e ) => progressSink.Report( new FileDownloadProgress( uri, sw.Elapsed, e.BytesReceived, e.TotalBytesToReceive ) );
sw.Start( );
return webClient.DownloadFileTaskAsync( uri.Host, uri.LocalPath );
}
}
/// <summary>Asynchronously save the index file to the specified file location</summary>
/// <param name="filePath">Path of the file to save to</param>
/// <returns>Task for the Asynchronous operation</returns>
public Task SaveAsync( string filePath )
{
if( string.IsNullOrWhiteSpace( filePath ) )
throw new ArgumentException( "Path cannot be null or empty", nameof( filePath ) );
return Task.Run( ( ) =>
{
var dir = Path.GetDirectoryName( filePath );
if( dir != null )
{
if( !Directory.Exists( dir ) )
Directory.CreateDirectory( dir );
}
File.WriteAllText( filePath, Content );
} );
}
/// <summary>Parses the contents of an index file</summary>
/// <param name="indexContent">contents of a CMSIS-PACK index file</param>
/// <returns>Task for the Asynchronous operation</returns>
public Task ParseAsync( string indexContent )
{
Packs_.Clear( );
Content = indexContent;
return Task.Run( ()=>
{
var settings = new XmlReaderSettings
{ IgnoreComments = true
, IgnoreProcessingInstructions = true
, ConformanceLevel = ConformanceLevel.Fragment
};
using( var strm = new StringReader( indexContent ) )
using( var rdr = XmlReader.Create( strm, settings ) )
{
// Despite having an xml doc processing instruction the index file is *NOT*
// valid XML. It has multiple pdsc elements at the root, which is invalid
// XML. This deals with that by reading the nodes individually rather than
// as a whole document.
//
// skip past the XML declaration and move to the first pdsc element
rdr.Read( );
rdr.ReadToFollowing( "pdsc" );
while( rdr.ReadState != ReadState.EndOfFile )
{
var pdsc = ( XElement )XNode.ReadFrom( rdr );
var pack = new PackIndexEntry( pdsc.Attribute( "url" ).Value
, pdsc.Attribute( "name" ).Value
, pdsc.Attribute( "version" ).Value
);
Packs_.Add( pack );
rdr.ReadToFollowing( "pdsc" );
}
}
});
}
private string Content;
}
}

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

@ -0,0 +1,128 @@
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using CMSIS.Pack.PackDescription;
namespace CMSIS.Pack
{
/// <summary>Reference to a CMSIS-PACK</summary>
/// <remarks>
/// Packs are listed in a published index (index.idx)
/// this class represents a single entry in the
/// index.
/// </remarks>
public class PackIndexEntry
: IPackIndexEntry
{
/// <summary>Creates a new PackIndexEntry from data read out of the index</summary>
/// <param name="descriptorUri">Base URI for the pack</param>
/// <param name="packName">Name of the pack in VENDOR.NAME form</param>
/// <param name="packVersion">Pack version (in semantic Version 2.0 form)</param>
public PackIndexEntry( string descriptorUri, string packName, string packVersion )
{
if( string.IsNullOrWhiteSpace( descriptorUri ) )
throw new ArgumentException( "Non empty string required", nameof( descriptorUri ) );
if( string.IsNullOrWhiteSpace( packName ) )
throw new ArgumentException( "Non empty string required", nameof( packName ) );
if( string.IsNullOrWhiteSpace( packVersion ) )
throw new ArgumentException( "Non empty string required", nameof( packVersion ) );
Url = CreateUriWithTrailingSeperator( descriptorUri );
PdscName = packName;
var parts = PdscName.Trim().Split( '.' );
if( parts.Length != 3 )
throw new ArgumentException( "Invalid pack name format", nameof( packName ) );
Vendor = parts[ 0 ];
Name = parts[ 1 ];
if( !SemanticVersion.TryParse( packVersion, out Version_ ) )
throw new ArgumentException( "Invalid semantic version provided", nameof( packVersion ) );
}
/// <summary>File name of the pack file this reference is for</summary>
/// <remarks>
/// The file name is of the form: VENDOR.NAME.VERSION.pack
/// </remarks>
public string PackName
{
get
{
return Path.ChangeExtension( PdscName, Version + ".pack" );
}
}
/// <summary>Vendor name parsed out of the PackName from the index</summary>
public string Vendor { get; private set; }
/// <summary>Name of the pack parsed out of the Pack name from the index</summary>
public string Name { get; private set; }
/// <summary>Name of the PDSC file for this pack</summary>
/// <remarks>
/// The PDSC filename takes the form: VENDOR.NAME.pdsc
/// </remarks>
public string PdscName { get; private set; }
/// <summary>Full URL of the Package Description (PDSC) file for this pack</summary>
public Uri PdscUrl
{
get
{
return new Uri( Url, PdscName );
}
}
/// <summary>FULL URL of the Package file for this pack</summary>
public Uri PackUrl
{
get
{
return new Uri( Url, PackName );
}
}
/// <summary>Base URI for this pack read from the index</summary>
public Uri Url { get; private set; }
/// <summary>Version of the pack</summary>
public SemanticVersion Version { get { return Version_; } }
private readonly SemanticVersion Version_;
public string LocalPath
{
get { return Path.Combine( Vendor, Name, Version.ToString( ) ); }
}
/// <summary>Retrieves the contents of the Package Description file</summary>
/// <returns>string containing the XML content of the description</returns>
public async Task<string> GetPackageDescriptionDocumentAsync()
{
using( var client = new HttpClient( ) )
{
client.BaseAddress = Url;
return await client.GetStringAsync( PdscName );
}
}
/// <summary>Asynchronously download and parse the package description file for this pack</summary>
/// <returns>parsed package instance for the package description</returns>
public async Task<Package> GetPackageDescriptionAsync( )
{
var xml = await GetPackageDescriptionDocumentAsync( );
return await Package.ParseFromAsync( xml );
}
private static Uri CreateUriWithTrailingSeperator( string descriptorUri )
{
var baseUri = new UriBuilder( descriptorUri );
baseUri.Path = baseUri.Path.TrimEnd( '\\' );
baseUri.Path = baseUri.Path.TrimEnd( '/' );
baseUri.Path = baseUri.Path + '/';
return baseUri.Uri;
}
}
}

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

@ -0,0 +1,11 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace CMSIS.Pack
{
public struct PackInstallProgress
{
}
}

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

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace CMSIS.Pack
{
public class PackRepository
: IRepository
{
public PackRepository( Uri source, string localPath )
{
SourceUri = source;
LocalPath = localPath;
WebRoot = Path.Combine( LocalPath, ".Web" );
DownloadRoot = Path.Combine( LocalPath, ".Download" );
PackIdxWatcher = new FileSystemWatcher( LocalPath, "pack.idx" );
PackIdxWatcher.Changed += ( s, e ) => Updated( this, new RepositoryUpdateEventArgs( ) );
}
public PackRepository( string localPath )
: this( new Uri( PackIndex.DefaultIndexUriPath ), localPath )
{
}
public DateTime LastUpdatedTimeUTC
{
get { return File.GetLastWriteTimeUtc( Path.Combine( LocalPath, "pack.idx" ) ); }
}
public string WebRoot { get; }
public string DownloadRoot { get; }
public Uri SourceUri { get; }
public string LocalPath { get; }
public event EventHandler<RepositoryUpdateEventArgs> Updated = delegate { };
public IEnumerable<IRepositoryPackage> Packs => Packs_.AsEnumerable( );
private List<IRepositoryPackage> Packs_;
public Task Download( IRepositoryPackage package, IProgress<FileDownloadProgress> progressSink )
{
throw new NotImplementedException( );
}
public Task InstallPack( IRepositoryPackage package, IProgress<PackInstallProgress> progressSink )
{
throw new NotImplementedException( );
}
public async Task LoadFromLocal()
{
Updated( this, new RepositoryUpdateEventArgs( RepositoryState.DownloadingIndex, null ) );
Packs_ = new List<IRepositoryPackage>( );
var index = new PackIndex( );
await index.LoadAsync( Path.Combine( WebRoot, "index.idx" ) );
foreach( var pack in index.Packs )
{
var repositoryPack = new RepositoryPackage( this, pack, await GetInstallState( pack ) );
Packs_.Add( repositoryPack );
}
}
public Task UpdateLocalFromSource( )
{
return Task.FromResult<object>( null );
}
private Task<PackInstallState> GetInstallState( IPackIndexEntry pack )
{
return Task.Run( ( ) =>
{
var retVal = PackInstallState.AvailableForDownload;
if( File.Exists( Path.Combine( DownloadRoot, pack.PackName ) ) )
retVal = PackInstallState.Downloaded;
if( File.Exists( Path.Combine( LocalPath, pack.LocalPath, pack.PdscName ) ) )
retVal = PackInstallState.Installed;
return retVal;
} );
}
private readonly FileSystemWatcher PackIdxWatcher;
}
}

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

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CMSIS.Pack")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CMSIS.Pack")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0fc7a2b0-1a23-456b-b17e-0afbc0034a67")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

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

@ -0,0 +1,135 @@
using System;
using System.IO;
using System.Threading.Tasks;
using CMSIS.Pack.PackDescription;
namespace CMSIS.Pack
{
class RepositoryPackage
: IRepositoryPackage
{
internal RepositoryPackage( IRepository repository, IPackIndexEntry details, PackInstallState installState )
{
if( repository == null )
throw new ArgumentNullException( nameof( repository ) );
if( details == null )
throw new ArgumentNullException( nameof( details ) );
Repository = repository;
Details_ = details;
InstallState = installState;
}
public IPackIndexEntry Details
{
get { return Details_; }
}
private readonly IPackIndexEntry Details_;
public IRepository Repository { get; private set; }
public PackInstallState InstallState { get; private set; }
public string PackName
{
get { return Details_.PackName; }
}
public string Vendor
{
get { return Details_.Vendor; }
}
public string Name
{
get { return Details_.Name; }
}
public string PdscName
{
get { return Details_.PdscName; }
}
public Uri PdscUrl
{
get { return Details_.PdscUrl; }
}
public Uri PackUrl
{
get { return Details_.PackUrl; }
}
public Uri Url
{
get { return Details_.Url; }
}
public string LocalPath
{
get { return Details_.LocalPath; }
}
public SemanticVersion Version
{
get { return Details_.Version; }
}
public async Task<string> GetPackageDescriptionDocumentAsync( )
{
using( var strm = File.OpenText( Path.Combine( Repository.WebRoot, PdscName ) ) )
{
return await strm.ReadToEndAsync( );
}
}
public async Task<Package> GetPackageDescriptionAsync( )
{
string content = await GetPackageDescriptionDocumentAsync( );
return await Package.ParseFromAsync( content );
}
public async Task Download( IProgress<FileDownloadProgress> progressSink )
{
if( InstallState == PackInstallState.Downloaded )
return;
if( InstallState != PackInstallState.AvailableForDownload )
throw new InvalidOperationException( );
InstallState = PackInstallState.Downloading;
try
{
await Repository.Download( this, progressSink );
}
catch
{
InstallState = PackInstallState.AvailableForDownload;
throw;
}
InstallState = PackInstallState.Downloaded;
}
public async Task InstallPack( IProgress<PackInstallProgress> progressSink )
{
if( InstallState == PackInstallState.Installed )
return;
if( InstallState != PackInstallState.Downloaded )
throw new InvalidOperationException( );
InstallState = PackInstallState.Installing;
try
{
await Repository.InstallPack( this, progressSink );
}
catch
{
InstallState = PackInstallState.Downloaded;
throw;
}
InstallState = PackInstallState.Downloaded;
}
}
}

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

@ -0,0 +1,31 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace CMSIS.Pack
{
public class RepositoryUpdateEventArgs
: EventArgs
{
public RepositoryUpdateEventArgs( )
: this( RepositoryState.Idle, null )
{
}
public RepositoryUpdateEventArgs( RepositoryState state, IPackIndexEntry pack )
{
if( pack == null && ( state != RepositoryState.Idle ) && (state != RepositoryState.DownloadingIndex ) )
throw new ArgumentNullException( nameof( pack ), "pack cannot be null for states other than idle" );
if( ( ( state == RepositoryState.Idle) || ( state == RepositoryState.DownloadingIndex ) ) && pack != null )
throw new ArgumentException( "pack must be null for this state", nameof( pack ) );
State = state;
Pack = pack;
}
public RepositoryState State { get; private set; }
public IPackIndexEntry Pack { get; private set; }
}
}

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

@ -0,0 +1,399 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace CMSIS.Pack
{
/// <summary>Version structure for versions based on Semantic Versioning v2.0 as defined by http://semver.org </summary>
/// <remarks>
/// 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.
/// </remarks>
public struct SemanticVersion
: IComparable
, IComparable<SemanticVersion>
, IEquatable<SemanticVersion>
{
/// <summary>Constructs a semantic version from its independent parts</summary>
/// <param name="major">Major version number</param>
/// <param name="minor">Minor Version number</param>
/// <param name="patch">Patch version number</param>
/// <param name="preReleaseParts">Array of individual pre-release 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, string[] preReleaseParts, string[] metadataParts)
{
if( major < 0 )
throw new ArgumentOutOfRangeException( nameof( major ) );
if( minor < 0 )
throw new ArgumentOutOfRangeException( nameof( minor ) );
if( patch < 0 )
throw new ArgumentOutOfRangeException( nameof( patch ) );
Major_ = major;
Minor_ = minor;
Patch_ = patch;
PreReleaseParts_ = preReleaseParts ?? new string[0];
BuildMetadata_ = metadataParts ?? new string[0];
// Validate each part conforms to an "identifier" as defined by the spec
if(!ValidateIdentifierParts( PreReleaseParts_ ) )
throw new ArgumentException( "Invalid identifier for pre-release part", nameof( preReleaseParts ) );
if( !ValidateIdentifierParts( BuildMetadata_ ) )
throw new ArgumentException( "Invalid identifier for build metadata part", nameof( metadataParts ) );
HashCode = null;
}
/// <summary>Constructs a semantic version from its independent parts</summary>
/// <param name="major">Major version number</param>
/// <param name="minor">Minor Version number</param>
/// <param name="patch">Patch version number</param>
public SemanticVersion( int major, int minor, int patch )
: this( major
, minor
, patch
, null
, null
)
{
}
/// <inheritdoc/>
public override int GetHashCode( )
{
// HashCode is the cached result value of the computed hash code determined
// from the other read-only fields and therefore does not participate in the
// computation of the hash.
#pragma warning disable RECS0025 // Non-readonly field referenced in 'GetHashCode()'
// ReSharper disable NonReadonlyFieldInGetHashCode
if( !HashCode.HasValue )
HashCode = ComputeHashCode( );
return HashCode.Value;
// ReSharper restore NonReadonlyFieldInGetHashCode
#pragma warning restore RECS0025 // Non-readonly field referenced in 'GetHashCode()'
}
/// <inheritdoc/>
public override bool Equals( object obj )
{
if( !( obj is SemanticVersion ) )
return false;
return Equals( (SemanticVersion)obj );
}
/// <inheritdoc/>
public bool Equals( SemanticVersion other )
{
return 0 == CompareTo( other );
}
/// <inheritdoc/>
public int CompareTo( object obj )
{
if( !( obj is SemanticVersion ) )
throw new ArgumentException();
return CompareTo( ( SemanticVersion )obj );
}
// Precedence Rules:
// Paraphrased From http://semver.org/ Section 11
// Precedence is determined by the first difference when comparing each of these
// identifiers from left to right as follows:
// 1) Major, minor, and patch versions are always compared numerically.
// Example: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1.
// 2) When major, minor, and patch are equal, a pre-release version has lower
// precedence than a normal version.
// Example: 1.0.0-alpha < 1.0.0.
// 3) Precedence for two pre-release versions with the same major, minor, and
// patch version MUST be determined by comparing each dot separated identifier
// from left to right until a difference is found as follows:
// a) identifiers consisting of only digits are compared numerically
// b) identifiers with letters or hyphens are compared lexically in ASCII sort order.
// c) Numeric identifiers always have lower precedence than non-numeric identifiers.
// d) A larger set of pre-release fields has a higher precedence than a smaller set,
// if all of the preceding identifiers are equal.
// Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
/// <inheritdoc/>
public int CompareTo( SemanticVersion other )
{
// Rule #1
var retVal = Major.CompareTo( other.Major );
if( retVal != 0 )
return retVal;
retVal = Minor.CompareTo( other.Minor );
if( retVal != 0 )
return retVal;
retVal = Patch.CompareTo( other.Patch );
if( retVal != 0 )
return retVal;
// Rule #2
if( PreReleaseParts.Count == 0 && other.PreReleaseParts.Count == 0 )
return 0;
if( PreReleaseParts.Count == 0 )
return 1;
if( other.PreReleaseParts.Count == 0 )
return -1;
// Rules 3.a-c
var partCount = Math.Min( PreReleaseParts.Count, other.PreReleaseParts.Count );
for( var i =0; i< partCount; ++i )
{
// rule 3.c
retVal = string.Compare( PreReleaseParts[ i ], other.PreReleaseParts[ i ], StringComparison.Ordinal );
if( retVal == 0 )
continue;
// Rule 3.a
int left,right;
if( !int.TryParse( PreReleaseParts[i], out left )
|| !int.TryParse( other.PreReleaseParts[ i ], out right )
)
{
return retVal;
}
return left.CompareTo( right );
}
// Rule #3.d
return PreReleaseParts.Count.CompareTo( other.PreReleaseParts.Count );
}
/// <summary>Indicates if this version is a development version (e.g. Major Version == 0 )</summary>
public bool IsDevelopment { get { return Major_ == 0; } }
/// <summary>Indicates if this version is a pre-release version (e.g. IsDevelopment or Has pre-release parts following the Patch)</summary>
public bool IsPrerelease { get { return IsDevelopment || PreReleaseParts.Count > 0; } }
/// <summary>Indicates if this is a valid version</summary>
public bool IsValid { get { return Major_ >= 0 && Minor_ >=0 && Patch_ >= 0; } }
/// <summary>Major version number</summary>
public int Major { get { return Major_; } }
private readonly int Major_;
/// <summary>Minor version number</summary>
public int Minor { get { return Minor_; } }
private readonly int Minor_;
/// <summary>Patch version number</summary>
public int Patch { get { return Patch_; } }
private readonly int Patch_;
/// <summary>List of identifier parts forming the pre-release value</summary>
/// <remarks>
/// Pre-release values are optional and follow the patch with a '-'. The pre-release
/// 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
{
get
{
if( PreReleaseParts_ == null )
return new string[ 0 ];
return Array.AsReadOnly( PreReleaseParts_ );
}
}
private readonly string[ ] PreReleaseParts_;
/// <summary>List of identifier parts forming the build Metadata value</summary>
/// <remarks>
/// Metadata values are optional and follow the patch with a '+'. The Metadata
/// 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
{
get
{
if( BuildMetadata_ == null )
return new string[ 0 ];
return Array.AsReadOnly( BuildMetadata_ );
}
}
private readonly string[ ] BuildMetadata_;
/// <inheritdoc/>
public override string ToString( )
{
return ToString( true );
}
/// <summary>Creates a valid semantic version string from the component values of this version</summary>
/// <param name="includeBuildMetadata">Flag to indicate if the Build Metadata should be included</param>
/// <returns>Semantic version string for this version</returns>
/// <remarks>
/// The <paramref name="includeBuildMetadata"/> parameter is used to control whether the build information
/// portion of the version is included or not. The Build Metadata is the only portion of the semantic
/// version that does not participate in precedence evaluation for comparing versions.
/// </remarks>
public string ToString( bool includeBuildMetadata)
{
var bldr = new StringBuilder( string.Format( CultureInfo.InvariantCulture, "{0}.{1}.{2}", Major, Minor, Patch ) );
if( PreReleaseParts.Count > 0 )
{
bldr.Append( '-' );
bldr.Append( string.Join( ".", PreReleaseParts ) );
}
if( BuildMetadata.Count > 0 && includeBuildMetadata)
{
bldr.Append( '+' );
bldr.Append( string.Join( ".", BuildMetadata ) );
}
return bldr.ToString();
}
/// <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 )
{
return Parse( versionString, false );
}
/// <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, bool patchOptional )
{
var match = SemVersionRegEx.Match( versionString );
if( !match.Success )
throw new FormatException();
var major = int.Parse( match.Groups["Major"].Value );
var minor = int.Parse( match.Groups["Minor"].Value );
int patch = 0;
var patchGroup = match.Groups["Patch"];
if( !patchOptional || patchGroup.Success )
patch = int.Parse( patchGroup.Value );
var preReleaseGroup = match.Groups["PreRelease"];
var preReleaseParts = new string[ 0 ];
if( preReleaseGroup.Success )
preReleaseParts = preReleaseGroup.Value.Split( '.' );
var metadataGroup = match.Groups["Metadata"];
var metadataParts = new string[ 0 ];
if( metadataGroup.Success )
metadataParts = metadataGroup.Value.Split( '.' );
return new SemanticVersion( major, minor, patch, preReleaseParts, metadataParts );
}
/// <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 )
{
version = new SemanticVersion();
var match = SemVersionRegEx.Match( versionString );
if( !match.Success )
return false;
int major,minor,patch;
if( !int.TryParse( match.Groups["Major"].Value, out major ) )
return false;
if( !int.TryParse( match.Groups["Minor"].Value, out minor ) )
return false;
if( !int.TryParse( match.Groups["Patch"].Value, out patch ) )
return false;
var preReleaseGroup = match.Groups[ "PreRelease" ];
var preReleaseParts = new string[ 0 ];
if( preReleaseGroup.Success )
preReleaseParts = preReleaseGroup.Value.Split( '.' );
var metadataGroup = match.Groups[ "Metadata" ];
var metadataParts = new string[ 0 ];
if( metadataGroup.Success )
metadataParts = metadataGroup.Value.Split( '.' );
version = new SemanticVersion(major, minor, patch, preReleaseParts, metadataParts );
return true;
}
/// <summary>Compares two <see cref="SemanticVersion"/> instances for equality</summary>
/// <param name="lhs">Left hand side of the comparison</param>
/// <param name="rhs">Right hand side of the comparison</param>
/// <returns><see langword="true"/> if the two versions are equivalent</returns>
public static bool operator==(SemanticVersion lhs, SemanticVersion rhs)
{
return lhs.Equals( rhs );
}
/// <summary>Compares two <see cref="SemanticVersion"/> instances for inequality</summary>
/// <param name="lhs">Left hand side of the comparison</param>
/// <param name="rhs">Right hand side of the comparison</param>
/// <returns><see langword="true"/> if the two versions are not equivalent</returns>
public static bool operator !=( SemanticVersion lhs, SemanticVersion rhs )
{
return !lhs.Equals( rhs );
}
private static bool ValidateIdentifierParts( IEnumerable< string > metadataParts )
{
var q = from part in metadataParts
let match = IdentifierRegEx.Match( part )
where !match.Success || match.Index != 0 || match.Length != part.Length
select part;
return !q.Any();
}
private int ComputeHashCode()
{
return ToString( false ).GetHashCode( );
}
// 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.
private int? HashCode;
private static readonly Regex IdentifierRegEx = new Regex("[1-9A-Za-z-][0-9A-Za-z-]*");
// see: http://semver.org/
// Semantic version is:
// Major'.'Minor'.'Patch('-'Identifier('.'Identifier)*)?('+'Identifier('.'Identifier)*)?
// Where Major,Minor and Patch match 0|[1-9][0-9]* (0 or a non-leading zero sequence of digits)
// Identifier is a sequence of ASCII alphanumerics or '-' without a leading 0
// the - signifies the pre-release information and impacts precedence if present
// the + signifies the build meta data and has no impact on precedence
private const string SemVerRegExPattern = "(?<Major>(0|[1-9][0-9]*))"
+ @"\.(?<Minor>(0|[1-9][0-9]*))"
+ @"(\.(?<Patch>(0|[1-9][0-9]*)))?"
+ @"(-(?<PreRelease>[1-9A-Za-z-][0-9A-Za-z-]*(\.[1-9A-Za-z-][0-9A-Za-z-]*)*))?"
+ @"(\+(?<Metadata>[1-9A-Za-z-][0-9A-Za-z-]*(\.[1-9A-Za-z-][0-9A-Za-z-]*)*))?";
private static readonly Regex SemVersionRegEx = new Regex(SemVerRegExPattern);
}
}

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

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Sprache.JetBrains" version="2.0.0.44" targetFramework="net45" />
</packages>

34
NetmfPackInstaller.sln Normal file
Просмотреть файл

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetmfPackInstaller", "NetmfPackInstaller\NetmfPackInstaller.csproj", "{4D6FE417-4296-4C77-8B3E-26976A1F8C08}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CMSIS.Pack", "CMSIS.Pack\CMSIS.Pack.csproj", "{145D7231-C105-41BE-B646-5D400097C744}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{E4D675B0-5DBD-45BE-A4A0-B2C0F1BF42E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4D6FE417-4296-4C77-8B3E-26976A1F8C08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D6FE417-4296-4C77-8B3E-26976A1F8C08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D6FE417-4296-4C77-8B3E-26976A1F8C08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D6FE417-4296-4C77-8B3E-26976A1F8C08}.Release|Any CPU.Build.0 = Release|Any CPU
{145D7231-C105-41BE-B646-5D400097C744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{145D7231-C105-41BE-B646-5D400097C744}.Debug|Any CPU.Build.0 = Debug|Any CPU
{145D7231-C105-41BE-B646-5D400097C744}.Release|Any CPU.ActiveCfg = Release|Any CPU
{145D7231-C105-41BE-B646-5D400097C744}.Release|Any CPU.Build.0 = Release|Any CPU
{E4D675B0-5DBD-45BE-A4A0-B2C0F1BF42E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4D675B0-5DBD-45BE-A4A0-B2C0F1BF42E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4D675B0-5DBD-45BE-A4A0-B2C0F1BF42E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4D675B0-5DBD-45BE-A4A0-B2C0F1BF42E3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

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

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

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

@ -0,0 +1,8 @@
<Application x:Class="NetmfPackInstaller.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

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

@ -0,0 +1,11 @@
using System.Windows;
namespace NetmfPackInstaller
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

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

@ -0,0 +1,38 @@
using System;
using System.Windows.Data;
using System.Windows.Markup;
namespace NetmfPackInstaller
{
[ValueConversion(typeof(LoadState),typeof(string))]
public class LoadStateConverter
: MarkupExtension
, IValueConverter
{
public override object ProvideValue( IServiceProvider serviceProvider )
{
return this;
}
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
var state = (LoadState)value;
switch( state )
{
case LoadState.LoadingIndex:
return "Loading Index";
case LoadState.ParsingDescriptions:
return "Parsing Descriptors";
case LoadState.Ready:
return "Ready";
default:
return string.Empty;
}
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
throw new NotSupportedException( );
}
}
}

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

@ -0,0 +1,156 @@
<Window x:Class="NetmfPackInstaller.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NetmfPackInstaller"
Title="CMSIS-Pack Viewer"
Height="600"
Width="800">
<Window.Resources>
<!-- Higlight pre-release packs in red/italic font -->
<Style TargetType="{x:Type DataGridRow}"
BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="FontStyle"
Value="Normal" />
<Setter Property="Foreground"
Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding Version.IsPrerelease}"
Value="True">
<Setter Property="FontStyle"
Value="Italic" />
<Setter Property="Foreground"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
<!-- Trigger appearance of indeterminate progress while loading the index from the source URL -->
<Style x:Key="IndexLoadProgressStyle"
TargetType="{x:Type ProgressBar}">
<Setter Property="Visibility"
Value="Visible" />
<Setter Property="Orientation"
Value="Horizontal" />
<Setter Property="Width"
Value="120" />
<Setter Property="Height"
Value="15" />
<Setter Property="IsIndeterminate"
Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding State}"
Value="Ready">
<Setter Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
<!-- Grouping collection view to group the Packs by Vendor-->
<CollectionViewSource x:Key="VendorGroupViewSource"
Source="{Binding Packs}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Vendor" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<!-- Expandalbe group container for vendor groups-->
<Style x:Key="VendorGroupContainerStyle"
TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<Grid>
<ContentPresenter />
</Grid>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Header template for the Vendor group to show "<Vendor> # Pack(s)"-->
<DataTemplate x:Key="VendorGroupHeaderTemplate"
DataType="GroupItem">
<StackPanel Orientation="Horizontal">
<TextBlock Padding="2"
Text="{Binding Name}" />
<TextBlock Padding="2"
Text="{Binding ItemCount}" />
<TextBlock Padding="2"
Text="Pack(s)" />
</StackPanel>
</DataTemplate>
<Style x:Key="ToolBarOverflowButtonStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
<Style x:Key="ImageButton" TargetType="{x:Type Button}">
<Setter Property="Opacity"
Value="1.0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=IsEnabled}" Value="false">
<Setter Property="Opacity" Value="0.5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<DockPanel>
<ToolBarPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<ToolBar ToolBarTray.IsLocked="True" Loaded="ToolBar_Loaded">
<Button ToolBar.OverflowMode="Never"
Style="{StaticResource ImageButton}"
Command="{Binding RefreshIndexCommand}">
<Image Source="Refresh.png"
Stretch="None" />
</Button>
</ToolBar>
</ToolBarPanel>
<StatusBar DockPanel.Dock="Bottom"
Height="Auto">
<StatusBarItem DockPanel.Dock="Right">
<TextBlock Text="{Binding LastUpdated, StringFormat=Last Updated: \{0:g\}}" />
</StatusBarItem>
<TextBlock Text="{Binding State, Converter={local:LoadStateConverter}}" />
<Separator />
<ProgressBar Style="{StaticResource ResourceKey=IndexLoadProgressStyle}" />
</StatusBar>
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Source={StaticResource VendorGroupViewSource}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Vendor"
Width="SizeToCells"
IsReadOnly="True"
Binding="{Binding Vendor}" />
<DataGridTextColumn Header="Name"
Width="SizeToCells"
IsReadOnly="True"
Binding="{Binding Name}" />
<DataGridTextColumn Header="Version"
Width="SizeToCells"
IsReadOnly="True"
Binding="{Binding Version}" />
<DataGridTextColumn Header="InstallState"
Width="SizeToCells"
IsReadOnly="True"
Binding="{Binding InstallState}" />
<DataGridTextColumn Header="Description"
Width="SizeToCells"
IsReadOnly="True"
Binding="{Binding Description}" />
</DataGrid.Columns>
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource VendorGroupContainerStyle}"
HeaderTemplate="{StaticResource VendorGroupHeaderTemplate}" />
</DataGrid.GroupStyle>
</DataGrid>
</DockPanel>
</Window>

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

@ -0,0 +1,40 @@
using System.Windows;
using System.Windows.Controls;
using CMSIS.Pack;
namespace NetmfPackInstaller
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow( )
{
InitializeComponent( );
}
protected override async void OnActivated( System.EventArgs e )
{
base.OnActivated( e );
if( DataContext != null )
return;
var viewModel = new PackRepositoryViewModel( );
DataContext = viewModel;
await viewModel.LoadAsync( );
}
private void ToolBar_Loaded( object sender, RoutedEventArgs e )
{
var toolBar = ( ToolBar )sender;
foreach( FrameworkElement a in toolBar.Items )
ToolBar.SetOverflowMode(a, OverflowMode.Never);
var overflowGrid = toolBar.Template.FindName( "OverflowGrid", toolBar ) as FrameworkElement;
if( overflowGrid != null )
overflowGrid.Visibility = Visibility.Collapsed;
}
}
}

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

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4D6FE417-4296-4C77-8B3E-26976A1F8C08}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NetmfPackInstaller</RootNamespace>
<AssemblyName>NetmfPackInstaller</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="GalaSoft.MvvmLight">
<HintPath>..\packages\MvvmLightLibs.5.1.1.0\lib\net45\GalaSoft.MvvmLight.dll</HintPath>
</Reference>
<Reference Include="GalaSoft.MvvmLight.Extras">
<HintPath>..\packages\MvvmLightLibs.5.1.1.0\lib\net45\GalaSoft.MvvmLight.Extras.dll</HintPath>
</Reference>
<Reference Include="GalaSoft.MvvmLight.Platform">
<HintPath>..\packages\MvvmLightLibs.5.1.1.0\lib\net45\GalaSoft.MvvmLight.Platform.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="LoadStateConverter.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="PackRepositoryViewModel.cs" />
<Compile Include="PackReferenceViewModel.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CMSIS.Pack\CMSIS.Pack.csproj">
<Project>{145d7231-c105-41be-b646-5d400097c744}</Project>
<Name>CMSIS.Pack</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="Refresh.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

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

@ -0,0 +1,57 @@
using CMSIS.Pack;
using GalaSoft.MvvmLight;
using System;
using System.Threading.Tasks;
using CMSIS.Pack.PackDescription;
namespace NetmfPackInstaller
{
public enum PackReferenceState
{
Initialized,
DownloadingPdsc,
Ready
}
public class PackReferenceViewModel
: ViewModelBase
{
public PackReferenceViewModel( IRepositoryPackage packRef )
{
if( packRef == null )
throw new ArgumentNullException( nameof( packRef ) );
PackageRef = packRef;
State = PackReferenceState.Initialized;
}
public async Task LoadAndParseDescriptionAsync( )
{
State = PackReferenceState.DownloadingPdsc;
// get the PDSC async, parse to get description
PackageDescription = await PackageRef.GetPackageDescriptionAsync( );
State = PackReferenceState.Ready;
}
public PackReferenceState State
{
get { return State__; }
private set
{
State__ = value;
RaisePropertyChanged( );
}
}
private PackReferenceState State__;
public SemanticVersion Version => PackageRef.Version;
public string Name => PackageRef.Name;
public string Vendor => PackageRef.Vendor;
public string Description => PackageDescription?.Description ?? string.Empty;
public PackInstallState InstallState => PackageRef.InstallState;
private readonly IRepositoryPackage PackageRef;
private Package PackageDescription;
}
}

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

@ -0,0 +1,81 @@
using System.Windows.Input;
using CMSIS.Pack;
using GalaSoft.MvvmLight;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Threading;
using GalaSoft.MvvmLight.CommandWpf;
namespace NetmfPackInstaller
{
public enum LoadState
{
LoadingIndex,
ParsingDescriptions,
Ready,
}
public class PackRepositoryViewModel
: ViewModelBase
{
public PackRepositoryViewModel()
{
// for now, just hard code location of local repository
// and use the default cloud URL
Repository = new PackRepository(@"c:\Keil_v5\ARM\Pack");
State = LoadState.LoadingIndex;
Packs = new ObservableCollection<PackReferenceViewModel>( );
RefreshIndexCommand_ = new RelayCommand( RefreshIndexAsync, CanRefreshIndex );
}
internal async Task LoadAsync( )
{
await Repository.LoadFromLocal( );
State = LoadState.ParsingDescriptions;
foreach( var pack in Repository.Packs )
{
var packVm = new PackReferenceViewModel( pack );
await packVm.LoadAndParseDescriptionAsync( );
Packs.Add( packVm );
}
State = LoadState.Ready;
}
public ICommand RefreshIndexCommand
{
get { return RefreshIndexCommand_; }
}
private readonly RelayCommand RefreshIndexCommand_;
public DateTime LastUpdated { get { return Repository.LastUpdatedTimeUTC.ToLocalTime(); } }
public ObservableCollection<PackReferenceViewModel> Packs { get; private set; }
public LoadState State
{
get { return State__; }
private set
{
State__ = value;
RaisePropertyChanged( );
}
}
private LoadState State__;
private bool CanRefreshIndex( )
{
return State == LoadState.Ready;
}
private async void RefreshIndexAsync( )
{
await Repository.UpdateLocalFromSource( );
}
private readonly PackRepository Repository;
private readonly Dispatcher Dispatcher = Dispatcher.CurrentDispatcher;
}
}

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

@ -0,0 +1,614 @@
using System;
#pragma warning disable 1591
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedParameter.Local
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable IntroduceOptionalParameters.Global
// ReSharper disable MemberCanBeProtected.Global
// ReSharper disable InconsistentNaming
namespace NetmfPackInstaller.Annotations
{
/// <summary>
/// Indicates that the value of the marked element could be <c>null</c> sometimes,
/// so the check for <c>null</c> is necessary before its usage
/// </summary>
/// <example><code>
/// [CanBeNull] public object Test() { return null; }
/// public void UseTest() {
/// var p = Test();
/// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException'
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter |
AttributeTargets.Property | AttributeTargets.Delegate |
AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public sealed class CanBeNullAttribute : Attribute { }
/// <summary>
/// Indicates that the value of the marked element could never be <c>null</c>
/// </summary>
/// <example><code>
/// [NotNull] public object Foo() {
/// return null; // Warning: Possible 'null' assignment
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter |
AttributeTargets.Property | AttributeTargets.Delegate |
AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public sealed class NotNullAttribute : Attribute { }
/// <summary>
/// Indicates that the marked method builds string by format pattern and (optional) arguments.
/// Parameter, which contains format string, should be given in constructor. The format string
/// should be in <see cref="string.Format(IFormatProvider,string,object[])"/>-like form
/// </summary>
/// <example><code>
/// [StringFormatMethod("message")]
/// public void ShowError(string message, params object[] args) { /* do something */ }
/// public void Foo() {
/// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Constructor | AttributeTargets.Method,
AllowMultiple = false, Inherited = true)]
public sealed class StringFormatMethodAttribute : Attribute
{
/// <param name="formatParameterName">
/// Specifies which parameter of an annotated method should be treated as format-string
/// </param>
public StringFormatMethodAttribute(string formatParameterName)
{
FormatParameterName = formatParameterName;
}
public string FormatParameterName { get; private set; }
}
/// <summary>
/// Indicates that the function argument should be string literal and match one
/// of the parameters of the caller function. For example, ReSharper annotates
/// the parameter of <see cref="System.ArgumentNullException"/>
/// </summary>
/// <example><code>
/// public void Foo(string param) {
/// if (param == null)
/// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public sealed class InvokerParameterNameAttribute : Attribute { }
/// <summary>
/// Indicates that the method is contained in a type that implements
/// <see cref="System.ComponentModel.INotifyPropertyChanged"/> interface
/// and this method is used to notify that some property value changed
/// </summary>
/// <remarks>
/// The method should be non-static and conform to one of the supported signatures:
/// <list>
/// <item><c>NotifyChanged(string)</c></item>
/// <item><c>NotifyChanged(params string[])</c></item>
/// <item><c>NotifyChanged{T}(Expression{Func{T}})</c></item>
/// <item><c>NotifyChanged{T,U}(Expression{Func{T,U}})</c></item>
/// <item><c>SetProperty{T}(ref T, T, string)</c></item>
/// </list>
/// </remarks>
/// <example><code>
/// public class Foo : INotifyPropertyChanged {
/// public event PropertyChangedEventHandler PropertyChanged;
/// [NotifyPropertyChangedInvocator]
/// protected virtual void NotifyChanged(string propertyName) { ... }
///
/// private string _name;
/// public string Name {
/// get { return _name; }
/// set { _name = value; NotifyChanged("LastName"); /* Warning */ }
/// }
/// }
/// </code>
/// Examples of generated notifications:
/// <list>
/// <item><c>NotifyChanged("Property")</c></item>
/// <item><c>NotifyChanged(() =&gt; Property)</c></item>
/// <item><c>NotifyChanged((VM x) =&gt; x.Property)</c></item>
/// <item><c>SetProperty(ref myField, value, "Property")</c></item>
/// </list>
/// </example>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{
public NotifyPropertyChangedInvocatorAttribute() { }
public NotifyPropertyChangedInvocatorAttribute(string parameterName)
{
ParameterName = parameterName;
}
public string ParameterName { get; private set; }
}
/// <summary>
/// Describes dependency between method input and output
/// </summary>
/// <syntax>
/// <p>Function Definition Table syntax:</p>
/// <list>
/// <item>FDT ::= FDTRow [;FDTRow]*</item>
/// <item>FDTRow ::= Input =&gt; Output | Output &lt;= Input</item>
/// <item>Input ::= ParameterName: Value [, Input]*</item>
/// <item>Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value}</item>
/// <item>Value ::= true | false | null | notnull | canbenull</item>
/// </list>
/// If method has single input parameter, it's name could be omitted.<br/>
/// Using <c>halt</c> (or <c>void</c>/<c>nothing</c>, which is the same)
/// for method output means that the methos doesn't return normally.<br/>
/// <c>canbenull</c> annotation is only applicable for output parameters.<br/>
/// You can use multiple <c>[ContractAnnotation]</c> for each FDT row,
/// or use single attribute with rows separated by semicolon.<br/>
/// </syntax>
/// <examples><list>
/// <item><code>
/// [ContractAnnotation("=> halt")]
/// public void TerminationMethod()
/// </code></item>
/// <item><code>
/// [ContractAnnotation("halt &lt;= condition: false")]
/// public void Assert(bool condition, string text) // regular assertion method
/// </code></item>
/// <item><code>
/// [ContractAnnotation("s:null => true")]
/// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty()
/// </code></item>
/// <item><code>
/// // A method that returns null if the parameter is null, and not null if the parameter is not null
/// [ContractAnnotation("null => null; notnull => notnull")]
/// public object Transform(object data)
/// </code></item>
/// <item><code>
/// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")]
/// public bool TryParse(string s, out Person result)
/// </code></item>
/// </list></examples>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class ContractAnnotationAttribute : Attribute
{
public ContractAnnotationAttribute([NotNull] string contract)
: this(contract, false) { }
public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates)
{
Contract = contract;
ForceFullStates = forceFullStates;
}
public string Contract { get; private set; }
public bool ForceFullStates { get; private set; }
}
/// <summary>
/// Indicates that marked element should be localized or not
/// </summary>
/// <example><code>
/// [LocalizationRequiredAttribute(true)]
/// public class Foo {
/// private string str = "my string"; // Warning: Localizable string
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class LocalizationRequiredAttribute : Attribute
{
public LocalizationRequiredAttribute() : this(true) { }
public LocalizationRequiredAttribute(bool required)
{
Required = required;
}
public bool Required { get; private set; }
}
/// <summary>
/// Indicates that the value of the marked type (or its derivatives)
/// cannot be compared using '==' or '!=' operators and <c>Equals()</c>
/// should be used instead. However, using '==' or '!=' for comparison
/// with <c>null</c> is always permitted.
/// </summary>
/// <example><code>
/// [CannotApplyEqualityOperator]
/// class NoEquality { }
/// class UsesNoEquality {
/// public void Test() {
/// var ca1 = new NoEquality();
/// var ca2 = new NoEquality();
/// if (ca1 != null) { // OK
/// bool condition = ca1 == ca2; // Warning
/// }
/// }
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Interface | AttributeTargets.Class |
AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
public sealed class CannotApplyEqualityOperatorAttribute : Attribute { }
/// <summary>
/// When applied to a target attribute, specifies a requirement for any type marked
/// with the target attribute to implement or inherit specific type or types.
/// </summary>
/// <example><code>
/// [BaseTypeRequired(typeof(IComponent)] // Specify requirement
/// public class ComponentAttribute : Attribute { }
/// [Component] // ComponentAttribute requires implementing IComponent interface
/// public class MyComponent : IComponent { }
/// </code></example>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
[BaseTypeRequired(typeof(Attribute))]
public sealed class BaseTypeRequiredAttribute : Attribute
{
public BaseTypeRequiredAttribute([NotNull] Type baseType)
{
BaseType = baseType;
}
[NotNull] public Type BaseType { get; private set; }
}
/// <summary>
/// Indicates that the marked symbol is used implicitly
/// (e.g. via reflection, in external library), so this symbol
/// will not be marked as unused (as well as by other usage inspections)
/// </summary>
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class UsedImplicitlyAttribute : Attribute
{
public UsedImplicitlyAttribute()
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { }
public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
: this(useKindFlags, ImplicitUseTargetFlags.Default) { }
public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
: this(ImplicitUseKindFlags.Default, targetFlags) { }
public UsedImplicitlyAttribute(
ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
{
UseKindFlags = useKindFlags;
TargetFlags = targetFlags;
}
public ImplicitUseKindFlags UseKindFlags { get; private set; }
public ImplicitUseTargetFlags TargetFlags { get; private set; }
}
/// <summary>
/// Should be used on attributes and causes ReSharper
/// to not mark symbols marked with such attributes as unused
/// (as well as by other usage inspections)
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class MeansImplicitUseAttribute : Attribute
{
public MeansImplicitUseAttribute()
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { }
public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
: this(useKindFlags, ImplicitUseTargetFlags.Default) { }
public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
: this(ImplicitUseKindFlags.Default, targetFlags) { }
public MeansImplicitUseAttribute(
ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
{
UseKindFlags = useKindFlags;
TargetFlags = targetFlags;
}
[UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; }
[UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; }
}
[Flags]
public enum ImplicitUseKindFlags
{
Default = Access | Assign | InstantiatedWithFixedConstructorSignature,
/// <summary>Only entity marked with attribute considered used</summary>
Access = 1,
/// <summary>Indicates implicit assignment to a member</summary>
Assign = 2,
/// <summary>
/// Indicates implicit instantiation of a type with fixed constructor signature.
/// That means any unused constructor parameters won't be reported as such.
/// </summary>
InstantiatedWithFixedConstructorSignature = 4,
/// <summary>Indicates implicit instantiation of a type</summary>
InstantiatedNoFixedConstructorSignature = 8,
}
/// <summary>
/// Specify what is considered used implicitly
/// when marked with <see cref="MeansImplicitUseAttribute"/>
/// or <see cref="UsedImplicitlyAttribute"/>
/// </summary>
[Flags]
public enum ImplicitUseTargetFlags
{
Default = Itself,
Itself = 1,
/// <summary>Members of entity marked with attribute are considered used</summary>
Members = 2,
/// <summary>Entity marked with attribute and all its members considered used</summary>
WithMembers = Itself | Members
}
/// <summary>
/// This attribute is intended to mark publicly available API
/// which should not be removed and so is treated as used
/// </summary>
[MeansImplicitUse]
public sealed class PublicAPIAttribute : Attribute
{
public PublicAPIAttribute() { }
public PublicAPIAttribute([NotNull] string comment)
{
Comment = comment;
}
[NotNull] public string Comment { get; private set; }
}
/// <summary>
/// Tells code analysis engine if the parameter is completely handled
/// when the invoked method is on stack. If the parameter is a delegate,
/// indicates that delegate is executed while the method is executed.
/// If the parameter is an enumerable, indicates that it is enumerated
/// while the method is executed
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = true)]
public sealed class InstantHandleAttribute : Attribute { }
/// <summary>
/// Indicates that a method does not make any observable state changes.
/// The same as <c>System.Diagnostics.Contracts.PureAttribute</c>
/// </summary>
/// <example><code>
/// [Pure] private int Multiply(int x, int y) { return x * y; }
/// public void Foo() {
/// const int a = 2, b = 2;
/// Multiply(a, b); // Waring: Return value of pure method is not used
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public sealed class PureAttribute : Attribute { }
/// <summary>
/// Indicates that a parameter is a path to a file or a folder
/// within a web project. Path can be relative or absolute,
/// starting from web root (~)
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class PathReferenceAttribute : Attribute
{
public PathReferenceAttribute() { }
public PathReferenceAttribute([PathReference] string basePath)
{
BasePath = basePath;
}
[NotNull] public string BasePath { get; private set; }
}
// ASP.NET MVC attributes
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute
{
public AspMvcAreaMasterLocationFormatAttribute(string format) { }
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute
{
public AspMvcAreaPartialViewLocationFormatAttribute(string format) { }
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute
{
public AspMvcAreaViewLocationFormatAttribute(string format) { }
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcMasterLocationFormatAttribute : Attribute
{
public AspMvcMasterLocationFormatAttribute(string format) { }
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute
{
public AspMvcPartialViewLocationFormatAttribute(string format) { }
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcViewLocationFormatAttribute : Attribute
{
public AspMvcViewLocationFormatAttribute(string format) { }
}
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC action. If applied to a method, the MVC action name is calculated
/// implicitly from the context. Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcActionAttribute : Attribute
{
public AspMvcActionAttribute() { }
public AspMvcActionAttribute([NotNull] string anonymousProperty)
{
AnonymousProperty = anonymousProperty;
}
[NotNull] public string AnonymousProperty { get; private set; }
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC area.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcAreaAttribute : PathReferenceAttribute
{
public AspMvcAreaAttribute() { }
public AspMvcAreaAttribute([NotNull] string anonymousProperty)
{
AnonymousProperty = anonymousProperty;
}
[NotNull] public string AnonymousProperty { get; private set; }
}
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that
/// the parameter is an MVC controller. If applied to a method,
/// the MVC controller name is calculated implicitly from the context.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcControllerAttribute : Attribute
{
public AspMvcControllerAttribute() { }
public AspMvcControllerAttribute([NotNull] string anonymousProperty)
{
AnonymousProperty = anonymousProperty;
}
[NotNull] public string AnonymousProperty { get; private set; }
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(String, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcMasterAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(String, Object)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcModelTypeAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that
/// the parameter is an MVC partial view. If applied to a method,
/// the MVC partial view name is calculated implicitly from the context.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute { }
/// <summary>
/// ASP.NET MVC attribute. Allows disabling all inspections
/// for MVC views within a class or a method.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class AspMvcSupressViewErrorAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcDisplayTemplateAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcEditorTemplateAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC template.
/// Use this attribute for custom wrappers similar to
/// <c>System.ComponentModel.DataAnnotations.UIHintAttribute(System.String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcTemplateAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC view. If applied to a method, the MVC view name is calculated implicitly
/// from the context. Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(Object)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcViewAttribute : PathReferenceAttribute { }
/// <summary>
/// ASP.NET MVC attribute. When applied to a parameter of an attribute,
/// indicates that this parameter is an MVC action name
/// </summary>
/// <example><code>
/// [ActionName("Foo")]
/// public ActionResult Login(string returnUrl) {
/// ViewBag.ReturnUrl = Url.Action("Foo"); // OK
/// return RedirectToAction("Bar"); // Error: Cannot resolve action
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public sealed class AspMvcActionSelectorAttribute : Attribute { }
[AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.Property |
AttributeTargets.Field, Inherited = true)]
public sealed class HtmlElementAttributesAttribute : Attribute
{
public HtmlElementAttributesAttribute() { }
public HtmlElementAttributesAttribute([NotNull] string name)
{
Name = name;
}
[NotNull] public string Name { get; private set; }
}
[AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.Field |
AttributeTargets.Property, Inherited = true)]
public sealed class HtmlAttributeValueAttribute : Attribute
{
public HtmlAttributeValueAttribute([NotNull] string name)
{
Name = name;
}
[NotNull] public string Name { get; private set; }
}
// Razor attributes
/// <summary>
/// Razor attribute. Indicates that a parameter or a method is a Razor section.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.WebPages.WebPageBase.RenderSection(String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)]
public sealed class RazorSectionAttribute : Attribute { }
}

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

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "NetmfPackInstaller" )]
[assembly: AssemblyDescription( "" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "" )]
[assembly: AssemblyProduct( "NetmfPackInstaller" )]
[assembly: AssemblyCopyright( "Copyright © 2015" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion( "1.0.0.0" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]

Двоичные данные
NetmfPackInstaller/Refresh.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 606 B

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

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommonServiceLocator" version="1.3" targetFramework="net45" />
<package id="MvvmLightLibs" version="5.1.1.0" targetFramework="net45" />
</packages>

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

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "UnitTests" )]
[assembly: AssemblyDescription( "" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "" )]
[assembly: AssemblyProduct( "UnitTests" )]
[assembly: AssemblyCopyright( "Copyright © 2015" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid( "92d9e867-901f-45de-8816-4c1c79457061" )]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion( "1.0.0.0" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]

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

@ -0,0 +1,220 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CMSIS.Pack;
namespace UnitTests
{
[TestClass]
public class SemanticVersionTests
{
[TestMethod]
public void DefaultConstructorTest( )
{
var ver = new SemanticVersion( );
Assert.AreEqual( 0, ver.Major );
Assert.AreEqual( 0, ver.Minor );
Assert.AreEqual( 0, ver.Patch );
Assert.IsTrue( ver.IsValid );
Assert.IsTrue( ver.IsDevelopment );
Assert.IsTrue( ver.IsPrerelease );
Assert.AreEqual( "0.0.0", ver.ToString() );
VerifyToStringReverseParse( ver );
}
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void NegativeMajorThrowsTest( )
{
var ver = new SemanticVersion( -1, 0, 0 );
}
[TestMethod]
[ExpectedException( typeof( ArgumentOutOfRangeException ) )]
public void NegativeMinorThrowsTest( )
{
var ver = new SemanticVersion( 0, -1, 0 );
}
[TestMethod]
[ExpectedException( typeof( ArgumentOutOfRangeException ) )]
public void NegativePatchThrowsTest( )
{
var ver = new SemanticVersion( 0, 0, -1 );
}
[TestMethod]
public void NullPartsTest( )
{
var ver = new SemanticVersion( 0, 0, 0, null, null );
Assert.AreEqual( 0, ver.Major );
Assert.AreEqual( 0, ver.Minor );
Assert.AreEqual( 0, ver.Patch );
Assert.IsTrue( ver.IsValid );
Assert.IsTrue( ver.IsDevelopment );
Assert.IsTrue( ver.IsPrerelease );
Assert.AreEqual( "0.0.0", ver.ToString( ) );
VerifyToStringReverseParse( ver );
}
[TestMethod]
[ExpectedException( typeof(ArgumentException))]
public void InvalidPreReleasePartTest( )
{
var ver = new SemanticVersion( 0, 0, 0, new[ ] { "abcd", "12$", "bar" }, null );
}
[TestMethod]
[ExpectedException( typeof( ArgumentException ) )]
public void InvalidMetadataPartTest( )
{
var ver = new SemanticVersion( 0, 0, 0, new[ ] { "abcd" }, new[ ] { "abcd", "12$", "bar" } );
}
[TestMethod]
public void PrereleasePartsOnlyTest( )
{
var ver = new SemanticVersion( 0, 1, 2, new[ ] { "abcd", "123", "bar" }, null );
Assert.AreEqual( 0, ver.Major );
Assert.AreEqual( 1, ver.Minor );
Assert.AreEqual( 2, ver.Patch );
Assert.IsTrue( ver.IsValid );
Assert.IsTrue( ver.IsDevelopment );
Assert.IsTrue( ver.IsPrerelease );
Assert.AreEqual( 3, ver.PreReleaseParts.Count );
Assert.AreEqual( "abcd", ver.PreReleaseParts[ 0 ] );
Assert.AreEqual( "123", ver.PreReleaseParts[ 1 ] );
Assert.AreEqual( "bar", ver.PreReleaseParts[ 2 ] );
Assert.AreEqual( "0.1.2-abcd.123.bar", ver.ToString( ) );
VerifyToStringReverseParse( ver );
}
[TestMethod]
public void MetadataPartsOnlyTest( )
{
var ver = new SemanticVersion( 0, 1, 2, null, new[ ] { "abcd", "123", "bar" } );
Assert.AreEqual( 0, ver.Major );
Assert.AreEqual( 1, ver.Minor );
Assert.AreEqual( 2, ver.Patch );
Assert.IsTrue( ver.IsValid );
Assert.IsTrue( ver.IsDevelopment );
Assert.IsTrue( ver.IsPrerelease );
Assert.AreEqual( 3, ver.BuildMetadata.Count );
Assert.AreEqual( "abcd", ver.BuildMetadata[ 0 ] );
Assert.AreEqual( "123", ver.BuildMetadata[ 1 ] );
Assert.AreEqual( "bar", ver.BuildMetadata[ 2 ] );
Assert.AreEqual( "0.1.2+abcd.123.bar", ver.ToString( ) );
VerifyToStringReverseParse( ver );
}
[TestMethod]
public void StaticParseTest()
{
var ver = SemanticVersion.Parse( "0.1.2-alpha.beta+foo-bar.baz" );
Assert.AreEqual( 0, ver.Major );
Assert.AreEqual( 1, ver.Minor );
Assert.AreEqual( 2, 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.2-alpha.beta+foo-bar.baz", ver.ToString( ) );
VerifyToStringReverseParse( ver );
}
[TestMethod]
public void StaticParseDefaultPatchTest()
{
var ver = SemanticVersion.Parse( "0.1-alpha.beta+foo-bar.baz", patchOptional:true );
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]
[ExpectedException(typeof(FormatException))]
public void StaticParseDefaultPatchExceptionTest()
{
SemanticVersion.Parse( "0.1-alpha.beta+foo-bar.baz" );
}
[TestMethod]
public void PrecedenceRule1Test()
{
//1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
var versions = new []
{ new SemanticVersion( 1, 0, 0 )
, new SemanticVersion( 2, 0, 0 )
, new SemanticVersion( 2, 1, 0 )
, new SemanticVersion( 2, 1, 1 )
};
VerifyPrecedence( versions );
}
[TestMethod]
public void PrecedenceRule2Test()
{
// 1.0.0-alpha < 1.0.0
var versions = new [ ]
{ SemanticVersion.Parse( "1.0.0-alpha" )
, new SemanticVersion( 1, 0, 0 )
};
VerifyPrecedence( versions );
}
[TestMethod]
public void PrecedenceRule3Test()
{
// 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
var versions = new [ ]
{ SemanticVersion.Parse( "1.0.0-alpha" )
, SemanticVersion.Parse( "1.0.0-alpha.1" )
, SemanticVersion.Parse( "1.0.0-alpha.beta" )
, SemanticVersion.Parse( "1.0.0-beta" )
, SemanticVersion.Parse( "1.0.0-beta.2" )
, SemanticVersion.Parse( "1.0.0-beta.11" )
, SemanticVersion.Parse( "1.0.0-rc.1" )
, SemanticVersion.Parse( "1.0.0" )
};
VerifyPrecedence( versions );
}
private static void VerifyPrecedence( SemanticVersion[ ] versions )
{
for( var i = 0; i < versions.Length - 1; ++i )
{
VerifyToStringReverseParse( versions[ i ] );
Assert.IsTrue( versions[ i ].CompareTo( versions[ i + 1 ] ) < 0, string.Format( "FAILED Comparing '{0}' to '{1}", versions[ i ], versions[ i + 1 ] ) );
Assert.IsTrue( versions[ i + 1 ].CompareTo( versions[ i ] ) > 0, string.Format( "FAILED Comparing '{1}' to '{0}", versions[ i ], versions[ i + 1 ] ) );
}
VerifyToStringReverseParse( versions[ versions.Length - 1 ] );
}
private static void VerifyToStringReverseParse( SemanticVersion ver )
{
SemanticVersion parsed;
Assert.IsTrue( SemanticVersion.TryParse( ver.ToString( ), out parsed ) );
Assert.IsTrue( parsed == ver, string.Format("FAILED equality check: '{0}'=='{1}'", parsed, ver ) );
parsed = SemanticVersion.Parse( ver.ToString() );
Assert.IsTrue( parsed == ver, string.Format("FAILED equality check: '{0}'=='{1}'", parsed, ver ) );
}
}
}

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

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E4D675B0-5DBD-45BE-A4A0-B2C0F1BF42E3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnitTests</RootNamespace>
<AssemblyName>UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="SemanticVersionTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CMSIS.Pack\CMSIS.Pack.csproj">
<Project>{145d7231-c105-41be-b646-5d400097c744}</Project>
<Name>CMSIS.Pack</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>