Fake.Deploy Running custom Windows Service locks deployment files and thus updates - f#

I'd like to deploy some Windows Services using FAKE.
After deploying the package using a FAKE build script I install the services using the after deployment build script (*.fsx).
This is all working great except that as soon as the service is started, the files become locked. This prohibits any further (update) deployments.
Is it somehow possible to stop the service before FAKE.Deploy tries to overwrite the files?

Just do not install your service from directory where FAKE unzip it.
Do it like this:
Check that target directory is exist. Create it if it is not
Check if service is installed and uninstall in this case
Clean target directory (to be sure that everything is removed)
Copy files of new version
Install new version of service in target directory
Deployment script from my project:
#r #"c:\Project\FAKE.Deploy\bin\FAKE\tools\FakeLib.dll"
open Fake
open System
open System.IO
let targetDirectory = #"c:\Project\Service"
let runScript file =
if File.Exists file then
let result, messages =
ExecProcessRedirected
(fun info ->
info.FileName <- file
info.WorkingDirectory <- targetDirectory)
(TimeSpan.FromMinutes 10.0)
for msg in messages do
(if msg.IsError then traceError else traceImportant) msg.Message
if not result then
failwithf "MyProc.exe returned with a non-zero exit code"
else
traceImportant <| sprintf "File %s is not found" file
// *** Define Targets ***
Target "EnsureDirectory" (fun () ->
trace <| sprintf " --- Ensure that directory '%s' is exist --- " targetDirectory
CreateDir targetDirectory
)
Target "UninstallService" (fun () ->
trace " --- Uninstall service --- "
targetDirectory ## "uninstall.bat"
|> runScript
)
Target "CleanDirectory" (fun () ->
trace " --- Clean target directory --- "
CleanDir targetDirectory
)
Target "CopyFiles" (fun () ->
trace " --- Copy new files --- "
XCopy (__SOURCE_DIRECTORY__ ## "content") targetDirectory
)
Target "InstallService" (fun () ->
trace " --- Install service --- "
targetDirectory ## "install.bat"
|> runScript
)
Target "Deploy" DoNothing
// *** Define Dependencies ***
"EnsureDirectory"
==> "UninstallService"
==> "CleanDirectory"
==> "CopyFiles"
==> "InstallService"
==> "Deploy"
// *** Start Build ***
RunParameterTargetOrDefault "target" "Deploy"

Related

Add Firebase Analytics and Crashlytics to iOS project with multiple schemes

I have a projects with multiple schemes (Not targets).
I have Dev, QA and Prod and I want to add Firebase Analytics and Crashlytics to all of the schemes note that each scheme has its own Bundle id and different name.
How can I achieve this this?
if you have multple scheme on just one target:
you can change plist files following the scheme like this:
#if DEV_DEBUG || DEV_RELEASE
let filePath = Bundle.main.path(forResource: "GoogleService-Info-Dev", ofType: "plist")
#else
let filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")
#endif
guard let fileopts = FirebaseOptions(contentsOfFile: filePath!)
else { assert(false, "Couldn't load config file") }
FirebaseApp.configure(options: fileopts)
in this code I have two schem one is Dev other is Prod
Tested on Xcode 13.3.X
Assuming you already have a Google Firebase account and opened an app in the Firebase console add an app in the console for iOS.
Follow the steps and register your Bundle id for the app now for each scheme (Dev, QA and Prod) you will need to register a different app with different Bundle id and download the GoogleService-Info.plist file DO NOT rename the Plist files.
In your Xcode project Create separate folders for each environment drag each GoogleService-Info.plist files to their folder and Uncheck Copy to target.
In your pod file add pod 'Firebase/Crashlytics' (if you are also using analytics add the pod) and run pod install in the terminal.
After this go to pods target (this is a bug that google suggested a workaround for) and search Apple Clang - Warnings - All Languages and set Quoted include in Framework Header to NO).
After this Go to your target Build Settings under Build Options -> Debug Information Format set all to :
DWARF with dSYM File
On Build Phase tab in the Target add 2 Run Scripts.
The first call Firebase Plist selector (or any other name you want just make sure it runs BEFORE the script to upload the dSYM) and add the following script :
INFO_PLIST=GoogleService-Info.plist
DEVELOPMENT_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Environment/Dev/${INFO_PLIST}
QA_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Environment/QA/${INFO_PLIST}
PROD_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Environment/Prod/${INFO_PLIST}
echo "DEV -> CHECKING in development! ${INFO_PLIST} in ${DEVELOPMENT_INFO_PLIST}"
if [ ! -f $DEVELOPMENT_INFO_PLIST ] ; then
echo "DEV GoogleService-Info.plist not found."
exit 1
fi
echo "QA -> CHECKING in QA ${INFO_PLIST} in ${QA_INFO_PLIST}"
if [ ! -f $QA_INFO_PLIST ] ; then
echo "QA GoogleService-Info.plist not found."
exit 1
fi
echo "PROD -> CHECKING in PROD ${INFO_PLIST} in ${PROD_INFO_PLIST}"
if [ ! -f $PROD_INFO_PLIST ] ; then
echo "PROD GoogleService-Info.plist not found."
exit 1
fi
PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Copying ${INFO_PLIST} to final destination: ${PLIST_DESTINATION}"
elif [ "${CONFIGURATION}" == "QA MyProject" ] ; then
echo "QA -> Copied FILE : ${QA_INFO_PLIST}."
cp "${QA_INFO_PLIST}" "${PLIST_DESTINATION}"
elif [ "${CONFIGURATION}" == "Prod MyProject" ] ; then
echo "PROD -> Copied FILE : ${PROD_INFO_PLIST}."
cp "${PROD_INFO_PLIST}" "${PLIST_DESTINATION}"
else
echo "DEV -> Copied ${DEVELOPMENT_INFO_PLIST}."
cp "${DEVELOPMENT_INFO_PLIST}" "${PLIST_DESTINATION}"
fi
Here you are checking for the GoogleService-Info.plist file for each scheme (note where it says /Environment/Dev QA Prod etc change it to your folder path) if the file is found then it will be added in build time and the correct Plist file will be added to the build each time.
Now in the second script add this:
"${PODS_ROOT}/FirebaseCrashlytics/run"
And under Input Files add these 2:
$(SRCROOT)/${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)
Clean and build project if everything is correct when your enter the Crashlytics part in the console and simulate a crash (you can put fatalError on a IBAction or Button action to simulate) and you will be able to see your crash for each scheme you configured.
As a note if you wish to copy a folder use :
cp -R
This will copy the folder and all its contents.
Very important to add a / at the end of the name for example change
INFO_PLIST=GoogleService-Info.plist
to
INFO_PLIST=MYFOLDERNAME/
Kindest regards.

