├── paket.references ├── src ├── FSharp.ProjectTemplate │ ├── paket.references │ ├── Script.fsx │ ├── Library.fs │ ├── AssemblyInfo.fs │ ├── paket.template │ └── FSharp.ProjectTemplate.fsproj └── FSharp.ConsoleTemplate │ ├── paket.references │ ├── Program.fs │ ├── FSharp.ConsoleTemplate.fsproj │ ├── CommandLine.fsi │ └── CommandLine.fs ├── .paket ├── paket.exe └── Paket.Restore.targets ├── docsrc ├── files │ └── img │ │ ├── logo.png │ │ └── logo-template.pdn ├── content │ ├── tutorial.fsx │ └── index.fsx └── tools │ └── templates │ └── template.cshtml ├── tests └── FSharp.ProjectTemplate.Tests │ ├── paket.references │ ├── RunTests.fs │ ├── FSharp.ProjectTemplate.Tests.fsproj │ ├── Tests.fs │ └── Generators.fs ├── appveyor.yml ├── lib └── README.md ├── RELEASE_NOTES.md ├── .travis.yml ├── .gitattributes ├── .github └── ISSUE_TEMPLATE.md ├── paket.dependencies ├── LICENSE.txt ├── README.md ├── .gitignore ├── FSharp.ProjectScaffold.sln └── init.fsx /paket.references: -------------------------------------------------------------------------------- 1 | dotnet-fake -------------------------------------------------------------------------------- /src/FSharp.ProjectTemplate/paket.references: -------------------------------------------------------------------------------- 1 | FSharp.Core -------------------------------------------------------------------------------- /src/FSharp.ConsoleTemplate/paket.references: -------------------------------------------------------------------------------- 1 | FSharp.Core 2 | Argu -------------------------------------------------------------------------------- /.paket/paket.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/ProjectScaffold/HEAD/.paket/paket.exe -------------------------------------------------------------------------------- /docsrc/files/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/ProjectScaffold/HEAD/docsrc/files/img/logo.png -------------------------------------------------------------------------------- /docsrc/files/img/logo-template.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/ProjectScaffold/HEAD/docsrc/files/img/logo-template.pdn -------------------------------------------------------------------------------- /tests/FSharp.ProjectTemplate.Tests/paket.references: -------------------------------------------------------------------------------- 1 | FSharp.Core 2 | 3 | Expecto 4 | Expecto.BenchmarkDotNet 5 | Expecto.FsCheck 6 | Expecto.VisualStudio.TestAdapter -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | init: 4 | - git config --global core.autocrlf input 5 | build_script: 6 | - cmd: build.cmd All 7 | test: off 8 | version: 0.0.1.{build} 9 | artifacts: 10 | - path: bin 11 | name: bin 12 | -------------------------------------------------------------------------------- /src/FSharp.ProjectTemplate/Script.fsx: -------------------------------------------------------------------------------- 1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project 2 | // for more guidance on F# programming. 3 | 4 | #load "Library.fs" 5 | open FSharp.ProjectTemplate 6 | 7 | let num = Library.hello 42 8 | printfn "%i" num 9 | -------------------------------------------------------------------------------- /tests/FSharp.ProjectTemplate.Tests/RunTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectScaffold.Tests 2 | 3 | open Expecto 4 | 5 | module RunTests = 6 | 7 | [] 8 | let main args = 9 | 10 | Tests.runTestsWithArgs defaultConfig args Tests.testSimpleTests |> ignore 11 | 12 | 0 13 | 14 | -------------------------------------------------------------------------------- /src/FSharp.ProjectTemplate/Library.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectTemplate 2 | 3 | /// Documentation for my library 4 | /// 5 | /// ## Example 6 | /// 7 | /// let h = Library.hello 1 8 | /// printfn "%d" h 9 | /// 10 | module Library = 11 | 12 | /// Returns 42 13 | /// 14 | /// ## Parameters 15 | /// - `num` - whatever 16 | let hello num = 42 17 | -------------------------------------------------------------------------------- /docsrc/content/tutorial.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | // This block of code is omitted in the generated HTML documentation. Use 3 | // it to define helpers that you do not want to show in the documentation. 4 | #I "../../bin" 5 | 6 | (** 7 | Introducing your project 8 | ======================== 9 | 10 | Say more 11 | 12 | *) 13 | #r "FSharp.ProjectScaffold.dll" 14 | open FSharp.ProjectScaffold 15 | 16 | Library.hello 0 17 | (** 18 | Some more info 19 | *) 20 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | This file is in the `lib` directory. 2 | 3 | Any **libraries** on which your project depends and which are **NOT managed via NuGet** should be kept **in this directory**. 4 | This typically includes custom builds of third-party software, private (i.e. to a company) codebases, and native libraries. 5 | 6 | --- 7 | NOTE: 8 | 9 | This file is a placeholder, used to preserve directory structure in Git. 10 | 11 | This file does not need to be edited. 12 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | ### 1.0.1 2 | * Removed SourceLink 3 | 4 | ### 1.0 5 | * More awesome stuff coming 6 | * Added SourceLink for Source Indexing PDB 7 | 8 | #### 0.5.1-beta - November 6 2013 9 | * Improved quality of solution-wide README.md files 10 | 11 | #### 0.5.0-beta - October 29 2013 12 | * Improved quality of solution-wide README.md files 13 | 14 | #### 0.0.1-beta - October 24 2013 15 | * Changed name from fsharp-project-scaffold to FSharp.ProjectScaffold 16 | * Initial release 17 | -------------------------------------------------------------------------------- /src/FSharp.ProjectTemplate/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | namespace System 2 | open System.Reflection 3 | 4 | [] 5 | [] 6 | [] 7 | [] 8 | [] 9 | do () 10 | 11 | module internal AssemblyVersionInformation = 12 | let [] Version = "1.0" 13 | -------------------------------------------------------------------------------- /src/FSharp.ConsoleTemplate/Program.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectTemplate 2 | 3 | open CommandLine 4 | open System 5 | 6 | module console1 = 7 | 8 | [] 9 | let main argv = 10 | printfn "%A" argv 11 | 12 | let parsedCommand = parse (System.Reflection.Assembly.GetExecutingAssembly().GetName().Name) argv 13 | 14 | match parsedCommand.Error with 15 | | Some e -> 16 | printfn "%s" parsedCommand.Usage 17 | | None -> 18 | printfn "%A" parsedCommand 19 | 20 | printfn "Hit any key to exit." 21 | System.Console.ReadKey() |> ignore 22 | 0 -------------------------------------------------------------------------------- /src/FSharp.ProjectTemplate/paket.template: -------------------------------------------------------------------------------- 1 | type file 2 | id ##ProjectName## 3 | title 4 | ##ProjectName## 5 | owners 6 | ##Author## 7 | authors 8 | ##Author## 9 | projectUrl 10 | ##GitUrl##/##GitHome##/##GitName## 11 | iconUrl 12 | ##GitRawUrl##/##GitHome##/##GitName##/master/docs/files/img/logo.png 13 | licenseUrl 14 | ##GitUrl##/##GitHome##/##GitName##/blob/master/LICENSE.txt 15 | requireLicenseAcceptance 16 | false 17 | language 18 | F# 19 | copyright 20 | Copyright 2017 21 | tags 22 | ##Tags## 23 | summary 24 | ##Summary## 25 | description 26 | ##Description## 27 | 28 | files 29 | ../../bin/##ProjectName## ==> lib 30 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | 3 | sudo: false # use the new container-based Travis infrastructure 4 | 5 | mono: 5.12.0 6 | 7 | dotnet: 2.1.300 8 | 9 | install: 10 | 11 | # workaround for missing .net 4.5 targing pack 12 | 13 | - export FrameworkPathOverride=$(dirname $(which mono))/../lib/mono/4.5/ 14 | 15 | before_install: 16 | - chmod +x build.sh 17 | 18 | matrix: 19 | include: 20 | - os: linux # Ubuntu 14.04 21 | dist: trusty 22 | sudo: required 23 | dotnet : 2.1.300 24 | - os: osx # OSX 10.12 25 | osx_image: xcode9.1 26 | dotnet : 2.1.300 27 | dist: trusty 28 | sudo: required 29 | 30 | script: 31 | - ./build.sh All 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp text=auto eol=lf 6 | *.vb diff=csharp text=auto eol=lf 7 | *.fs diff=csharp text=auto eol=lf 8 | *.fsi diff=csharp text=auto eol=lf 9 | *.fsx diff=csharp text=auto eol=lf 10 | *.sln text eol=crlf merge=union 11 | *.csproj merge=union 12 | *.vbproj merge=union 13 | *.fsproj merge=union 14 | *.dbproj merge=union 15 | 16 | # Standard to msysgit 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Please provide a succinct description of your issue. 4 | 5 | ### Repro steps 6 | 7 | Please provide the steps required to reproduce the problem 8 | 9 | 1. Step A 10 | 11 | 2. Step B 12 | 13 | ### Expected behavior 14 | 15 | Please provide a description of the behavior you expect. 16 | 17 | ### Actual behavior 18 | 19 | Please provide a description of the actual behavior you observe. 20 | 21 | ### Known workarounds 22 | 23 | Please provide a description of any known workarounds. 24 | 25 | ### Related information 26 | 27 | * Operating system 28 | * Branch 29 | * .NET Runtime, CoreCLR or Mono Version 30 | * Performance information, links to performance testing scripts 31 | -------------------------------------------------------------------------------- /paket.dependencies: -------------------------------------------------------------------------------- 1 | framework: auto-detect 2 | 3 | source https://nuget.org/api/v2 4 | 5 | nuget FSharp.Core 6 | nuget Argu 7 | 8 | nuget Expecto 9 | nuget Expecto.BenchmarkDotNet 10 | nuget Expecto.FsCheck 11 | nuget Expecto.VisualStudio.TestAdapter version_in_path: true 12 | 13 | clitool dotnet-fake 14 | 15 | group Formatting 16 | source https://nuget.org/api/v2 17 | 18 | nuget FSharp.Formatting 19 | nuget FSharp.Formatting.CommandTool 20 | 21 | group FakeBuild 22 | source https://api.nuget.org/v3/index.json 23 | 24 | storage: none 25 | 26 | nuget Fake.Core.Target 27 | nuget Fake.IO.FileSystem 28 | nuget Fake.DotNet.Cli 29 | nuget Fake.Tools.Git 30 | nuget Fake.DotNet.MSBuild 31 | nuget Fake.Core.ReleaseNotes 32 | nuget Fake.DotNet.AssemblyInfoFile 33 | nuget Fake.DotNet.Paket 34 | nuget Fake.DotNet.Testing.Expecto 35 | nuget Fake.DotNet.FSFormatting 36 | nuget Fake.Api.GitHub 37 | -------------------------------------------------------------------------------- /src/FSharp.ConsoleTemplate/FSharp.ConsoleTemplate.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net47;netcoreapp2.1 4 | FSharp.ConsoleTemplate 5 | FSharp.ConsoleTemplate 6 | FSharp.ConsoleTemplate 7 | Exe 8 | Properties 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net47 5 | FSharp.ProjectTemplate.Tests 6 | FSharp.ProjectTemplate.Tests 7 | FSharp.ProjectTemplate.Tests 8 | Exe 9 | Properties 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/FSharp.ConsoleTemplate/CommandLine.fsi: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectTemplate 2 | 3 | open System 4 | 5 | /// Command line parsing. 6 | module CommandLine = 7 | 8 | type PredicateOperator = 9 | | EQ 10 | | GT 11 | | LT 12 | | Between 13 | 14 | type Predicate = 15 | { 16 | Operator : PredicateOperator 17 | StartDate : DateTime 18 | EndDate : DateTime option 19 | } 20 | with 21 | static member Create : operator : PredicateOperator -> startDate : DateTime -> endDate : DateTime option -> Predicate 22 | 23 | type Source = 24 | | File of string list 25 | | Console of string 26 | | NoSource 27 | 28 | type Target = 29 | | File of string 30 | | Console 31 | 32 | type ParsedCommand = 33 | { 34 | Usage : string 35 | Predicate : Predicate option 36 | Source : Source 37 | Target : Target 38 | Error: Exception option 39 | } 40 | 41 | val parse : programName : string -> argv : string [] -> ParsedCommand 42 | -------------------------------------------------------------------------------- /tests/FSharp.ProjectTemplate.Tests/Tests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectScaffold.Tests 2 | 3 | open Expecto 4 | open FsCheck 5 | open GeneratorsCode 6 | 7 | module Tests = 8 | let config10k = { FsCheckConfig.defaultConfig with maxTest = 10000} 9 | // bug somewhere: registering arbitrary generators causes Expecto VS test adapter not to work 10 | //let config10k = { FsCheckConfig.defaultConfig with maxTest = 10000; arbitrary = [typeof] } 11 | let configReplay = { FsCheckConfig.defaultConfig with maxTest = 10000 ; replay = Some <| (1940624926, 296296394) } 12 | 13 | [] 14 | let testSimpleTests = 15 | 16 | testList "DomainTypes.Tag" [ 17 | testCase "equality" <| fun () -> 18 | let result = 42 19 | Expect.isTrue (result = 42) "Expected True" 20 | 21 | testPropertyWithConfig config10k "whitespace" <| 22 | fun () -> 23 | Prop.forAll (Arb.fromGen <| whitespaceString()) 24 | (fun (x : string) -> 25 | x = x) 26 | ] 27 | 28 | -------------------------------------------------------------------------------- /src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net45;net47;netstandard2.0 4 | FSharp.ProjectTemplate 5 | FSharp.ProjectTemplate 6 | FSharp.ProjectTemplate 7 | Library 8 | true 9 | 10 | true 11 | 12 | true 13 | 14 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /docsrc/content/index.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | // This block of code is omitted in the generated HTML documentation. Use 3 | // it to define helpers that you do not want to show in the documentation. 4 | #I "../../bin" 5 | 6 | (** 7 | FSharp.ProjectScaffold 8 | ====================== 9 | 10 | Documentation 11 | 12 |
13 |
14 |
15 |
16 | The FSharp.ProjectScaffold library can be installed from NuGet: 17 |
PM> Install-Package FSharp.ProjectScaffold
18 |
19 |
20 |
21 |
22 | 23 | Example 24 | ------- 25 | 26 | This example demonstrates using a function defined in this sample library. 27 | 28 | *) 29 | #r "FSharp.ProjectScaffold.dll" 30 | open FSharp.ProjectScaffold 31 | 32 | printfn "hello = %i" <| Library.hello 0 33 | 34 | (** 35 | Some more info 36 | 37 | Samples & documentation 38 | ----------------------- 39 | 40 | The library comes with comprehensible documentation. 41 | It can include tutorials automatically generated from `*.fsx` files in [the content folder][content]. 42 | The API reference is automatically generated from Markdown comments in the library implementation. 43 | 44 | * [Tutorial](tutorial.html) contains a further explanation of this sample library. 45 | 46 | * [API Reference](reference/index.html) contains automatically generated documentation for all types, modules 47 | and functions in the library. This includes additional brief samples on using most of the 48 | functions. 49 | 50 | Contributing and copyright 51 | -------------------------- 52 | 53 | The project is hosted on [GitHub][gh] where you can [report issues][issues], fork 54 | the project and submit pull requests. If you're adding a new public API, please also 55 | consider adding [samples][content] that can be turned into a documentation. You might 56 | also want to read the [library design notes][readme] to understand how it works. 57 | 58 | The library is available under Public Domain license, which allows modification and 59 | redistribution for both commercial and non-commercial purposes. For more information see the 60 | [License file][license] in the GitHub repository. 61 | 62 | [content]: https://github.com/fsprojects/FSharp.ProjectScaffold/tree/master/docs/content 63 | [gh]: https://github.com/fsprojects/FSharp.ProjectScaffold 64 | [issues]: https://github.com/fsprojects/FSharp.ProjectScaffold/issues 65 | [readme]: https://github.com/fsprojects/FSharp.ProjectScaffold/blob/master/README.md 66 | [license]: https://github.com/fsprojects/FSharp.ProjectScaffold/blob/master/LICENSE.txt 67 | *) 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Issue Stats](http://issuestats.com/github/fsprojects/ProjectScaffold/badge/issue)](http://issuestats.com/github/fsprojects/ProjectScaffold) 2 | [![Issue Stats](http://issuestats.com/github/fsprojects/ProjectScaffold/badge/pr)](http://issuestats.com/github/fsprojects/ProjectScaffold) 3 | 4 | # ProjectScaffold 5 | 6 | This project can be used to scaffold a prototypical .NET solution including file system layout and tooling. This includes a build process that: 7 | 8 | * updates all AssemblyInfo files 9 | * compiles the application and runs all test projects 10 | * generates API docs based on XML document tags 11 | * generates [documentation based on Markdown files](http://fsprojects.github.io/ProjectScaffold/writing-docs.html) 12 | * generates [NuGet](http://www.nuget.org) packages 13 | * and allows a simple [one step release process](http://fsprojects.github.io/ProjectScaffold/release-process.html). 14 | 15 | In order to start the scaffolding process run 16 | 17 | > build.cmd // on windows 18 | $ ./build.sh // on unix 19 | 20 | Read the [Getting started tutorial](http://fsprojects.github.io/ProjectScaffold/index.html#Getting-started) to learn more. 21 | 22 | Documentation: http://fsprojects.github.io/ProjectScaffold 23 | 24 | 25 | ## Tips for migrating existing project to Scaffold format 26 | 27 | * clone ProjectScaffold to new folder 28 | * run the initializing build 29 | * delete .git folder 30 | * copy intitialized scaffold files and folders to original project folder 31 | * git add / commit project -m"first pass migrating to scaffold format" (otherwise git may be confused by next mv) 32 | * git mv necessary project file folders into src folder 33 | * git commit, and any following cleanup 34 | 35 | Be sure to do only ````git mv```` file renames in a single commit. If you try to commit anything else git will treat the renames as file delete / file add and you will loose history on those files. 36 | 37 | ## Requirements 38 | 39 | ProjectScaffold requires a local git installation. You can download git from [Git Downloads](https://git-scm.com/downloads). 40 | 41 | ## Build Status 42 | 43 | Mono | .NET 44 | ---- | ---- 45 | [![Mono CI Build Status](https://img.shields.io/travis/fsprojects/ProjectScaffold/master.svg)](https://travis-ci.org/fsprojects/ProjectScaffold) | [![.NET Build Status](https://img.shields.io/appveyor/ci/fsgit/ProjectScaffold/master.svg)](https://ci.appveyor.com/project/fsgit/projectscaffold) 46 | 47 | ## Maintainer(s) 48 | 49 | - [@forki](https://github.com/forki) 50 | - [@jackfoxy](https://github.com/jackfoxy) 51 | - [@sergey-tihon](https://github.com/sergey-tihon) 52 | 53 | The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) - F# Community Project Incubation Space (repo management) 54 | -------------------------------------------------------------------------------- /docsrc/tools/templates/template.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 |
24 |
25 | 29 |

