1*cc02d7e2SAndroid Build Coastguard Worker #region Copyright notice and license 2*cc02d7e2SAndroid Build Coastguard Worker 3*cc02d7e2SAndroid Build Coastguard Worker // Copyright 2018 gRPC authors. 4*cc02d7e2SAndroid Build Coastguard Worker // 5*cc02d7e2SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 6*cc02d7e2SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 7*cc02d7e2SAndroid Build Coastguard Worker // You may obtain a copy of the License at 8*cc02d7e2SAndroid Build Coastguard Worker // 9*cc02d7e2SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 10*cc02d7e2SAndroid Build Coastguard Worker // 11*cc02d7e2SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 12*cc02d7e2SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 13*cc02d7e2SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*cc02d7e2SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 15*cc02d7e2SAndroid Build Coastguard Worker // limitations under the License. 16*cc02d7e2SAndroid Build Coastguard Worker 17*cc02d7e2SAndroid Build Coastguard Worker #endregion 18*cc02d7e2SAndroid Build Coastguard Worker 19*cc02d7e2SAndroid Build Coastguard Worker using System.Collections.Generic; 20*cc02d7e2SAndroid Build Coastguard Worker using Microsoft.Build.Framework; 21*cc02d7e2SAndroid Build Coastguard Worker using Microsoft.Build.Utilities; 22*cc02d7e2SAndroid Build Coastguard Worker 23*cc02d7e2SAndroid Build Coastguard Worker namespace Grpc.Tools 24*cc02d7e2SAndroid Build Coastguard Worker { 25*cc02d7e2SAndroid Build Coastguard Worker public class ProtoCompilerOutputs : Task 26*cc02d7e2SAndroid Build Coastguard Worker { 27*cc02d7e2SAndroid Build Coastguard Worker /// <summary> 28*cc02d7e2SAndroid Build Coastguard Worker /// Code generator. Currently supported are "csharp", "cpp". 29*cc02d7e2SAndroid Build Coastguard Worker /// </summary> 30*cc02d7e2SAndroid Build Coastguard Worker [Required] 31*cc02d7e2SAndroid Build Coastguard Worker public string Generator { get; set; } 32*cc02d7e2SAndroid Build Coastguard Worker 33*cc02d7e2SAndroid Build Coastguard Worker /// <summary> 34*cc02d7e2SAndroid Build Coastguard Worker /// All Proto files in the project. The task computes possible outputs 35*cc02d7e2SAndroid Build Coastguard Worker /// from these proto files, and returns them in the PossibleOutputs list. 36*cc02d7e2SAndroid Build Coastguard Worker /// Not all of these might be actually produced by protoc; this is dealt 37*cc02d7e2SAndroid Build Coastguard Worker /// with later in the ProtoCompile task which returns the list of 38*cc02d7e2SAndroid Build Coastguard Worker /// files actually produced by the compiler. 39*cc02d7e2SAndroid Build Coastguard Worker /// </summary> 40*cc02d7e2SAndroid Build Coastguard Worker [Required] 41*cc02d7e2SAndroid Build Coastguard Worker public ITaskItem[] Protobuf { get; set; } 42*cc02d7e2SAndroid Build Coastguard Worker 43*cc02d7e2SAndroid Build Coastguard Worker /// <summary> 44*cc02d7e2SAndroid Build Coastguard Worker /// All Proto files in the project. A patched copy of all items from 45*cc02d7e2SAndroid Build Coastguard Worker /// Protobuf that might contain updated OutputDir and GrpcOutputDir 46*cc02d7e2SAndroid Build Coastguard Worker /// attributes. 47*cc02d7e2SAndroid Build Coastguard Worker /// </summary> 48*cc02d7e2SAndroid Build Coastguard Worker [Output] 49*cc02d7e2SAndroid Build Coastguard Worker public ITaskItem[] PatchedProtobuf { get; set; } 50*cc02d7e2SAndroid Build Coastguard Worker 51*cc02d7e2SAndroid Build Coastguard Worker /// <summary> 52*cc02d7e2SAndroid Build Coastguard Worker /// Output items per each potential output. We do not look at existing 53*cc02d7e2SAndroid Build Coastguard Worker /// cached dependency even if they exist, since file may be refactored, 54*cc02d7e2SAndroid Build Coastguard Worker /// affecting whether or not gRPC code file is generated from a given proto. 55*cc02d7e2SAndroid Build Coastguard Worker /// Instead, all potentially possible generated sources are collected. 56*cc02d7e2SAndroid Build Coastguard Worker /// It is a wise idea to generate empty files later for those potentials 57*cc02d7e2SAndroid Build Coastguard Worker /// that are not actually created by protoc, so the dependency checks 58*cc02d7e2SAndroid Build Coastguard Worker /// result in a minimal recompilation. The Protoc task can output the 59*cc02d7e2SAndroid Build Coastguard Worker /// list of files it actually produces, given right combination of its 60*cc02d7e2SAndroid Build Coastguard Worker /// properties. 61*cc02d7e2SAndroid Build Coastguard Worker /// Output items will have the Source metadata set on them: 62*cc02d7e2SAndroid Build Coastguard Worker /// <ItemName Include="MyProto.cs" Source="my_proto.proto" /> 63*cc02d7e2SAndroid Build Coastguard Worker /// </summary> 64*cc02d7e2SAndroid Build Coastguard Worker [Output] 65*cc02d7e2SAndroid Build Coastguard Worker public ITaskItem[] PossibleOutputs { get; private set; } 66*cc02d7e2SAndroid Build Coastguard Worker Execute()67*cc02d7e2SAndroid Build Coastguard Worker public override bool Execute() 68*cc02d7e2SAndroid Build Coastguard Worker { 69*cc02d7e2SAndroid Build Coastguard Worker var generator = GeneratorServices.GetForLanguage(Generator, Log); 70*cc02d7e2SAndroid Build Coastguard Worker if (generator == null) 71*cc02d7e2SAndroid Build Coastguard Worker { 72*cc02d7e2SAndroid Build Coastguard Worker // Error already logged, just return. 73*cc02d7e2SAndroid Build Coastguard Worker return false; 74*cc02d7e2SAndroid Build Coastguard Worker } 75*cc02d7e2SAndroid Build Coastguard Worker 76*cc02d7e2SAndroid Build Coastguard Worker // Get language-specific possible output. The generator expects certain 77*cc02d7e2SAndroid Build Coastguard Worker // metadata be set on the proto item. 78*cc02d7e2SAndroid Build Coastguard Worker var possible = new List<ITaskItem>(); 79*cc02d7e2SAndroid Build Coastguard Worker var patched = new List<ITaskItem>(); 80*cc02d7e2SAndroid Build Coastguard Worker foreach (var proto in Protobuf) 81*cc02d7e2SAndroid Build Coastguard Worker { 82*cc02d7e2SAndroid Build Coastguard Worker var patchedProto = generator.PatchOutputDirectory(proto); 83*cc02d7e2SAndroid Build Coastguard Worker patched.Add(patchedProto); 84*cc02d7e2SAndroid Build Coastguard Worker 85*cc02d7e2SAndroid Build Coastguard Worker var outputs = generator.GetPossibleOutputs(patchedProto); 86*cc02d7e2SAndroid Build Coastguard Worker foreach (string output in outputs) 87*cc02d7e2SAndroid Build Coastguard Worker { 88*cc02d7e2SAndroid Build Coastguard Worker var ti = new TaskItem(output); 89*cc02d7e2SAndroid Build Coastguard Worker ti.SetMetadata(Metadata.Source, patchedProto.ItemSpec); 90*cc02d7e2SAndroid Build Coastguard Worker possible.Add(ti); 91*cc02d7e2SAndroid Build Coastguard Worker } 92*cc02d7e2SAndroid Build Coastguard Worker } 93*cc02d7e2SAndroid Build Coastguard Worker 94*cc02d7e2SAndroid Build Coastguard Worker PatchedProtobuf = patched.ToArray(); 95*cc02d7e2SAndroid Build Coastguard Worker PossibleOutputs = possible.ToArray(); 96*cc02d7e2SAndroid Build Coastguard Worker 97*cc02d7e2SAndroid Build Coastguard Worker return !Log.HasLoggedErrors; 98*cc02d7e2SAndroid Build Coastguard Worker } 99*cc02d7e2SAndroid Build Coastguard Worker }; 100*cc02d7e2SAndroid Build Coastguard Worker } 101