rename.fsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// -------------------------------------------------------------------------------
// Initial rename of library and project script
// -------------------------------------------------------------------------------

// Bind operator
let (>>=) m f = Option.bind f m

// Args function that parses command line arguments
let getArg argv key =
  let arg = Array.tryFind(fun (a:string) -> a.StartsWith(key)) argv
  match arg with
  | Some x -> x.Replace(key, "") |> Some
  | None -> None

// Thread-safe console logger
let ts () = System.DateTime.Now.ToString("o")           // ISO-8601
let cw (s:string) = System.Console.WriteLine(s)         // Threadsafe console writer
let cew (s:string) = System.Console.Error.WriteLine(s)  // Threadsafe console error writer
type LogLevel = Info | Warning | Error
let log level x y =
  let msg = sprintf "%s - %A: %A (%A)" (ts()) level x y
  match level with
  | LogLevel.Error -> cew msg
  | LogLevel.Info | LogLevel.Warning -> cw msg

// Generic process executer (needed for "git mv source target")
let executeProcess exe args dir =
  try
    let psi = new System.Diagnostics.ProcessStartInfo(exe,args) 
    psi.CreateNoWindow <- true        
    psi.UseShellExecute <- false
    psi.RedirectStandardOutput <- true
    psi.RedirectStandardError <- true
    psi.WorkingDirectory <- dir
    let p = System.Diagnostics.Process.Start(psi)
    let o = new System.Text.StringBuilder()
    let e = new System.Text.StringBuilder()
    p.OutputDataReceived.Add(fun x -> o.AppendLine(x.Data) |> ignore)
    p.ErrorDataReceived.Add(fun x -> e.AppendLine(x.Data) |> ignore)
    p.BeginErrorReadLine()
    p.BeginOutputReadLine()
    p.WaitForExit()
    (p.ExitCode, o.ToString(), e.ToString()) |> Some
  with ex -> log LogLevel.Error (exe,args,dir) ex; None

// Scaffold & Template
let scaffold = "FSharp.ProjectScaffold"
let template = "FSharp.ProjectTemplate"

// The name of the library (will replace "FSharp.ProjectScaffold")
let lib = 
  ((fsi.CommandLineArgs,"lib=") ||> getArg, "FSharp.Foo")
  ||> defaultArg

// The name of the project (will replace "FSharp.ProjectTemplate")
let proj =
  ((fsi.CommandLineArgs,"proj=") ||> getArg, "FSharp.Bar")
  ||> defaultArg

// Folder & file helper functions
let root = __SOURCE_DIRECTORY__
let recursively = System.IO.SearchOption.AllDirectories
let pattern filter = "*" + filter + "*"
let pattern' filter = "*" + filter
let dirs path filter =
  System.IO.Directory.EnumerateDirectories(path,filter,recursively)
let files path filter =
  System.IO.Directory.EnumerateFiles(path,filter,recursively)
let rev (s:string) =
  s |> Seq.toArray |> Array.fold(fun a x -> (x |> string) + a) ""