ClassNotFoundException using Spark library through Bazel

I am trying to run a "hello world" server in Spark building it with Bazel, but I am getting this error:
$ bazel run //:app
INFO: Analysed target //:app (0 packages loaded).
INFO: Found 1 target...
Target //:app up-to-date:
bazel-bin/app.jar
bazel-bin/app
INFO: Elapsed time: 0.201s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at spark.Service.<clinit>(Service.java:56)
at spark.Spark$SingletonHolder.<clinit>(Spark.java:51)
at spark.Spark.getInstance(Spark.java:55)
at spark.Spark.<clinit>(Spark.java:61)
at io.app.server.Main.main(Main.java:7)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 5 more
BUILD:
java_binary(
name = "app",
main_class = "io.app.server.Main",
srcs = ["src/main/java/io/app/server/Main.java"],
deps = [
"#org_slf4j_slf4j_simple//jar",
"#com_sparkjava_spark_core//jar",
]
)
The same error happens if I don't include slf4j, and it should not be a required dependency of spark.
WORKSPACE:
maven_jar(
name = "com_sparkjava_spark_core",
artifact = "com.sparkjava:spark-core:2.7.2"
)
maven_jar(
name = "org_slf4j_slf4j_simple",
artifact = "org.slf4j:slf4j-simple:1.7.21"
)
And finally, src/main/java/io/app/server/Main.java:
package io.app.server;
import static spark.Spark.*;
public class Main {
public static void main(String[] args) {
port(3000);
get("/", (req, res) -> "Hello World");
}
}
Any idea of what I could be doing wrong here?
Found what I was missing. It seems that maven_jar does not automatically fetch the "transitive dependencies" that the library itself has, see this.
Bazel only reads dependencies listed in your WORKSPACE file. If your
project (A) depends on another project (B) which list a dependency on
a third project (C) in its WORKSPACE file, you'll have to add both B
and C to your project's WORKSPACE file. This requirement can balloon
the WORKSPACE file size, but hopefully limits the chances of having
one library include C at version 1.0 and another include C at 2.0.
Large WORKSPACE files can be generated using the tool
generate_workspace. For details, see Generate external dependencies
from Maven projects.
So the solution seems to be to write a pom.xml and use generate_workspace.
EDIT: generate_workspace seems to be deprecated, use bazel_deps instead.
Another solution might be to use maven_install
git_repository(
name = "rules_jvm_external",
commit = "22b463c485f31b240888c89d17e67c460d7e68c0",
remote = "https://github.com/bazelbuild/rules_jvm_external.git",
)
load("#rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"org.apache.spark:spark-core_2.12:3.1.2",
"org.apache.spark:spark-sql_2.12:3.1.2",
],
repositories = [
"https://repo.maven.apache.org/maven2/",
]
)