@Properties["project-name"]

30 |
31 |
32 |
33 |
34 | @RenderBody() 35 |
36 |
37 | F# Project 38 | 53 |
54 |
55 |
56 | Fork me on GitHub 57 | 58 | 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Xamarin Studio / monodevelop user-specific 10 | *.userprefs 11 | *.dll.mdb 12 | *.exe.mdb 13 | 14 | # Build results 15 | 16 | [Dd]ebug/ 17 | [Rr]elease/ 18 | x64/ 19 | build/ 20 | [Bb]in/ 21 | [Oo]bj/ 22 | 23 | # MSTest test Results 24 | [Tt]est[Rr]esult*/ 25 | [Bb]uild[Ll]og.* 26 | 27 | *_i.c 28 | *_p.c 29 | *.ilk 30 | *.meta 31 | *.obj 32 | *.pch 33 | *.pdb 34 | *.pgc 35 | *.pgd 36 | *.rsp 37 | *.sbr 38 | *.tlb 39 | *.tli 40 | *.tlh 41 | *.tmp 42 | *.tmp_proj 43 | *.log 44 | *.vspscc 45 | *.vssscc 46 | .builds 47 | *.pidb 48 | *.log 49 | *.scc 50 | 51 | # Visual C++ cache files 52 | ipch/ 53 | *.aps 54 | *.ncb 55 | *.opensdf 56 | *.sdf 57 | *.cachefile 58 | 59 | # Visual Studio profiler 60 | *.psess 61 | *.vsp 62 | *.vspx 63 | 64 | # Other Visual Studio data 65 | .vs/ 66 | 67 | # Guidance Automation Toolkit 68 | *.gpState 69 | 70 | # ReSharper is a .NET coding add-in 71 | _ReSharper*/ 72 | *.[Rr]e[Ss]harper 73 | 74 | # TeamCity is a build add-in 75 | _TeamCity* 76 | 77 | # DotCover is a Code Coverage Tool 78 | *.dotCover 79 | 80 | # NCrunch 81 | *.ncrunch* 82 | .*crunch*.local.xml 83 | 84 | # Installshield output folder 85 | [Ee]xpress/ 86 | 87 | # DocProject is a documentation generator add-in 88 | DocProject/buildhelp/ 89 | DocProject/Help/*.HxT 90 | DocProject/Help/*.HxC 91 | DocProject/Help/*.hhc 92 | DocProject/Help/*.hhk 93 | DocProject/Help/*.hhp 94 | DocProject/Help/Html2 95 | DocProject/Help/html 96 | 97 | # Click-Once directory 98 | publish/ 99 | 100 | # Publish Web Output 101 | *.Publish.xml 102 | 103 | # Enable nuget.exe in the .nuget folder (though normally executables are not tracked) 104 | !.nuget/NuGet.exe 105 | 106 | # Windows Azure Build Output 107 | csx 108 | *.build.csdef 109 | 110 | # Windows Store app package directory 111 | AppPackages/ 112 | 113 | # VSCode 114 | .vscode/ 115 | 116 | # Others 117 | sql/ 118 | *.Cache 119 | ClientBin/ 120 | [Ss]tyle[Cc]op.* 121 | ~$* 122 | *~ 123 | *.dbmdl 124 | *.[Pp]ublish.xml 125 | *.pfx 126 | *.publishsettings 127 | 128 | # RIA/Silverlight projects 129 | Generated_Code/ 130 | 131 | # Backup & report files from converting an old project file to a newer 132 | # Visual Studio version. Backup files are not needed, because we have git ;-) 133 | _UpgradeReport_Files/ 134 | Backup*/ 135 | UpgradeLog*.XML 136 | UpgradeLog*.htm 137 | 138 | # SQL Server files 139 | App_Data/*.mdf 140 | App_Data/*.ldf 141 | 142 | 143 | #LightSwitch generated files 144 | GeneratedArtifacts/ 145 | _Pvt_Extensions/ 146 | ModelManifest.xml 147 | 148 | # ========================= 149 | # Windows detritus 150 | # ========================= 151 | 152 | # Windows image file caches 153 | Thumbs.db 154 | ehthumbs.db 155 | 156 | # Folder config file 157 | Desktop.ini 158 | 159 | # Recycle Bin used on file shares 160 | $RECYCLE.BIN/ 161 | 162 | # Mac desktop service store files 163 | .DS_Store 164 | 165 | # =================================================== 166 | # Exclude F# project specific directories and files 167 | # =================================================== 168 | 169 | # NuGet Packages Directory 170 | packages/ 171 | 172 | # Test results produced by build 173 | TestResults.xml 174 | 175 | # Nuget outputs 176 | nuget/*.nupkg 177 | release.cmd 178 | release.sh 179 | localpackages/ 180 | paket-files 181 | *.orig 182 | docsrc/content/license.md 183 | docsrc/content/release-notes.md 184 | .fake 185 | docsrc/tools/FSharp.Formatting.svclog 186 | -------------------------------------------------------------------------------- /FSharp.ProjectScaffold.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2000 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{63297B98-5CED-492C-A5B7-A5B4F73CF142}" 7 | ProjectSection(SolutionItems) = preProject 8 | paket.dependencies = paket.dependencies 9 | paket.references = paket.references 10 | paket.lock = paket.lock 11 | EndProjectSection 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}" 14 | EndProject 15 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ProjectTemplate", "src\FSharp.ProjectTemplate\FSharp.ProjectTemplate.fsproj", "{7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}" 16 | EndProject 17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{BF60BC93-E09B-4E5F-9D85-95A519479D54}" 18 | ProjectSection(SolutionItems) = preProject 19 | README.md = README.md 20 | RELEASE_NOTES.md = RELEASE_NOTES.md 21 | EndProjectSection 22 | EndProject 23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{83F16175-43B1-4C90-A1EE-8E351C33435D}" 24 | ProjectSection(SolutionItems) = preProject 25 | docsrc\tools\generate.fsx = docsrc\tools\generate.fsx 26 | docsrc\tools\templates\template.cshtml = docsrc\tools\templates\template.cshtml 27 | EndProjectSection 28 | EndProject 29 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{8E6D5255-776D-4B61-85F9-73C37AA1FB9A}" 30 | ProjectSection(SolutionItems) = preProject 31 | docsrc\content\index.fsx = docsrc\content\index.fsx 32 | docsrc\content\tutorial.fsx = docsrc\content\tutorial.fsx 33 | EndProjectSection 34 | EndProject 35 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{ED8079DD-2B06-4030-9F0F-DC548F98E1C4}" 36 | EndProject 37 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ProjectTemplate.Tests", "tests\FSharp.ProjectTemplate.Tests\FSharp.ProjectTemplate.Tests.fsproj", "{E789C72A-5CFD-436B-8EF1-61AA2852A89F}" 38 | EndProject 39 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "git", "git", "{078A9C52-DDC1-46F4-9235-9E6C89C87AFD}" 40 | ProjectSection(SolutionItems) = preProject 41 | .gitattributes = .gitattributes 42 | .gitignore = .gitignore 43 | EndProjectSection 44 | EndProject 45 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{7C6D08E7-3EAC-4335-8F4B-252C193C27C9}" 46 | ProjectSection(SolutionItems) = preProject 47 | .travis.yml = .travis.yml 48 | appveyor.yml = appveyor.yml 49 | build.cmd = build.cmd 50 | build.fsx = build.fsx 51 | build.proj = build.proj 52 | build.sh = build.sh 53 | EndProjectSection 54 | EndProject 55 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ConsoleTemplate", "src\FSharp.ConsoleTemplate\FSharp.ConsoleTemplate.fsproj", "{B7339FEC-0891-4DF8-8BB5-0B806A64F32F}" 56 | EndProject 57 | Global 58 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 59 | Debug|Any CPU = Debug|Any CPU 60 | Release|Any CPU = Release|Any CPU 61 | EndGlobalSection 62 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 63 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}.Release|Any CPU.Build.0 = Release|Any CPU 67 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 68 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Debug|Any CPU.Build.0 = Debug|Any CPU 69 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Release|Any CPU.ActiveCfg = Release|Any CPU 70 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F}.Release|Any CPU.Build.0 = Release|Any CPU 71 | {B7339FEC-0891-4DF8-8BB5-0B806A64F32F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 72 | {B7339FEC-0891-4DF8-8BB5-0B806A64F32F}.Debug|Any CPU.Build.0 = Debug|Any CPU 73 | {B7339FEC-0891-4DF8-8BB5-0B806A64F32F}.Release|Any CPU.ActiveCfg = Release|Any CPU 74 | {B7339FEC-0891-4DF8-8BB5-0B806A64F32F}.Release|Any CPU.Build.0 = Release|Any CPU 75 | EndGlobalSection 76 | GlobalSection(SolutionProperties) = preSolution 77 | HideSolutionNode = FALSE 78 | EndGlobalSection 79 | GlobalSection(NestedProjects) = preSolution 80 | {83F16175-43B1-4C90-A1EE-8E351C33435D} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1} 81 | {8E6D5255-776D-4B61-85F9-73C37AA1FB9A} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1} 82 | {E789C72A-5CFD-436B-8EF1-61AA2852A89F} = {ED8079DD-2B06-4030-9F0F-DC548F98E1C4} 83 | EndGlobalSection 84 | EndGlobal 85 | -------------------------------------------------------------------------------- /tests/FSharp.ProjectTemplate.Tests/Generators.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectScaffold.Tests 2 | 3 | open FsCheck 4 | open System 5 | 6 | module GeneratorsCode = 7 | 8 | //https://msdn.microsoft.com/en-us/library/system.char.iswhitespace(v=vs.110).aspx 9 | let spaceSeparator = [ 10 | '\u0020' 11 | '\u1680' 12 | '\u2000' 13 | '\u2001' 14 | '\u2002' 15 | '\u2003' 16 | '\u2004' 17 | '\u2005' 18 | '\u2006' 19 | '\u2007' 20 | '\u2008' 21 | '\u2009' 22 | '\u200A' 23 | '\u202F' 24 | '\u205F' 25 | '\u3000' 26 | ] 27 | 28 | let lineSeparator = ['\u2028'] 29 | 30 | let paragraphSeparator = ['\u2029'] 31 | 32 | let miscWhitespace = [ 33 | '\u0009' 34 | '\u000A' 35 | '\u000B' 36 | '\u000C' 37 | '\u000D' 38 | '\u0085' 39 | '\u00A0' 40 | ] 41 | 42 | let whiteSpace = 43 | List.concat [spaceSeparator; lineSeparator; paragraphSeparator; miscWhitespace] 44 | 45 | let nonDigitalString() = 46 | gen { 47 | let! a = Arb.generate 48 | return! Gen.elements [a.ToString()] 49 | } 50 | |> Gen.filter(fun x -> 51 | let (isInt, _) =Int32.TryParse x 52 | not isInt) 53 | 54 | let whitespaceString() = 55 | let length = 56 | Gen.sample 1 1 <| Gen.choose (1, 30) 57 | |> List.head 58 | |> int 59 | 60 | Gen.arrayOfLength length <| Gen.elements whiteSpace 61 | |> Gen.map (fun x -> new string(x)) 62 | 63 | let nonEmptyNonAllWhitespaceString() = 64 | gen { 65 | return! 66 | Arb.generate 67 | } 68 | |> Gen.filter (fun x -> 69 | let charA = x.ToString().ToCharArray() 70 | Array.fold (fun s t -> 71 | if List.exists (fun x' -> x' = t) whiteSpace |> not then true 72 | else s 73 | ) false charA ) 74 | |> Gen.map (fun x -> x.ToString()) 75 | 76 | let genNonEmptyNonAllWhitespaceStringList() = 77 | let positiveInt = Arb.generate 78 | let length = 79 | Gen.sample 30 1 positiveInt 80 | |> List.head 81 | |> int 82 | 83 | Gen.listOfLength length <| nonEmptyNonAllWhitespaceString() 84 | 85 | let genDigitsInWhiteSpace () = 86 | gen { 87 | let! frontWhitespace = whitespaceString() 88 | let! digits = Arb.generate 89 | let! endWhitespace = whitespaceString() 90 | return sprintf "%s%s%s" frontWhitespace (digits.ToString()) endWhitespace 91 | } 92 | 93 | let validDigits digits length = 94 | if digits.ToString().Length = length then 95 | digits.ToString() 96 | elif digits.ToString().Length < length then 97 | digits.ToString().PadLeft(length, '0') 98 | else 99 | digits.ToString().Substring(0, length) 100 | 101 | let invalidDigits digits length = 102 | if digits.ToString().Length = length then 103 | sprintf "0%s" <| digits.ToString() 104 | else 105 | digits.ToString() 106 | 107 | let genDigitsOfLengthInWhiteSpace length = 108 | gen { 109 | let! frontWhitespace = whitespaceString() 110 | let! digits = Arb.generate 111 | let! endWhitespace = whitespaceString() 112 | return sprintf "%s%s%s" frontWhitespace (validDigits digits length) endWhitespace |> Some 113 | } 114 | |> Gen.filter Option.isSome 115 | |> Gen.map (fun x -> x.Value) 116 | 117 | let inputZip5Plus4() = 118 | gen { 119 | let! digits = Arb.generate 120 | return validDigits digits 9 121 | } 122 | 123 | let genUsPhone7() = 124 | gen { 125 | let! digitsExchange = Arb.generate 126 | let exchange = validDigits digitsExchange 3 127 | let! digitsSuffix = Arb.generate 128 | let suffix = validDigits digitsSuffix 4 129 | let! divide = Gen.elements["";"-";" -";" -";"- ";"- ";" ";" ";] 130 | let! start = Gen.elements["";" ";] 131 | let! after = Gen.elements["";" ";] 132 | 133 | return sprintf "%s%s%s%s%s" start exchange divide suffix after 134 | } 135 | 136 | let genUsPhone10() = 137 | gen { 138 | let! digitsAreaCode = Arb.generate 139 | let areaCode = validDigits digitsAreaCode 3 140 | let! usPhone7 = genUsPhone7() 141 | let! start = Gen.elements["";" ";"(";"( ";"( ";" (";" (";" ( ";] 142 | let! divide = Gen.elements["";" ";")";" )";" )";") ";") ";" ) ";] 143 | 144 | return sprintf "%s%s%s%s" start areaCode divide usPhone7 145 | } 146 | 147 | let genUsPhone() = 148 | gen { 149 | let! usPhone7 = genUsPhone7() 150 | let! usPhone10 = genUsPhone10() 151 | return! Gen.elements [usPhone7; usPhone10] 152 | } 153 | 154 | let genUsPhoneList() = 155 | Gen.listOf <| genUsPhone() 156 | 157 | let genOtherPhone() = 158 | //other phone accespts any digit at least 5 and no more than 14 long 159 | //to do: fix to reject international prefixes 160 | gen { 161 | let! length = Gen.choose (5, 14) 162 | return! genDigitsOfLengthInWhiteSpace length 163 | } 164 | 165 | 166 | let genOtherPhoneList() = 167 | Gen.listOf <| genOtherPhone() 168 | 169 | let genPhoneList() = 170 | gen { 171 | let! usPhone = genUsPhoneList() 172 | let! otherPhone = genOtherPhoneList() 173 | return 174 | usPhone 175 | |> List.append otherPhone 176 | |> List.sortDescending 177 | } 178 | 179 | let genCallingCode() = 180 | let callingCode digits length = 181 | let x = validDigits digits length 182 | if x.StartsWith("0") then 183 | x.Replace("0", "1") 184 | else x 185 | |> UInt16.Parse 186 | 187 | gen { 188 | let! digits = Arb.generate 189 | let! callingCode = Gen.elements [callingCode digits 4 |> Some; callingCode digits 3 |> Some; callingCode digits 2 |> Some; callingCode digits 1 |> Some; None] 190 | 191 | return callingCode 192 | } 193 | 194 | let genPhoneNumber() = 195 | gen { 196 | let! callingCodeRaw = genCallingCode() 197 | let callingCode = callingCodeRaw |> Option.map (fun x -> x.ToString()) 198 | 199 | let! usPhone = genUsPhone() 200 | let! otherPhone = genOtherPhone() 201 | let! phone = Gen.elements[usPhone; otherPhone] 202 | let! extensionRaw = Arb.generate 203 | 204 | let! extension = Gen.elements [extensionRaw.ToString() |> Some; None] 205 | 206 | let! whiteSpace1Raw = whitespaceString() 207 | let! whiteSpace2Raw = whitespaceString() 208 | let! whiteSpace3Raw = whitespaceString() 209 | let! whiteSpace4Raw = whitespaceString() 210 | let! whiteSpace5Raw = whitespaceString() 211 | 212 | let! whiteSpace1 = Gen.elements [whiteSpace1Raw |> Some; None] 213 | let! whiteSpace2 = Gen.elements [whiteSpace2Raw |> Some; None] 214 | let! whiteSpace3 = Gen.elements [whiteSpace3Raw |> Some; None] 215 | let! whiteSpace4 = Gen.elements [whiteSpace4Raw |> Some; None] 216 | let! whiteSpace5 = Gen.elements [whiteSpace5Raw |> Some; None] 217 | 218 | let symbolValueWhitespace symbol value whiteSpace = 219 | sprintf "%s%s%s%s" symbol (defaultArg whiteSpace String.Empty) value (defaultArg whiteSpace String.Empty) 220 | 221 | let phoneNumber = 222 | sprintf "%s%s%s%s%s%s" 223 | (defaultArg whiteSpace1 String.Empty) 224 | (match callingCode with | Some x -> symbolValueWhitespace "+" x whiteSpace2 | None -> String.Empty) 225 | phone 226 | (defaultArg whiteSpace3 String.Empty) 227 | (match extension with | Some x -> symbolValueWhitespace "X" x whiteSpace4 | None -> String.Empty) 228 | (defaultArg whiteSpace5 String.Empty) 229 | 230 | return (callingCode, phone, extension, phoneNumber) 231 | } 232 | 233 | let genUri() = 234 | gen { 235 | let! uriRaw = nonEmptyNonAllWhitespaceString() 236 | let! uri = Gen.elements [" http://" + uriRaw; " https://" + uriRaw; " ftp://" + uriRaw; " ftps://" + uriRaw;] 237 | return uri 238 | } 239 | 240 | type Generators = 241 | static member NonEmptyStringList() = 242 | {new Arbitrary() with 243 | override __.Generator = 244 | GeneratorsCode.genNonEmptyNonAllWhitespaceStringList() 245 | } 246 | -------------------------------------------------------------------------------- /src/FSharp.ConsoleTemplate/CommandLine.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.ProjectTemplate 2 | 3 | open Argu 4 | open System 5 | 6 | module CommandLine = 7 | let private bind f = 8 | function 9 | | Ok x -> f x 10 | | Error x -> Error x 11 | 12 | let private returnM = Ok 13 | 14 | type EitherBuilder() = 15 | member __.Return a = returnM a 16 | member __.Bind (m, f) = bind f m 17 | member __.ReturnFrom m = m 18 | 19 | let choose = EitherBuilder() 20 | 21 | type PredicateOperator = 22 | | EQ 23 | | GT 24 | | LT 25 | | Between 26 | override __.ToString() = 27 | match __ with 28 | | EQ -> "eq" 29 | | GT -> "gt" 30 | | LT -> "lt" 31 | | Between -> "between" 32 | 33 | type Predicate = 34 | { 35 | Operator : PredicateOperator 36 | StartDate : DateTime 37 | EndDate : DateTime option 38 | } 39 | static member Create operator startDate endDate = 40 | match endDate with 41 | | Some _x -> 42 | match operator with 43 | | EQ 44 | | GT 45 | | LT -> 46 | sprintf "operator is %O and end date is requested" operator 47 | |> invalidArg "Log Predicate Create" 48 | | Between -> 49 | { 50 | Operator = operator 51 | StartDate = startDate 52 | EndDate = endDate 53 | } 54 | 55 | | None -> 56 | match operator with 57 | | EQ 58 | | GT 59 | | LT -> 60 | { 61 | Operator = operator 62 | StartDate = startDate 63 | EndDate = endDate 64 | } 65 | | Between -> 66 | sprintf "operator is %O and no end date is requested" operator 67 | |> invalidArg "Log Predicate Create" 68 | 69 | type Source = 70 | | File of string list 71 | | Console of string 72 | | NoSource 73 | 74 | type Target = 75 | | File of string 76 | | Console 77 | 78 | type ParsedCommand = 79 | { 80 | Usage : string 81 | Predicate : Predicate option 82 | Source : Source 83 | Target : Target 84 | Error: Exception option 85 | } 86 | 87 | type CLIArguments = 88 | | [] EQ of string 89 | | [] GT of string 90 | | [] LT of string 91 | | [] Between of string * string 92 | 93 | | [] InputFiles of string list 94 | 95 | | [] InputFolder of string list 96 | 97 | | [] Output of string 98 | | [] ConsoleInput of string 99 | | [] Print 100 | 101 | with 102 | interface IArgParserTemplate with 103 | member s.Usage = 104 | match s with 105 | | EQ _ -> "equals datetime, e.g. \"08/23/2017 14:57:32\" or 08/23/2017" 106 | | GT _ -> "greater than datetime" 107 | | LT _ -> "less than datetime" 108 | | Between _ -> "between datetimes, comma separated" 109 | | InputFiles _ -> "(optional) file path to process" 110 | | InputFolder _ -> "(optional) folder path to process" 111 | | Output _ -> "(optional, not implemented) output path" 112 | | ConsoleInput _ -> "input from console" 113 | | Print -> "print target" 114 | 115 | let parseCommandLine programName (argv : string []) = 116 | 117 | try 118 | match argv, argv.Length with 119 | | _, 0 -> 120 | Error (invalidArg "no arguments" "") 121 | | help, 1 when help.[0].ToLower() = "--help" -> 122 | Error (invalidArg "" "") 123 | | _, _ -> 124 | let parser = 125 | ArgumentParser.Create(programName = programName) 126 | 127 | let commandLine = parser.Parse argv 128 | let usage = parser.PrintUsage() 129 | 130 | Ok (commandLine, usage) 131 | with e -> 132 | Error e 133 | 134 | let parseDate msg (date : string) = 135 | let d = date.Replace("\'", "").Replace("\"", "") 136 | match DateTime.TryParse d with 137 | | true, dt -> dt 138 | | _ -> 139 | match DateTime.TryParse (sprintf "%s 0:0:0" d) with 140 | | true, dt -> dt 141 | | _ -> 142 | invalidArg msg date 143 | 144 | let getEq (commandLine : ParseResults) = 145 | try 146 | match commandLine.TryGetResult <@ EQ @> with 147 | | Some dateTime -> 148 | { 149 | Operator = PredicateOperator.EQ 150 | StartDate = parseDate "error parsing EQ date" dateTime 151 | EndDate = None 152 | } |> Some |> Ok 153 | | None -> Ok None 154 | 155 | with e -> 156 | Error e 157 | 158 | let getGt (commandLine : ParseResults) = 159 | try 160 | match commandLine.TryGetResult <@ GT @> with 161 | | Some dateTime -> 162 | { 163 | Operator = PredicateOperator.GT 164 | StartDate = parseDate "error parsing GT date" dateTime 165 | EndDate = None 166 | } |> Some |> Ok 167 | | None -> Ok None 168 | 169 | with e -> 170 | Error e 171 | 172 | let getLt (commandLine : ParseResults) = 173 | try 174 | match commandLine.TryGetResult <@ LT @> with 175 | | Some dateTime -> 176 | { 177 | Operator = PredicateOperator.LT 178 | StartDate = parseDate "error parsing LT date" dateTime 179 | EndDate = None 180 | } |> Some |> Ok 181 | | None -> Ok None 182 | 183 | with e -> 184 | Error e 185 | 186 | let getBetween (commandLine : ParseResults) = 187 | try 188 | match commandLine.TryGetResult <@ Between @> with 189 | | Some (dateTime1, dateTime2) -> 190 | let dt1 = parseDate "error parsing Between first date" dateTime1 191 | let dt2 = parseDate "error parsing Between 2nd date" dateTime2 192 | 193 | if dt2 > dt1 then 194 | { 195 | Operator = PredicateOperator.Between 196 | StartDate = dt1 197 | EndDate = Some dt2 198 | } |> Some |> Ok 199 | else invalidArg "start date not less than end date" "" 200 | | None -> Ok None 201 | 202 | with e -> 203 | Error e 204 | 205 | let mergePredicate eq gt lt between= 206 | try 207 | match ([eq; gt; lt; between] |> List.choose id) with 208 | | [predicate] -> 209 | predicate 210 | |> Ok 211 | | hd::tl -> 212 | sprintf "%s, %s" (hd.Operator.ToString()) (tl.Head.Operator.ToString()) 213 | |> invalidArg "multiple predicates selected" 214 | | _ -> invalidArg "no predicate selected" "EQ, GT, LT, Between" 215 | with e -> 216 | Error e 217 | 218 | let parseTarget (commandLine : ParseResults) = 219 | 220 | let targetList = 221 | [] 222 | |> (fun x -> 223 | if commandLine.Contains <@ Output @> then 224 | match commandLine.TryGetResult <@ Output @> with 225 | | Some path -> (Target.File path)::x 226 | | None -> x 227 | else x) 228 | 229 | match targetList with 230 | | [] -> Ok Target.Console 231 | | [x] -> Ok x 232 | | hd::tl -> 233 | ArgumentException(sprintf "more than one output target specified: %s, %s" (hd.ToString()) (tl.Head.ToString())) :> Exception 234 | |> Error 235 | 236 | let parseSource (commandLine : ParseResults) = 237 | 238 | let sourceList = 239 | [] 240 | |> (fun x -> 241 | if commandLine.Contains <@ InputFiles @> then 242 | match commandLine.TryGetResult <@ InputFiles @> with 243 | | Some path -> (Source.File path)::x 244 | | None -> x 245 | 246 | else x) 247 | |> (fun x -> 248 | if commandLine.Contains <@ ConsoleInput @> then 249 | match commandLine.TryGetResult <@ ConsoleInput @> with 250 | | Some consoleInput -> (Source.Console consoleInput)::x 251 | | None -> x 252 | else x) 253 | 254 | match sourceList with 255 | | [] -> Ok Source.NoSource 256 | | [x] -> Ok x 257 | | hd::tl -> 258 | ArgumentException(sprintf "more than one input source specified: %s, %s" (hd.ToString()) (tl.Head.ToString())) :> Exception 259 | |> Error 260 | 261 | let parse programName argv = 262 | 263 | match choose { 264 | let! commandLine, usage = parseCommandLine programName argv 265 | 266 | let! eq = getEq commandLine 267 | let! gt = getGt commandLine 268 | let! lt = getLt commandLine 269 | let! between = getBetween commandLine 270 | let! mergedPredicate = mergePredicate eq gt lt between 271 | 272 | let! target = parseTarget commandLine 273 | let! source = parseSource commandLine 274 | 275 | return 276 | { 277 | Usage = usage 278 | Predicate = Some mergedPredicate 279 | Source = source 280 | Target = target 281 | Error = None 282 | } 283 | } with 284 | | Ok x -> x 285 | | Error (e : Exception) -> 286 | let usage = ArgumentParser.Create(programName = programName).PrintUsage() 287 | { 288 | Usage = usage 289 | Predicate = None 290 | Source = Source.NoSource 291 | Target = Target.Console 292 | ParsedCommand.Error = Some e 293 | } 294 | 295 | -------------------------------------------------------------------------------- /init.fsx: -------------------------------------------------------------------------------- 1 | #r "paket: groupref FakeBuild //" 2 | 3 | #load "./.fake/init.fsx/intellisense.fsx" 4 | 5 | open System.Collections.Generic 6 | open System.IO 7 | open Fake.Core 8 | open Fake.IO 9 | open Fake.IO.FileSystemOperators 10 | open Fake.Tools 11 | 12 | // -------------------------------- 13 | // init.fsx 14 | // This file is run the first time that you run build.sh/build.cmd 15 | // It generates the build.fsx and generate.fsx files 16 | // -------------------------------- 17 | 18 | let dirsWithProjects = ["src";"tests";"docsrc/content"] 19 | |> List.map (fun d -> DirectoryInfo (__SOURCE_DIRECTORY__ @@ d)) 20 | 21 | // special funtions 22 | // many whom might be replaceable with FAKE functions 23 | 24 | let failfUnlessExists f msg p = if not <| File.Exists f then failwithf msg p 25 | let combine p1 p2 = Path.Combine(p2, p1) 26 | let move p1 p2 = 27 | if File.Exists p1 then 28 | printfn "moving %s to %s" p1 p2 29 | File.Move(p1, p2) 30 | elif Directory.Exists p1 then 31 | printfn "moving directory %s to %s" p1 p2 32 | Directory.Move(p1, p2) 33 | else 34 | failwithf "Could not move %s to %s" p1 p2 35 | let localFile f = combine f __SOURCE_DIRECTORY__ 36 | let buildTemplatePath = localFile "build.template" 37 | let outputPath = localFile "build.fsx" 38 | 39 | let prompt (msg:string) = 40 | System.Console.Write(msg) 41 | System.Console.ReadLine().Trim() 42 | |> function | "" -> None | s -> Some s 43 | |> Option.map (fun s -> s.Replace ("\"","\\\"")) 44 | let runningOnAppveyor = 45 | not <| System.String.IsNullOrEmpty(Environment.environVar("CI")) 46 | let runningOnTravis = 47 | not <| System.String.IsNullOrEmpty(Environment.environVar("TRAVIS")) 48 | let inCI = runningOnAppveyor || runningOnTravis 49 | let promptFor friendlyName = 50 | if inCI then Some "CONTINUOUSINTEGRATION" 51 | else prompt (sprintf "%s: " friendlyName) 52 | let rec promptForNoSpaces friendlyName = 53 | match promptFor friendlyName with 54 | | None -> None 55 | | Some s when not <| String.exists (fun c -> c = ' ') s -> Some s 56 | | _ -> System.Console.WriteLine("Sorry, spaces are disallowed"); promptForNoSpaces friendlyName 57 | let rec promptYesNo msg = 58 | match prompt (sprintf "%s [Yn]: " msg) with 59 | | None 60 | | Some "Y" | Some "y" -> true 61 | | Some "N" | Some "n" -> false 62 | | _ -> System.Console.WriteLine("Sorry, invalid answer"); promptYesNo msg 63 | 64 | failfUnlessExists buildTemplatePath "Cannot find build template file %s" 65 | (Path.GetFullPath buildTemplatePath) 66 | 67 | // User input 68 | let border = "#####################################################" 69 | let print msg = 70 | printfn """ 71 | %s 72 | %s 73 | %s 74 | """ border msg border 75 | 76 | print """ 77 | # Project Scaffold Init Script 78 | # Please answer a few questions and we will generate 79 | # two files: 80 | # 81 | # build.fsx This will be your build script 82 | # docsrc/tools/generate.fsx This script will generate your 83 | # documentation 84 | # 85 | # NOTE: Aside from the Project Name, you may leave any 86 | # of these blank, but you will need to change the defaults 87 | # in the generated scripts. 88 | # 89 | """ 90 | 91 | let [] defaultGitUrl = "https://github.com" 92 | let [] defaultGitRawUrl = "https://raw.githubusercontent.com" 93 | 94 | let normalizeUrl (url : string) = url.TrimEnd('/') 95 | let promptAndNormalizeFor (normalize : string -> string) = promptFor >> (function | Some e -> Some(normalize e) | e -> e) 96 | let promptAndNormalizeUrlFor = promptAndNormalizeFor normalizeUrl 97 | 98 | let vars = Dictionary() 99 | vars.["##ProjectName##"] <- promptForNoSpaces "Project Name (used for solution/project files)" 100 | vars.["##Summary##"] <- promptFor "Summary (a short description)" 101 | vars.["##Description##"] <- promptFor "Description (longer description used by NuGet)" 102 | vars.["##Author##"] <- promptFor "Author" 103 | vars.["##Tags##"] <- promptFor "Tags (separated by spaces)" 104 | vars.["##GitUrl##"] <- promptAndNormalizeUrlFor (sprintf "Github url (leave blank to use \"%s\")" defaultGitUrl) 105 | vars.["##GitRawUrl##"] <- promptAndNormalizeUrlFor (sprintf "Github raw url (leave blank to use \"%s\")" defaultGitRawUrl) 106 | vars.["##GitHome##"] <- promptFor "Github User or Organization" 107 | vars.["##GitName##"] <- promptFor "Github Project Name (leave blank to use Project Name)" 108 | 109 | let wantGit = if inCI 110 | then false 111 | else promptYesNo "Initialize git repo" 112 | let givenOrigin = if wantGit 113 | then promptForNoSpaces "Origin (url of git remote; blank to skip)" 114 | else None 115 | 116 | //Basic settings 117 | let solutionTemplateName = "FSharp.ProjectScaffold" 118 | let projectTemplateName = "FSharp.ProjectTemplate" 119 | let consoleTemplateName = "FSharp.ConsoleTemplate" 120 | let oldProjectGuid = "7E90D6CE-A10B-4858-A5BC-41DF7250CBCA" 121 | let projectGuid = System.Guid.NewGuid().ToString() 122 | let oldTestProjectGuid = "E789C72A-5CFD-436B-8EF1-61AA2852A89F" 123 | let testProjectGuid = System.Guid.NewGuid().ToString() 124 | 125 | //Rename solution file 126 | let templateSolutionFile = localFile (sprintf "%s.sln" solutionTemplateName) 127 | failfUnlessExists templateSolutionFile "Cannot find solution file template %s" 128 | (templateSolutionFile |> Path.GetFullPath) 129 | 130 | let projectName = 131 | match vars.["##ProjectName##"] with 132 | | Some p -> p.Replace(" ", "") 133 | | None -> "ProjectScaffold" 134 | 135 | let consoleName = sprintf "%sConsole" projectName 136 | let solutionFile = localFile (projectName + ".sln") 137 | move templateSolutionFile solutionFile 138 | 139 | //Rename project files and directories 140 | dirsWithProjects 141 | |> List.iter (fun pd -> 142 | // project files 143 | pd 144 | |> DirectoryInfo.getSubDirectories 145 | |> Array.collect (fun d -> DirectoryInfo.getMatchingFiles "*.?sproj" d) 146 | |> Array.iter (fun f -> f.MoveTo(f.Directory.FullName @@ (f.Name.Replace(projectTemplateName, projectName).Replace(consoleTemplateName, consoleName)))) 147 | // project directories 148 | pd 149 | |> DirectoryInfo.getSubDirectories 150 | |> Array.iter (fun d -> d.MoveTo(pd.FullName @@ (d.Name.Replace(projectTemplateName, projectName).Replace(consoleTemplateName, consoleName)))) 151 | ) 152 | 153 | //Now that everything is renamed, we need to update the content of some files 154 | let replace t r (lines:seq) = 155 | seq { 156 | for s in lines do 157 | if s.Contains(t) then yield s.Replace(t, r) 158 | else yield s } 159 | 160 | let replaceWithVarOrMsg t n lines = 161 | replace t (vars.[t] |> function | None -> n | Some s -> s) lines 162 | 163 | let overwrite file content = File.WriteAllLines(file, content |> Seq.toArray); file 164 | 165 | let replaceContent file = 166 | File.ReadAllLines(file) |> Array.toSeq 167 | |> replace projectTemplateName projectName 168 | |> replace consoleTemplateName consoleName 169 | |> replace (oldProjectGuid.ToLowerInvariant()) (projectGuid.ToLowerInvariant()) 170 | |> replace (oldTestProjectGuid.ToLowerInvariant()) (testProjectGuid.ToLowerInvariant()) 171 | |> replace (oldProjectGuid.ToUpperInvariant()) (projectGuid.ToUpperInvariant()) 172 | |> replace (oldTestProjectGuid.ToUpperInvariant()) (testProjectGuid.ToUpperInvariant()) 173 | |> replace solutionTemplateName projectName 174 | |> replaceWithVarOrMsg "##Author##" "Author not set" 175 | |> replaceWithVarOrMsg "##Description##" "Description not set" 176 | |> replaceWithVarOrMsg "##Summary##" "Summary not set" 177 | |> replaceWithVarOrMsg "##ProjectName##" "FSharpSolution" 178 | |> replaceWithVarOrMsg "##Tags##" "fsharp" 179 | |> replaceWithVarOrMsg "##GitUrl##" defaultGitUrl 180 | |> replaceWithVarOrMsg "##GitRawUrl##" defaultGitRawUrl 181 | |> replaceWithVarOrMsg "##GitHome##" "[github-user]" 182 | |> replaceWithVarOrMsg "##GitName##" projectName 183 | |> overwrite file 184 | |> sprintf "%s updated" 185 | 186 | let rec filesToReplace dir = seq { 187 | yield! Directory.GetFiles(dir, "*.?sproj") 188 | yield! Directory.GetFiles(dir, "*.fs") 189 | yield! Directory.GetFiles(dir, "*.fsi") 190 | yield! Directory.GetFiles(dir, "*.cs") 191 | yield! Directory.GetFiles(dir, "*.xaml") 192 | yield! Directory.GetFiles(dir, "*.fsx") 193 | yield! Directory.GetFiles(dir, "paket.template") 194 | yield! Directory.EnumerateDirectories(dir) |> Seq.collect filesToReplace 195 | } 196 | 197 | [solutionFile] @ (dirsWithProjects 198 | |> List.collect (fun d -> d.FullName |> filesToReplace |> List.ofSeq)) 199 | |> List.map replaceContent 200 | |> List.iter print 201 | 202 | //Replace tokens in build template 203 | let generate templatePath generatedFilePath = 204 | failfUnlessExists templatePath "Cannot find template %s" (templatePath |> Path.GetFullPath) 205 | 206 | let newContent = 207 | File.ReadAllLines(templatePath) |> Array.toSeq 208 | |> replace "##ProjectName##" projectName 209 | |> replace "##ConsoleName##" consoleName 210 | |> replaceWithVarOrMsg "##Summary##" "Project has no summmary; update build.fsx" 211 | |> replaceWithVarOrMsg "##Description##" "Project has no description; update build.fsx" 212 | |> replaceWithVarOrMsg "##Author##" "Update Author in build.fsx" 213 | |> replaceWithVarOrMsg "##Tags##" "" 214 | |> replaceWithVarOrMsg "##GitUrl##" defaultGitUrl 215 | |> replaceWithVarOrMsg "##GitRawUrl##" defaultGitRawUrl 216 | |> replaceWithVarOrMsg "##GitHome##" "Update GitHome in build.fsx" 217 | |> replaceWithVarOrMsg "##GitName##" projectName 218 | 219 | File.WriteAllLines(generatedFilePath, newContent) 220 | File.Delete(templatePath) 221 | print (sprintf "# Generated %s" generatedFilePath) 222 | 223 | generate (localFile "build.template") (localFile "build.fsx") 224 | 225 | //Handle source control 226 | let isGitRepo () = 227 | try 228 | let info = Git.CommandHelper.findGitDir __SOURCE_DIRECTORY__ 229 | info.Exists 230 | with 231 | | _ -> false 232 | 233 | let setRemote (name,url) _ = 234 | try 235 | let cmd = sprintf "remote add %s %s" name url 236 | match Git.CommandHelper.runGitCommand __SOURCE_DIRECTORY__ cmd with 237 | | true ,_,_ -> Trace.tracefn "Successfully add remote '%s' = '%s'" name url 238 | | false,_,x -> Trace.traceError <| sprintf "Couldn't add remote: %s" x 239 | with 240 | | x -> Trace.traceException x 241 | 242 | let isRemote (name,url) value = 243 | let remote = String.getRegEx <| sprintf @"^%s\s+(https?:\/\/|git@)github.com(\/|:)%s(\.git)?\s+\(push\)$" name url 244 | remote.IsMatch value 245 | 246 | let isScaffoldRemote = isRemote ("origin","fsprojects/ProjectScaffold") 247 | 248 | let hasScaffoldOrigin () = 249 | try 250 | match Git.CommandHelper.runGitCommand __SOURCE_DIRECTORY__ "remote -v" with 251 | | true ,remotes,_ -> remotes |> Seq.exists isScaffoldRemote 252 | | false,_ ,_ -> false 253 | with 254 | | _ -> false 255 | 256 | if isGitRepo () && hasScaffoldOrigin () then 257 | Shell.deleteDir (Git.CommandHelper.findGitDir __SOURCE_DIRECTORY__).FullName 258 | 259 | if wantGit then 260 | Git.Repository.init __SOURCE_DIRECTORY__ false false 261 | givenOrigin |> Option.iter (fun url -> setRemote ("origin",url) __SOURCE_DIRECTORY__) 262 | 263 | //overwrite release notes 264 | let releaseNotesContent = [sprintf "#### 0.0.1 - %s" <| System.DateTime.Now.ToLongDateString(); "* Initial release"] 265 | overwrite "RELEASE_NOTES.md" releaseNotesContent 266 | 267 | //overwrite readme 268 | let readmeContent = [sprintf "# %s" projectName] 269 | overwrite "README.md" readmeContent 270 | 271 | //Clean up 272 | File.Delete "init.fsx" 273 | -------------------------------------------------------------------------------- /.paket/Paket.Restore.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 8 | 9 | true 10 | $(MSBuildThisFileDirectory) 11 | $(MSBuildThisFileDirectory)..\ 12 | $(PaketRootPath)paket-files\paket.restore.cached 13 | $(PaketRootPath)paket.lock 14 | /Library/Frameworks/Mono.framework/Commands/mono 15 | mono 16 | 17 | $(PaketRootPath)paket.exe 18 | $(PaketToolsPath)paket.exe 19 | "$(PaketExePath)" 20 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" 21 | 22 | 23 | <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)")) 24 | dotnet "$(PaketExePath)" 25 | 26 | 27 | "$(PaketExePath)" 28 | 29 | $(PaketRootPath)paket.bootstrapper.exe 30 | $(PaketToolsPath)paket.bootstrapper.exe 31 | "$(PaketBootStrapperExePath)" 32 | $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" 33 | 34 | 35 | 36 | 37 | true 38 | true 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | $(NoWarn);NU1603;NU1604;NU1605;NU1608 47 | 48 | 49 | 50 | 51 | /usr/bin/shasum "$(PaketRestoreCacheFile)" | /usr/bin/awk '{ print $1 }' 52 | /usr/bin/shasum "$(PaketLockFilePath)" | /usr/bin/awk '{ print $1 }' 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) 69 | $([System.IO.File]::ReadAllText('$(PaketLockFilePath)')) 70 | true 71 | false 72 | true 73 | 74 | 75 | 76 | true 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | $(MSBuildProjectDirectory)\obj\$(MSBuildProjectFile).paket.references.cached 93 | 94 | $(MSBuildProjectFullPath).paket.references 95 | 96 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references 97 | 98 | $(MSBuildProjectDirectory)\paket.references 99 | 100 | false 101 | true 102 | true 103 | references-file-or-cache-not-found 104 | 105 | 106 | 107 | 108 | $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) 109 | $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) 110 | references-file 111 | false 112 | 113 | 114 | 115 | 116 | false 117 | 118 | 119 | 120 | 121 | true 122 | target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths) 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | false 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) 145 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) 146 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4]) 147 | 148 | 149 | %(PaketReferencesFileLinesInfo.PackageVersion) 150 | All 151 | runtime 152 | true 153 | 154 | 155 | 156 | 157 | $(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).paket.clitools 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) 167 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) 168 | 169 | 170 | %(PaketCliToolFileLinesInfo.PackageVersion) 171 | 172 | 173 | 174 | 178 | 179 | 180 | 181 | 182 | 183 | false 184 | 185 | 186 | 187 | 188 | 189 | <_NuspecFilesNewLocation Include="$(BaseIntermediateOutputPath)$(Configuration)\*.nuspec"/> 190 | 191 | 192 | 193 | $(MSBuildProjectDirectory)/$(MSBuildProjectFile) 194 | true 195 | false 196 | true 197 | $(BaseIntermediateOutputPath)$(Configuration) 198 | $(BaseIntermediateOutputPath) 199 | 200 | 201 | 202 | <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.nuspec"/> 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 255 | 256 | 297 | 298 | 299 | 300 | --------------------------------------------------------------------------------