grails base.dir system property - configuration

I have a simple grails file upload app.
I am using transferTo to save the file to the file system.
To get the base path in my controller I am using
def basePath = System.properties['base.dir'] // HERE IS HOW I GET IT
println "Getting new file"
println "copying file to "+basePath+"/files"
def f = request.getFile('file')
def okcontents = ['application/zip','application/x-zip-compressed']
if (! okcontents.contains(f.getContentType())) {
flash.message = "File must be of a valid zip archive"
render(view:'create', model:[zone:create])
return;
}
if(!f.empty) {
f.transferTo( new File(basePath+"/files/"+zoneInstance.title+".zip") )
}
else
{
flash.message = 'file cannot be empty'
redirect(action:'upload')
}
println "Done getting new file"
For some reason this is always null when deployed to my WAS 6.1 server.
Why does it work when running dev but not in prod on the WAS server? Should I be accessing this information in a different way?

Thanks j,
I found the best dynamic solution possible. As a rule I never like to code absolute paths into any piece of software. Property file or no.
So here is how it is done:
def basePath = grailsAttributes.getApplicationContext().getResource("/files/").getFile().toString()
grailsAttributes is available in any controller.
getResource(some relative dir) will look for anything inside of the web-app folder.
So for example in my dev system it will toString out to "C:\WORKSPACEFOLDER\PROJECTFOLDER\web-app\ with the relative dir concated to the end
like so in my example above
C:\WORKSPACEFOLDER\PROJECTFOLDER\web-app\files
I tried it in WAS 6.1 and it worked in the container no problems.
You have to toString it or it will try to return the object.
mugafuga

There's a definitive way...
grailsApplication.parentContext.getResource("dir/or/file").file.toString()
Out of controllers (ex. bootstrap)? Just inject..
def grailsApplication
Best regards!

Grails, when it's run in dev mode, provides a whole host of environment properties to its Gant scripts and the app in turn, including basedir.
Take a look at the grails.bat or grails.sh script and you will find these lines:
Unix: -Dbase.dir="." \
Windows: set JAVA_OPTS=%JAVA_OPTS% -Dbase.dir="."
When these scripts start your environment in dev mode you get these thrown in for free.
When you take the WAR and deploy you no longer use these scripts and therefore you need to solve the problem another way; you can either
Specify the property yourself to the startup script for the app server, eg: -Dbase.dir=./some/dir .. however
... it usually makes more sense to use the Grails Config object which allows for per-environment properties

Another option:
def basePath = BuildSettingsHolder.settings.baseDir

Related

Can you preview ASP.NET Core's appsettings.json environment overrides?

