How to combine two shell.nix files? - shell

I have the first shell.nix file:
{ pkgs ? import ./nix { }
, useClang ? false
, ae_name ? "ae"
}:
with pkgs;
(if useClang then tvb.aeClangStdenv else tvb.aeGccStdenv).mkDerivation rec {
name = ae_name;
nativeBuildInputs = tvb.cppNativeBuildInputs;
buildInputs = tvb.rustBuildInputs
++ tvb.cppBuildInputs
++ tvb.rBuildInputs
;
TZDIR = "${tzdata}/share/zoneinfo";
LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive";
out_dir = (toString ./out);
cur_dir = (toString ./.);
shellHook = ''
export PS1="\[\033[38;5;10m\]\u#\h[${name} nix-shell]\[$(tput sgr0)\]\[\033[38;5;15m\]:\[$(tput sgr0)\]\[\033[38;5;39m\]\w\[$(tput sgr0)\]\\$\[$(tput sgr0)\] \[$(tput sgr0)\]"
# for tools only bin paths are needed
for prog in ${toString tvb.shellTools}; do
export PATH="$prog/bin:$PATH"
done
export DEPLOY_CFG=${cur_dir}/.deploy.json
export LD_LIBRARY_PATH="${out_dir}/lib:${fts5-snowball}/lib"
export PATH="${cur_dir}/lua/bin:${out_dir}/bin:$PATH"
export AE_SHARE="${out_dir}/share/ae"
export AE_LIBEXEC="${out_dir}/libexec/ae"
## LuaJIT
export LUA_PATH="$LUA_PATH;${cur_dir}/lua/lib/?.lua;${out_dir}/share/lua/5.1/?.lua;;"
export LUA_CPATH="$LUA_CPATH;${out_dir}/lib/lua/5.1/?.so;;"
## Lua box
export LUABOX_UNIT_PATH="${out_dir}/share/ae/box/units/?.lua;"
## Python
export PYTHONPATH="${out_dir}/lib/python2.7:$PYTHONPATH"
'';
}
and I have the seconds shell.nix file:
let
jupyter = import (builtins.fetchGit {
url = https://github.com/tweag/jupyterWith;
rev = "37cd8caefd951eaee65d9142544aa4bd9dfac54f";
}) {};
iPython = jupyter.kernels.iPythonWith {
name = "python";
packages = p: with p; [ numpy ];
};
iHaskell = jupyter.kernels.iHaskellWith {
extraIHaskellFlags = "--codemirror Haskell"; # for jupyterlab syntax highlighting
name = "haskell";
packages = p: with p; [ hvega formatting ];
};
jupyterEnvironment =
jupyter.jupyterlabWith {
kernels = [ iPython iHaskell ];
};
in
jupyterEnvironment.env
Firstly, I tried to append the second to the first one, but then I received the following error:
jbezdek#ubuntu:~$ nix-shell
error: syntax error, unexpected ID, expecting '{', at /home/jbezdek/shell.nix:51:3
After that, I tried many other combinations how to put those two together, but I have never been successful. Could you help me with that, please?

Merging two shell.nix files in full generality is tricky, and unlikely to be solved off the shelf.
To solve the case in point, I think you will just have to dig into the Nix expression language a little more to write a syntactically valid .nix file, that contains the content of both files. Something along the lines of this could work:
{ pkgs ? import ./nix { }
, useClang ? false
, ae_name ? "ae"
}:
with pkgs;
let
jupyter = import (builtins.fetchGit { ... })
...
jupyterEnvironment = ...
in
{
first_file = (if useClang ...).mkDerivation rec {
name = ae_name;
...
};
second_file = jupyterEnvironment.env;
}

Related

Script to get structs with specific keys from a JSON like format stored in a Config File

