owenG
home learn tableau about
divider
SDLC VS 2010 Coded UI Test Coded UI Test and Fitnesse MSBuild 4.0 MSBuild and IronPython MSBuild and IronPython - TFS checkins MSBuild and IronPython - Custom SQL Data








previous next

IronPython Class Factory for MSBuild 4.0 Part 3


Example 2: PyCombinePath task, get IronPython and the CLR involved

Next example illustrates using IronPython and the ability to communicate directly with the .Net runtime, in this case to do a simple System.IO.Path.Combine:

.targets
  <!-- Task: PyCombinePath, use IronPython to combine paths via System.IO.Path -->
  <UsingTask TaskName="PyCombinePath"  TaskFactory="PythonClassFactory" 
        AssemblyFile="..\_compiled\PythonClassFactory.dll" >
    <ParameterGroup>
      <inFirstPath ParameterType="System.String" Required="true" />
      <inSecondPath ParameterType="System.String" Required="true" />
      <outCombinedPath1 Output="true" />
      <outCombinedPath2 Output="true" />
    </ParameterGroup>

    <Task>
      <![CDATA[
from System.IO import Path
outCombinedPath1 = Path.Combine(inFirstPath, inSecondPath)

class FileInformation(object): 
    def __init__(self): 
        self.fullPath = Path.Combine(inFirstPath, inSecondPath)
        self.fileName = Path.GetFileName(self.fullPath)
 
    def PrintFileInfo(self): 
        print 'Full path: ', self.fullPath, '\nFile name: ', self.fileName

myFile = FileInformation()
myFile.PrintFileInfo()
outCombinedPath2 = myFile.fullPath
      ]]>
    </Task>
  </UsingTask>

  <PropertyGroup>
    <inFirstPathValue>C:\source</inFirstPathValue>
    <inSecondPathValue>subFolder1\someFile.txt</inSecondPathValue>
  </PropertyGroup>

  <Target Name="PyTarget2" >
    <PyCombinePath inFirstPath="$(inFirstPathValue)" inSecondPath="$(inSecondPathValue)" >
      <Output PropertyName="localProperty1" TaskParameter="outCombinedPath1"  />
      <Output PropertyName="localProperty2" TaskParameter="outCombinedPath2"  />
    </PyCombinePath>
    <Message Text="First path: $(inFirstPathValue)  ::  Second path: $(inSecondPathValue)"
         Importance="High" />
    <Message Text="Path from simple Path.Combine: $(localProperty1)" Importance="High" />
    <Message Text="Path from custom FileInformation class: $(localProperty2)" Importance="High" />
  </Target>

Three parent elements again:

1) UsingTask element

Two string parameters going in and two coming out. The two output values should be the same but are populated using slightly different methodologies. The CDATA holds an IronPython snippet that is somewhat more complicated than the first example. Right off the bat IronPython knows about some of the most common .Net namespaces like System.IO, allowing me to directly import (System.IO).Path. To access other .Net libraries I would have needed to insert an 'import clr' line, followed by one or more clr.AddReference calls. The first output parameter, outCombinedPath1, is assigned the result of a .Net Path.Combine on the two input parameters. Then a very simple FileInformation class is defined and initialized with a .fullPath attribute set to the result of Path.Combine on inFirstPath and inSecondPath parameters. An instance of this class is then created and the value of .fullPath assigned to the second output parameter, outCombinedPath2.

2) PropertyGroup element

Provides default values for two path values. Overridden in this example via the command line call from MSBuild_PythonTargets, which sets first and second properties to "C:\temp" and "logfile.log" respectively.

3) Target element

PyTarget2 is among the targets called by MSBuild_PythonTargets. Tasks within include the custom PyCombinePath, with two parameters passed in and two passed out, values for which are then assigned to local properties. Three Message tasks perform the job of logging the current values of all related variables.


Queue a build, review contents of log file:

log
 PyTarget2:
   First path: C:\temp  ::  Second path: logfile.log
   Path from simple Path.Combine: C:\temp\logfile.log
   Path from custom FileInformation class: C:\temp\logfile.log


divider element

Example 3: PyJoinPath task, 'combine' paths again but use standard Python library

Again, combining two path values into a valid full path, taking care of things like making sure there is only a single path separator character between the joined sections. Use strictly Python libraries:

.targets
  <!-- Task: PyJoinPath, use Python to join paths via os.path.join -->
  <UsingTask TaskName="PyJoinPath"  TaskFactory="PythonClassFactory" 
        AssemblyFile="..\_compiled\PythonClassFactory.dll" >
    <ParameterGroup>
      <inFirstPath ParameterType="System.String" Required="true" />
      <inSecondPath ParameterType="System.String" Required="true" />
      <outJoinedPath Output="true" />
    </ParameterGroup>

    <Task>
      <![CDATA[
import sys
sys.path.append(r'\\localhost\drops\_Python\Lib')
import os
outJoinedPath = os.path.join(inFirstPath, inSecondPath)
      ]]>
    </Task>
  </UsingTask>

  <Target Name="PyTarget3" >
    <PyJoinPath inFirstPath="$(inFirstPathValue)" inSecondPath="$(inSecondPathValue)" >
      <Output PropertyName="localProperty3" TaskParameter="outJoinedPath"  />
    </PyJoinPath>
    <Message Text="First path: $(inFirstPathValue)  ::  Second path: $(inSecondPathValue)" 
        Importance="High" />
    <Message Text="Path from simple path.join: $(localProperty3)" Importance="High" />
  </Target>

Only two main elements now, since PyTarget3 will use MSBuild properties discussed in Example 2:

1) UsingTask element

Same parameter setup as with IronPython PyCombinePath but with only one output parameter. The new Task body code illustrates how to use additional Python libraries and presupposes the existence of those library files on the target build server, specifically in a (local) shared \drops folder. To set that up manually, I would have needed to copy the Lib folder from the original IronPython installation (e.g. C:\Program Files (x86)\IronPython 2.6 for .NET 4.0\Lib) and place it in \\localhost\drops\_Python\ before kicking off the build. Then at build runtime the PyJoinPath task will load the 'os' Python library from that directory and use its .path.join() method to combine the two paths and store in outJoinedPath output parameter.

2) Target element

Similar structure as that of earlier PyTarget2 but there is only one output parameter, storing the result of the single code path.


The myPythonTargetsLog.log from a new build includes expected data:

log
 PyTarget3:
   First path: C:\temp  ::  Second path: logfile.log
   Path from simple path.join: C:\temp\logfile.log

Next, something a little bit more complicated...



previous next