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
Related
Is it possible to use environment variables in a Cargo.toml file?
Like so:
[package]
name = "tmp-xzxgxn"
version = "0.1.0"
edition = "2021"
[dependencies]
# bevy = {branch = "main", git = "https://github.com/bevyengine/bevy.git"}
# bevy = { path = "~/Documents/GitHub/bevy" }
bevy = { path = "%USERPROFILE%/Documents/GitHub/bevy" }
Note that ~ doesn't work either.
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;
}
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.
On Windows, Path::canonicalize() returns the path in the format:
\\\\?\\C:\\projects\\3rdparty\\rust...
This is because it is the correct canonical path, and allows 'long' paths on Windows (see Why does my canonicalized path get prefixed with \\?\).
However, this is not a user-friendly path, and people do not understand it.
For display and logging purposes how can I easily remove this prefix in a generic platform independent way?
Path::components will return a component \\?\C: as the first component...
Should I convert this to a &str and use a regex? Is there some other more ergonomic method for removing the prefix, e.g. some type with a Display implementation that automatically does the right thing?
My requirements specifically are:
Correctly displays X:\\... for a canonical path on Windows.
Doesn't screw up non-Windows platforms (e.g. strip or change path components)
Example:
use std::path::{Path, PathBuf};
fn simple_path<P: AsRef<Path>>(p: P) -> String {
String::from(p.as_ref().to_str().unwrap()) // <-- ?? What to do here?
}
pub fn main() {
let path = PathBuf::from("C:\temp").canonicalize().unwrap();
let display_path = simple_path(path);
println!("Output: {}", display_path);
}
Use the dunce crate:
extern crate dunce;
…
let compatible_path = dunce::canonicalize(&any_path);
Just stripping \\?\ may give wrong/invalid paths. The dunce crate checks whether the UNC path is compatible and converts the path accurately whenever possible. It passes through all other paths. It compiles to plain fs::canonicalize() on non-Windows.
The straightforward answer is to do platform-specific string munging:
use std::path::{Path, PathBuf};
#[cfg(not(target_os = "windows"))]
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
p.as_ref().display().to_string()
}
#[cfg(target_os = "windows")]
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
const VERBATIM_PREFIX: &str = r#"\\?\"#;
let p = p.as_ref().display().to_string();
if p.starts_with(VERBATIM_PREFIX) {
p[VERBATIM_PREFIX.len()..].to_string()
} else {
p
}
}
pub fn main() {
let path = PathBuf::from(r#"C:\Windows\System32"#)
.canonicalize()
.unwrap();
let display_path = adjust_canonicalization(path);
println!("Output: {}", display_path);
}
For the record, I don't agree that your premise is a good idea. Windows Explorer handles these verbatim paths just fine, and I think users are capable of handling it as well.
For [...] logging purposes
This sounds like a terrible idea. If you are logging something, you want to know the exact path, not some potentially incorrect path.
Here's a version that reconstructs the path from the components.
It helps with std::fs::canonicalize on Windows, but a naive Path::new(r"\\?\C:\projects\3rdparty\rust") at play.rust-lang.org will produce a single-component Path.
use std::path::{Component, Path, PathBuf, Prefix};
// Should remove the “\\?” prefix from the canonical path
// in order to avoid CMD bailing with “UNC paths are not supported”.
let head = path.components().next().ok_or("empty path?")?;
let diskˢ;
let head = if let Component::Prefix(prefix) = head {
if let Prefix::VerbatimDisk(disk) = prefix.kind() {
diskˢ = format!("{}:", disk as char);
Path::new(&diskˢ).components().next().ok_or("empty path?")?
} else {
head
}
} else {
head
};
println!("{:?}", head);
let path = std::iter::once(head)
.chain(path.components().skip(1))
.collect::<PathBuf>();
I want to write a yocto recipe for a cross-compiled golang application with Yocto 2.4.1 but I cannot get external dependencies to work.
Can anyone help me?
current RECIPE_FILE: hello-world_%.bb
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
DESCRIPTION = "Hello world test with golang."
inherit go
COMPATIBLE_MACHINE = "(<machine>)"
DEPENDS = "go-cross-${TARGET_ARCH}"
GO_IMPORT = "hello-world"
SRC_URI = "<git_url>/${GO_IMPORT}.git;branch=${SRCBRANCH};tag=${PV}"
SRCBRANCH = "master"
PV = "0.01"
S = "${WORKDIR}/git"
do_compile() {
export GOPATH="${WORKDIR}/build"
export GOARCH="<machine_arch>"
export GOOS="linux"
export CGO_ENABLED="0"
go build src/${GO_IMPORT}/hello-world.go
}
do_install() {
install -d "${D}/${bindir}"
install -m 0755 "${WORKDIR}/build/hello-world" "${D}/${bindir}/hello-world"
}
RDEPENDS_${PN}-dev += "bash"
This recipe works fine for internal dependencies only. But how do I integrate external dependencies like "github.com/golang/protobuf/ptypes"?
PROJECT_FILE: hello-world.go
package main
import (
"fmt"
"github.com/golang/protobuf/ptypes"
)
func main() {
timestamp := ptypes.TimestampNow()
fmt.Println(timestamp)
}
Does anyone knows a solution for this use case?
Or does anyone know how "go-dep" could handle this?
Best regards
I used go dep for the deps, here's an example. Most trouble was about the proxy which is also solved in the recipe:
inherit go
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
DESCRIPTION = "Hello world test with golang."
COMPATIBLE_MACHINE = "(<machine>)"
DEPENDS += "go-dep-native"
GO_LINKSHARED = ""
GO_IMPORT = "<git_url>/hello-world.git"
SRC_URI = "<git_url>/${GO_IMPORT}.git;branch=${SRCBRANCH};tag=${PV}"
SRCBRANCH = "master"
do_compile() {
export SSH_AUTH_SOCK="${SSH_AUTH_SOCK}"
export HTTP_PROXY="${HTTP_PROXY}"
( cd ${WORKDIR}/build/src/${GO_IMPORT} && dep ensure -v )
}
do_compile[vardepsexclude] += "SSH_AUTH_SOCK HTTP_PROXY"
do_install() {
install -d "${D}/${bindir}"
install -m 0755 "${WORKDIR}/bin/<arch>/hello-world" "${D}/${bindir}/hello-world"
}
I believe there is only two types of dependencies
1. host dependencies (dependencies when the app compiling time in yocto)
in yocto recipe(.bb file) keep DEPENDS = "some lib"
target dependencies (dependencies when the app running time on board)
your yocto recipe RDEPENDS = "some lib"
hello.bb
DESCRIPTION =
LIC =
SRC_URI =
DEPENDS ="sqlite3"
inherit autools
you can add external go dependencies with SRC_URI:
SRC_URI = "\
<git_url>/${GO_IMPORT}.git;branch=${SRCBRANCH};tag=${PV} \
git://github.com/golang/protobuf/ptypes;protocol=https;name=ptype;destsuffix=${PN}-${PV}/src/github.com/golang/protobuf/ptypes \
"
SRCREV_ptype = "v0.1.0" <-- whatever revision you need (branch, tag, sha)