Skip to content

Commit cb935be

Browse files
committed
Initial port of Microsoft.Fx.Portability.Offline, Microsoft.Fx.Portability.Reports.Html, and Microsoft.Fx.Portability.Reports.Json.
1 parent 9aefcfd commit cb935be

25 files changed

+1914
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ rcf
2323
*.swp
2424
.vs
2525
project.lock.json
26+
src/Microsoft.Fx.Portability.Offline/data/

PortabilityTools.sln

+21
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Fx.Portability.Te
3333
EndProject
3434
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Fx.Portability.MetadataReader.Tests", "tests\Microsoft.Fx.Portability.MetadataReader.Tests\Microsoft.Fx.Portability.MetadataReader.Tests.csproj", "{B44085A7-0DCD-4CE2-BDD9-B2E5268DCCCC}"
3535
EndProject
36+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Fx.Portability.Reports.Html", "src\Microsoft.Fx.Portability.Reports.Html\Microsoft.Fx.Portability.Reports.Html.csproj", "{83F4A5FE-FAF8-4952-899E-EA0BB08F8E60}"
37+
EndProject
38+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Fx.Portability.Reports.Json", "src\Microsoft.Fx.Portability.Reports.Json\Microsoft.Fx.Portability.Reports.Json.csproj", "{DBD3216D-7901-490D-B219-C63D3E001E0D}"
39+
EndProject
40+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Fx.Portability.Offline", "src\Microsoft.Fx.Portability.Offline\Microsoft.Fx.Portability.Offline.csproj", "{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549}"
41+
EndProject
3642
Global
3743
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3844
Debug|Any CPU = Debug|Any CPU
@@ -67,6 +73,18 @@ Global
6773
{B44085A7-0DCD-4CE2-BDD9-B2E5268DCCCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
6874
{B44085A7-0DCD-4CE2-BDD9-B2E5268DCCCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
6975
{B44085A7-0DCD-4CE2-BDD9-B2E5268DCCCC}.Release|Any CPU.Build.0 = Release|Any CPU
76+
{83F4A5FE-FAF8-4952-899E-EA0BB08F8E60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
77+
{83F4A5FE-FAF8-4952-899E-EA0BB08F8E60}.Debug|Any CPU.Build.0 = Debug|Any CPU
78+
{83F4A5FE-FAF8-4952-899E-EA0BB08F8E60}.Release|Any CPU.ActiveCfg = Release|Any CPU
79+
{83F4A5FE-FAF8-4952-899E-EA0BB08F8E60}.Release|Any CPU.Build.0 = Release|Any CPU
80+
{DBD3216D-7901-490D-B219-C63D3E001E0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
81+
{DBD3216D-7901-490D-B219-C63D3E001E0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
82+
{DBD3216D-7901-490D-B219-C63D3E001E0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
83+
{DBD3216D-7901-490D-B219-C63D3E001E0D}.Release|Any CPU.Build.0 = Release|Any CPU
84+
{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
85+
{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549}.Debug|Any CPU.Build.0 = Debug|Any CPU
86+
{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549}.Release|Any CPU.ActiveCfg = Release|Any CPU
87+
{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549}.Release|Any CPU.Build.0 = Release|Any CPU
7088
EndGlobalSection
7189
GlobalSection(SolutionProperties) = preSolution
7290
HideSolutionNode = FALSE
@@ -79,5 +97,8 @@ Global
7997
{C556C618-D062-4988-9379-99A716D8F2C1} = {F8292A68-AF7C-4B26-B1B8-B232548EF118}
8098
{6900A49C-D463-43E2-AB21-487E8B73EF5C} = {7DC7AA2C-0401-495B-B42C-32F44085EBE6}
8199
{B44085A7-0DCD-4CE2-BDD9-B2E5268DCCCC} = {7DC7AA2C-0401-495B-B42C-32F44085EBE6}
100+
{83F4A5FE-FAF8-4952-899E-EA0BB08F8E60} = {6234AABE-C4F3-4094-9C0D-FFD589235DBE}
101+
{DBD3216D-7901-490D-B219-C63D3E001E0D} = {6234AABE-C4F3-4094-9C0D-FFD589235DBE}
102+
{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549} = {6234AABE-C4F3-4094-9C0D-FFD589235DBE}
82103
EndGlobalSection
83104
EndGlobal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Microsoft.Fx.Portability.ObjectModel;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Diagnostics;
8+
using System.IO;
9+
using System.Linq;
10+
11+
namespace Microsoft.Fx.Portability
12+
{
13+
internal static class Data
14+
{
15+
public static DotNetCatalog LoadCatalog()
16+
{
17+
using (var stream = OpenFileOrResource("catalog.bin"))
18+
{
19+
return stream.DecompressToObject<DotNetCatalog>();
20+
}
21+
}
22+
23+
public static IEnumerable<BreakingChange> LoadBreakingChanges()
24+
{
25+
// Prefer a local 'BreakingChanges' directory to embedded breaking changes
26+
if (Directory.Exists(Path.Combine(GetCurrentDirectoryName(), "BreakingChanges")))
27+
{
28+
var breakingChanges = new List<BreakingChange>();
29+
foreach (var file in Directory.GetFiles(Path.Combine(GetCurrentDirectoryName(), "BreakingChanges"), "*", SearchOption.AllDirectories))
30+
{
31+
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read))
32+
{
33+
breakingChanges.AddRange(ParseBreakingChange(fs, Path.GetExtension(file)));
34+
}
35+
}
36+
37+
return breakingChanges;
38+
}
39+
// If no BreakingChanges folder exists, then we'll fall back to the old model of looking for
40+
// BreakingChanges.json either next to the assembly or, if not there, embedded as a resource
41+
else
42+
{
43+
using (var stream = OpenFileOrResource("BreakingChanges.json"))
44+
{
45+
var breakingChanges = stream.Deserialize<IEnumerable<BreakingChange>>();
46+
47+
if (breakingChanges == null)
48+
{
49+
Trace.WriteLine("No data was found in 'BreakingChanges.json'");
50+
return Enumerable.Empty<BreakingChange>();
51+
}
52+
53+
return breakingChanges;
54+
}
55+
}
56+
}
57+
58+
private static Stream OpenFileOrResource(string path)
59+
{
60+
var file = Path.Combine(GetCurrentDirectoryName(), path);
61+
62+
if (File.Exists(file))
63+
{
64+
return File.OpenRead(file);
65+
}
66+
else
67+
{
68+
var stream = typeof(Data).Assembly.GetManifestResourceStream("Microsoft.Fx.Portability.data." + path);
69+
70+
if (stream == null)
71+
{
72+
throw new FileNotFoundException("Could not find data file next to or embedded in assembly.", path);
73+
}
74+
75+
return stream;
76+
}
77+
}
78+
79+
private static string GetCurrentDirectoryName()
80+
{
81+
return Path.GetDirectoryName(typeof(Data).Assembly.Location);
82+
}
83+
84+
private static IEnumerable<BreakingChange> ParseBreakingChange(Stream stream, string extension)
85+
{
86+
if (string.Equals(".md", extension, StringComparison.OrdinalIgnoreCase))
87+
{
88+
return BreakingChangeParser.FromMarkdown(stream);
89+
}
90+
if (string.Equals(".json", extension, StringComparison.OrdinalIgnoreCase))
91+
{
92+
return stream.Deserialize<IEnumerable<BreakingChange>>();
93+
}
94+
else
95+
{
96+
return Enumerable.Empty<BreakingChange>();
97+
}
98+
}
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{F3D148CA-D49D-4315-9CD6-AE7B0EEA9549}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>Microsoft.Fx.Portability</RootNamespace>
11+
<AssemblyName>Microsoft.Fx.Portability.Offline</AssemblyName>
12+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<DebugSymbols>true</DebugSymbols>
17+
<DebugType>full</DebugType>
18+
<Optimize>false</Optimize>
19+
<OutputPath>bin\Debug\</OutputPath>
20+
<DefineConstants>DEBUG;TRACE</DefineConstants>
21+
<ErrorReport>prompt</ErrorReport>
22+
<WarningLevel>4</WarningLevel>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25+
<DebugType>pdbonly</DebugType>
26+
<Optimize>true</Optimize>
27+
<OutputPath>bin\Release\</OutputPath>
28+
<DefineConstants>TRACE</DefineConstants>
29+
<ErrorReport>prompt</ErrorReport>
30+
<WarningLevel>4</WarningLevel>
31+
</PropertyGroup>
32+
<ItemGroup>
33+
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
34+
<SpecificVersion>False</SpecificVersion>
35+
<HintPath>..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
36+
</Reference>
37+
<Reference Include="System" />
38+
<Reference Include="System.Core" />
39+
<Reference Include="System.Net.Http" />
40+
<Reference Include="System.Runtime.Serialization" />
41+
<Reference Include="System.Xml.Linq" />
42+
<Reference Include="System.Data.DataSetExtensions" />
43+
<Reference Include="Microsoft.CSharp" />
44+
<Reference Include="System.Data" />
45+
<Reference Include="System.Xml" />
46+
</ItemGroup>
47+
<ItemGroup>
48+
<ProjectReference Include="..\Microsoft.Fx.Portability-net45\Microsoft.Fx.Portability-net45.csproj">
49+
<Project>{fc1429e3-46c3-49ed-b99f-b45e1ccfb86b}</Project>
50+
<Name>Microsoft.Fx.Portability-net45</Name>
51+
</ProjectReference>
52+
</ItemGroup>
53+
<ItemGroup>
54+
<Compile Include="Data.cs" />
55+
<Compile Include="OfflineApiCatalogLookup.cs" />
56+
<Compile Include="OfflineApiPortService.cs" />
57+
<Compile Include="OfflineApiRecommendations.cs" />
58+
<Compile Include="OfflineBreakingChanges.cs" />
59+
</ItemGroup>
60+
<ItemGroup>
61+
<Folder Include="Properties\" />
62+
</ItemGroup>
63+
<PropertyGroup>
64+
<DataPath>$(MSBuildThisFileDirectory)data\</DataPath>
65+
<CatalogDataFile>$(DataPath)catalog.bin</CatalogDataFile>
66+
</PropertyGroup>
67+
<ItemGroup>
68+
<EmbeddedResource Include="$(CatalogDataFile)" />
69+
<None Include="download.ps1" />
70+
<None Include="unity.config" />
71+
<None Include="packages.config" />
72+
</ItemGroup>
73+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
74+
<Target Name="DownloadContent" BeforeTargets="BeforeBuild">
75+
<Exec Command="powershell.exe -noprofile -noninteractive -ExecutionPolicy unrestricted -file $(MSBuildThisFileDirectory)download.ps1 $(CatalogDataFile) $(DataPath)" />
76+
</Target>
77+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
78+
Other similar extension points exist, see Microsoft.Common.targets.
79+
<Target Name="BeforeBuild">
80+
</Target>
81+
<Target Name="AfterBuild">
82+
</Target>
83+
-->
84+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Microsoft.Fx.Portability.ObjectModel;
5+
using System;
6+
7+
namespace Microsoft.Fx.Portability
8+
{
9+
public class OfflineApiCatalogLookup : CloudApiCatalogLookup
10+
{
11+
public OfflineApiCatalogLookup(IProgressReporter progressReporter)
12+
: base(GetData(progressReporter))
13+
{ }
14+
15+
private static DotNetCatalog GetData(IProgressReporter progressReporter)
16+
{
17+
using (var progressTask = progressReporter.StartTask("Loading catalog"))
18+
{
19+
try
20+
{
21+
return Data.LoadCatalog();
22+
}
23+
catch (Exception)
24+
{
25+
progressTask.Abort();
26+
throw;
27+
}
28+
}
29+
}
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Microsoft.Fx.Portability.Analyzer;
5+
using Microsoft.Fx.Portability.ObjectModel;
6+
using Microsoft.Fx.Portability.Reporting;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.IO;
10+
using System.Linq;
11+
using System.Runtime.Versioning;
12+
using System.Threading.Tasks;
13+
14+
namespace Microsoft.Fx.Portability
15+
{
16+
public class OfflineApiPortService : IApiPortService
17+
{
18+
private readonly ITargetMapper _mapper;
19+
private readonly IApiCatalogLookup _lookup;
20+
private readonly ICollection<FrameworkName> _defaultTargets;
21+
private readonly IRequestAnalyzer _requestAnalyzer;
22+
private readonly ICollection<IReportWriter> _reportWriters;
23+
24+
public OfflineApiPortService(IApiCatalogLookup lookup, IRequestAnalyzer requestAnalyzer, ITargetMapper mapper, ICollection<IReportWriter> reportWriters,ITargetNameParser targetNameParser)
25+
{
26+
_lookup = lookup;
27+
_requestAnalyzer = requestAnalyzer;
28+
_mapper = mapper;
29+
_reportWriters = reportWriters;
30+
_defaultTargets = new HashSet<FrameworkName>(targetNameParser.DefaultTargets);
31+
}
32+
33+
public Task<ServiceResponse<IEnumerable<AvailableTarget>>> GetTargetsAsync()
34+
{
35+
var targets = _lookup
36+
.GetPublicTargets()
37+
.Select(target => new AvailableTarget { Name = target.Identifier, Version = target.Version, IsSet = _defaultTargets.Contains(target) });
38+
39+
var response = new ServiceResponse<IEnumerable<AvailableTarget>>(targets);
40+
41+
return Task.FromResult(response);
42+
}
43+
44+
public Task<ServiceResponse<AnalyzeResponse>> SendAnalysisAsync(AnalyzeRequest a)
45+
{
46+
var response = _requestAnalyzer.AnalyzeRequest(a, Guid.NewGuid().ToString());
47+
var serviceResponse = new ServiceResponse<AnalyzeResponse>(response);
48+
49+
return Task.FromResult(serviceResponse);
50+
}
51+
52+
public Task<ServiceResponse<byte[]>> SendAnalysisAsync(AnalyzeRequest a, string format)
53+
{
54+
var response = _requestAnalyzer.AnalyzeRequest(a, Guid.NewGuid().ToString());
55+
56+
var writer = _reportWriters.FirstOrDefault(w => string.Equals(w.Format.DisplayName, format, StringComparison.InvariantCultureIgnoreCase));
57+
58+
if (writer == null)
59+
{
60+
throw new UnknownReportFormatException(format);
61+
}
62+
63+
using (var ms = new MemoryStream())
64+
{
65+
writer.WriteStream(ms, response);
66+
67+
return WrapResponse(ms.ToArray());
68+
}
69+
}
70+
71+
public Task<ServiceResponse<IEnumerable<ResultFormatInformation>>> GetResultFormatsAsync()
72+
{
73+
var formats = _reportWriters.Select(r => r.Format);
74+
75+
return WrapResponse(formats);
76+
}
77+
78+
private Task<ServiceResponse<T>> WrapResponse<T>(T data)
79+
{
80+
var response = new ServiceResponse<T>(data);
81+
82+
return Task.FromResult(response);
83+
}
84+
85+
public Task<ServiceResponse<UsageDataCollection>> GetUsageDataAsync(int? skip = null, int? top = null, UsageDataFilter? filter = null, IEnumerable<string> targets = null)
86+
{
87+
throw new NotImplementedException();
88+
}
89+
90+
public Task<ServiceResponse<AnalyzeResponse>> GetAnalysisAsync(string submissionId)
91+
{
92+
throw new NotImplementedException();
93+
}
94+
95+
public Task<ServiceResponse<byte[]>> GetAnalysisAsync(string submissionId, string format)
96+
{
97+
throw new NotImplementedException();
98+
}
99+
100+
public Task<ServiceResponse<ApiInformation>> GetApiInformationAsync(string docId)
101+
{
102+
throw new NotImplementedException();
103+
}
104+
105+
public Task<ServiceResponse<IReadOnlyCollection<ApiDefinition>>> SearchFxApiAsync(string query, int? top = null)
106+
{
107+
throw new NotImplementedException();
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)