let replaceFirst input from to' =
  let r = new System.Text.RegularExpressions.Regex(from)
  r.Replace(input = input,replacement = to', count = 1)
let isGit =
  let exe  = "git"
  let args = sprintf "status"
  let git  = (exe,args,root) |||> executeProcess
  git |> function | Some (x,y,z) -> x = 0 | None -> false
let renameGit path path' =
  let exe  = "git"
  let args = sprintf "mv \"%s\" \"%s\"" path path'
  (exe,args,root) |||> executeProcess, path, path'
let renameDirs path path' =
  System.IO.Directory.Move(path,path') |> ignore
  (0,"","") |> Some,path,path'
let renameFiles path path' =
  System.IO.File.Move(path,path') |> ignore
  (0,"","") |> Some,path,path'
let rename' path path' =
  match isGit with
  | true -> (path,path') ||> renameGit
  | false ->
    match System.IO.File.GetAttributes(path) with
    | System.IO.FileAttributes.Directory -> (path,path') ||> renameDirs 
    | _ -> (path,path') ||> renameFiles
let rename (path:string) from to' =
  let from' = from  |> rev
  let to''  = to'   |> rev
  let path' = (path |> rev, from', to'') |||> replaceFirst |> rev
  (path,path') ||> rename'
let rollback xs = xs |> List.iter(fun (x,y) -> (y,x) ||> rename' |> ignore)

// File content helper functions
let utf8 = System.Text.UTF8Encoding.UTF8
let readLines path = System.IO.File.ReadLines(path,utf8)
let writeLines path (contents:string seq)  =
  System.IO.File.WriteAllLines(path,contents,utf8)
let copy from to' =
  System.IO.File.Copy(from,to',true)
let delete path = System.IO.File.Delete(path)
let extensions = [ ".sln"; ".fs"; ".fsx"; ".fsproj"; ".nuspec"; ".md" ]

// Rename files or directories
let renameIO from to' fn atomic' =
  try
      (root,from |> pattern) ||> fn
      |> Seq.map(fun x -> (x,from,to') |||> rename)
      |> Seq.fold(fun (i,acc) (x,y,z) ->
                  let i' =
                    match x with
                    | Some (a,b,c) -> a
                    | None -> 1
                  (i+i',(y,z)::acc)) (0,[])
      |> fun (x,y) ->
        match x with
        | 0 -> (y,atomic') ||> List.append |> Some
        | _ -> atomic' |> rollback; None
  with ex -> log LogLevel.Error (atomic',from,to') ex; None

// Update files content
let updateContent exts atomic' =
  try
    exts
    |> Seq.map(fun x -> (root,x |> pattern') ||> files)
    |> Seq.fold(fun a x -> (x,a) ||> Seq.append) Seq.empty
    |> Seq.filter(fun x -> not (x.Contains "rename.fsx"))
    |> Seq.fold(fun a x ->
                let x' = x + "_"
                x |> readLines
                  |> Seq.map(fun y -> y.Replace(scaffold,lib)
                                       .Replace(template,proj))
                  |> writeLines x'
                (x,x')::a) []
    |> Seq.iter(fun (x,y) -> (y,x) ||> copy; y |> delete)
    |> Some
  with ex ->
    let git =
      match isGit with
      | false -> (0,"","") |> Some // Not really rollback but ...
      | true ->
        let exe  = "git"
        let args = sprintf "checkout -- *"
        (exe,args,root) |||> executeProcess
    atomic' |> rollback
    log LogLevel.Error (exts,git) ex; None

// Rename with atomicity "git mv file2 file1"
[] |> Some >>= (renameIO scaffold lib dirs)
           >>= (renameIO template proj dirs)
           >>= (renameIO scaffold lib files)
           >>= (renameIO template proj files)

// Update content
           >>= (updateContent extensions)

rename.cmd:

@echo off
:: Add the paths for the F# SDK 3.x (from higher version to lower)
set FSHARPSDK=^
C:\Program Files (x86)\Microsoft SDKs\F#\3.1\Framework\v4.0\;^
C:\Program Files (x86)\Microsoft SDKs\F#\3.0\Framework\v4.0\

cls
:: Execute the script "only" with the first "fsianycpu.exe" found
for %%i in (fsianycpu.exe) do "%%~$FSHARPSDK:i" rename.fsx %*

pause

rename.sh:

#!/bin/bash
#workaround to handle different path for fsi
export FSHARPI=`which fsharpi`
cat - > fsharpi <<"EOF"
#!/bin/bash
$FSHARPI $@
EOF
chmod +x fsharpi
fsharpi rename.fsx $@
rm fsharpi

Git clone FSharp.ProjectScaffold

[ mon@mbai7 rename ] git clone git@github.com:fsprojects/FSharp.ProjectScaffold.git
Cloning into 'FSharp.ProjectScaffold'...
remote: Reusing existing pack: 674, done.
remote: Total 674 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (674/674), 593.40 KiB | 375.00 KiB/s, done.
Resolving deltas: 100% (342/342), done.
Checking connectivity... done.
[ mon@mbai7 rename ] cd FSharp.ProjectScaffold/

Grep for FSharp.ProjectScaffold and FSharp.ProjectTemplate:

[ mon@mbai7 FSharp.ProjectScaffold ] grep -R "FSharp.ProjectScaffold" .
./build.fsx:let solutionFile  = "FSharp.ProjectScaffold"
./build.fsx:let gitName = "FSharp.ProjectScaffold"
./docs/content/index.fsx:  [content]: https://github.com/fsprojects/FSharp.ProjectScaffold/tree/master/docs/content
./docs/content/index.fsx:  [gh]: https://github.com/fsprojects/FSharp.ProjectScaffold
./docs/content/index.fsx:  [issues]: https://github.com/fsprojects/FSharp.ProjectScaffold/issues
./docs/content/index.fsx:  [readme]: https://github.com/fsprojects/FSharp.ProjectScaffold/blob/master/README.md
./docs/content/index.fsx:  [license]: https://github.com/fsprojects/FSharp.ProjectScaffold/blob/master/LICENSE.txt
./docs/tools/generate.fsx:let website = "/FSharp.ProjectScaffold"
./docs/tools/generate.fsx:let githubLink = "http://github.com/fsprojects/FSharp.ProjectScaffold"
./docs/tools/generate.fsx:  [ "project-name", "FSharp.ProjectScaffold"
./docs/tools/generate.fsx:    "project-nuget", "http://nuget.com/packages/FSharp.ProjectScaffold" ]
./nuget/FSharp.ProjectTemplate.nuspec:    <licenseUrl>http://github.com/fsprojects/FSharp.ProjectScaffold/blob/master/LICENSE.txt</licenseUrl>
./nuget/FSharp.ProjectTemplate.nuspec:    <projectUrl>http://fsprojects.github.com/FSharp.ProjectScaffold</projectUrl>
./nuget/FSharp.ProjectTemplate.nuspec:    <iconUrl>https://raw.github.com/fsharp/FSharp.ProjectScaffold/master/nuget/logo.png</iconUrl>
./README.md:FSharp.ProjectScaffold
./README.md:      <td><a href="FSharp.ProjectScaffold.sln">FSharp.ProjectScaffold.sln</a></td>
./README.md:<a href="http://fsprojects.github.io/FSharp.ProjectScaffold" target="_blank">Sample API documents available here.</a>
./RELEASE_NOTES.md:* Changed name from fsharp-project-scaffold to FSharp.ProjectScaffold
./rename.fsx:let scaffold = "FSharp.ProjectScaffold"
./rename.fsx:// The name of the library (will replace "FSharp.ProjectScaffold")
./tests/FSharp.ProjectTemplate.Tests/Tests.fs:module FSharp.ProjectScaffold.Tests
[ mon@mbai7 FSharp.ProjectScaffold ] grep -R "FSharp.ProjectTemplate" .
./build.fsx:let project = "FSharp.ProjectTemplate"
./docs/content/index.fsx:      The F# ProjectTemplate library can be <a href="https://nuget.org/packages/FSharp.ProjectTemplate">installed from NuGet</a>:
./docs/content/index.fsx:      <pre>PM> Install-Package FSharp.ProjectTemplate</pre>
./docs/content/index.fsx:#r "FSharp.ProjectTemplate.dll"
./docs/content/index.fsx:open FSharp.ProjectTemplate
./docs/content/tutorial.fsx:#r "FSharp.ProjectTemplate.dll"
./docs/content/tutorial.fsx:open FSharp.ProjectTemplate
./docs/tools/generate.fsx:let referenceBinaries = [ "FSharp.ProjectTemplate.dll" ]
./FSharp.ProjectScaffold.sln:Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ProjectTemplate", "src\FSharp.ProjectTemplate\FSharp.ProjectTemplate.fsproj", "{7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}"
./FSharp.ProjectScaffold.sln:																									 	 nuget\FSharp.ProjectTemplate.nuspec = nuget\FSharp.ProjectTemplate.nuspec
./FSharp.ProjectScaffold.sln:Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ProjectTemplate.Tests", "tests\FSharp.ProjectTemplate.Tests\FSharp.ProjectTemplate.Tests.fsproj", "{E789C72A-5CFD-436B-8EF1-61AA2852A89F}"
./nuget/FSharp.ProjectTemplate.nuspec:    <file src="..\bin\FSharp.ProjectTemplate.dll" target="lib/net40" />
./README.md:        A good way to get started is to rename the project included in this sample (FSharp.ProjectTemplate). 
./rename.fsx:let template = "FSharp.ProjectTemplate"
./rename.fsx:// The name of the project (will replace "FSharp.ProjectTemplate")
./src/FSharp.ProjectTemplate/AssemblyInfo.fs:[<assembly: AssemblyTitleAttribute("FSharp.ProjectTemplate")>]
./src/FSharp.ProjectTemplate/AssemblyInfo.fs:[<assembly: AssemblyProductAttribute("FSharp.ProjectTemplate")>]
./src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj:    <RootNamespace>FSharp.ProjectTemplate</RootNamespace>
./src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj:    <AssemblyName>FSharp.ProjectTemplate</AssemblyName>
./src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj:    <Name>FSharp.ProjectTemplate</Name>
./src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj:    <DocumentationFile>bin\Debug\FSharp.ProjectTemplate.xml</DocumentationFile>
./src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj:    <DocumentationFile>..\..\bin\FSharp.ProjectTemplate.xml</DocumentationFile>
./src/FSharp.ProjectTemplate/Library.fs:namespace FSharp.ProjectTemplate
./src/FSharp.ProjectTemplate/Script.fsx:open FSharp.ProjectTemplate
./tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj:    <RootNamespace>FSharp.ProjectTemplate.Tests</RootNamespace>
./tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj:    <AssemblyName>FSharp.ProjectTemplate.Tests</AssemblyName>
./tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj:    <Name>FSharp.ProjectTemplate.Tests</Name>
./tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj:    <DocumentationFile>bin\Release\FSharp.ProjectTemplate.Tests.xml</DocumentationFile>
./tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj:    <ProjectReference Include="..\..\src\FSharp.ProjectTemplate\FSharp.ProjectTemplate.fsproj">
./tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj:      <Name>FSharp.ProjectTemplate</Name>
./tests/FSharp.ProjectTemplate.Tests/Tests.fs:open FSharp.ProjectTemplate

Rename FSharp.ProjectScaffold and FSharp.ProjectTemplate:

[ mon@mbai7 FSharp.ProjectScaffold ] cp ../rename.* .
‘../rename.cmd’ -> ‘./rename.cmd’
‘../rename.fsx’ -> ‘./rename.fsx’
‘../rename.sh’ -> ‘./rename.sh’
[ mon@mbai7 FSharp.ProjectScaffold ] chmod +x rename.sh 
[ mon@mbai7 FSharp.ProjectScaffold ] ./rename.sh lib=Stermon.Foo proj=Stermon.Bar

Grep for FSharp.ProjectScaffold and FSharp.ProjectTemplate (again):

[ mon@mbai7 FSharp.ProjectScaffold ] grep -R "FSharp.ProjectScaffold" .
./rename.fsx:let scaffold = "FSharp.ProjectScaffold"
./rename.fsx:// The name of the library (will replace "FSharp.ProjectScaffold")
[ mon@mbai7 FSharp.ProjectScaffold ] grep -R "FSharp.ProjectTemplate" .
./rename.fsx:let template = "FSharp.ProjectTemplate"
./rename.fsx:// The name of the project (will replace "FSharp.ProjectTemplate")

Build FSharp.ProjectScaffold:

[ mon@mbai7 FSharp.ProjectScaffold ] chmod +x build.sh 
[ mon@mbai7 FSharp.ProjectScaffold ] ./build.sh 
Installing 'FAKE 2.15.2'.
Successfully installed 'FAKE 2.15.2'.
fsharpi build.fsx
Building project with version: LocalBuild
Shortened DependencyGraph for Target All:
<== All
<== RunTests
<== Build
<== AssemblyInfo
<== RestorePackages
      <== Clean

The resulting target order is:
 - Clean
 - RestorePackages
 - AssemblyInfo
 - Build
 - RunTests
 - All
Starting Target: All (==> RunTests)
Starting Target: RunTests (==> Build)
Starting Target: Build (==> AssemblyInfo)
Starting Target: AssemblyInfo (==> RestorePackages)
Starting Target: RestorePackages (==> Clean)
Starting Target: Clean 
Deleting contents of bin
Deleting contents of temp
Finished Target: Clean

...

Execution Runtime: mono-3.5
***** Stermon.Foo.Tests.hello returns 42
42

Tests run: 1, Errors: 0, Failures: 0, Inconclusive: 0, Time: 0.0387905 seconds
  Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0

Finished Target: RunTests
Finished Target: All
Killing all processes that are created by FAKE and are still running.

---------------------------------------------------------------------
Build Time Report
---------------------------------------------------------------------
Target            Duration
------            --------
Clean             00:00:00.0043722
RestorePackages   00:00:02.4633336
AssemblyInfo      00:00:00.0062624
Build             00:00:05.3281672
RunTests          00:00:01.1349369
All               00:00:00.0000441
Total:            00:00:08.9734871
Status:           Ok
---------------------------------------------------------------------

Stermon.Foo and Stermon.Bar:

[ mon@mbai7 FSharp.ProjectScaffold ] ll . bin/ src/ tests/
.:
total 64K
-rw-r--r--  1 mon staff 1.2K Apr 25 18:20 LICENSE.txt
-rw-r--r--  1 mon staff  16K Apr 25 18:45 README.md
-rw-r--r--  1 mon staff  374 Apr 25 18:45 RELEASE_NOTES.md
-rw-r--r--  1 mon staff 3.2K Apr 25 18:45 Stermon.Foo.sln
-rw-r--r--  1 mon staff 1.7K Apr 25 18:48 TestResults.xml
drwxr-xr-x  5 mon staff  170 Apr 25 18:48 bin/
-rw-r--r--  1 mon staff  182 Apr 25 18:20 build.cmd
-rw-r--r--  1 mon staff 5.6K Apr 25 18:45 build.fsx
-rwxr-xr-x  1 mon staff  398 Apr 25 18:20 build.sh*
drwxr-xr-x  6 mon staff  204 Apr 25 18:20 docs/
drwxr-xr-x  3 mon staff  102 Apr 25 18:45 lib/
drwxr-xr-x  5 mon staff  170 Apr 25 18:45 nuget/
drwxr-xr-x 10 mon staff  340 Apr 25 18:48 packages/
-rw-r--r--  1 mon staff   39 Apr 25 18:44 rename.cmd
-rw-r--r--  1 mon staff 5.2K Apr 25 18:44 rename.fsx
-rwxr-xr-x  1 mon staff   59 Apr 25 18:44 rename.sh*
drwxr-xr-x  3 mon staff  102 Apr 25 18:41 src/
drwxr-xr-x  2 mon staff   68 Apr 25 18:48 temp/
drwxr-xr-x  3 mon staff  102 Apr 25 18:41 tests/

bin/:
total 12K
-rwxr-xr-x 1 mon staff 4.0K Apr 25 18:48 Stermon.Bar.dll*
-rw-r--r-- 1 mon staff  276 Apr 25 18:48 Stermon.Bar.dll.mdb
-rw-r--r-- 1 mon staff  196 Apr 25 18:48 Stermon.Bar.xml

src/:
total 0
drwxr-xr-x 7 mon staff 238 Apr 25 18:48 Stermon.Bar/

tests/:
total 0
drwxr-xr-x 7 mon staff 238 Apr 25 18:48 Stermon.Bar.Tests/

Git status:

[ mon@mbai7 FSharp.ProjectScaffold ] git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	renamed:    FSharp.ProjectScaffold.sln -> Stermon.Foo.sln
	renamed:    nuget/FSharp.ProjectTemplate.nuspec -> nuget/Stermon.Bar.nuspec
	renamed:    src/FSharp.ProjectTemplate/AssemblyInfo.fs -> src/Stermon.Bar/AssemblyInfo.fs
	renamed:    src/FSharp.ProjectTemplate/Library.fs -> src/Stermon.Bar/Library.fs
	renamed:    src/FSharp.ProjectTemplate/Script.fsx -> src/Stermon.Bar/Script.fsx
	renamed:    src/FSharp.ProjectTemplate/FSharp.ProjectTemplate.fsproj -> src/Stermon.Bar/Stermon.Bar.fsproj
	renamed:    tests/FSharp.ProjectTemplate.Tests/FSharp.ProjectTemplate.Tests.fsproj -> tests/Stermon.Bar.Tests/Stermon.Bar.Tests.fsproj
	renamed:    tests/FSharp.ProjectTemplate.Tests/Tests.fs -> tests/Stermon.Bar.Tests/Tests.fs
	renamed:    tests/FSharp.ProjectTemplate.Tests/packages.config -> tests/Stermon.Bar.Tests/packages.config

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   README.md
	modified:   RELEASE_NOTES.md
	modified:   Stermon.Foo.sln
	deleted:    bin/README.md
	modified:   build.fsx
	modified:   build.sh
	modified:   docs/content/index.fsx
	modified:   docs/content/tutorial.fsx
	modified:   docs/output/README.md
	modified:   docs/tools/generate.fsx
	modified:   lib/README.md
	modified:   nuget/README.md
	modified:   nuget/Stermon.Bar.nuspec
	modified:   packages/README.md
	modified:   src/Stermon.Bar/AssemblyInfo.fs
	modified:   src/Stermon.Bar/Library.fs
	modified:   src/Stermon.Bar/Script.fsx
	modified:   src/Stermon.Bar/Stermon.Bar.fsproj
	deleted:    temp/README.md
	modified:   tests/Stermon.Bar.Tests/Stermon.Bar.Tests.fsproj
	modified:   tests/Stermon.Bar.Tests/Tests.fs

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	rename.cmd
	rename.fsx
	rename.sh

References: