Created
August 18, 2012 15:19
-
-
Save nrolland/3387537 to your computer and use it in GitHub Desktop.
Script for loading dependencies in fsx file from a solution/project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This script generates | |
//a file named __project.fsx, for each proejct which can be #load "__project.fsx" in script intending to use the same dependency graph as the code in VS | |
//a file named __solmerged.fsx, at the solution root which can be #load "__solmerged.fsx" in script intending to use the same dependency graph as the code in VS | |
//In both cases, this enforce that a script compiling in VS should work from within FSI | |
#if INTERACTIVE | |
#r "System.Xml" | |
#r "System.Xml.Linq" | |
#endif | |
open System | |
open System.IO | |
open System.Xml.Linq | |
let rec findsolutiondir (p:DirectoryInfo) = if (p.GetFiles("*.sln") |> Array.length > 0) then p | |
else findsolutiondir p.Parent | |
let root = findsolutiondir (DirectoryInfo(__SOURCE_DIRECTORY__)) | |
type Dependency = | |
| GacLocation of String | |
| ProjectFile of DirectoryInfo | |
| DllFile of DirectoryInfo | |
let refsforaproject (dirproject:DirectoryInfo) = [ | |
for fsProjFile in dirproject.GetFiles("*.fsproj") do | |
let getElemName name = XName.Get(name, "http://schemas.microsoft.com/developer/msbuild/2003") | |
let getElemValue name (parent:XElement) = | |
let elem = parent.Element(getElemName name) | |
if elem = null || String.IsNullOrEmpty elem.Value then None else Some(elem.Value) | |
let getAttrValue name (elem:XElement) = | |
let attr = elem.Attribute(XName.Get name) | |
if attr = null || String.IsNullOrEmpty attr.Value then None else Some(attr.Value) | |
let (|??) (option1: 'a Option) option2 = | |
if option1.IsSome then option1 else option2 | |
let fsProjFile = dirproject.GetFiles("*.fsproj") |> Seq.head | |
let fsProjXml = XDocument.Load fsProjFile.FullName | |
let refspath = | |
fsProjXml.Document.Descendants(getElemName "Reference") | |
|> Seq.choose (fun elem -> getElemValue "HintPath" elem) | |
|> Seq.map (fun ref -> //if dirproject.Name.Contains("divsharp") then printfn "fulname : %A" ( DirectoryInfo(dirproject.FullName + "\\" + ref).FullName) | |
DllFile(DirectoryInfo(dirproject.FullName + "\\" + ref)) ) | |
//("#r ", true, DirectoryInfo(dirproject.FullName + "\\" + ref).FullName) ) | |
let refsgac = | |
fsProjXml.Document.Descendants(getElemName "Reference") | |
|> Seq.choose (fun elem -> if (getElemValue "HintPath" elem).IsNone then getAttrValue "Include" elem else None) | |
|> Seq.map (fun ref -> GacLocation(ref)) | |
let fsFiles = | |
fsProjXml.Document.Descendants(getElemName "Compile") | |
|> Seq.choose (fun elem -> //printfn "%A" elem | |
getAttrValue "Include" elem) | |
|> Seq.map (fun fsFile -> ProjectFile( DirectoryInfo(dirproject.FullName + "\\" + fsFile))) | |
//#load ", true, DirectoryInfo(dirproject.FullName + "\\" + fsFile).FullName)) | |
let projDll = | |
fsProjXml.Document.Descendants(getElemName "ProjectReference") | |
|> Seq.choose (fun elem -> getAttrValue "Include" elem) | |
|> Seq.map (fun projFile -> let refedPrjDir = DirectoryInfo(dirproject.FullName + "\\" + projFile).Parent | |
//("#r " , true, refedPrjDir.FullName + "\\bin\\Debug\\" + refedPrjDir.Name + ".dll")) //refedPrjDir.Name -> assembly name | |
DllFile(DirectoryInfo(refedPrjDir.FullName + "\\bin\\Debug\\" + refedPrjDir.Name + ".dll"))) | |
yield! refspath | |
yield! refsgac | |
yield! projDll | |
yield! fsFiles | |
] | |
let toabsolute root rel = DirectoryInfo(root + rel).FullName | |
let f n = String.concat "." (Array.create (n+1) ".\\") | |
let writerelative root path = | |
let rec intwriterelative (root:DirectoryInfo) (path:DirectoryInfo) n = | |
if path.FullName.Contains(root.FullName + "\\" ) then f n + path.FullName.Remove(0,root.FullName.Length + 1) //most common acestor = root | |
else intwriterelative root.Parent path (n+1) | |
intwriterelative root path 0 | |
let getprojectdir (root:DirectoryInfo) = | |
let rec getdirs (root:DirectoryInfo) = seq { | |
yield! root.GetDirectories() |> Array.filter(fun f -> f.GetFiles("*.fsproj") |> Array.length > 0 ) | |
yield! root.GetDirectories() |> Array.map(fun d -> getdirs d) |> Seq.concat} | |
getdirs root | |
let orderKey = function | GacLocation(n) -> "A" + n | |
| ProjectFile(n) -> "C" + n.FullName | |
| DllFile(n) -> "B" + n.FullName | |
let tostrings rootwrite (dependencies) = | |
dependencies |> Seq.distinct | |
|> Seq.map (fun dep -> match dep with | |
| GacLocation(n) -> "#r \"" + n + "\"" | |
| ProjectFile(n) -> "#load @\"" + writerelative rootwrite n + "\"" | |
| DllFile(n) -> "#r @\"" + writerelative rootwrite n + "\"") | |
do | |
let projects = getprojectdir root |> Seq.map(fun p -> p, refsforaproject p) | |
projects |> Seq.iter (fun (p,ds) -> File.WriteAllLines(p.FullName+ "\\" + "__project.fsx", tostrings p (ds |> Seq.sortBy orderKey))) | |
let s = projects |> Seq.map ( fun (p, dep) -> seq{ yield sprintf "//project %A" p.Name | |
yield! dep |> Seq.sortBy orderKey |> tostrings root } ) | |
|> Seq.concat | |
File.WriteAllLines(root.FullName+ "\\" + "__solmerged.fsx", s) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment