overridePackages of local nixpkgs' config to add new packages - haskell

i'm looking for enlightenment on how to do the best way on my situation as follows:
I have a nixpkgs folder on my project, which I download from other repo. It located on my theproject/front-plat/default.nix then the code is look like this.
{ nixpkgsFunc ? import ./nixpkgs }: let nixpkgs = nixpkgsFunc ({ config = { ... }; lib = {...}; etc.
In my theproject/release.nix I want to add a new packages which will be used for my built using the nixpkgs' front-plat. So the code looks like this.
{ front-plat ? import ./deps/front-plat {}}:
let
nixpkgs = front-platform.nixpkgs;
packageCompiler = front-plat.compiler;
config = rec { ...
packageOverrides = pkgs: rec {
packageCompiler = pkgs.packageCompiler.override {
overrides = self: super: rec {
fronFrint = self.callPackage (import ./frontFrint { inherit front-plat; });
};
};
};
3 Which I assume, now i'm using the nixpkgs from the front-plat but i'm still not sure does my nixpkgs' packageCompiler already contains fronFrint package or not.
The question is, how can I add my new packages called "frontFrint" to the nixpkgs's packageCompiler. so that the packageCompiler can built fronFrint. for example in the end, the code will be
in { front = pkgs.packageCompiler.frontFrint; }

Related

Configuring withHoogle in default.nix:

I'm trying to setup withHoogle in my default.nix, but I'm getting this error:
developPackage, error: attempt to call something which is not a function but a set(at line 26).
Here is my default.nix code:
let
pkgs = import <nixpkgs> {};
compilerVersion = "ghc865";
compiler = pkgs.haskell.packages."${compilerVersion}";
in
compiler.developPackage
{
# returnShellEnv = false;
root = ./.;
# source-overrides = {};
modifier = drv:
let pkg = pkgs.haskell.lib.addBuildTools drv (with pkgs.haskellPackages;
[
cabal-install
cabal2nix
ghcid
control
text
brick
]);
in pkg // {
env = (pkg.env { withHoogle = true; }).overrideAttrs (old: {
shellHook =
''
export PS1='\n\[\033[1;32m\][\[\e]0;nix-shell: \W\a\]nix-shell:/\W]\$ \[\033[0m\]'
'';
});
};
}
I had a similar error message when trying to nix-build a seemingly correct derivation (default.nix).
Eventually I found out using the --show-trace parameter to nix-build, that the error lie in an overlay I had in my user's ~/.config/nixpkgs/overlays directory lying around.
HTH

What version of Node does my library support?

I'm hoping for a library or a tool which will run through my code and tell me what version of Node is required in order to run it. Perhaps better would be it alerts me to areas of the code which could be changed to support older versions.
Is there anything like that in the wild?
I'm not sure if this exactly what you are looking for, but there is an existing package.json property called "engines" where package developers can specify what version(s) they require. Not too difficult to use glob and semver packages to look through all package.json files with an "engines" requirement and compile that into an object of:
{
[version1]: [{ packageName, currentlySupported }, { ... }],
[version2]: [...],
...
}
Here is a rudimentary example of a script which will create that object for you:
npm install glob semver
checkversions.js:
const glob = require('glob');
const path = require('path');
const semver = require('semver');
const currentVersion = process.version;
const versions = {};
glob('node_modules/*/package.json', (err, files) => {
files.forEach((file) => {
const pkg = require(path.resolve(__dirname, file));
// only check add package if it specifies "engines"
if (pkg.engines && pkg.engines.node) {
const reqdVersion = pkg.engines.node.replace(/\s+/g, '');
// assume you are using a supported version
let currentlySupported = true;
// check if current node version satisfies package requirements
if (!semver.satisfies(currentVersion, reqdVersion)) {
currentlySupported = false;
}
if (!Array.isArray(versions[reqdVersion])) {
versions[reqdVersion] = [];
}
versions[reqdVersion].push({
package: file.replace(/node_modules\/(.*)\/package.json/, '$1'),
currentlySupported,
});
}
});
console.log(versions);
});
Run it:
node checkversions.js

How to add custom services in Nixos

using nixops one can easily configure services like:
{
network.description = "Web server";
webserver = { config, pkgs, ... }:
{
services.mysql = {
enable = true;
package = pkgs.mysql51;
};
but i want to extend services. for example by using override as done for pkgs below:
let
myfoo = callPackage ...
in
pkgs = pkgs.override {
overrides = self: super: {
myfoo-core = myfoo;
};
}
question
how to do that for services?
Adding a service requires that you first write a service definition for your service. That is, a nix file that declares the options of your service and provides an implementation.
Let's say our service is called foo, then we write a service definition for it an save it as the file foo.nix:
{ config, lib, pkgs, ... }:
with lib; # use the functions from lib, such as mkIf
let
# the values of the options set for the service by the user of the service
foocfg = config.services.foo;
in {
##### interface. here we define the options that users of our service can specify
options = {
# the options for our service will be located under services.foo
services.foo = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable foo.
'';
};
barOption = {
type = types.str;
default = "qux";
description = ''
The bar option for foo.
'';
};
};
};
##### implementation
config = mkIf foocfg.enable { # only apply the following settings if enabled
# here all options that can be specified in configuration.nix may be used
# configure systemd services
# add system users
# write config files, just as an example here:
environment.etc."foo-bar" = {
text = foocfg.bar; # we can use values of options for this service here
};
};
For example, for Hydra, this file can be found here: https://github.com/NixOS/hydra/blob/dd32033657fc7d6a755c2feae1714148ee43fc7e/hydra-module.nix.
After having written the service definition, we can use it our main configuration like this:
{
network.description = "Web server";
webserver = { config, pkgs, ... }: {
imports = [ ./foo.nix ]; # import our service
services.mysql = {
enable = true;
package = pkgs.mysql51;
};
services.foo = {
enable = true;
bar = "hello nixos modules!";
};
};
}
Disclaimer: there might be some typos in this, I have not tested it.
according to aszlig, we can do this:
configuration.nix
{ config, lib, ... }:
{
disabledModules = [ "services/monitoring/nagios.nix" ];
options.services.nagios.enable = lib.mkOption {
# Make sure that this option type conflicts with the one in
# the original NixOS module for illustration purposes.
type = lib.types.str;
default = "of course";
description = "Really enable nagios?";
};
config = lib.mkIf (config.services.nagios.enable == "of course") {
systemd.services.nagios = {
description = "my own shiny nagios service...";
};
};
}
evaluate it
$ nix-instantiate --eval '<nixpkgs/nixos>' --arg configuration ./test-disable.nix -A config.systemd.services.nagios.description
"my own shiny nagios service..."

versus without disabledModules:
$ nix-instantiate --eval '<nixpkgs/nixos>' --arg configuration ./test-disable.nix -A config.systemd.services.nagios.description
error: The option `services.nagios.enable' in `/home/aszlig/test-disable.nix' is already declared in `/nix/var/nix/profiles/per-user/root/channels/vuizvui/nixpkgs/nixos/modules/services/monitoring/nagios.nix'.
(use '--show-trace' to show detailed location information)

Conditional import to switch implementations

I have node.js application written in TypeScript and I need to switch between two interface implementations based on the config file. Currently I have this code which seems to be working.
"use strict";
import { config } from "../config";
let Something;
if (config.useFakeSomething) {
Something = require("./FakeSomething").FakeSomething;
} else {
Something = require("./RealSomething").RealSomething;
}
...
let s = new Something();
s.DoStuff();
...
But I have bad gut feeling about that (mainly because of the mixing require and import for loading modules). Is there some other way how to achieve implementation switching based on config file without importing both modules?
If you want to keep the client-code for your Something class clean, you can move the conditional importing to a single file. You can have the following directory structure for your Something module:
/Something
RealSomething.ts
FakeSomething.ts
index.ts
And in your index.ts, you can have the following:
import { config } from '../config';
const Something = config.useFakeSomething ?
require('./FakeSomething').FakeSomething :
require('./RealSomething').RealSomething;
export default Something;
And in your client code, you can just import Something:
import Something from './Something/index';
I can see nothing wrong with your approach. In fact lines like
import { config } from "../config";
When targeting commonjs will be compiled to the following javascript (ES6):
const config = require('../config');
So they are effectively identical and you are not mixing different module loading techniques.
You can do it like that:
let moduleLoader:any;
if( pladform == 1 ) {
moduleLoader = require('./module1');
} else {
moduleLoader = require('./module2');
}
and then
if( pladform === 1 ) {
platformBrowserDynamic().bootstrapModule(moduleLoader.module1, [ languageService ]);
}
else if ( pladform === 2 ) {
platformBrowserDynamic().bootstrapModule(moduleLoader.module2, [ languageService ]);
}
In addition to the correct answers above, in case you need this switching for many files within a single folder, you can use a symbolic-link (not available on Windows) that referenced to the right folder, so your code remains clean.
This approach is good for switching between real code and stubs, for instance
A modern answer using the import() function:
import { config } from "../config";
let Something;
if (config.useFakeSomething) {
Something = (await import("./FakeSomething")).FakeSomething;
} else {
Something = (await import("./RealSomething")).RealSomething;
}
...
let s = new Something();
s.DoStuff();
...
Remember that import() is non blocking, so you need to add await if the code that follows needs the result from the import().

How to load google maps javascript api in Aurelia javascript application?

I found npm module google-maps-api and installed it (npm install google-maps-api) but I can't figure out how to import it with systemjs/jspm (jspm cannot find this module). Here's the configuration from my config.js:
"paths": {
"*": "app/dist/*.js",
"github:*": "app/jspm_packages/github/*.js",
"npm:*": "app/jspm_packages/npm/*.js" }
So, when I try do something like this:
import {mapsapi} from 'google-maps-api';
I get the following error in browser console:
GET https://localhost:44308/app/dist/google-maps-api.js 404 (Not Found)
Looking at the filesystem I see that npm installed the module under app/node_modules/google-maps-api so how do I reference it in the import clause from Aurelia module?
I found a solution and answering my own question here:
I finally figured how to install it with jspm, so you just need to give a hint to jspm to install it from npm like so:
jspm install npm:google-maps-api
After jspm completes installation, import (no {} syntax) works fine:
import mapsapi from 'google-maps-api';
then I inject it in constructor and instantiate geocoder api:
#inject(mapsapi('InsertYourGMAPIKeyHere'))
export class MyClass {
constructor(mapsapi) {
let that = this;
let maps = mapsapi.then( function(maps) {
that.maps = maps;
that.geocoder = new google.maps.Geocoder();
});
...
}
In order to create map on a div I use EventAggregator to subscribe for router:navigation:complete event and use setTimeout to schedule map creation:
this.eventAggregator.subscribe('router:navigation:complete', function (e) {
if (e.instruction.fragment === "/yourRouteHere") {
setTimeout(function() {
that.map = new google.maps.Map(document.getElementById('map-div'),
{
center: new google.maps.LatLng(38.8977, -77.0366),
zoom: 15
});
}, 200);
}
});
Here's a complete view-model example that uses attached() to link to your view.
import {inject} from 'aurelia-framework';
import mapsapi from 'google-maps-api';
#inject(mapsapi('your map key here'))
export class MapClass {
constructor(mapsAPI) {
this.mapLoadingPromise = mapsAPI.then(maps => {
this.maps = maps;
});
}
attached() {
this.mapLoadingPromise.then(() => {
var startCoords = {
lat: 0,
long: 0
};
new this.maps.Map(document.getElementById('map-div'), {
center: new this.maps.LatLng(startCoords.lat, startCoords.long),
zoom: 15
});
});
}
}
For everyone using Typescript and getting "Cannot find module 'google-maps-api'" error,
you need to add typings to the solution. Something like this works
declare module 'google-maps-api' {
function mapsapi(apikey: string, libraries?, onComplete?);
namespace mapsapi {
}
export = mapsapi;
}
and then import it like this
import * as mapsapi from 'google-maps-api';

Resources