Why am I getting F# error FS0039: The namespace or module 'Http' is not defined

In Visual Studio 2015 and 2017, I'm trying out the Http class from several F# examples in FSharp Interactive, and I keep getting:
error FS0039: The namespace or module 'Http' is not defined
Here's the sample:
open FSharp.Data
let response = Http.RequestString("http://api.themoviedb.org/3/search/movie", silentHttpErrors = true)
This is clearly due to the version of FSharp.Data. Is there a way to specify the correct version for FSharp Interactive? What version of FSharp.Data contains the Http module?
Based on the comments, I put together a script to install Paket, intitialise it and then optionally install the dependencies whenever the script was run.
/// install.paket.fsx
open System
open System.IO
printfn "Initialising..."
Environment.CurrentDirectory <- __SOURCE_DIRECTORY__
// invisibly run a command (paket.exe in this case)
let init paket =
let psi = new System.Diagnostics.ProcessStartInfo(paket)
psi.Arguments <- "init"
psi.UseShellExecute <- false
let p = System.Diagnostics.Process.Start(psi)
p.WaitForExit()
p.ExitCode
if not (File.Exists "paket.exe") then
printfn "installing paket"
let url = "http://fsprojects.github.io/Paket/stable"
use wc = new Net.WebClient()
let tmp = Path.GetTempFileName()
let stable = wc.DownloadString(url)
wc.DownloadFile(stable, tmp)
File.Move(tmp,Path.GetFileName stable)
printfn "paket installed"
System.Threading.Thread.Sleep(100)
printfn "initialising paket"
init "paket.exe" |> ignore
System.Threading.Thread.Sleep(200)
printfn "paket initialised"
else
printfn "paket already exists"
/// install.dependencies.fsx
open System.IO
printfn "Installing dependencies"
System.Environment.CurrentDirectory <- __SOURCE_DIRECTORY__
#r "paket.exe"
open Paket
let dependencies = Paket.Dependencies.Locate(__SOURCE_DIRECTORY__)
printfn "%s" dependencies.DependenciesFile
if not (File.Exists "packages/Newtonsoft.Json/lib/net40/Newtonsoft.Json.dll") then
printfn "installing nuget depenencies"
// either use the dependencies.Install to add dependencies in the paket.dependencies file
//dependencies.Install true |> ignore
// or install them by name
// I remove the existing versions
dependencies.Remove "FSharp.Data"
dependencies.Remove "Newtonsoft.Json 8.0.3"
// then add them (because I'm pedantic about the way the dependencies file looks)
dependencies.Add "FSharp.Data"
dependencies.Add "Newtonsoft.Json 8.0.3"
printfn "nuget depenencies installed"
else
printfn "nuget depenencies already exist"
printfn "Dependencies installed"
Note the use of 8.0.3 for Newtonsoft.Json, The latest version brings over 20 additional dependencies, so I've found a nice old version that's very self contained. You may leave the version number out if you want the latest.
Then, I use these scripts in a shared utilities.fsx for reusable functionality
System.Environment.CurrentDirectory <- __SOURCE_DIRECTORY__
#load "install.paket.fsx"
#load "install.dependencies.fsx"
#r "packages/fsharp.data/lib/net40/fsharp.data.dll"
#r "packages/Newtonsoft.Json/lib/net40/Newtonsoft.Json.dll"
open FSharp.Data
open FSharp.Data.HtmlAttribute
open FSharp.Data.HtmlNode
open FSharp.Data.HttpRequestHeaders
open Newtonsoft.Json
open System.Net
open System.IO
// utilities like authentication, Http requests and JSON (de)serialization
Finally, I reference the whole lot in my target script by just loading utilities:
System.Environment.CurrentDirectory <- __SOURCE_DIRECTORY__
#load "utilities.fsx"
open Utilities
which takes care of all the dependencies. These can be run from Visual studio with the Alt + Enter key combination or from the command line with fsi.exe MyScript.fsx

