Setting Solution Filename on OutDir - f#

I have a file set which is a scan for all of the *.sln files in my source tree. There is currently 4 folders
With the masterParam I am passing in the GenerateProjectSpecificOutputFolder and setting the outdir
What I am looking to do is for every sln that is being built with the MSBuild to append the solution name as part of the outDir.
I am using F# FAKE
Below is from the Target Build.
let masterParam = [
("Configuration",buildMode);
("GenerateProjectSpecificOutputFolder","true");
("OutDir",("drop/<solutionName>");
("BuildInParallel", "false");
]
// compile all projects below src/app/
MSBuild buildDir "Build" masterParam appReferences
|> Log "Build-Output: "

I don't think you can do this in any "automatic" way, but since FAKE lets you write arbitrary F# code, you can iterate over the projects and run MSBuild on individual projects.
Something like this should do the trick (you might need to open System.IO):
for proj in appReferences do
let name = Path.GetFileNameWithoutExtension(proj)
let masterParam = [
("Configuration",buildMode);
("GenerateProjectSpecificOutputFolder","true");
("OutDir",("drop/" + name);
("BuildInParallel", "false");
]
MSBuild buildDir "Build" masterParam [proj]
|> Log "Build-Output: "

Related

Substitutions and Java library lifecycle

I've got a Java project I'm converting to Bazel.
As is typical with Java projects, there are property files with placeholders that need to be resolved/substituted at build time.
Some of the values can be hardcoded in a BUILD or BZL file:
BUILD_PROPERTIES = { "pom.version": "1.0.0", "pom.group.id": "com.mygroup"}
Some of the variables are "stamps" (e.g. BUILD_TIMESTAMP, GIT_REVISION, etc): The source for these variables are volatile-status.txt and stable-status.txt
I must generate a POM for publish, so I use #bazel_common//tools/maven:pom_file in BUILD
(assume that I need ALL the values described above for my pom template):
_local_build_properties = {}
_local_build_properties.update(BUILD_PROPERTIES)
# somehow add workspace status properties?
# add / override
_local_build_properties.update({
"pom.project.name": "my-submodule",
"pom.project.description": "My submodule description",
"pom.artifact.id": "my-submodule",
})
# Variable placeholders in the pom template are wrapped with {}
_pom_substitutions = { '{'+k+'}':v for (k,v) in _local_build_properties.items()}
pom_file(
name = "my_submodule_pom",
targets = [
"//my-submodule",
],
template_file = "//:pom_template.xml",
substitutions = _pom_substitutions,
)
So, my questions are:
How do I get key-value pairs from volatile/stable -status.txt into the
dictionary I need for pom_file.substitutions?
pom_file depends on java_library so that it can write its dependencies
into the POM. How do I update the jar generated by java_library with the
pom?
Once I have the pom and the updated jar containing the pom, how do I publish to a Maven repo?
When I look at existing code, for example rules_docker, it seems that the implementation always bails to a local executable (shell | python | go) to do the real work of substitution, jar manipulation and image publication. Am I trying to do too much in BUILD and BZL files? Should I be thinking, "Ultimately, what do I need to pass to local shell/python/go scripts to get real build work done?
(Answered on bazel-discuss group)
Hi,
You can't get these values from Starlark. You need a genrule to read the stable/volatile files and do the substitutions using an
external tool like 'sed'.
A file cannot be both an input and output of an action, i.e. you can't update the .jar from which you generate the pom. The action has
to produce a new .jar file.
I don't know -- how would you publish outside of Bazel, is there a tool to do so? Can you write a genrule / Starlark rule to wrap this
tool?
Cheers, László

CopyRecursive not working in FAKE script

I have the following target defined in my FAKE build script. It is being executed. I have verified this usuing trace statements. There is a large file structure in the folder at "MyWebApp". I get no output at the destination folder. What could I be doing wrong?
Target "Push" (fun _ ->
let dir= FileSystemHelper.currentDirectory
let src = dir+ #"\deploy\" + version + #"\MyWebApp"
let dest = #"c:\windows\temp\deploy\" + version
CopyRecursive src dest |> ignore
()
Thanks
Jim
If you look at the definition of CopyRecursive
let CopyRecursive dir outputDir = copyRecursive (directoryInfo dir) (directoryInfo outputDir)
you may notice it represents the partially evaluated (and, by the way, marked at the moment as obsolete) function copyRecursive having signature bool->string list.
Your script sends this partially evaluated function value to ignore and, apparently, nothing happens as the result.
In order to allow copyRecursive to do its work just provide the missing third input argument of type bool that defines if the function should override files with the same names in the target directory. Assuming this is the behavior that you want just change the correspondent line in your script by
CopyRecursive src dest true |> ignore
This will allow copyRecursive to perform its side-effect copying magic returning the list of names of copied files, that you may discard with ignore.

How to read attribute value from xml file - FAKE F#MAKE

Hi I am having an XML file , I want to read value of a particular attribute from XML file , how will I do this in FAKE . Please Help , I am new to F# and FAKE.And I just figured it out on fake documentation page and found that I can use XMLRead function of XMLHelper Class whose description is available at
https://github.com/fsharp/FAKE/blob/master/src/app/FakeLib/XMLHelper.fs#L14-14
But I could not understand how to do this , as there are no examples as such .
I have a huge XML file but for simplicity I am mentioning a piece of that file. XML File is as follows :
<version>
<major number="2">
<minor>1</minor>
<build>1</build>
<revised>1</revised>
</major>
</version>
Please tell me , how to read values from mentioned attributes .
If you look back a few posts you can find a related question.
The short answer is that in my 'build.fsx' file I can do somthing like this:
// Build the main module with MSBuild
Target "BuildMain" (fun _ ->
for s in XMLHelper.XMLRead true "./myxml.xml" "" "" "/version/major/minor"
do trace s
!! "./Kapoin_03_Main/Kapoin_03_Main.fsproj"
|> MSBuild buildDir "Build" buildProps
|> Log "Main build output: " )
That will in this case just write "1" in the console when you build.
Edit: If you are using a different target you may want to do something along the lines of the following to store a value as a variable:
let minver =
XMLHelper.XMLRead
true "./myxml.xml" "" "" "/version/major/minor"
|> Seq.head

Sharing const variables across FAKE fsx scripts

Is there any way to share a variable by including a fsx script within another fsx script.
e.g script buildConsts.fsx contains
let buildDir = "./build/"
I want to reference this in other build scripts e.g.
#load #".\buildConsts.fsx"
let testDlls = !! (buildDir + "*Test*.dll")
When I attempt to run the script the 'buildDir' variable the script fails to compile.
This is a fairly common approach that is used with tools such as MSBuild and PSAKE to modularise scripts. Is this the correct approach with FAKE ?
What you're doing should work - what exactly is the error message that you're getting?
I suspect that the problem is that F# automatically puts the contents of a file in a module and you need to open the module before you can access the constants. The module is named based on the file name, so in your case buildConsts.fsx will generate a module named BuildConsts. You should be able to use it as follows:
#load #".\buildConsts.fsx"
open BuildConsts
let testDlls = !! (buildDir + "*Test*.dll")
You can also add an explicit module declaration to buildconsts.fsx, which is probably a better idea as it is less fragile (won't change when you rename the file):
moule BuildConstants
let buildDir = "./build/"

How to Move TFS 2010 Build Definition between Projects?

I have some TFS 2010 build definitions that were created under ProjectX. Now the source code has moved to a folder subordinate to ProjectY. How can I move the build definitions to ProjectY so they display under the Builds node of the Team Explorer for ProjectY?
I don't think there is something out of the box to copy the build definitions from one project to another. However you should be able to do it using the TFS API. You will want to move the build process templates, which is what Pete is referring to, into the Build Process Template folder for the new project. After that you would do something like:
var server = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("<server uri>"));
IBuildServer buildServer = server.GetService<IBuildServer>();
var buildDetails = buildServer.QueryBuildDefinitions("Project X");
foreach(var build in buildDetails)
{
var buildDefinition = buildServer.CreateBuildDefinition("Project Y");
buildDefinition.Name = "Copy of " + build.Name;
buildDefinition.BuildController = build.BuildController;
// This finds the template to use
buildDefinition.Process = buildServer.QueryProcessTemplates("Project Y")[0];
buildDefinition.ProcessParameters = build.ProcessParameters;
buildDefinition.Save();
}
A couple of things to note. You will need deal with converting the workspace mappings from one project to the other. You will also need to change the buildDefinition.Process line to find the specific template.
A powershell version of Sean's answer above
# Copy some TFS build defintions from one project collection to another
[void][Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")
[void][Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")
$tfsUrl = "http://lontfs_at:8080/tfs/XXX"
$tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($tfsUrl)
$vcs = $tfs.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$buildServer = $tfs.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$buildDetails = $buildServer.QueryBuildDefinitions("Project X");
foreach( $build in $buildDetails)
{
$buildDefinition = $buildServer.CreateBuildDefinition("Project Y");
$buildDefinition.Name = "Copy of " + $build.Name;
$buildDefinition.BuildController = $build.BuildController;
# This finds the template to use
$buildDefinition.Process = $buildServer.QueryProcessTemplates("Project Y")[0];
$buildDefinition.ProcessParameters = $build.ProcessParameters;
$buildDefinition.Save();
}
In VS2010, the TFS Power Tools can move a build definition from one project to another as demonstrated in the 2nd answer in this link: Is it possible to Export TFS 2010 Build Definitions?, and as shown below.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>tfpt
builddefinition /collection:"http://ServerX:8080/tfs/Collection X" /clone "Project 1\Build
Definition X" "Project 2\Copy of Build Definition X"
The TFS Power Tools for VS2010 can be downloaded from: http://visualstudiogallery.msdn.microsoft.com/c255a1e4-04ba-4f68-8f4e-cd473d6b971f
Uggly but very efficient way to move (not to duplicate) only one or two Build Definitions:
Open SQL Server Management Studio,
Open your Collection DB
Edit the table tbl_BuildDefinition
Replace the current GroupId with the target Team Project's GroupId
That's it ;)
To determine the GroupId of the target Team Project, simply find any BuildDefinition of that Team Project in tbl_BuildDefinition and take its GroupId.
For sure, you have next to update the BuildDefinition's workspace, Items to build, ... to use the server path of the new Team Project !
If you get an error like "GroupItem cannot be move accross Team Project" when updating your BuildDefinition, it was most probably already open before updating the DB. Close and reopen it.
If you don't intend to repeat this operation too often, it's IMO the fastest solution.
V.
Build definitions are just another source controled file in TFS, you should be able to open the build definition in ProjectX and save it as a new file to projectY's build definitions folder.
Edit
In the above post I am assuming ProjectX and ProjectY are TFS projects, in which case their workflow build definition(s) are simply in the builddfinitions folder of their respective source control roots.
Sean's answer helped me out, but in my case, I have only one repository for my build templates and custom activities assemblies. So I don't need to edit settings, I just want to copy one build definition from TFS Project A to TFS Project B.
Here is my 'short' version of Sean's code:
var server = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("TFS URL"));
IBuildServer buildServer = server.GetService<IBuildServer>();
var buildDetails = buildServer.QueryBuildDefinitions("Proj_A");
foreach(var build in buildDetails)
{
var buildDefinition = buildServer.CreateBuildDefinition("Proj_B");
buildDefinition.CopyFrom(build);
buildDefinition.Save();
}

Resources