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