Deploying package using command line fails

What I've done:
1, Created a new Mvc Application project.
2, Build a deployment package using Visual Studio
3, Run this command in command the line
C:\TEMP\packages\MvcApplication6.deploy.cmd /t
and it crashes with this output
C:\Users\Fabik>C:\TEMP\packages\MvcApplication6.deploy.cmd /t
=========================================================
SetParameters from:
"C:\TEMP\packages\MvcApplication6.SetParameters.xml"
You can change IIS Application Name, Physical path, connectionString
or other deploy parameters in the above file.
-------------------------------------------------------
Start executing msdeploy.exe
-------------------------------------------------------
"C:\Program Files\IIS\Microsoft Web Deploy V3\\msdeploy.exe" -source:package='C
:\TEMP\packages\MvcApplication6.zip' -dest:auto,includeAcls='False' -verb:sync -
disableLink:AppPoolExtension -disableLink:ContentExtension -disableLink:Certific
ateExtension -setParamFile:"C:\TEMP\packages\MvcApplication6.SetParameters.xml"
-whatif
Unhandled Exception: System.Configuration.ConfigurationErrorsException: Configur
ation system failed to initialize ---> System.Configuration.ConfigurationErrorsE
xception: Unrecognized configuration section startup. (C:\Program Files\IIS\Micr
osoft Web Deploy V3\msdeploy.exe.Config line 2)
at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignor
eLocal)
at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(Configurat
ionSchemaErrors schemaErrors)
at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey
)
--- End of inner exception stack trace ---
at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey
)
at System.Configuration.ClientConfigurationSystem.System.Configuration.Intern
al.IInternalConfigSystem.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at System.Configuration.PrivilegedConfigurationManager.GetSection(String sect
ionName)
at System.Diagnostics.DiagnosticsConfiguration.Initialize()
at System.Diagnostics.TraceInternal.InitializeSettings()
at System.Diagnostics.TraceInternal.get_Listeners()
at System.Diagnostics.Trace.get_Listeners()
at MSDeploy.CommandLineTraceListener.EnableCommandLineTraceListeners()
at MSDeploy.MSDeploy.Main(String[] unusedArgs)
When I use the IIS manager to import the package it works fine. What could be the problem ?
I'm using Visual Studio 2010
That error message looks like the .NET 2 CLR is executing msdeploy.exe. Try (re-)installing .NET 4.0 Full Profile.

