sbt-native-packager - How to use AshScriptPlugin with LauncherJarPlugin in the same project - sbt-native-packager

My use case is to get a Play Framework application running in alpine docker container.
I would prefer to use a launcher jar.
So my build.sbt looks something like this:
lazy val root = (project in file(".")).enablePlugins(
PlayScala,
JavaAppPackaging,
LauncherJarPlugin,
AshScriptPlugin,
UniversalDeployPlugin
)
maintainer in Universal := "G. Richard Bellamy <rbellamy#terradatum.com>"
packageSummary in Universal := "some-server"
packageDescription := "The some-server microservice"
// Necessary because the PlayScala plugin uses sbt-native-packager, and defines the bashScriptExtraDefines in the
// expectation that the app will be using the JavaServerAppPackaging plugin with bash, and we need to use the
// JavaAppPackaging plugin with Ash
bashScriptExtraDefines := Nil
Which produces the following relevant start script stanza:
real_script_path="$(realpath "$0")"
app_home="$(realpath "$(dirname "$real_script_path")")"
lib_dir="$(realpath "${app_home}/../lib")"
app_mainclass="-jar" "$lib_dir/some-server.some-server-1.0.0-SNAPSHOT-launcher.jar"
script_conf_file="${app_home}/../conf/application.ini"
app_classpath=""
# If a configuration file exist, read the contents to $opts
[ -f "$script_conf_file" ] && opts=$(loadConfigFile "$script_conf_file")
java -classpath $app_classpath $opts $app_mainclass $#
Note the app_classpath="" variable. Given that I'm using a launcher jar, I would expect that line to be omitted.
Is this a bug, or am I doing something obviously wrong?

Related

How to use Sass with NetBeans on Linux / macOS

I used to be able to install and use Sass with NetBeans 8 as described in the top answer on How to use SASS with Netbeans 8.0.1
Now, with the current version of Sass (1.14.1), installing is different. Basically just download and untar. That's done and I've pointed NetBeans to the correct location. But this current version of Sass won't run correctly from NetBeans:
"/opt/dart-sass/sass" "--cache-location"
"/home/jasper/.cache/netbeans/8.2/sass-compiler"
"path_to_my.scss" "path_to_my.css"
Could not find an option named "cache-location".
This error is also covered by Sass output error in Netbeans 8.2 where they are using Windows.
I tried to add the cache location parameter (similar to the solution for Windows) to this line in the sass file:
exec "$path/src/dart" --no-preview-dart-2 "-Dversion=1.14.1" "$path/src/sass.dart.snapshot" "$#"
but I could not get it working (same error keeps appearing).
Anybody any ideas on how to get Sass 1.14.1 working from NetBeans 8.2 on Linux (Ubuntu)?
The issue is that --cache-location is no longer supported and should be removed. All of the original parameters are used by "$#". To remove the first two parameters, you should be able to use "${#:3}" (see Process all arguments except the first one (in a bash script)), but somehow that resulted into a "Bad substitution" error for me. So I opted to use shift 2 to remove them:
#!/bin/sh
# Copyright 2016 Google Inc. Use of this source code is governed by an MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.
# This script drives the standalone Sass package, which bundles together a Dart
# executable and a snapshot of Sass. It can be created with `pub run grinder
# package`.
follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
path=`dirname "$(follow_links "$0")"`
shift 2
exec "$path/src/dart" --no-preview-dart-2 "-Dversion=1.14.1" "$path/src/sass.dart.snapshot" "${#}"
Make sure to keep the original file and create a copy to only be used with NetBeans and make the change there.
macOS (Home Brew)
If you are looking for the Dart Sass install location (after installing it with Home Brew), it is located here:
/usr/local/Cellar/sass/{version}/bin
macOS (node.js)
When using node.js, you will run into the "env: node: No such file or directory" issue.
To work around that I created (make sure you make it executable (chmod a+x)):
/usr/local/lib/node_modules/sass/sass_nb.sh
and added:
#!/bin/zsh
export PATH="$PATH:"/usr/local/bin/
shift 3
sass ${#}
NetBeans 11+
On NetBeans 11 and 12 I had to use shift 3 instead of shift 2.
My response is based heavily on Jasper de Vries'one:
It seems that Netbeans simply adds some additional parameters that are no longer supported by sass compiler.
In my case the complete command issued by Netbeans was:
"/home/alex/tools/dart-sass/sass" "--cache-location" "/home/alex/snap/netbeans/common/cache/12.0/sass-compiler" "--debug-info" "/home/alex/projects/alexgheorghiu.com/web/aaa.scss" "/home/alex/projects/alexgheorghiu.com/web/aaa.css"
So the first 3 parameters
"--cache-location" "/home/alex/snap/netbeans/common/cache/12.0/sass-compiler" "--debug-info"
must be "deleted" or ignored.
So you need to either alter the sass file or make a copy of it (safest way)
and add
shift 3
instruction.
So if you start from original version like:
#!/bin/sh
# This script drives the standalone dart-sass package, which bundles together a
# Dart executable and a snapshot of dart-sass.
follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
path=`dirname "$(follow_links "$0")"`
exec "$path/src/dart" "$path/src/sass.snapshot" "$#"
You need to end up with something like:
#!/bin/sh
# This script drives the standalone dart-sass package, which bundles together a
# Dart executable and a snapshot of dart-sass.
follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
path=`dirname "$(follow_links "$0")"`
shift 3
exec "$path/src/dart" "$path/src/sass.snapshot" "$#"
An interesting aspect is that this bug is known by Netbeans developers (See: Could not find an option named "cache-location") but I was not able to achieve that because under my Xubuntu 18 the Netbeans is a "snap" and therefore it's netbeans.conf file is read only.
But in case you CAN modify that file it might be a cleaner solution.

How to replace paths to executables in source code with Nix that are not in PATH

I wish to write some Haskell that calls an executable as part of its work; and install this on a nixOS host. I don't want the executable to be in my PATH (and to rely on that would disrupt the beautiful dependency model of nix).
If this were, say, a Perl script, I would have a simple builder that looked for strings of a certain format, and replaced them with the executable names, based upon dependencies declared in the .nix file. But that seems somewhat harder with the cabal-based building common to haskell.
Is there a standard idiom for encoding the paths to executables at build time (including during development, as well as at install time) within Haskell code on nix?
For the sake of a concrete example, here is a trivial "script":
import System.Process ( readProcess )
main = do
stdout <- readProcess "hostname" [] ""
putStrLn $ "Hostname: " ++ stdout
I would like to be able to compile run this (in principle) without relying on hostname being in the PATH, but rather replacing hostname with the full /nix/store/-inetutils-/bin/hostname path, and thus also gaining the benefits of dependency management under nix.
This could possibly be managed by using a shell (or similar) script, built using a replacement scheme as defined above, that sets up an environment that the haskell executable expects; but still that would need some bootstrapping via the cabal.mkDerivation, and since I'm a lover of OptParse-Applicative's bash completion, I'm loathe to slow that down with another script to fire up every time I hit the tab key. But if that's what's needed, fair enough.
I did look through cabal.mkDerivation for some sort of pre-build step, but if it's there I'm not seeing it.
Thanks,
Assuming you're building the Haskell app in Nix, you can patch a configuration file via your Nix expression. For an example of how to do this, have a look at this small project.
The crux is that you can define a postConfigure hook like this:
pkgs.haskell.lib.overrideCabal yourProject (old: {
postConfigure = ''
substituteInPlace src/Configuration.hs --replace 'helloPrefix = Nothing' 'helloPrefix = Just "${pkgs.hello}"'
'';
})
What I do with my xmonad build in nix1 is refer to executable paths as things like ##compton##/bin/compton. Then I use a script like this to generate my default.nix file:
#!/usr/bin/env bash
set -eu
packages=($(grep '##[^#]*##' src/Main.hs | sed -e 's/.*##\(.*\)##.*/\1/' | sort -u))
extra_args=()
for p in "${packages[#]}"; do
extra_args+=(--extra-arguments "$p")
done
cabal2nix . "${extra_args[#]}" \
| head -n-1
echo " patchPhase = ''";
echo " substituteInPlace src/Main.hs \\"
for p in "${packages[#]}"; do
echo " --replace '##$p##' '\${$p}' \\"
done
echo " '';"
echo "}"
What it does is grep through src/Main.hs (could easily be changed to find all haskell files, or to some specific configuration module) and pick out all the tags surrounded by## like ##some-package-name##. It then does 2 things with them:
passes them to cabal2nix as extra arguments for the nix expression it generates
post-processes nix expression output from cabal2nix to add a patch phase, which replaces the ##some-package-name## tag in the Haskell source file with the actual path to the derivation.2
This generates a nix-expression like this:
{ mkDerivation, base, compton, networkmanagerapplet, notify-osd
, powerline, setxkbmap, stdenv, synapse, system-config-printer
, taffybar, udiskie, unix, X11, xmonad, xmonad-contrib
}:
mkDerivation {
pname = "xmonad-custom";
version = "0.0.0.0";
src = ./.;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
base taffybar unix X11 xmonad xmonad-contrib
];
description = "My XMonad build";
license = stdenv.lib.licenses.bsd3;
patchPhase = ''
substituteInPlace src/Main.hs \
--replace '##compton##' '${compton}' \
--replace '##networkmanagerapplet##' '${networkmanagerapplet}' \
--replace '##notify-osd##' '${notify-osd}' \
--replace '##powerline##' '${powerline}' \
--replace '##setxkbmap##' '${setxkbmap}' \
--replace '##synapse##' '${synapse}' \
--replace '##system-config-printer##' '${system-config-printer}' \
--replace '##udiskie##' '${udiskie}' \
'';
}
The net result is I can just write Haskell code and a cabal package file; I don't have to worry much about maintaining the nix package file as well, only re-running my generate-nix script if my dependencies change.
In my Haskell code I just write paths to executables as if ##the-nix-package-name## was an absolute path to a folder where that package is installed, and everything magically works.
The installed xmonad binary ends up containing hardcoded references to the absolute paths to the executables I call, which is how nix likes to work (this means it automatically knows about the dependency during garbage collection, for example). And I don't have to worry about keeping the things I called in my interactive environment's PATH, or maintaining a wrapper that sets up PATH just for this executable.
1 I have it set up as a cabal project that gets built and installed into the nix store, rather than having it dynamically recompile itself from ~/.xmonad/xmonad.hs
2 Step 2 is a little meta, since I'm using a bash script to generate nix code with an embedded bash script in it
This is not indented to be the answer but if I post this in comment section it would turn out to be ugly formatted.
Also I am not sure if this hack is the right way to do the job.
I notice that if I use nix-shell I can get full path to nix store
Assume hash is always the same, AFAIK I believe it is, you can use it to hard-coded in build recipe.
$ which bash
/run/current-system/sw/bin/bash
[wizzup# ~]
$ nix-shell -p bash
[nix-shell:~]$ which bash
/nix/store/wb34dgkpmnssjkq7yj4qbjqxpnapq0lw-bash-4.4-p12/bin/bash
Lastly, I doubt if you have to to any of this if you use buildInput, it should be the same path.

How to compile Jigsaw http server on Linux?

I download the Jigsaw server source from w3c website, http://www.w3.org/Jigsaw/. I followed its instruction http://www.w3.org/Jigsaw/Doc/Programmer/compile.html, but still can not compile it on my linux. What does it mean to update your CLASSPATH to compile Jigsaw and use the new compiled classes? How could I set my classpath?
Plz give me some help.
Thanks.
It means you need to set the $CLASSPATH environment variable. I haven't looked at Jigsaw, but if you wanted to set your $CLASSPATH to include all the jar files within a directory (for example one that contains all the Jigsaw compiled jars) then you can use this script fragment:
CLASSPATH=""
for j in $(find /path/to/jigsaw/lib -name \*.jar)
do
if [ ! -z "$CLASSPATH" ]; then CLASSPATH="$CLASSPATH:"; fi
CLASSPATH="$CLASSPATH$j"
done
Now whenever you invoke the java command it will use the classes within /path/to/jigsaw/lib.
However this is not a good idea; better is to use the above technique to build an environment variable other than $CLASSPATH and pass that as the argument to the java -cp command line option:
cp=""
for j in $(find /path/to/jigsaw/lib -name \*.jar)
do
if [ ! -z "$cp" ]; then cp="$cp:"; fi
cp="$cp$j"
done
java -cp $cp ...

How do you configure GroovyConsole so I don't have to import libraries at startup?

I have a groovy script that uses a third party library. Each time I open the application and attempt to run my script I have to import the proper library.
I would like to be able to open GroovyConsole and run my application without having to import the library.
In Linux you also have
/usr/share/groovy/conf/groovy-starter.conf
Here you can add your specific libs:
# load user specific libraries
load !{user.home}/.groovy/lib/*.jar
load /home/squelsh/src/neo4j-community-1.4.M03/lib/*.jar
load /home/squelsh/src/neo4j-community-1.4.M03/system/lib/*.jar
Hope it helps, had to search long time to find this (:
If you just want to add the JARs to the classpath, copy (or symlink) them to ~/.groovy/lib (or %USER_HOME%/.groovy/lib on Windows).
If you want the actual import statements to run every time Groovy Console starts, edit the groovy-starter.conf file as suggested by Squelsh.
At least on Linux groovy GroovyConsole is a Script has the Following command:
startGroovy groovy.ui.Console "$#"
startGroovy itself is a script which starts Java. Within the startGroovy script you should be able to modify your classpath and add the missing librarys.
From startGroovy:
startGroovy ( ) {
CLASS=$1
shift
# Start the Profiler or the JVM
if $useprofiler ; then
runProfiler
else
exec "$JAVACMD" $JAVA_OPTS \
-classpath "$STARTER_CLASSPATH" \
-Dscript.name="$SCRIPT_PATH" \
-Dprogram.name="$PROGNAME" \
-Dgroovy.starter.conf="$GROOVY_CONF" \
-Dgroovy.home="$GROOVY_HOME" \
-Dtools.jar="$TOOLS_JAR" \
$STARTER_MAIN_CLASS \
--main $CLASS \
--conf "$GROOVY_CONF" \
--classpath "$CP" \
"$#"
fi
You can write an external Groovy script that does all the imports, creates a GroovyConsole object, and calls the run() method on this object.
See also http://groovy.codehaus.org/Groovy+Console#GroovyConsole-EmbeddingtheConsole
For example: start.groovy
import groovy.ui.Console;
import com.botkop.service.*
import com.botkop.service.groovy.*
def env = System.getenv()
def service = new ServiceWrapper(
userName:env.userName,
password:env.password,
host:env.host,
port:new Integer(env.port))
service.connect()
Console console = new Console()
console.setVariable("service", service)
console.run()
From a shell script call the groovy executable providing it with the groovy script:
#!/bin/bash
if [ $# -ne 4 ]
then
echo "usage: $0 userName password host port"
exit 10
fi
export userName=$1
export password=$2
export host=$3
export port=$4
export PATH=~/apps/groovy/bin:/usr/bin:$PATH
export CLASSPATH=$(find lib -name '*.jar' | tr '\n' ':')
groovy start.groovy
The code in GroovyConsole can now make use of the imports done in start.groovy, as well as of the variables created and passed with the setVariable method ('service' in the example).
If you are on a Mac, I would highly recommend using SDKMAN to manage Groovy installations.
Once installed via SDKMAN, you can modify ~/.sdkman/candidates/groovy/current/bin/groovy/conf/groovy-starter.conf. Packages you add here will be automatically imported at runtime whenever you start a Groovy Console session. You would want to add them under the section labelled in the example below:
# load user specific libraries
load !{user.home}/.groovy/lib/*.jar
load !{user.home}/.groovy/lib/additional_package.jar

How do I create a directory in a makefile

I'm using Visual Studio 2005 nmake, and I have a test makefile like this:
sometarget:
-mkdir c:\testdir
I want to always create the directory, without having to specify 'sometarget'. For example, I can do this:
!if [if not exist c:\testdir\$(null) mkdir c:\testdir]
!endif
But that requires two lines, where I really only want to do the "-mkdir c:\testdir". If I just replace it with "-mkdir c:\testdir" I get an error from nmake - "fatal error U1034: syntax error : separator missing".
How can I always execute the mkdir, without messing about with !if [] stuff?
I think this will work:
-# if NOT EXIST "dir" mkdir "dir"
Make always wants to do things based on targets. It's not a general scripting tool. It looks at the targets and checks to see if they exist. If the target does not exist it executes the commands for that target.
The usual way to do this is to have a dummy target that is never going to be generated by the make scripts, so every time make runs it has to execute the relevant commands.
Or, you could add the command to a batch file that then calls your make file.
I'm not sure if there is an equivalent in Windows with nmake, but I managed to create a directory without using targets on Linux. I used the make function "shell". For example:
# Find where we are
TOPDIR := $(shell pwd)
# Define destination directory
ROOTFS := $(TOPDIR)/rootfs
# Make sure destination directory exists before invoking any tags
$(shell [ -d "$(ROOTFS)" ] || mkdir -p $(ROOTFS))
all:
#if [ -d "$(ROOTFS)" ]; then echo "Cool!"; else echo "Darn!"; fi
I hope Windows has the equivalent.
$(DIRNAME):
#[ -d $# ] || mkdir -p $#
Try using this:
-mkdir -p c:\testdir

Resources