|
|
|
@ -16,7 +16,6 @@ |
|
|
|
|
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
using System; |
|
|
|
|
using System.IO; |
|
|
|
|
using System.Text; |
|
|
|
|
using Microsoft.Build.Framework; |
|
|
|
@ -55,7 +54,62 @@ namespace Grpc.Tools |
|
|
|
|
&& !gsm.EqualNoCase("false"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public abstract string[] GetPossibleOutputs(ITaskItem proto); |
|
|
|
|
// Update OutputDir and GrpcOutputDir for the item and all subsequent |
|
|
|
|
// targets using this item. This should only be done if the real |
|
|
|
|
// output directories for protoc should be modified. |
|
|
|
|
public virtual ITaskItem PatchOutputDirectory(ITaskItem protoItem) |
|
|
|
|
{ |
|
|
|
|
// Nothing to do |
|
|
|
|
return protoItem; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public abstract string[] GetPossibleOutputs(ITaskItem protoItem); |
|
|
|
|
|
|
|
|
|
// Calculate part of proto path relative to root. Protoc is very picky |
|
|
|
|
// about them matching exactly, so can be we. Expect root be exact prefix |
|
|
|
|
// to proto, minus some slash normalization. |
|
|
|
|
protected static string GetRelativeDir(string root, string proto, TaskLoggingHelper log) |
|
|
|
|
{ |
|
|
|
|
string protoDir = Path.GetDirectoryName(proto); |
|
|
|
|
string rootDir = EndWithSlash(Path.GetDirectoryName(EndWithSlash(root))); |
|
|
|
|
if (rootDir == s_dotSlash) |
|
|
|
|
{ |
|
|
|
|
// Special case, otherwise we can return "./" instead of "" below! |
|
|
|
|
return protoDir; |
|
|
|
|
} |
|
|
|
|
if (Platform.IsFsCaseInsensitive) |
|
|
|
|
{ |
|
|
|
|
protoDir = protoDir.ToLowerInvariant(); |
|
|
|
|
rootDir = rootDir.ToLowerInvariant(); |
|
|
|
|
} |
|
|
|
|
protoDir = EndWithSlash(protoDir); |
|
|
|
|
if (!protoDir.StartsWith(rootDir)) |
|
|
|
|
{ |
|
|
|
|
log.LogWarning("Protobuf item '{0}' has the ProtoRoot metadata '{1}' " + |
|
|
|
|
"which is not prefix to its path. Cannot compute relative path.", |
|
|
|
|
proto, root); |
|
|
|
|
return ""; |
|
|
|
|
} |
|
|
|
|
return protoDir.Substring(rootDir.Length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// './' or '.\', normalized per system. |
|
|
|
|
protected static string s_dotSlash = "." + Path.DirectorySeparatorChar; |
|
|
|
|
|
|
|
|
|
protected static string EndWithSlash(string str) |
|
|
|
|
{ |
|
|
|
|
if (str == "") |
|
|
|
|
{ |
|
|
|
|
return s_dotSlash; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (str[str.Length - 1] != '\\' && str[str.Length - 1] != '/') |
|
|
|
|
{ |
|
|
|
|
return str + Path.DirectorySeparatorChar; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return str; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// C# generator services. |
|
|
|
@ -63,23 +117,42 @@ namespace Grpc.Tools |
|
|
|
|
{ |
|
|
|
|
public CSharpGeneratorServices(TaskLoggingHelper log) : base(log) { } |
|
|
|
|
|
|
|
|
|
public override ITaskItem PatchOutputDirectory(ITaskItem protoItem) |
|
|
|
|
{ |
|
|
|
|
var outputItem = new TaskItem(protoItem); |
|
|
|
|
string root = outputItem.GetMetadata(Metadata.ProtoRoot); |
|
|
|
|
string proto = outputItem.ItemSpec; |
|
|
|
|
string relative = GetRelativeDir(root, proto, Log); |
|
|
|
|
|
|
|
|
|
string outdir = outputItem.GetMetadata(Metadata.OutputDir); |
|
|
|
|
string pathStem = Path.Combine(outdir, relative); |
|
|
|
|
outputItem.SetMetadata(Metadata.OutputDir, pathStem); |
|
|
|
|
|
|
|
|
|
// Override outdir if GrpcOutputDir present, default to proto output. |
|
|
|
|
string grpcdir = outputItem.GetMetadata(Metadata.GrpcOutputDir); |
|
|
|
|
if (grpcdir != "") |
|
|
|
|
{ |
|
|
|
|
pathStem = Path.Combine(grpcdir, relative); |
|
|
|
|
} |
|
|
|
|
outputItem.SetMetadata(Metadata.GrpcOutputDir, pathStem); |
|
|
|
|
return outputItem; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override string[] GetPossibleOutputs(ITaskItem protoItem) |
|
|
|
|
{ |
|
|
|
|
bool doGrpc = GrpcOutputPossible(protoItem); |
|
|
|
|
var outputs = new string[doGrpc ? 2 : 1]; |
|
|
|
|
string basename = Path.GetFileNameWithoutExtension(protoItem.ItemSpec); |
|
|
|
|
|
|
|
|
|
string proto = protoItem.ItemSpec; |
|
|
|
|
string basename = Path.GetFileNameWithoutExtension(proto); |
|
|
|
|
string outdir = protoItem.GetMetadata(Metadata.OutputDir); |
|
|
|
|
string filename = LowerUnderscoreToUpperCamelProtocWay(basename); |
|
|
|
|
outputs[0] = Path.Combine(outdir, filename) + ".cs"; |
|
|
|
|
|
|
|
|
|
if (doGrpc) |
|
|
|
|
{ |
|
|
|
|
// Override outdir if kGrpcOutputDir present, default to proto output. |
|
|
|
|
string grpcdir = protoItem.GetMetadata(Metadata.GrpcOutputDir); |
|
|
|
|
filename = LowerUnderscoreToUpperCamelGrpcWay(basename); |
|
|
|
|
outputs[1] = Path.Combine( |
|
|
|
|
grpcdir != "" ? grpcdir : outdir, filename) + "Grpc.cs"; |
|
|
|
|
outputs[1] = Path.Combine(grpcdir, filename) + "Grpc.cs"; |
|
|
|
|
} |
|
|
|
|
return outputs; |
|
|
|
|
} |
|
|
|
@ -142,7 +215,7 @@ namespace Grpc.Tools |
|
|
|
|
string proto = protoItem.ItemSpec; |
|
|
|
|
string filename = Path.GetFileNameWithoutExtension(proto); |
|
|
|
|
// E. g., ("foo/", "foo/bar/x.proto") => "bar" |
|
|
|
|
string relative = GetRelativeDir(root, proto); |
|
|
|
|
string relative = GetRelativeDir(root, proto, Log); |
|
|
|
|
|
|
|
|
|
var outputs = new string[doGrpc ? 4 : 2]; |
|
|
|
|
string outdir = protoItem.GetMetadata(Metadata.OutputDir); |
|
|
|
@ -151,7 +224,7 @@ namespace Grpc.Tools |
|
|
|
|
outputs[1] = fileStem + ".pb.h"; |
|
|
|
|
if (doGrpc) |
|
|
|
|
{ |
|
|
|
|
// Override outdir if kGrpcOutputDir present, default to proto output. |
|
|
|
|
// Override outdir if GrpcOutputDir present, default to proto output. |
|
|
|
|
outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir); |
|
|
|
|
if (outdir != "") |
|
|
|
|
{ |
|
|
|
@ -162,52 +235,5 @@ namespace Grpc.Tools |
|
|
|
|
} |
|
|
|
|
return outputs; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Calculate part of proto path relative to root. Protoc is very picky |
|
|
|
|
// about them matching exactly, so can be we. Expect root be exact prefix |
|
|
|
|
// to proto, minus some slash normalization. |
|
|
|
|
string GetRelativeDir(string root, string proto) |
|
|
|
|
{ |
|
|
|
|
string protoDir = Path.GetDirectoryName(proto); |
|
|
|
|
string rootDir = EndWithSlash(Path.GetDirectoryName(EndWithSlash(root))); |
|
|
|
|
if (rootDir == s_dotSlash) |
|
|
|
|
{ |
|
|
|
|
// Special case, otherwise we can return "./" instead of "" below! |
|
|
|
|
return protoDir; |
|
|
|
|
} |
|
|
|
|
if (Platform.IsFsCaseInsensitive) |
|
|
|
|
{ |
|
|
|
|
protoDir = protoDir.ToLowerInvariant(); |
|
|
|
|
rootDir = rootDir.ToLowerInvariant(); |
|
|
|
|
} |
|
|
|
|
protoDir = EndWithSlash(protoDir); |
|
|
|
|
if (!protoDir.StartsWith(rootDir)) |
|
|
|
|
{ |
|
|
|
|
Log.LogWarning("Protobuf item '{0}' has the ProtoRoot metadata '{1}' " + |
|
|
|
|
"which is not prefix to its path. Cannot compute relative path.", |
|
|
|
|
proto, root); |
|
|
|
|
return ""; |
|
|
|
|
} |
|
|
|
|
return protoDir.Substring(rootDir.Length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// './' or '.\', normalized per system. |
|
|
|
|
static string s_dotSlash = "." + Path.DirectorySeparatorChar; |
|
|
|
|
|
|
|
|
|
static string EndWithSlash(string str) |
|
|
|
|
{ |
|
|
|
|
if (str == "") |
|
|
|
|
{ |
|
|
|
|
return s_dotSlash; |
|
|
|
|
} |
|
|
|
|
else if (str[str.Length - 1] != '\\' && str[str.Length - 1] != '/') |
|
|
|
|
{ |
|
|
|
|
return str + Path.DirectorySeparatorChar; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
return str; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|