What am i trying to do
I am trying to use FAKE TemplateHelperto instantiate some template files that become shell scripts (both Unix and DOS). I did this in the FAKE task as follows:
CopyFile (buildApp @@ product + ".sh") (srcTem @@ "mono-launcher.sh")
processTemplates substs [(buildApp @@ product + ".sh")]
where substsare the var-> value mappings for substitution, and srcTemand buildAppare the source directories of the templates and directories of the output of the assembly, respectively.
What happened wrong
I ran into three problems:
First I TemplateHelper.processTemplateswrote down the UTF-8 specification at the beginning of the generated script. At least on Unix, this will ruin the shebang line and give an error message when running the script. The octal dump of the first line of the source template and the generated file show the appearance of these 3 nasty bytes:
$ head -1 ./src/templates/mono-launcher.sh | od -c
0000000 # ! / b i n / s h \n
$ head -1 ./build/app/Hello-Fsharp.sh | od -c
0000000 357 273 277
Secondly, there was no way to say that the generated Unix sh scripts should have Unix EOL in them, while Windows.bat scripts should have EOS DOS.
Thirdly, there was no obvious way to say that the resulting files should have read and execute permissions.
This question is about whether anyone knows how to deal with these problems, at least better than what I came up with below.
TemplateHelper . processTemplate WriteFile, WriteToFile, encoding, EnvironmentHelper System.Text.Encoding.Default, UTF-8. , , , ASCIIEncoding.
... - TemplateHelper , , :
let processTemplate substs fromEncoding fromTemplate toEncoding toFile unixEOL readExecute =
let ReadTemplate encoding fileName =
File.ReadLines(fileName, encoding)
let SubstituteVariables substs =
Seq.map (fun (line : string) ->
substs
|> Seq.fold (fun (sb : StringBuilder) (KeyValue(k : string, v : string)) ->
sb.Replace(k, v))
(new StringBuilder(line))
|> toText)
let MaybeAddReturn =
Seq.map (fun line -> if unixEOL then line else line + "\r")
let WriteTemplate encoding fileName (lines : seq<string>) =
File.WriteAllLines(fileName, lines, encoding)
fileName
let MaybeSetReadExecute fileName =
if readExecute then
if isMono then
Shell.Exec("chmod", "a+rx " + fileName, here) |> ignore
else
let fs = File.GetAccessControl(fileName)
fs.AddAccessRule(new FileSystemAccessRule(
new SecurityIdentifier(WellKnownSidType.WorldSid, null),
FileSystemRights.ReadAndExecute,
AccessControlType.Allow))
File.SetAccessControl(fileName, fs)
let shortClassName obj =
let str = obj.ToString() in str.Substring(str.LastIndexOf('.') + 1)
logfn " Template %s (%s) generating %s (%s, %s EOLs%s)."
fromTemplate (shortClassName fromEncoding)
toFile (shortClassName toEncoding)
(if unixEOL then "Unix" else "DOS")
(if readExecute then ", read/execute" else "")
fromTemplate
|> ReadTemplate fromEncoding
|> SubstituteVariables substs
|> MaybeAddReturn
|> WriteTemplate toEncoding toFile
|> MaybeSetReadExecute
, , TemplateHelper, . , , , - . - , EOL , , .
:
Target "BuildLauncherScripts" (fun _ ->
let asciiEncoding = new ASCIIEncoding()
let generateAScript (fromTempl : String) =
let ext = fromTempl.Substring(fromTempl.LastIndexOf('.'))
processTemplate projProps
asciiEncoding (srcTem @@ fromTempl)
asciiEncoding (buildApp @@ (projProps.Item("@product")) + ext)
(ext = ".sh") true
generateAScript "mono-launcher.sh"
generateAScript "bat-launcher.bat"
)
TemplateHelper /, EOL /?- , ?
- In particular, can the EOL code work on Windows or will it double upon return?
- Also, is there a way to set read / execute permissions on a neutral platform? (My code above
MaybeSetReadExecuteis a frighteningly mixed combination of crawling and emulating some .NET code that I found but hardly understand.)