feat: implement hash related primops
This commit is contained in:
@@ -37,7 +37,7 @@ deno_error = "0.7"
|
|||||||
nix-nar = "0.3"
|
nix-nar = "0.3"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
sha1 = "0.10"
|
sha1 = "0.10"
|
||||||
md5 = "0.7"
|
md5 = "0.8"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
|||||||
@@ -1,21 +1,37 @@
|
|||||||
import { forceStringNoCtx } from "../type-assert";
|
import { forceAttrs, forceStringNoCtx, forceStringValue } from "../type-assert";
|
||||||
import type { NixValue } from "../types";
|
import type { NixValue } from "../types";
|
||||||
import { realisePath } from "./io";
|
import { realisePath } from "./io";
|
||||||
|
|
||||||
export const hashFile =
|
export const hashFile =
|
||||||
(type: NixValue) =>
|
(type: NixValue) =>
|
||||||
(p: NixValue): string => {
|
(p: NixValue): string => {
|
||||||
const _ty = forceStringNoCtx(type);
|
const algo = forceStringNoCtx(type);
|
||||||
const _pathStr = realisePath(p);
|
const pathStr = realisePath(p);
|
||||||
throw new Error("Not implemented: hashFile");
|
return Deno.core.ops.op_hash_file(algo, pathStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const hashString =
|
export const hashString =
|
||||||
(_type: NixValue) =>
|
(type: NixValue) =>
|
||||||
(_p: NixValue): never => {
|
(s: NixValue): string => {
|
||||||
throw new Error("Not implemented: hashString");
|
const algo = forceStringNoCtx(type);
|
||||||
|
const data = forceStringValue(s);
|
||||||
|
return Deno.core.ops.op_hash_string(algo, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const convertHash = (_args: NixValue): never => {
|
export const convertHash = (args: NixValue): string => {
|
||||||
throw new Error("Not implemented: convertHash");
|
const attrs = forceAttrs(args);
|
||||||
|
const hash = forceStringNoCtx(attrs.hash);
|
||||||
|
|
||||||
|
let hashAlgo: string | null = null;
|
||||||
|
if ("hashAlgo" in attrs) {
|
||||||
|
hashAlgo = forceStringNoCtx(attrs.hashAlgo);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toHashFormat = forceStringNoCtx(attrs.toHashFormat);
|
||||||
|
|
||||||
|
return Deno.core.ops.op_convert_hash({
|
||||||
|
hash,
|
||||||
|
hashAlgo,
|
||||||
|
toHashFormat,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
7
nix-js/runtime-ts/src/types/global.d.ts
vendored
7
nix-js/runtime-ts/src/types/global.d.ts
vendored
@@ -20,6 +20,13 @@ declare global {
|
|||||||
function op_make_placeholder(output: string): string;
|
function op_make_placeholder(output: string): string;
|
||||||
function op_store_path(path: string): string;
|
function op_store_path(path: string): string;
|
||||||
|
|
||||||
|
function op_convert_hash(input: {
|
||||||
|
hash: string;
|
||||||
|
hashAlgo: string | null;
|
||||||
|
toHashFormat: string;
|
||||||
|
}): string;
|
||||||
|
function op_hash_string(algo: string, data: string): string;
|
||||||
|
function op_hash_file(algo: string, path: string): string;
|
||||||
function op_parse_hash(hashStr: string, algo: string | null): { hex: string; algo: string };
|
function op_parse_hash(hashStr: string, algo: string | null): { hex: string; algo: string };
|
||||||
|
|
||||||
function op_add_path(
|
function op_add_path(
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ fn runtime_extension<Ctx: RuntimeContext>() -> Extension {
|
|||||||
op_make_placeholder(),
|
op_make_placeholder(),
|
||||||
op_store_path::<Ctx>(),
|
op_store_path::<Ctx>(),
|
||||||
|
|
||||||
|
op_convert_hash(),
|
||||||
|
op_hash_string(),
|
||||||
|
op_hash_file(),
|
||||||
op_parse_hash(),
|
op_parse_hash(),
|
||||||
|
|
||||||
op_add_path::<Ctx>(),
|
op_add_path::<Ctx>(),
|
||||||
|
|||||||
@@ -1106,3 +1106,135 @@ fn op_make_fixed_output_path_impl(
|
|||||||
crate::nix_utils::make_store_path(store_dir, "output:out", &inner_hash, name)
|
crate::nix_utils::make_store_path(store_dir, "output:out", &inner_hash, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deno_core::op2]
|
||||||
|
#[string]
|
||||||
|
pub(super) fn op_hash_string(
|
||||||
|
#[string] algo: String,
|
||||||
|
#[string] data: String,
|
||||||
|
) -> std::result::Result<String, NixRuntimeError> {
|
||||||
|
use sha2::{Digest, Sha256, Sha512};
|
||||||
|
|
||||||
|
let hash_bytes: Vec<u8> = match algo.as_str() {
|
||||||
|
"sha256" => {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(data.as_bytes());
|
||||||
|
hasher.finalize().to_vec()
|
||||||
|
}
|
||||||
|
"sha512" => {
|
||||||
|
let mut hasher = Sha512::new();
|
||||||
|
hasher.update(data.as_bytes());
|
||||||
|
hasher.finalize().to_vec()
|
||||||
|
}
|
||||||
|
"sha1" => {
|
||||||
|
use sha1::Digest as _;
|
||||||
|
let mut hasher = sha1::Sha1::new();
|
||||||
|
hasher.update(data.as_bytes());
|
||||||
|
hasher.finalize().to_vec()
|
||||||
|
}
|
||||||
|
"md5" => {
|
||||||
|
let digest = md5::compute(data.as_bytes());
|
||||||
|
digest.to_vec()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(NixRuntimeError::from(format!(
|
||||||
|
"unknown hash algorithm '{}'",
|
||||||
|
algo
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(hex::encode(hash_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deno_core::op2]
|
||||||
|
#[string]
|
||||||
|
pub(super) fn op_hash_file(
|
||||||
|
#[string] algo: String,
|
||||||
|
#[string] path: String,
|
||||||
|
) -> std::result::Result<String, NixRuntimeError> {
|
||||||
|
let data = std::fs::read(&path)
|
||||||
|
.map_err(|e| NixRuntimeError::from(format!("cannot read '{}': {}", path, e)))?;
|
||||||
|
|
||||||
|
use sha2::{Digest, Sha256, Sha512};
|
||||||
|
|
||||||
|
let hash_bytes: Vec<u8> = match algo.as_str() {
|
||||||
|
"sha256" => {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(&data);
|
||||||
|
hasher.finalize().to_vec()
|
||||||
|
}
|
||||||
|
"sha512" => {
|
||||||
|
let mut hasher = Sha512::new();
|
||||||
|
hasher.update(&data);
|
||||||
|
hasher.finalize().to_vec()
|
||||||
|
}
|
||||||
|
"sha1" => {
|
||||||
|
use sha1::Digest as _;
|
||||||
|
let mut hasher = sha1::Sha1::new();
|
||||||
|
hasher.update(&data);
|
||||||
|
hasher.finalize().to_vec()
|
||||||
|
}
|
||||||
|
"md5" => {
|
||||||
|
let digest = md5::compute(&data);
|
||||||
|
digest.to_vec()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(NixRuntimeError::from(format!(
|
||||||
|
"unknown hash algorithm '{}'",
|
||||||
|
algo
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(hex::encode(hash_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deno_core::op2]
|
||||||
|
#[string]
|
||||||
|
pub(super) fn op_convert_hash(
|
||||||
|
#[serde] input: ConvertHashInput,
|
||||||
|
) -> std::result::Result<String, NixRuntimeError> {
|
||||||
|
use nix_compat::nixhash::{HashAlgo, NixHash};
|
||||||
|
|
||||||
|
let hash_algo = input
|
||||||
|
.hash_algo
|
||||||
|
.as_deref()
|
||||||
|
.and_then(|a| HashAlgo::from_str(a).ok());
|
||||||
|
|
||||||
|
let hash = NixHash::from_str(&input.hash, hash_algo).map_err(|e| {
|
||||||
|
NixRuntimeError::from(format!("cannot convert hash '{}': {}", input.hash, e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let bytes = hash.digest_as_bytes();
|
||||||
|
|
||||||
|
match input.to_format.as_str() {
|
||||||
|
"base16" => Ok(hex::encode(bytes)),
|
||||||
|
"nix32" | "base32" => Ok(nix_compat::nixbase32::encode(bytes)),
|
||||||
|
"base64" => {
|
||||||
|
use base64::Engine as _;
|
||||||
|
Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
|
||||||
|
}
|
||||||
|
"sri" => Ok(format!(
|
||||||
|
"{}-{}",
|
||||||
|
hash.algo(),
|
||||||
|
{
|
||||||
|
use base64::Engine as _;
|
||||||
|
base64::engine::general_purpose::STANDARD.encode(bytes)
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
_ => Err(NixRuntimeError::from(format!(
|
||||||
|
"unknown hash format '{}'",
|
||||||
|
input.to_format
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
pub(super) struct ConvertHashInput {
|
||||||
|
hash: String,
|
||||||
|
#[serde(rename = "hashAlgo")]
|
||||||
|
hash_algo: Option<String>,
|
||||||
|
#[serde(rename = "toHashFormat")]
|
||||||
|
to_format: String,
|
||||||
|
}
|
||||||
|
|||||||
@@ -122,10 +122,7 @@ eval_okay_test!(concatmap);
|
|||||||
eval_okay_test!(concatstringssep);
|
eval_okay_test!(concatstringssep);
|
||||||
eval_okay_test!(context);
|
eval_okay_test!(context);
|
||||||
eval_okay_test!(context_introspection);
|
eval_okay_test!(context_introspection);
|
||||||
eval_okay_test!(
|
eval_okay_test!(convertHash);
|
||||||
#[ignore = "not implemented: convertHash"]
|
|
||||||
convertHash
|
|
||||||
);
|
|
||||||
eval_okay_test!(curpos);
|
eval_okay_test!(curpos);
|
||||||
eval_okay_test!(deepseq);
|
eval_okay_test!(deepseq);
|
||||||
eval_okay_test!(delayed_with);
|
eval_okay_test!(delayed_with);
|
||||||
@@ -158,24 +155,15 @@ eval_okay_test!(
|
|||||||
fromTOML_timestamps
|
fromTOML_timestamps
|
||||||
);
|
);
|
||||||
eval_okay_test!(functionargs);
|
eval_okay_test!(functionargs);
|
||||||
eval_okay_test!(
|
eval_okay_test!(hashfile);
|
||||||
#[ignore = "not implemented: hashFile"]
|
eval_okay_test!(hashstring);
|
||||||
hashfile
|
|
||||||
);
|
|
||||||
eval_okay_test!(
|
|
||||||
#[ignore = "not implemented: hashString"]
|
|
||||||
hashstring
|
|
||||||
);
|
|
||||||
eval_okay_test!(getattrpos);
|
eval_okay_test!(getattrpos);
|
||||||
eval_okay_test!(getattrpos_functionargs);
|
eval_okay_test!(getattrpos_functionargs);
|
||||||
eval_okay_test!(getattrpos_undefined);
|
eval_okay_test!(getattrpos_undefined);
|
||||||
eval_okay_test!(getenv, || {
|
eval_okay_test!(getenv, || {
|
||||||
unsafe { std::env::set_var("TEST_VAR", "foo") };
|
unsafe { std::env::set_var("TEST_VAR", "foo") };
|
||||||
});
|
});
|
||||||
eval_okay_test!(
|
eval_okay_test!(groupBy);
|
||||||
#[ignore = "not implemented: hashString"]
|
|
||||||
groupBy
|
|
||||||
);
|
|
||||||
eval_okay_test!(r#if);
|
eval_okay_test!(r#if);
|
||||||
eval_okay_test!(ind_string);
|
eval_okay_test!(ind_string);
|
||||||
eval_okay_test!(import);
|
eval_okay_test!(import);
|
||||||
@@ -265,10 +253,7 @@ eval_okay_test!(tryeval);
|
|||||||
eval_okay_test!(types);
|
eval_okay_test!(types);
|
||||||
eval_okay_test!(versions);
|
eval_okay_test!(versions);
|
||||||
eval_okay_test!(with);
|
eval_okay_test!(with);
|
||||||
eval_okay_test!(
|
eval_okay_test!(zipAttrsWith);
|
||||||
#[ignore = "not implemented: hashString"]
|
|
||||||
zipAttrsWith
|
|
||||||
);
|
|
||||||
|
|
||||||
eval_fail_test!(fail_abort);
|
eval_fail_test!(fail_abort);
|
||||||
eval_fail_test!(fail_addDrvOutputDependencies_empty_context);
|
eval_fail_test!(fail_addDrvOutputDependencies_empty_context);
|
||||||
|
|||||||
BIN
nix-js/tests/lang/binary-data
Normal file
BIN
nix-js/tests/lang/binary-data
Normal file
Binary file not shown.
Reference in New Issue
Block a user