I have the following struct (JSON-like format) saved in a config file.
exampleStruct = {
valueOne = {
irrelevant_key_1 = true;
irrelevant_key_2 = true;
relevant_key = true;
};
valueTwo = {
irrelevant_key_1 = true;
irrelevant_key_2 = true;
relevant_key = true;
};
valueThree = {
irrelevant_key_1 = true;
irrelevant_key_2 = true;
};
valueFour = {
irrelevant_key_1 = true;
relevant_key = true;
};
}
The structs inside the main struct i.e. valueOne, valueTwo may or may not have "relevant_key" as a key.
I want to find the structs which have "relevant_key" as a key.
So, for the above example, I want the following list to be stored in a file
valueOne
valueTwo
valueFour
Since valueThree does not have "relevant_key" as a key.
I am completely new to writing scripts, is using jq an option?
I don't want the whole script as the answer, but a direction to go forward will help a lot.
Thanks
First you need to convert this to a valid JSON. This trickery should do it :
semiJson=$( printf "{\n%s\n}" "$( sed -E $'s/=/:/g;s/;/,/g;s/([a-zA-Z0-9_]+)/"\\1"/g;s/"true"/True/g' semiJson.sjson )")
okJson=$( python3 -c "
import json
dict = $semiJson
print(json.dumps(dict, indent=' '))
")
Once you have a valid JSON ( okJson variable in this case ) you can easily use JQ to accomplish what you intend :
echo "$okJson" | jq '.exampleStruct | with_entries(select(.value.relevant_key == true)) | keys'
[
"valueFour",
"valueOne",
"valueTwo"
]
Let me know if it helps!

std::process::Command cannot run hdiutil on macOS (mount failed - No such file or directory) but the command works fine when run in the terminal

hdiutils, when fed a correct path to a valid file, returns error 2, no such file or directory. When I join the indices of the command array with " ", print them, copy them and run the exact string in a terminal, it works fine.
This is the function edited to contain only the relevant bits. In order to reproduce my error, you will need a disk image located at ~/Downloads/StarUML.dmg.
use std::env;
use std::fs;
use std::process::Command;
fn setup_downloads(download_name: &str) {
let downloads_path: String = {
if cfg!(unix) {
//these both yield options to unwrap
let path = env::home_dir().unwrap();
let mut downloads_path = path.to_str().unwrap().to_owned();
downloads_path += "/Downloads/";
downloads_path
} else {
"we currently only support Mac OS".to_string()
}
};
let files_in_downloads =
fs::read_dir(&downloads_path).expect("the read_dir that sets files_in_downloads broke");
let mut file_path: String = "None".to_string();
for file_name in files_in_downloads {
let file_name: String = file_name
.expect("the pre string result which sets file_name has broken")
.file_name()
.into_string()
.expect("the post string result which sets file_name has broken")
.to_owned();
if file_name.contains(&download_name) {
file_path = format!("'{}{}'", &downloads_path, &file_name);
}
}
let len = file_path.len();
if file_path[len - 4..len - 1] == "dmg".to_string() {
let mount_command = ["hdiutil", "mount"];
let output = Command::new(&mount_command[0])
.arg(&mount_command[1])
.arg(&file_path)
.output()
.expect("failed to execute mount cmd");
if output.status.success() {
println!(
"command successful, returns: {}",
String::from_utf8_lossy(&output.stderr).into_owned()
);
} else {
println!(
"command failed, returns: {}",
String::from_utf8_lossy(&output.stderr).into_owned()
);
}
}
}
fn main() {
setup_downloads(&"StarUML".to_string());
}
Split your Command into a variable and print it using the debugging formatter after you have specified the arguments:
let mut c = Command::new(&mount_command[0]);
c
.arg(&mount_command[1])
.arg(&file_path);
println!("{:?}", c);
This outputs
"hdiutil" "mount" "\'/Users/shep/Downloads/StarUML.dmg\'"
Note that Command automatically provides quoting for each argument, but you have added your own set of single quotes:
format!("'{}{}'", &downloads_path, &file_name);
// ^ ^
Remove these single quotes.

Nix: Compile Vim with Ruby

I am using the Nix package manager on OS X. Let's say for the sake of argument I have a config.nix file that uses a pattern like so, allowing me to install the vimEnv no problem.
# ~/.nixpkgs/config.nix
{ pkgs }: {
# Looking around I have seen overrides something along these lines...
# nixpkgs.config.packageOverrides = pkgs: rec {
# vim = pkgs.vim_configurable.override {
# ruby = true;
# };
# };
packageOverrides = super: let pkgs = super.pkgs; in with pkgs; rec {
myEnv = pkgs.buildEnv {
name = "myEnv";
paths = [
# ...snip
vim
# ...snip
];
};
};
}
I know that there are elaborate options available for maintaining a .vimrc and vim plugins using Nix and by overriding vim_configurable options and so forth (for example), and it would be nice to find the time to do that at some point. However, all I want to do for now is to install via Nix a version of Vim which is compiled with Ruby support.
What would be the easiest or most concise way for me to achieve this in my config.nix?
And, after some hacking, here is the simplest solution I have found:
# ~/.nixpkgs/config.nix
{ pkgs }: {
packageOverrides = super: let pkgs = super.pkgs; in with pkgs; rec {
myVim = pkgs.vim_configurable.override {
config.vim = {
ruby = true;
};
ruby = ruby;
};
myEnv = pkgs.buildEnv {
name = "myEnv";
paths = [
myVim
];
};
};
}
And install it with nix-env -i myEnv.
You can try to compile vim yourself. In order to get ruby support this way all you have to do is add the --rubyinterp flag when you run ./configure

Getting an swift class var without Optional("value")

I'm creating a utility to add archival events to a calendar.
example run
./create-events-from-dvd-contents.swift --path /Volumes/ARCHIVE/DVD\ 1255/2451-01_LLA_Assets\ Folder\ Nov\ 2015/
Optional("DVD 1255")
The class is
class Event {
var location: String? ;
var start: String? ;
var notes: String? ;
}
The code to print the dvd location is
let event = Event() ;
let pathArray = path.characters.split {$0 == "/"}.map { String($0) } ;
event.location = pathArray[2] ;
print(event.location) ;
What is the simplest way to get 'DVD 1255' output instead of 'Optional("DVD 1255")'?
you must unwrap the value first into its own (non optional) variable.
let event = Event() ;
let pathArray = path.characters.split {$0 == "/"}.map { String($0) } ;
event.location = pathArray[2];
if let location = event.location {
print(location);
}
or you could put an ! after event.location if you wanted.
let event = Event() ;
let pathArray = path.characters.split {$0 == "/"}.map { String($0) } ;
event.location = pathArray[2] ;
print(event.location!) ;
The nil-coalescing operator is a clean way to do this:
var x: String? = "foo"
print(x) // Optional('foo')
x = nil
var y: String = x ?? "bar" // note y is not an optional
print(y) // Bar
print(x ?? "Not optional") // Not optional
Also, I noticed you are using semi-colons, which are unnecessary in Swift. I mention this, not as an opinion, but because it is a good practice of Swift to not use semi-colons unless necessary (multiple statements on one line or something)

Script to rename files

I have about 2200 different files in a few different folders, and I need to rename about about 1/3 of them which are in their own subfolder. Those 700 are also in various folders as well.
For example, there might be
The top-most folder is Employees, which has a few files in it, then the folder 2002 has a few, 2003 has more files, 2004 etc.
I just need to attach the word "Agreement" before the existing name of each file. So instead of it just being "Joe Schmoe.doc" It would be "Agreement Joe Schmoe.doc" instead.
I've tried googling such scripts, and I can find stuff similar to what I want but it all looks completely foreign to me so I can't understand how I'd modify it to suit my needs.
Oh, and this is for windows server '03.
I need about 2 minutes to write such script for *NIX systems (may be less), but for Windows it is a long song ... ))
I've write simple VBS script for WSH, try it (save to {script-name}.vbs, change Path value (on the first line of the script) and execute). I recommend to test script on small amount of data for the first time just to be sure if it works correctly.
Path = "C:\Users\rootDirectory"
Set FSO = CreateObject("Scripting.FileSystemObject")
Sub visitFolder(folderVar)
For Each fileToRename In folderVar.Files
fileToRename.Name = "Agreement " & fileToRename.Name
Next
For Each folderToVisit In folderVar.SubFolders
visitFolder(folderToVisit)
Next
End Sub
If FSO.FolderExists(Path) Then
visitFolder(FSO.getFolder(Path))
End If
I used to do bulk renaming with batch scripts under Windows. I know it's a snap on *nix (find . -maxdepth N -type f -name "$pattern" | sed -e 'p' -e "s/$str1/$str2/g" | xargs -n2 mv). Buf after some struggle in vain, I found out, to achieve that effect using batch scripts is almost impossible. So I turned to javascript.
With this script, you can add prefix to file names by 'rename.js "s/^/Agreement /" -r *.doc'. A caret(^) means to match the beginning. The '-r' options means 'recursively', i.e. including sub-folders. You can specify a max depth with the '-d N' option. If neither '-r' or '-d N' is given, the script does not recurse.
If you know the *nix 'find' utility, you would notice that 'find' will match the full path (not just the file name part) to specified regular expression. This behavior can be achieved by supplying the '-f' option. By default, this script will match the file name part with the given regular expression.
If you are familiar with regular expressions, complicated renaming is possible. For example, 'rename.js "s/(\d+)/[$1]/" *' which uses grouping to add brackets to number sequences in filenames.
// rename.js --- bulk file renaming utility (like *nix rename.pl)
// (c) Copyright 2012, Ji Han (hanji <at> outlook <dot> com)
// you are free to distribute it under the BSD license.
// oops... jscript doesn't have array.map
Array.prototype.map = function(f, t){
var o = Object(this);
var a = new Array(o.length >>> 0);
for (var i = 0; i < a.length; ++i){ if (i in o) a[i] = f.call(t, o[i], i, o) }
return a;
};
/// main
(function(){
if (WScript.Arguments.Length == 0){
WScript.Echo('rename "<operator>/<pattern>/<string>/[<modifiers>]" [-f] [-r] [-d <maxdepth>] [<files>]');
WScript.Quit(1);
}
var fso = new ActiveXObject('Scripting.FileSystemObject');
// folder is a Folder object [e.g. from fso.GetFolder()]
// fn is a function which operates on File/Folder object
var recurseFolder = function(folder, fn, depth, maxdepth){
if (folder.Files){
for (var e = new Enumerator(folder.Files); !e.atEnd(); e.moveNext()){
fn(e.item())
}
}
if (folder.Subfolders){
for (var e = new Enumerator(folder.SubFolders); !e.atEnd(); e.moveNext()){
fn(e.item());
if (depth < maxdepth){ arguments.callee(e.item(), fn, depth + 1, maxdepth) }
}
}
}
// expand wildcards (asterisk [*] and question mark [?]) recursively
// given path may be relative, and may contain environment variables.
// but wildcards only work for the filename part of a path.
// return an array of full paths of matched files.
// {{{
var expandWildcardsRecursively = function(n, md){
var pattern = fso.GetFileName(n);
// escape regex metacharacters (except \, /, * and ?)
// \ and / wouldn't appear in filename
// * and ? are treated as wildcards
pattern = pattern.replace(/([\[\](){}^$.+|-])/g, '\\$1');
pattern = pattern.replace(/\*/g, '.*'); // * matches zero or more characters
pattern = pattern.replace(/\?/g, '.'); // ? matches one character
pattern = pattern.replace(/^(.*)$/, '\^$1\$'); // matches the whole filename
var re = new RegExp(pattern, 'i'); // case insensitive
var folder = fso.GetFolder(fso.GetParentFolderName(fso.GetAbsolutePathName(n)));
var l = [];
recurseFolder(folder, function(i){ if (i.Name.match(re)) l.push(i.Path) }, 0, md);
return l;
}
// }}}
// parse "<operator>/<pattern>/<string>/[<modifiers>]"
// return an array splitted at unescaped forward slashes
// {{{
var parseExpr = function(s){
// javascript regex doesn't have lookbehind...
// reverse the string and lookahead to parse unescaped forward slashes.
var z = s.split('').reverse().join('');
// match unescaped forward slashes and get their positions.
var re = /\/(\\\\)*(?!\\)/g;
var l = [];
while (m = re.exec(z)){ l.push(m.index) }
// split s at unescaped forward slashes.
var b = [0].concat(l.map(function(x){ return s.length - x }).reverse());
var e = (l.map(function(x){ return s.length - x - 1 }).reverse()).concat([s.length]);
return b.map(function(_, i){ return s.substring(b[i], e[i]) });
}
// }}}
var expr = WScript.Arguments(0);
var args = [];
var options = {};
for (var i = 1; i < WScript.Arguments.Length; ++i){
if (WScript.Arguments(i).substring(0, 1) != '-'){
args.push(WScript.Arguments(i));
} else if (WScript.Arguments(i) == '-f'){
options['fullpath'] = true;
} else if (WScript.Arguments(i) == '-r'){
options['recursive'] = true;
} else if (WScript.Arguments(i) == '-d'){
options['maxdepth'] = WScript.Arguments(++i);
} else if (WScript.Arguments(i) == '--'){
continue;
} else {
WScript.Echo('invalid option \'' + WScript.Arguments(i) +'\'');
WScript.Quit(1);
}
}
if (options['maxdepth']){
var md = options['maxdepth'];
} else if (options['recursive']){
var md = 1<<31>>>0;
} else {
var md = 0;
}
var tokens = parseExpr(expr);
if (tokens.length != 4){
WScript.Echo('error parsing expression \'' + expr + '\'.');
WScript.Quit(1);
}
if (tokens[0] != 's'){
WScript.Echo('<operator> must be s.');
WScript.Quit(1);
}
var pattern = tokens[1];
var substr = tokens[2];
var modifiers = tokens[3];
var re = new RegExp(pattern, modifiers);
for (var i = 0; i < args.length; ++i){
var l = expandWildcardsRecursively(args[i], md);
for (var j = 0; j < l.length; ++j){
var original = l[j];
if (options['fullpath']){
var nouveau = original.replace(re, substr);
} else {
var nouveau = fso.GetParentFolderName(original) + '\\' + fso.GetFileName(original).replace(re, substr);
}
if (nouveau != original){
(fso.FileExists(original) && fso.GetFile(original) || fso.GetFolder(original)).Move(nouveau)
}
}
}
})();

Resources