How to use MsBuild MsDeployPublish to target local file system?

I'm trying to replicate the Visual Studio 2010 "Publish..." command (applicable to Web Application projects) where I would in the UI choose Publish Method: "File System".
My attempt at this is...
%msbuild% /t:MsDeployPublish /property:MsDeployServiceUrl="file:///d:\MyDeploymentFolder";MsDeployPublishMethod="File System" "d:\MySourceFolder\Project.csproj"
... and having tried a method of "FileSystem", "File System", "Local", and a few others.
The error I get implies that MsDeploy is still trying to push to an IIS server:
"D:\MySourceFolder\Project.csproj" (MsDeployPub
lish target) (1) ->
(MSDeployPublish target) ->
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web
.Publishing.targets(3847,5): error : Web deployment task failed.(The metabase k
ey '/lm/w3svc' could not be found.) [D:\MySourceFolder\Project.csproj]
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.P
ublishing.targets(3847,5): error : \r [D:\MySourceFolder\Project.csproj]
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.P
ublishing.targets(3847,5): error : The metabase key '/lm/w3svc' could not be fo
und.\r [D:\MySourceFolder\Project.csproj]
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.P
ublishing.targets(3847,5): error : Unable to access the IIS configuration syste
m. Please make sure you have IIS 7 (or later) installed.\r [D:\MySourceFolder\Project.csproj]
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.P
ublishing.targets(3847,5): error : Retrieving the COM class factory for compone
nt with CLSID {2B72133B-3F5B-4602-8952-803546CE3344} failed due to the followin
g error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REG
DB_E_CLASSNOTREG)). [D:\MySourceFolder\Project.csproj]
How can I target the file system for deployment, as Visual Studio normally lets me in the GUI?
As per my answer from Using MSBuild, how do I build an MVC4 solution from the command line (applying Web.config transformations in the process) and output to a folder?
msbuild ProjectFile.csproj /p:Configuration=Release ^
/p:Platform=AnyCPU ^
/t:WebPublish ^
/p:WebPublishMethod=FileSystem ^
/p:DeleteExistingFiles=True ^
/p:publishUrl=c:\output
Or if you are building the solution file:
msbuild Solution.sln /p:Configuration=Release ^
/p:DeployOnBuild=True ^
/p:DeployDefaultTarget=WebPublish ^
/p:WebPublishMethod=FileSystem ^
/p:DeleteExistingFiles=True ^
/p:publishUrl=c:\output
You can also target the project via the solution using the /t:SolutionFolder/Project:Target syntax:
msbuild Solution.sln /t:SolutionFolder/ProjectFile:WebPublish ^
/p:Configuration=Release ^
/p:WebPublishMethod=FileSystem ^
/p:DeleteExistingFiles=True ^
/p:publishUrl=c:\output
I gave up trying to get MSBuild to copy deployable web files (and not do anything else but that), so I scripted it in PowerShell and am really happy with the result. Much faster than anything I tried through MSBuild. Here's the gist (literally):
function copy-deployable-web-files($proj_path, $deploy_dir) {
# copy files where Build Action = "Content"
$proj_dir = split-path -parent $proj_path
[xml]$xml = get-content $proj_path
$xml.Project.ItemGroup | % { $_.Content } | % { $_.Include } | ? { $_ } | % {
$from = "$proj_dir\$_"
$to = split-path -parent "$deploy_dir\$_"
if (!(test-path $to)) { md $to }
cp $from $to
}
# copy everything in bin
cp "$proj_dir\bin" $deploy_dir -recurse
}
I don't think you are being specific enough with what you are telling msbuild.
Pulled this out of one of my bookmarks on the subject, hopefully it will help: http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild

Resources