代码之家  ›  专栏  ›  技术社区  ›  Simon Randy Burden

实现microsoft.build.utilities.task时,如何访问生成的各种环境变量?

  •  2
  • Simon Randy Burden  · 技术社区  · 14 年前

    实现microsoft.build.utilities.task时,如何访问生成的各种环境变量?

    我知道我可以把它作为任务XML的一部分传递进来

    <MyTask TargetPath="$(TargetPath)" />
    

    但是如果我可以在代码中访问变量,我不想强迫任务的使用者必须这样做。

    http://msdn.microsoft.com/en-us/library/microsoft.build.utilities.task.aspx

    2 回复  |  直到 14 年前
        1
  •  5
  •   Simon Randy Burden    13 年前

    我想出了办法

    public static class BuildEngineExtensions
    {
        const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public;
    
        public static IEnumerable GetEnvironmentVariable(this IBuildEngine buildEngine, string key,bool throwIfNotFound)
        {
            var projectInstance = GetProjectInstance(buildEngine);
    
            var items = projectInstance.Items
                .Where(x => string.Equals(x.ItemType, key, StringComparison.InvariantCultureIgnoreCase)).ToList();
            if (items.Count > 0)
            {
                return items.Select(x => x.EvaluatedInclude);
            }
    
    
            var properties = projectInstance.Properties
                .Where(x => string.Equals(x.Name, key, StringComparison.InvariantCultureIgnoreCase)).ToList();
            if (properties.Count > 0)
            {
                return properties.Select(x => x.EvaluatedValue);
            }
    
            if (throwIfNotFound)
            {
                throw new Exception(string.Format("Could not extract from '{0}' environmental variables.", key));
            }
    
            return Enumerable.Empty();
        }
    
        static ProjectInstance GetProjectInstance(IBuildEngine buildEngine)
        {
            var buildEngineType = buildEngine.GetType();
            var targetBuilderCallbackField = buildEngineType.GetField("targetBuilderCallback", bindingFlags);
            if (targetBuilderCallbackField == null)
            {
                throw new Exception("Could not extract targetBuilderCallback from " + buildEngineType.FullName);
            }
            var targetBuilderCallback = targetBuilderCallbackField.GetValue(buildEngine);
            var targetCallbackType = targetBuilderCallback.GetType();
            var projectInstanceField = targetCallbackType.GetField("projectInstance", bindingFlags);
            if (projectInstanceField == null)
            {
                throw new Exception("Could not extract projectInstance from " + targetCallbackType.FullName);
            }
            return (ProjectInstance)projectInstanceField.GetValue(targetBuilderCallback);
        }
    }
    

    它可以这样使用

    string targetPath = buildEngine.GetEnvironmentVariable("TargetPath", true).First();
    string intermediateAssembly = buildEngine.GetEnvironmentVariable("IntermediateAssembly", true).First();
    IEnumerable<string> referencePaths = buildEngine.GetEnvironmentVariable("ReferencePath", true);
    

    是的,这是丑陋和黑魔法,但它的工作。

        2
  •  2
  •   Julien Hoarau    14 年前

    你不可能轻易做到这一点,你也不应该这么做。任务不应该知道它的执行上下文,而应该使用它的输入参数。

    如果你真的想这样做,你需要用类似的东西重新分析项目文件。

    public override bool Execute()
    {
      string projectFile = BuildEngine.ProjectFileOfTaskNode;
    
      Engine buildEngine = new Engine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory());
    
      Project project = new Project(buildEngine);
      project.Load(projectFile);
      foreach(var o in project.EvaluatedProperties)
      {
        // Use properties
      }
    
      // Do what you want
    
      return true;
    }