-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.fsx
175 lines (144 loc) · 6.7 KB
/
build.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
165
166
167
168
169
170
171
172
173
174
175
// --------------------------------------------------------------------------------------
// A simple FAKE build script that:
// 1) Hosts Suave server locally & reloads web part that is defined in 'app.fsx'
// 2) Deploys the web application to Azure web sites when called with 'build deploy'
// --------------------------------------------------------------------------------------
#r "packages/FSharp.Compiler.Service/lib/net45/FSharp.Compiler.Service.dll"
#r "packages/Suave/lib/net40/Suave.dll"
#r "packages/FAKE/tools/FakeLib.dll"
open Fake
open System
open System.IO
open Suave
open Suave.Web
open Microsoft.FSharp.Compiler.Interactive.Shell
// --------------------------------------------------------------------------------------
// The following uses FileSystemWatcher to look for changes in 'app.fsx'. When
// the file changes, we run `#load "app.fsx"` using the F# Interactive service
// and then get the `App.app` value (top-level value defined using `let app = ...`).
// The loaded WebPart is then hosted at localhost:8083.
// --------------------------------------------------------------------------------------
let sbOut = new Text.StringBuilder()
let sbErr = new Text.StringBuilder()
let fsiSession =
let inStream = new StringReader("")
let outStream = new StringWriter(sbOut)
let errStream = new StringWriter(sbErr)
let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
let argv = Array.append [|"/fake/fsi.exe"; "--quiet"; "--noninteractive"; "-d:DO_NOT_START_SERVER"|] [||]
FsiEvaluationSession.Create(fsiConfig, argv, inStream, outStream, errStream)
let reportFsiError (e:exn) =
traceError "Reloading app.fsx script failed."
traceError (sprintf "Message: %s\nError: %s" e.Message (sbErr.ToString().Trim()))
sbErr.Clear() |> ignore
let reloadScript () =
try
//Reload application
traceImportant "Reloading app.fsx script..."
let appFsx = __SOURCE_DIRECTORY__ @@ "app.fsx"
fsiSession.EvalInteraction(sprintf "#load @\"%s\"" appFsx)
fsiSession.EvalInteraction("open App")
match fsiSession.EvalExpression("app") with
| Some app -> Some(app.ReflectionValue :?> WebPart)
| None -> failwith "Couldn't get 'app' value"
with e -> reportFsiError e; None
// --------------------------------------------------------------------------------------
// Suave server that redirects all request to currently loaded version
// --------------------------------------------------------------------------------------
let currentApp = ref (fun _ -> async { return None })
let rec findPort port =
try
let tcpListener = System.Net.Sockets.TcpListener(System.Net.IPAddress.Parse("127.0.0.1"), port)
tcpListener.Start()
tcpListener.Stop()
port
with :? System.Net.Sockets.SocketException as ex ->
findPort (port + 1)
let getLocalServerConfig port =
{ defaultConfig with
homeFolder = Some __SOURCE_DIRECTORY__
logger = Logging.Loggers.saneDefaultsFor Logging.LogLevel.Debug
bindings = [ HttpBinding.mkSimple HTTP "127.0.0.1" port ] }
let reloadAppServer (changedFiles: string seq) =
traceImportant <| sprintf "Changes in %s" (String.Join(",",changedFiles))
reloadScript() |> Option.iter (fun app ->
currentApp.Value <- app
traceImportant "Refreshed app." )
Target "run" (fun _ ->
let app ctx = currentApp.Value ctx
let port = findPort 8083
let _, server = startWebServerAsync (getLocalServerConfig port) app
// Start Suave to host it on localhost
reloadAppServer ["app.fsx"]
Async.Start(server)
// Open web browser with the loaded file
System.Diagnostics.Process.Start(sprintf "http://localhost:%d" port) |> ignore
// Watch for changes & reload when app.fsx changes
let sources =
{ BaseDirectory = __SOURCE_DIRECTORY__
Includes = [ "**/*.fsx"; "**/*.fs" ; "**/*.fsproj"; "web/content/app/*.js" ];
Excludes = [] }
use watcher = sources |> WatchChanges (Seq.map (fun x -> x.FullPath) >> reloadAppServer)
traceImportant "Waiting for app.fsx edits. Press any key to stop."
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite)
)
// --------------------------------------------------------------------------------------
// Targets for running build script in background (for Atom)
// --------------------------------------------------------------------------------------
open System.Diagnostics
let runningFileLog = __SOURCE_DIRECTORY__ @@ "build.log"
let runningFile = __SOURCE_DIRECTORY__ @@ "build.running"
Target "spawn" (fun _ ->
if File.Exists(runningFile) then
failwith "The build is already running!"
let ps =
ProcessStartInfo
( WorkingDirectory = __SOURCE_DIRECTORY__,
FileName = __SOURCE_DIRECTORY__ @@ "packages/FAKE/tools/FAKE.exe",
Arguments = "run --fsiargs build.fsx",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false )
use fs = new FileStream(runningFileLog, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)
use sw = new StreamWriter(fs)
let p = Process.Start(ps)
p.ErrorDataReceived.Add(fun data -> printfn "%s" data.Data; sw.WriteLine(data.Data); sw.Flush())
p.OutputDataReceived.Add(fun data -> printfn "%s" data.Data; sw.WriteLine(data.Data); sw.Flush())
p.EnableRaisingEvents <- true
p.BeginOutputReadLine()
p.BeginErrorReadLine()
File.WriteAllText(runningFile, string p.Id)
while File.Exists(runningFile) do
System.Threading.Thread.Sleep(500)
p.Kill()
)
Target "attach" (fun _ ->
if not (File.Exists(runningFile)) then
failwith "The build is not running!"
use fs = new FileStream(runningFileLog, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
use sr = new StreamReader(fs)
while File.Exists(runningFile) do
let msg = sr.ReadLine()
if not (String.IsNullOrEmpty(msg)) then
printfn "%s" msg
else System.Threading.Thread.Sleep(500)
)
Target "stop" (fun _ ->
if not (File.Exists(runningFile)) then
failwith "The build is not running!"
File.Delete(runningFile)
)
// --------------------------------------------------------------------------------------
// Minimal Azure deploy script - just overwrite old files with new ones
// --------------------------------------------------------------------------------------
Target "deploy" (fun _ ->
let sourceDirectory = __SOURCE_DIRECTORY__
let wwwrootDirectory = __SOURCE_DIRECTORY__ @@ "../wwwroot"
CleanDir wwwrootDirectory
CopyRecursive sourceDirectory wwwrootDirectory false |> ignore
)
// -------------------------------------------------------------------------------------
// Minifying JS for better performance
// This is using built in NPMHelper and other things are getting done by node js
// -------------------------------------------------------------------------------------
RunTargetOrDefault "run"