fixup! Add Grpc.Tools MsBuild taks assembly, test and scripting

pull/13207/head
kkm 7 years ago
parent a93e3d2753
commit 17df1f8cf5
  1. 14
      src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
  2. 12
      src/csharp/Grpc.Tools/Common.cs
  3. 77
      src/csharp/Grpc.Tools/DepFileUtil.cs
  4. 12
      src/csharp/Grpc.Tools/GeneratorServices.cs
  5. 31
      src/csharp/Grpc.Tools/Grpc.Tools.csproj
  6. 8
      src/csharp/Grpc.Tools/ProtoCompile.cs
  7. 2
      src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs
  8. 2
      src/csharp/Grpc.Tools/ProtoReadDependencies.cs
  9. 4
      src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets

@ -1,23 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Grpc.Core\Version.csproj.include" />
<PropertyGroup>
<TargetFrameworks>netcoreapp1.0;net45</TargetFrameworks>
<TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>
<Import Project="..\Grpc.Core\SourceLink.csproj.include" />
<ItemGroup>
<ProjectReference Include="..\Grpc.Tools\Grpc.Tools.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Moq" Version="4.7.145" />
<PackageReference Include="NUnit" Version="3.9.0" />
<PackageReference Include="NUnitLite" Version="3.9.0" />
<PackageReference Include="Moq" Version="4.8.3" />
<PackageReference Include="NUnit; NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
<PackageReference Include="Microsoft.Build.Framework" Version="15.5.180" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.5.180" />
<PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.85" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

@ -25,15 +25,15 @@ using System.Security;
[assembly: InternalsVisibleTo("Grpc.Tools.Tests")]
namespace Grpc.Tools {
// Metadata names that we refer to often.
// Metadata names (MSBuild item attributes) that we refer to often.
static class Metadata {
// On output dependency lists.
public static string kSource = "Source";
public static string Source = "Source";
// On ProtoBuf items.
public static string kProtoRoot = "ProtoRoot";
public static string kOutputDir = "OutputDir";
public static string kGrpcServices = "GrpcServices";
public static string kGrpcOutputDir = "GrpcOutputDir";
public static string ProtoRoot = "ProtoRoot";
public static string OutputDir = "OutputDir";
public static string GrpcServices = "GrpcServices";
public static string GrpcOutputDir = "GrpcOutputDir";
};
// A few flags used to control the behavior under various platforms.

@ -25,7 +25,7 @@ using Microsoft.Build.Utilities;
namespace Grpc.Tools {
internal static class DepFileUtil {
/*
/*
Sample dependency files. Notable features we have to deal with:
* Slash doubling, must normalize them.
* Spaces in file names. Cannot just "unwrap" the line on backslash at eof;
@ -33,21 +33,30 @@ namespace Grpc.Tools {
the ':' separator, as containing exactly two.
* Deal with ':' also being drive letter separator (second example).
obj\Release\net45\/Foo.cs \
obj\Release\net45\/FooGrpc.cs: C:/foo/include/google/protobuf/wrappers.proto\
obj\Release\net45\/Foo.cs \
obj\Release\net45\/FooGrpc.cs: C:/foo/include/google/protobuf/wrappers.proto\
C:/projects/foo/src//foo.proto
C:\projects\foo\src\./foo.grpc.pb.cc \
C:\projects\foo\src\./foo.grpc.pb.h \
C:\projects\foo\src\./foo.pb.cc \
C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
C:\projects\foo\src\./foo.grpc.pb.cc \
C:\projects\foo\src\./foo.grpc.pb.h \
C:\projects\foo\src\./foo.pb.cc \
C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
C:/foo/include/google/protobuf/any.proto\
C:/foo/include/google/protobuf/source_context.proto\
C:/foo/include/google/protobuf/type.proto\
foo.proto
*/
// Read file names from the dependency file to the right of ':'.
*/
/// <summary>
/// Read file names from the dependency file to the right of ':'
/// </summary>
/// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param>
/// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param>
/// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param>
/// <returns>
/// Array of the proto file <b>input</b> dependencies as written by protoc, or empty
/// array if the dependency file does not exist or cannot be parsed.
/// </returns>
public static string[] ReadDependencyInputs(string protoDepDir, string proto,
TaskLoggingHelper log) {
string depFilename = GetDepFilenameForProto(protoDepDir, proto);
@ -80,7 +89,20 @@ C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
return result.ToArray();
}
// Read file names from the dependency file to the left of ':'.
/// <summary>
/// Read file names from the dependency file to the left of ':'
/// </summary>
/// <param name="depFilename">Path to dependency file written by protoc</param>
/// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param>
/// <returns>
/// Array of the protoc-generated outputs from the given dependency file
/// written by protoc, or empty array if the file does not exist or cannot
/// be parsed.
/// </returns>
/// <remarks>
/// Since this is called after a protoc invocation, an unparsable or missing
/// file causes an error-level message to be logged.
/// </remarks>
public static string[] ReadDependencyOutputs(string depFilename,
TaskLoggingHelper log) {
string[] lines = ReadDepFileLines(depFilename, true, log);
@ -106,10 +128,31 @@ C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
return result.ToArray();
}
// Get complete dependency file name from directory hash and file name,
// tucked onto protoDepDir, e. g.
// ("out", "foo/file.proto") => "out/deadbeef12345678_file.protodep".
// This way, the filenames are unique but still possible to make sense of.
/// <summary>
/// Construct relative dependency file name from directory hash and file name
/// </summary>
/// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param>
/// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param>
/// <returns>
/// Full relative path to the dependency file, e. g.
/// "out/deadbeef12345678_file.protodep"
/// </returns>
/// <remarks>
/// Since a project may contain proto files with the same filename but in different
/// directories, a unique filename for the dependency file is constructed based on the
/// proto file name both name and directory. The directory path can be arbitrary,
/// for example, it can be outside of the project, or an absolute path including
/// a drive letter, or a UNC network path. A name constructed from such a path by,
/// for example, replacing disallowed name characters with an underscore, may well
/// be over filesystem's allowed path length, since it will be located under the
/// project and solution directories, which are also some level deep from the root.
/// Instead of creating long and unwieldy names for these proto sources, we cache
/// the full path of the name without the filename, and append the filename to it,
/// as in e. g. "foo/file.proto" will yield the name "deadbeef12345678_file", where
/// "deadbeef12345678" is a presumed hash value of the string "foo/". This allows
/// the file names be short, unique (up to a hash collision), and still allowing
/// the user to guess their provenance.
/// </remarks>
public static string GetDepFilenameForProto(string protoDepDir, string proto) {
string dirname = Path.GetDirectoryName(proto);
if (Platform.IsFsCaseInsensitive) {
@ -177,7 +220,7 @@ C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
// Read entire dependency file. The 'required' parameter controls error
// logging behavior in case the file not found. We require this file when
// compiling, but reading it is optional when computing depnedencies.
// compiling, but reading it is optional when computing dependencies.
static string[] ReadDepFileLines(string filename, bool required,
TaskLoggingHelper log) {
try {
@ -189,7 +232,7 @@ C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
if (required) {
log.LogError($"Unable to load {filename}: {ex.GetType().Name}: {ex.Message}");
} else {
log.LogMessage(MessageImportance.Low, $"Skippping {filename}: {ex.Message}");
log.LogMessage(MessageImportance.Low, $"Skipping {filename}: {ex.Message}");
}
return new string[0];
}

@ -49,7 +49,7 @@ namespace Grpc.Tools {
// we do not try to validate the value; scripts take care of that.
// It is safe to assume that gRPC is requested for any other value.
protected bool GrpcOutputPossible(ITaskItem proto) {
string gsm = proto.GetMetadata(Metadata.kGrpcServices);
string gsm = proto.GetMetadata(Metadata.GrpcServices);
return !gsm.EqualNoCase("") && !gsm.EqualNoCase("none")
&& !gsm.EqualNoCase("false");
}
@ -67,12 +67,12 @@ namespace Grpc.Tools {
Path.GetFileNameWithoutExtension(protoItem.ItemSpec));
var outputs = new string[doGrpc ? 2 : 1];
string outdir = protoItem.GetMetadata(Metadata.kOutputDir);
string outdir = protoItem.GetMetadata(Metadata.OutputDir);
string fileStem = Path.Combine(outdir, filename);
outputs[0] = fileStem + ".cs";
if (doGrpc) {
// Override outdir if kGrpcOutputDir present, default to proto output.
outdir = protoItem.GetMetadata(Metadata.kGrpcOutputDir);
outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
if (outdir != "") {
fileStem = Path.Combine(outdir, filename);
}
@ -105,20 +105,20 @@ namespace Grpc.Tools {
public override string[] GetPossibleOutputs(ITaskItem protoItem) {
bool doGrpc = GrpcOutputPossible(protoItem);
string root = protoItem.GetMetadata(Metadata.kProtoRoot);
string root = protoItem.GetMetadata(Metadata.ProtoRoot);
string proto = protoItem.ItemSpec;
string filename = Path.GetFileNameWithoutExtension(proto);
// E. g., ("foo/", "foo/bar/x.proto") => "bar"
string relative = GetRelativeDir(root, proto);
var outputs = new string[doGrpc ? 4 : 2];
string outdir = protoItem.GetMetadata(Metadata.kOutputDir);
string outdir = protoItem.GetMetadata(Metadata.OutputDir);
string fileStem = Path.Combine(outdir, relative, filename);
outputs[0] = fileStem + ".pb.cc";
outputs[1] = fileStem + ".pb.h";
if (doGrpc) {
// Override outdir if kGrpcOutputDir present, default to proto output.
outdir = protoItem.GetMetadata(Metadata.kGrpcOutputDir);
outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
if (outdir != "") {
fileStem = Path.Combine(outdir, relative, filename);
}

@ -6,7 +6,19 @@
<AssemblyName>Protobuf.MSBuild</AssemblyName>
<Version>$(GrpcCsharpVersion)</Version>
<!-- If changing targets, change also paths in Google.Protobuf.Tools.targets. -->
<TargetFrameworks>netstandard1.3;net40</TargetFrameworks>
<TargetFrameworks>net45;netstandard1.3</TargetFrameworks>
</PropertyGroup>
<!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings
in that file conflict with the intent of this build, as it cannot be signed,
and may not compile Grpc.Core/Version.cs, as that file references constants
in Grpc.Core.dll.
TODO(kkm): Refactor imports. -->
<PropertyGroup Condition="'$(OS)' != 'Windows_NT'">
<!-- Workaround for https://github.com/dotnet/sdk/issues/335 -->
<FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride>
<FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride>
<FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride>
</PropertyGroup>
<PropertyGroup Label="Asset root folders. TODO(kkm): Change with package separation.">
@ -32,9 +44,6 @@
</PropertyGroup>
<PropertyGroup Label="NuGet package definition" Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageOutputPath>../../../artifacts</PackageOutputPath>
<!-- TODO(kkm): Change to "build\" after splitting. -->
<BuildOutputTargetFolder>build\_protobuf\</BuildOutputTargetFolder>
<DevelopmentDependency>true</DevelopmentDependency>
@ -57,10 +66,9 @@ Linux and MacOS. Managed runtime is supplied separately in the Grpc.Core package
<None Pack="true" PackagePath="build\" Include="build\**\*.xml; build\**\*.props; build\**\*.targets;" />
<!-- Protobuf assets (for Google.Protobuf.Tools) -->
<_ProtoTemp Include="any.proto;api.proto;descriptor.proto;duration.proto;" />
<_ProtoTemp Include="empty.proto;field_mask.proto;source_context.proto;" />
<_ProtoTemp Include="struct.proto;timestamp.proto;type.proto;wrappers.proto" />
<_Asset PackagePath="build/native/include/google/protobuf/" Include="@(_ProtoTemp->'$(Assets_ProtoInclude)%(Identity)')" />
<_ProtoAssetName Include="any;api;descriptor;duration;empty;field_mask;
source_context;struct;timestamp;type;wrappers" />
<_Asset PackagePath="build/native/include/google/protobuf/" Include="@(_ProtoAssetName->'$(Assets_ProtoInclude)%(Identity).proto')" />
<!-- TODO(kkm): GPB builds assets into "macosx", GRPC into "macos". -->
<_Asset PackagePath="build/native/bin/windows/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x86/protoc.exe" />
@ -85,10 +93,9 @@ Linux and MacOS. Managed runtime is supplied separately in the Grpc.Core package
</ItemGroup>
<ItemGroup Condition="$(_NetStandard)">
<PackageReference Include="Microsoft.Build.Framework" Version="15.5.180" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.5.180" />
<!-- Set PrivateAssets="All" on all items, so that even implicit package
dependencies do not become dependencies of this package. -->
<PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.85" />
<!-- Set PrivateAssets="All" on all items, even those implicitly added,
so that they do not become dependencies of this package. -->
<PackageReference Update="@(PackageReference)" PrivateAssets="All" />
</ItemGroup>

@ -32,10 +32,10 @@ namespace Grpc.Tools {
/// any language outputs.
/// </summary>
public class ProtoCompile : ToolTask {
/*
/*
Usage: /home/kkm/work/protobuf/src/.libs/lt-protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:
Usage: /home/kkm/work/protobuf/src/.libs/lt-protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:
-IPATH, --proto_path=PATH Specify the directory in which to search for
imports. May be specified multiple times;
directories will be searched in order. If not
@ -116,7 +116,7 @@ Parse PROTO_FILES and generate output based on the options given:
quotes, wildcards, escapes, commands, etc.).
Each line corresponds to a single argument,
even if it contains spaces.
*/
*/
static string[] s_supportedGenerators = new[] {
"cpp", "csharp", "java",
"javanano", "js", "objc",

@ -68,7 +68,7 @@ namespace Grpc.Tools {
var outputs = generator.GetPossibleOutputs(proto);
foreach (string output in outputs) {
var ti = new TaskItem(output);
ti.SetMetadata(Metadata.kSource, proto.ItemSpec);
ti.SetMetadata(Metadata.Source, proto.ItemSpec);
possible.Add(ti);
}
}

@ -55,7 +55,7 @@ namespace Grpc.Tools {
string[] deps = DepFileUtil.ReadDependencyInputs(ProtoDepDir, proto.ItemSpec, Log);
foreach (string dep in deps) {
var ti = new TaskItem(dep);
ti.SetMetadata(Metadata.kSource, proto.ItemSpec);
ti.SetMetadata(Metadata.Source, proto.ItemSpec);
dependencies.Add(ti);
}
}

@ -7,7 +7,7 @@
<!-- Configuration is passing the smoke test. -->
<Protobuf_ProjectSupported Condition=" '$(Protobuf_Generator)' != '' ">true</Protobuf_ProjectSupported>
<_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' == 'Core' ">netstandard1.3\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
<_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net40\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
<_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net45\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
</PropertyGroup>
<UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoToolsPlatform" />
@ -370,7 +370,7 @@
Design-time support
=================================================================================-->
<!-- Add all .proto files to the SourceFilesProjectOutputGroupOutput, so that
<!-- Add all .proto files to the SourceFilesProjectOutputGroupOutput, so that:
* Visual Studio triggers a build when any of them changed;
* The Pack target includes .proto files into the source package. -->
<Target Name="_Protobuf_SourceFilesProjectOutputGroup"

Loading…
Cancel
Save