diff --git a/build.fsx b/build.fsx index e6bd840..1fef632 100644 --- a/build.fsx +++ b/build.fsx @@ -2,16 +2,20 @@ // FAKE build script // -------------------------------------------------------------------------------------- -#r @"packages/build/FAKE/tools/FakeLib.dll" -open Fake -open Fake.Git -open Fake.AssemblyInfoFile -open Fake.ReleaseNotesHelper -open Fake.UserInputHelper +#r "paket: groupref FakeBuild //" + +#load "./.fake/build.fsx/intellisense.fsx" -open System open System.IO -open System.Diagnostics +open Fake.Core +open Fake.Core.TargetOperators +open Fake.DotNet +open Fake.IO +open Fake.IO.FileSystemOperators +open Fake.IO.Globbing.Operators +open Fake.DotNet.Testing +open Fake.Tools +open Fake.Api // -------------------------------------------------------------------------------------- // START TODO: Provide project-specific details below @@ -36,7 +40,7 @@ let summary = "A data science framework for analyzing Chrome browser extensions. let description = "A data science framework for analyzing Chrome browser extensions." // List of author names (for NuGet package) -let authors = [ "Achim D. Brucker" ] +let author = "Achim D. Brucker" // Tags for your project (for NuGet package) let tags = "ChromeExtension DataScience BrowserSecurity" @@ -47,8 +51,8 @@ let solutionFile = "LogicalHacking.ExtensionDsLab.sln" // Default target configuration let configuration = "Release" -// Pattern specifying assemblies to be tested using NUnit -let testAssemblies = "tests/**/bin" configuration "*Tests*.dll" +// Pattern specifying assemblies to be tested using Expecto +let testAssemblies = "tests/**/bin" configuration "**" "*Tests.exe" // Git configuration (used for publishing documentation in gh-pages branch) // The profile where the project is posted @@ -59,14 +63,16 @@ let gitHome = sprintf "%s/%s" "https://git.logicalhacking.com" gitOwner let gitName = "ExtensionDsLab" // The url for the raw files hosted -let gitRaw = environVarOrDefault "gitRaw" "https://git.logicalhacking.com/BrowserSecurity" +let gitRaw = Environment.environVarOrDefault "gitRaw" "https://raw.githubusercontent.com/BrowserSecurity" + +let website = "/ExtensionDsLab" // -------------------------------------------------------------------------------------- // END TODO: The rest of the file includes standard build steps // -------------------------------------------------------------------------------------- // Read additional information from the release notes document -let release = LoadReleaseNotes "RELEASE_NOTES.md" +let release = ReleaseNotes.load "RELEASE_NOTES.md" // Helper active pattern for project types let (|Fsproj|Csproj|Vbproj|Shproj|) (projFileName:string) = @@ -78,30 +84,30 @@ let (|Fsproj|Csproj|Vbproj|Shproj|) (projFileName:string) = | _ -> failwith (sprintf "Project file %s not supported. Unknown project type." projFileName) // Generate assembly info files with the right version & up-to-date information -Target "AssemblyInfo" (fun _ -> +Target.create "AssemblyInfo" (fun _ -> let getAssemblyInfoAttributes projectName = - [ Attribute.Title (projectName) - Attribute.Product project - Attribute.Description summary - Attribute.Version release.AssemblyVersion - Attribute.FileVersion release.AssemblyVersion - Attribute.Configuration configuration ] + [ AssemblyInfo.Title (projectName) + AssemblyInfo.Product project + AssemblyInfo.Description summary + AssemblyInfo.Version release.AssemblyVersion + AssemblyInfo.FileVersion release.AssemblyVersion + AssemblyInfo.Configuration configuration ] let getProjectDetails projectPath = - let projectName = System.IO.Path.GetFileNameWithoutExtension(projectPath) + let projectName = Path.GetFileNameWithoutExtension(projectPath) ( projectPath, projectName, - System.IO.Path.GetDirectoryName(projectPath), + Path.GetDirectoryName(projectPath), (getAssemblyInfoAttributes projectName) ) !! "src/**/*.??proj" |> Seq.map getProjectDetails - |> Seq.iter (fun (projFileName, projectName, folderName, attributes) -> + |> Seq.iter (fun (projFileName, _, folderName, attributes) -> match projFileName with - | Fsproj -> CreateFSharpAssemblyInfo (folderName "AssemblyInfo.fs") attributes - | Csproj -> CreateCSharpAssemblyInfo ((folderName "Properties") "AssemblyInfo.cs") attributes - | Vbproj -> CreateVisualBasicAssemblyInfo ((folderName "My Project") "AssemblyInfo.vb") attributes + | Fsproj -> AssemblyInfoFile.createFSharp (folderName "AssemblyInfo.fs") attributes + | Csproj -> AssemblyInfoFile.createCSharp ((folderName "Properties") "AssemblyInfo.cs") attributes + | Vbproj -> AssemblyInfoFile.createVisualBasic ((folderName "My Project") "AssemblyInfo.vb") attributes | Shproj -> () ) ) @@ -109,63 +115,57 @@ Target "AssemblyInfo" (fun _ -> // Copies binaries from default VS location to expected bin folder // But keeps a subdirectory structure for each project in the // src folder to support multiple project outputs -Target "CopyBinaries" (fun _ -> +Target.create "CopyBinaries" (fun _ -> !! "src/**/*.??proj" -- "src/**/*.shproj" - |> Seq.map (fun f -> ((System.IO.Path.GetDirectoryName f) "bin" configuration, "bin" (System.IO.Path.GetFileNameWithoutExtension f))) - |> Seq.iter (fun (fromDir, toDir) -> CopyDir toDir fromDir (fun _ -> true)) + |> Seq.map (fun f -> ((Path.getDirectory f) "bin" configuration, "bin" (Path.GetFileNameWithoutExtension f))) + |> Seq.iter (fun (fromDir, toDir) -> Shell.copyDir toDir fromDir (fun _ -> true)) ) // -------------------------------------------------------------------------------------- // Clean build results -let vsProjProps = -#if MONO - [ ("DefineConstants","MONO"); ("Configuration", configuration) ] -#else - [ ("Configuration", configuration); ("Platform", "Any CPU") ] -#endif +let buildConfiguration = DotNet.Custom <| Environment.environVarOrDefault "configuration" configuration -Target "Clean" (fun _ -> - !! solutionFile |> MSBuildReleaseExt "" vsProjProps "Clean" |> ignore - CleanDirs ["bin"; "temp"; "docs"] +Target.create "Clean" (fun _ -> + Shell.cleanDirs ["bin"; "temp"] +) + +Target.create "CleanDocs" (fun _ -> + Shell.cleanDirs ["docs"] ) // -------------------------------------------------------------------------------------- // Build library & test project -Target "Build" (fun _ -> - !! solutionFile - |> MSBuildReleaseExt "" vsProjProps "Rebuild" - |> ignore +Target.create "Build" (fun _ -> + solutionFile + |> DotNet.build (fun p -> + { p with + Configuration = buildConfiguration }) ) // -------------------------------------------------------------------------------------- // Run the unit tests using test runner -Target "RunTests" (fun _ -> +Target.create "RunTests" (fun _ -> !! testAssemblies - |> NUnit (fun p -> - { p with - DisableShadowCopy = true - TimeOut = TimeSpan.FromMinutes 20. - OutputFile = "TestResults.xml" }) + |> Expecto.run id ) - // -------------------------------------------------------------------------------------- // Build a NuGet package -Target "NuGet" (fun _ -> - Paket.Pack(fun p -> +Target.create "NuGet" (fun _ -> + Paket.pack(fun p -> { p with OutputPath = "bin" Version = release.NugetVersion - ReleaseNotes = toLines release.Notes}) + ReleaseNotes = String.toLines release.Notes}) ) -Target "PublishNuget" (fun _ -> - Paket.Push(fun p -> +Target.create "PublishNuget" (fun _ -> + Paket.push(fun p -> { p with PublishUrl = "https://www.nuget.org" WorkingDir = "bin" }) @@ -175,193 +175,191 @@ Target "PublishNuget" (fun _ -> // -------------------------------------------------------------------------------------- // Generate the documentation +// Paths with template/source/output locations +let bin = __SOURCE_DIRECTORY__ @@ "bin" +let content = __SOURCE_DIRECTORY__ @@ "docsrc/content" +let output = __SOURCE_DIRECTORY__ @@ "docs" +let files = __SOURCE_DIRECTORY__ @@ "docsrc/files" +let templates = __SOURCE_DIRECTORY__ @@ "docsrc/tools/templates" +let formatting = __SOURCE_DIRECTORY__ @@ "packages/formatting/FSharp.Formatting" +let docTemplate = "docpage.cshtml" -let fakePath = "packages" "build" "FAKE" "tools" "FAKE.exe" -let fakeStartInfo script workingDirectory args fsiargs environmentVars = - (fun (info: ProcessStartInfo) -> - info.FileName <- System.IO.Path.GetFullPath fakePath - info.Arguments <- sprintf "%s --fsiargs -d:FAKE %s \"%s\"" args fsiargs script - info.WorkingDirectory <- workingDirectory - let setVar k v = - info.EnvironmentVariables.[k] <- v - for (k, v) in environmentVars do - setVar k v - setVar "MSBuild" msBuildExe - setVar "GIT" Git.CommandHelper.gitPath - setVar "FSI" fsiPath) +let github_release_user = Environment.environVarOrDefault "github_release_user" gitOwner +let githubLink = sprintf "https://github.com/%s/%s" github_release_user gitName -/// Run the given buildscript with FAKE.exe -let executeFAKEWithOutput workingDirectory script fsiargs envArgs = - let exitCode = - ExecProcessWithLambdas - (fakeStartInfo script workingDirectory "" fsiargs envArgs) - TimeSpan.MaxValue false ignore ignore - System.Threading.Thread.Sleep 1000 - exitCode +// Specify more information about your project +let info = + [ "project-name", "LogicalHacking.ExtensionDsLab" + "project-author", "Achim D. Brucker" + "project-summary", "A data science framework for analyzing Chrome browser extensions." + "project-github", githubLink + "project-nuget", "http://nuget.org/packages/LogicalHacking.ExtensionDsLab" ] -// Documentation -let buildDocumentationTarget fsiargs target = - trace (sprintf "Building documentation (%s), this could take some time, please wait..." target) - let exit = executeFAKEWithOutput "docsrc/tools" "generate.fsx" fsiargs ["target", target] - if exit <> 0 then - failwith "generating reference documentation failed" - () +let root = website -Target "GenerateReferenceDocs" (fun _ -> - buildDocumentationTarget "-d:RELEASE -d:REFERENCE" "Default" +let referenceBinaries = [] + +let layoutRootsAll = new System.Collections.Generic.Dictionary() +layoutRootsAll.Add("en",[ templates; + formatting @@ "templates" + formatting @@ "templates/reference" ]) + +Target.create "ReferenceDocs" (fun _ -> + Directory.ensure (output @@ "reference") + + let binaries () = + let manuallyAdded = + referenceBinaries + |> List.map (fun b -> bin @@ b) + + let conventionBased = + DirectoryInfo.getSubDirectories <| DirectoryInfo bin + |> Array.collect (fun d -> + let name, dInfo = + let net45Bin = + DirectoryInfo.getSubDirectories d |> Array.filter(fun x -> x.FullName.ToLower().Contains("net45")) + let net47Bin = + DirectoryInfo.getSubDirectories d |> Array.filter(fun x -> x.FullName.ToLower().Contains("net47")) + if net45Bin.Length > 0 then + d.Name, net45Bin.[0] + else + d.Name, net47Bin.[0] + + dInfo.GetFiles() + |> Array.filter (fun x -> + x.Name.ToLower() = (sprintf "%s.dll" name).ToLower()) + |> Array.map (fun x -> x.FullName) + ) + |> List.ofArray + + conventionBased @ manuallyAdded + + binaries() + |> FSFormatting.createDocsForDlls (fun args -> + { args with + OutputDirectory = output @@ "reference" + LayoutRoots = layoutRootsAll.["en"] + ProjectParameters = ("root", root)::info + SourceRepository = githubLink @@ "tree/master" } + ) ) -let generateHelp' fail debug = - let args = - if debug then "--define:HELP" - else "--define:RELEASE --define:HELP" - try - buildDocumentationTarget args "Default" - traceImportant "Help generated" - with - | e when not fail -> - traceImportant "generating help documentation failed" +let copyFiles () = + Shell.copyRecursive files output true + |> Trace.logItems "Copying file: " + Directory.ensure (output @@ "content") + Shell.copyRecursive (formatting @@ "styles") (output @@ "content") true + |> Trace.logItems "Copying styles and scripts: " + +Target.create "Docs" (fun _ -> + File.delete "docsrc/content/release-notes.md" + Shell.copyFile "docsrc/content/" "RELEASE_NOTES.md" + Shell.rename "docsrc/content/release-notes.md" "docsrc/content/RELEASE_NOTES.md" -let generateHelp fail = - generateHelp' fail false + File.delete "docsrc/content/license.md" + Shell.copyFile "docsrc/content/" "LICENSE" + Shell.rename "docsrc/content/license.md" "docsrc/content/LICENSE" -Target "GenerateHelp" (fun _ -> - DeleteFile "docsrc/content/release-notes.md" - CopyFile "docsrc/content/" "RELEASE_NOTES.md" - Rename "docsrc/content/release-notes.md" "docsrc/content/RELEASE_NOTES.md" + + DirectoryInfo.getSubDirectories (DirectoryInfo.ofPath templates) + |> Seq.iter (fun d -> + let name = d.Name + if name.Length = 2 || name.Length = 3 then + layoutRootsAll.Add( + name, [templates @@ name + formatting @@ "templates" + formatting @@ "templates/reference" ])) + copyFiles () + + for dir in [ content; ] do + let langSpecificPath(lang, path:string) = + path.Split([|'/'; '\\'|], System.StringSplitOptions.RemoveEmptyEntries) + |> Array.exists(fun i -> i = lang) + let layoutRoots = + let key = layoutRootsAll.Keys |> Seq.tryFind (fun i -> langSpecificPath(i, dir)) + match key with + | Some lang -> layoutRootsAll.[lang] + | None -> layoutRootsAll.["en"] // "en" is the default language - DeleteFile "docsrc/content/license.md" - CopyFile "docsrc/content/" "LICENSE" - Rename "docsrc/content/license.md" "docsrc/content/LICENSE" - - generateHelp true -) - -Target "GenerateHelpDebug" (fun _ -> - DeleteFile "docsrc/content/release-notes.md" - CopyFile "docsrc/content/" "RELEASE_NOTES.md" - Rename "docsrc/content/release-notes.md" "docsrc/content/RELEASE_NOTES.md" - - DeleteFile "docsrc/content/license.md" - CopyFile "docsrc/content/" "LICENSE" - Rename "docsrc/content/license.md" "docsrc/content/LICENSE" - - generateHelp' true true -) - -Target "KeepRunning" (fun _ -> - use watcher = !! "docsrc/content/**/*.*" |> WatchChanges (fun changes -> - generateHelp' true true - ) - - traceImportant "Waiting for help edits. Press any key to stop." - - System.Console.ReadKey() |> ignore - - watcher.Dispose() -) - -Target "GenerateDocs" DoNothing - -let createIndexFsx lang = - let content = """(*** hide ***) -// This block of code is omitted in the generated HTML documentation. Use -// it to define helpers that you do not want to show in the documentation. -#I "../../../bin" - -(** -F# Project Scaffold ({0}) -========================= -*) -""" - let targetDir = "docsrc/content" lang - let targetFile = targetDir "index.fsx" - ensureDirectory targetDir - System.IO.File.WriteAllText(targetFile, System.String.Format(content, lang)) - -Target "AddLangDocs" (fun _ -> - let args = System.Environment.GetCommandLineArgs() - if args.Length < 4 then - failwith "Language not specified." - - args.[3..] - |> Seq.iter (fun lang -> - if lang.Length <> 2 && lang.Length <> 3 then - failwithf "Language must be 2 or 3 characters (ex. 'de', 'fr', 'ja', 'gsw', etc.): %s" lang - - let templateFileName = "template.cshtml" - let templateDir = "docsrc/tools/templates" - let langTemplateDir = templateDir lang - let langTemplateFileName = langTemplateDir templateFileName - - if System.IO.File.Exists(langTemplateFileName) then - failwithf "Documents for specified language '%s' have already been added." lang - - ensureDirectory langTemplateDir - Copy langTemplateDir [ templateDir templateFileName ] - - createIndexFsx lang) + FSFormatting.createDocs (fun args -> + { args with + Source = content + OutputDirectory = output + LayoutRoots = layoutRoots + ProjectParameters = ("root", root)::info + Template = docTemplate } ) ) // -------------------------------------------------------------------------------------- // Release Scripts -#load "paket-files/build/fsharp/FAKE/modules/Octokit/Octokit.fsx" -open Octokit +//#load "paket-files/fsharp/FAKE/modules/Octokit/Octokit.fsx" +//open Octokit -Target "Release" (fun _ -> - let user = - match getBuildParam "github-user" with - | s when not (String.IsNullOrWhiteSpace s) -> s - | _ -> getUserInput "Username: " - let pw = - match getBuildParam "github-pw" with - | s when not (String.IsNullOrWhiteSpace s) -> s - | _ -> getUserPassword "Password: " - let remote = - Git.CommandHelper.getGitResult "" "remote -v" - |> Seq.filter (fun (s: string) -> s.EndsWith("(push)")) - |> Seq.tryFind (fun (s: string) -> s.Contains(gitOwner + "/" + gitName)) - |> function None -> gitHome + "/" + gitName | Some (s: string) -> s.Split().[0] +Target.create "Release" (fun _ -> + // not fully converted from FAKE 4 - StageAll "" - Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion) - Branches.pushBranch "" remote (Information.getBranchName "") + //let user = + // match getBuildParam "github-user" with + // | s when not (String.isNullOrWhiteSpace s) -> s + // | _ -> getUserInput "Username: " + //let pw = + // match getBuildParam "github-pw" with + // | s when not (String.isNullOrWhiteSpace s) -> s + // | _ -> getUserPassword "Password: " + //let remote = + // Git.CommandHelper.getGitResult "" "remote -v" + // |> Seq.filter (fun (s: string) -> s.EndsWith("(push)")) + // |> Seq.tryFind (fun (s: string) -> s.Contains(gitOwner + "/" + gitName)) + // |> function None -> gitHome + "/" + gitName | Some (s: string) -> s.Split().[0] - Branches.tag "" release.NugetVersion - Branches.pushTag "" remote release.NugetVersion + //Git.Staging.stageAll "" + //Git.Commit.exec "" (sprintf "Bump version to %s" release.NugetVersion) + //Git.Branches.pushBranch "" remote (Git.Information.getBranchName "") - // release on github - createClient user pw - |> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes - // TODO: |> uploadFile "PATH_TO_FILE" - |> releaseDraft - |> Async.RunSynchronously + //Git.Branches.tag "" release.NugetVersion + //Git.Branches.pushTag "" remote release.NugetVersion + + //// release on github + //GitHub.createClient user pw + //|> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes + //// TODO: |> uploadFile "PATH_TO_FILE" + //|> releaseDraft + //|> Async.RunSynchronously + + // using simplified FAKE 5 release for now + + Git.Staging.stageAll "" + Git.Commit.exec "" (sprintf "Bump version to %s" release.NugetVersion) + Git.Branches.push "" + + Git.Branches.tag "" release.NugetVersion + Git.Branches.pushTag "" "origin" release.NugetVersion ) -Target "BuildPackage" DoNothing +Target.create "BuildPackage" ignore +Target.create "GenerateDocs" ignore // -------------------------------------------------------------------------------------- // Run all targets by default. Invoke 'build ' to override -Target "All" DoNothing +Target.create "All" ignore -"AssemblyInfo" +"Clean" + ==> "AssemblyInfo" ==> "Build" ==> "CopyBinaries" ==> "RunTests" - ==> "GenerateReferenceDocs" ==> "GenerateDocs" ==> "NuGet" - ==> "BuildPackage" ==> "All" -"GenerateHelp" - ==> "GenerateReferenceDocs" - ==> "GenerateDocs" +"RunTests" ?=> "CleanDocs" -"GenerateHelpDebug" - ==> "KeepRunning" +"CleanDocs" + ==>"Docs" + ==> "ReferenceDocs" + ==> "GenerateDocs" "Clean" ==> "Release" @@ -370,4 +368,4 @@ Target "All" DoNothing ==> "PublishNuget" ==> "Release" -RunTargetOrDefault "All" +Target.runOrDefault "All"