In ASP.NET Core, the JsonConfigurationProvider will load configuration from appsettings.json, and then will read in the environment version, appsettings.{Environment}.json, based on what IHostingEnvironment.EnvironmentName is. The environment version can override the values of the base appsettings.json.
Is there any reasonable way to preview what the resulting overridden configuration looks like?
Obviously, you could write unit tests that explicitly test that elements are overridden to your expectations, but that would be a very laborious workaround with upkeep for every time you change a setting. It's not a good solution if you just wanted to validate that you didn't misplace a bracket or misspell an element name.
Back in ASP.NET's web.config transforms, you could simply right-click on a transform in Visual Studio and choose "Preview Transform". There are also many other ways to preview an XSLT transform outside of Visual Studio. Even for web.config parameterization with Parameters.xml, you could at least execute Web Deploy and review the resulting web.config to make sure it came out right.
There does not seem to be any built-in way to preview appsettings.{Environment}.json's effects on the base file in Visual Studio. I haven't been able to find anything outside of VS to help with this either. JSON overriding doesn't appear to be all that commonplace, even though it is now an integral part of ASP.NET Core.
I've figured out you can achieve a preview with Json.NET's Merge function after loading the appsettings files into JObjects.
Here's a simple console app demonstrating this. Provide it the path to where your appsettings files are and it will emit previews of how they'll look in each environment.
static void Main(string[] args)
{
string targetPath = #"C:\path\to\my\app";
// Parse appsettings.json
var baseConfig = ParseAppSettings($#"{targetPath}\appsettings.json");
// Find all appsettings.{env}.json's
var regex = new Regex(#"appsettings\..+\.json");
var environmentConfigs = Directory.GetFiles(targetPath, "*.json")
.Where(path => regex.IsMatch(path));
foreach (var env in environmentConfigs)
{
// Parse appsettings.{env}.json
var transform = ParseAppSettings(env);
// Clone baseConfig since Merge is a void operation
var result = (JObject)baseConfig.DeepClone();
// Merge the two, making sure to overwrite arrays
result.Merge(transform, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
// Write the preview to file
string dest = $#"{targetPath}\preview-{Path.GetFileName(env)}";
File.WriteAllText(dest, result.ToString());
}
}
private static JObject ParseAppSettings(string path)
=> JObject.Load(new JsonTextReader(new StreamReader(path)));
While this is no guarantee there won't be some other config source won't override these once deployed, this will at least let you validate that the interactions between these two files will be handled correctly.
There's not really a way to do that, but I think a bit about how this actually works would help you understand why.
With config transforms, there was literal file modification, so it's easy enough to "preview" that, showing the resulting file. The config system in ASP.NET Core is completely different.
It's basically just a dictionary. During startup, each registered configuration provider is run in the order it was registered. The provider reads its configuration source, whether that be a JSON file, system environment variables, command line arguments, etc. and builds key-value pairs, which are then added to the main configuration "dictionary". An "override", such as appsettings.{environment}.json, is really just another JSON provider registered after the appsettings.json provider, which obviously uses a different source (JSON file). Since it's registered after, when an existing key is encountered, its value is overwritten, as is typical for anything being added to a dictionary.
In other words, the "preview" would be completed configuration object (dictionary), which is composed of a number of different sources, not just these JSON files, and things like environment variables or command line arguments will override even the environment-specific JSON (since they're registered after that), so you still wouldn't technically know the the environment-specific JSON applied or not, because the value could be coming from another source that overrode that.
You can use the GetDebugView extension method on the IConfigurationRoot with something like
app.UseEndpoints(endpoints =>
{
if(env.IsDevelopment())
{
endpoints.MapGet("/config", ctx =>
{
var config = (Configuration as IConfigurationRoot).GetDebugView();
return ctx.Response.WriteAsync(config);
});
}
});
However, doing this can impose security risks, as it'll expose all your configuration like connection strings so you should enable this only in development.
You can refer to this article by Andrew Lock to understand how it works: https://andrewlock.net/debugging-configuration-values-in-aspnetcore/

JavaScript import statements running code

I'm trying to diagnose a problem thats recently arisen for us, after upgrading our suppported browser (~40 -> ~60)
We have this effective code in an external (now unsupported) library, that sits in an iffe:
(function(window, undefined){
# external library
if(!window.terribleIdea){
window.terribleIdea = {}
}
<some code>
if(!window.terribleIdea.config.url){
window.terribleIdea.config.url = 'the wrong url'
}
localStorage.set('somethingImportant', getStuff(window.terribleIdea.config.url))
})( window );
Now we did have a bootstap type file that looked like this:
# appBootstrapper.js
import applyConfig from './app/configApplier';
import ALL_ANGULAR_MODULES from './app'; # contains angular.module set up for
# app and every dependency
fetchConfig()
.then(applyConfig)
.then () => angular.bootstrap(document, [ALL_ANGULAR_MODULES])
.catch( error => {
alert(`It borked: ${error.message}`)
});
Amongst other things applyConfig does:
window.terribleIdea = {
config: {
url: 'not terrible'
}
}
What now happens, is that the import statement of ALL_ANGULAR_MODULES ends up running the code in the external library, and setting local storage. What we think used to happen is that it was only called on angular.bootstrap running.
Now what I need to find out is, has the functionality of the import statement changed in a later version of chrome, or has it always been running this code and gone unnoticed?
All I can find is references to Dynamic Imports, and the order of scripts running, in <script></script> tags.
It is hard to debug without access to the project (see discussion in comments above). Here are some possibilities worth exploring while encountering such issues. It is of course possible that it was like this all along.
Change in the bundler configuration. Webpack accepts entries as arrays, and order matters in them.
Change in the way the bundler/dependency manager reacts to dynamic imports
Change in the way your application loads its dependency during the its bootstrap phase. It is not (imo) angular specific, as many app use some kind of "componentization" which translates in files executed in a different order they are imported (as they may only export constructors or whatnot).

ceylon run: Module default/unversioned not found

Today i installed the intelliJ ceylon IDE on my macbook. When compiling my project I get the following message
/Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/bin/java "-Dceylon.system.repo=/Users/Laust/Library/ApplicationSupport/IdeaIC2016.3/CeylonIDEA/classes/embeddedDist/repo" -Didea.launcher.port=7533 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Users/Laust/Library/Application Support/IdeaIC2016.3/CeylonIDEA/classes/embeddedDist/lib/ceylon-bootstrap.jar:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain com.redhat.ceylon.launcher.Bootstrap run --run main default/unversioned
ceylon run: Module default/unversioned not found in the following repositories:
/Users/Laust/Library/Application Support/IdeaIC2016.
3/CeylonIDEA/classes/embeddedDist/repo
/Users/Laust/.ceylon/cache
https://modules.ceylon-lang.org/repo/1
[Maven] Aether
[NPM] npm
Process finished with exit code 1
The code executes fine on my other computer (windows 7).
the folder 'modules' contains the following:
default
default.car
default.car.sha1
default.src
default.src.sha1
and my build configuration looks as follows.
this is my code (in the file source/main.ceylon)
shared void main() {
print("Generating pretty sweet g-code:");
{Gcommand+} myGcommands = {
G00( Vector3(0.0, 0.0, 0.0) ),
G00( Vector3(9.0, 0.0, 0.0) ),
G00( Vector3(9.0, 9.0, 0.0) ),
G00( Vector3(0.0, 9.0, 0.0) ),
G00( Vector3(0.0, 0.0, 0.0) )
};
GcodeProgram myGcodeProgram = GcodeProgram( *myGcommands );
print(myGcodeProgram.toString());
}
"A carthesian coordinate class"
alias X => Float;
alias Y => Float;
alias Z => Float;
class Vector3(shared X x, shared Y y, shared Z z) {
}
"An abstract spec class for all G-code command classes"
abstract class Gcommand() {
shared formal String toString();
}
"G-code command for moving in a straight line at rapid speed"
class G00( Vector3 endPoint ) extends Gcommand() {
toString() => "G0 " + "X" + endPoint.x.string
+ "Y" + endPoint.y.string
+ "Z" + endPoint.z.string + "\n";
}
class GcodeProgram( Gcommand+ gcommands ) {
variable String stringifiedGcodeProgram = "";
shared String toString() {
for (gcommand in gcommands) {
stringifiedGcodeProgram = stringifiedGcodeProgram + gcommand.toString();
}
return stringifiedGcodeProgram;
}
}
The screenshot you provided shows that the run configuration isn't based on any IntelliJ module (Use classpath of module is set to [none]). This means that the configuration will not be run in your project folder where the modules directory lives. That directory contains the compiled code, and ceylon run will look for that directory when you ask it to run the default module.
Generally speaking, you should avoid creating run configurations manually. By clicking on the green arrow next to a runnable function's name, Ceylon IDE will automatically create and configure a correct run configuration.
To fix your existing run configuration, simply select the IntelliJ module that contains your code in the field labeled Use classpath of module.
See also the getting started guide for more information on how to get started with Ceylon IDE for IntelliJ.
That might be a bug with the IntelliJ plugin not handling "default" modules correctly. We tend not to use default modules much because they're more limited than regular modules.
Try creating a module and moving your code to it. THat will most likely fix the problem. If so you can then open an issue to have this bug fixed here: https://github.com/ceylon/ceylon-ide-intellij/issues/new
There appears to be something messed up in the project setup here. Note the list of repos that are being searched:
Module default/unversioned not found in the following repositories:
/Users/Laust/Library/Application Support/IdeaIC2016.3/CeylonIDEA/classes/embeddedDist/repo
/Users/Laust/.ceylon/cache
https://modules.ceylon-lang.org/repo/1
[Maven] Aether
[NPM] npm
I would expect to see a repo of form your-project-dir/modules as the second entry in that list, but it's not there.
That is to say, ceylon run is not looking in the modules directory where the compiled .car is. So the question is why that repo is missing from the list.
What do you see in Project Structure > Modules > Ceylon > Repositories?
In this question, the first (and only) answer tells how to create a new module.
I have a few comments to that answer:
when beginning on a new project, you probably don't need an intricate nested naming hierarchy for your modules. You will get that, if you use periods in your module name (eg. my.ceylon.example), so I suggest you stick to a simple name such as main.
when creating your new module, you will (among other things) be asked to specify a 'Runnable unit name'. The purpose of this field is to tell IntelliJ which of your modules' classes it should execute when starting your program. In other words, this becomes the entry point to your program. A suitable name for this could (also) be main.
Ceylon projects are divided into modules, modules are divided into packages, and packages are divided into classes and top-level functions. When you create a module, a package is automatically created under this module. The path for your code files under this module will be 'source/moduleName/packageName'. When creating a new module, you don't get to specify the name for the first package in the module. Instead the package is given the same name as your module name. Thus a module named 'main' would have this path: source/main/main as the path for it's code files.
In your new modules folder (eg. source/main/main) three new files will be created. Find the file that is named after the 'Runnable unit name' you chose earlier. Your code should go into this file. Also, your code should have a class with the exact same name that you chose as your 'Runnable unit name'.
the answer used the fancy term 'runnable unit', by which he just means a file containing Ceylon code.
remember to delete the file containing your old 'default' module, before trying to run your new module.
a module name cannot start with a capital letter.
modules/ is the output directory where compiled code goes. It is automatically recreated from the code in source/ when the project is built.

Monodroid: Where should I put configuration settings?

From Miguel de Icaza:
We use a library profile that is better suited for mobile devices, so we removed features that are not necessary (like the entire System.Configuration stack, just like Silverlight does).
After years of .NET development, I'm accustomed to storing configuration settings in web.config and app.config files.
When using Mono for Android, where should I put my configuration settings?
If it matters, I'd like to store different configuration settings for different build configurations as well.
I would probably recommend using shared preferences and compilation symbols to manage different configurations. Below is an example of how you can use a preferences file to add or change keys based on the compilation symbols. Additionally, you could create a separate preferences file that is only available for a particular configuration. Because these keys are not available on all configurations, make sure to always perform checks for them before using.
var prefs = this.GetSharedPreferences("Config File Name", FileCreationMode.Private);
var editor = prefs.Edit();
#if MonoRelease
editor.PutString("MyKey", "My Release Value");
editor.PutString("ReleaseKey", "My Release Value");
#else
editor.PutString("MyKey", "My Debug Value");
editor.PutString("DebugKey", "My Debug Value");
#endif
editor.PutString("CommonKey", "Common Value");
editor.Commit();
We have had exactly the same problem in our current project.
My first impulse was to put the configuration in a sqlite key-value table but then my internal customer reminded me the main reason for a configuration file - it should support simple editing.
So instead we created an XML file and put it there:
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
And access it using these properties:
public string this[string key]
{
get
{
var document = XDocument.Load(ConfigurationFilePath);
var values = from n in document.Root.Elements()
where n.Name == key
select n.Value;
if(values.Any())
{
return values.First();
}
return null;
}
set
{
var document = XDocument.Load(ConfigurationFilePath);
var values = from n in document.Root.Elements()
where n.Name == key
select n;
if(values.Any())
{
values.First().Value = value;
}
else
{
document.Root.Add(new XElement(key, value));
}
document.Save(ConfigurationFilePath);
}
}
}
via a singleton class we call Configuration so for .NET developers it is very similar to using the app.config files. Might not be the most efficient solution but it gets the job done.
there's a Xamarin centric AppSetting reader: https://www.nuget.org/packages/PCLAppConfig
pretty useful for continuous delivery (so a deployment server such as octopus allows to alter your config file for each environment with values stored on the cd server)
there's a Xamarin centric AppSetting reader available at https://www.nuget.org/packages/PCLAppConfig
it is pretty useful for continuous delivery;
use as per below:
1) Add the nuget package reference to your pcl and platforms projects.
2) Add a app.config file on your PCL project, then as a linked file on all your platform projects. For android, make sure to set the build action to 'AndroidAsset', for UWP set the build action to 'Content'. Add you settings keys/values: <add key="config.text" value="hello from app.settings!" />
3) Initialize the ConfigurationManager.AppSettings on each of your platform project, just after the 'Xamarin.Forms.Forms.Init' statement, that's on AppDelegate in iOS, MainActivity.cs in Android, App in UWP/Windows 8.1/WP 8.1:
ConfigurationManager.Initialise(PCLAppConfig.FileSystemStream.PortableStream.Current);
3) Read your settings : ConfigurationManager.AppSettings["config.text"];
ITNOA
Maybe PCLAppConfig is help you to create and read from app.config in Xamarin.Forms PCL Project or other Xamarin projects.
For different configuration in different build mode such as release and debug you can use Configuration Transform on app.config.

How can I load external layout files using RazorEngine?

I've been trying for days (really, days) to use "external" files (provided from a different server using an ashx handler) as layouts in Razor.
#{
Layout = "http://someServer/templates.ashx?path=/my/template.cshtml";
}
This gives me an error about the path having to be a virtual one.
I've tried everything I could think of: VirtualPathProviders, custom RazorViewEngines, etc.
Nothing helps, has anyone done this or can someone give me a hint?
Make a VirtualPathProvider that handles virtual paths that start with a magic token and passes all other paths to its Previous property.
For example:
public override VirtualFile GetFile(string virtualPath) {
if (virtualPath.StartsWith("~/MySpecialTemplateServer"))
return new MyServerVirtualFile(virtualPath);
else
return Previous.GetFile(virtualPath);
}