feat: implement hash related primops
This commit is contained in:
@@ -37,7 +37,7 @@ deno_error = "0.7"
|
||||
nix-nar = "0.3"
|
||||
sha2 = "0.10"
|
||||
sha1 = "0.10"
|
||||
md5 = "0.7"
|
||||
md5 = "0.8"
|
||||
hex = "0.4"
|
||||
|
||||
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 { realisePath } from "./io";
|
||||
|
||||
export const hashFile =
|
||||
(type: NixValue) =>
|
||||
(p: NixValue): string => {
|
||||
const _ty = forceStringNoCtx(type);
|
||||
const _pathStr = realisePath(p);
|
||||
throw new Error("Not implemented: hashFile");
|
||||
const algo = forceStringNoCtx(type);
|
||||
const pathStr = realisePath(p);
|
||||
return Deno.core.ops.op_hash_file(algo, pathStr);
|
||||
};
|
||||
|
||||
export const hashString =
|
||||
(_type: NixValue) =>
|
||||
(_p: NixValue): never => {
|
||||
throw new Error("Not implemented: hashString");
|
||||
(type: NixValue) =>
|
||||
(s: NixValue): string => {
|
||||
const algo = forceStringNoCtx(type);
|
||||
const data = forceStringValue(s);
|
||||
return Deno.core.ops.op_hash_string(algo, data);
|
||||
};
|
||||
|
||||
export const convertHash = (_args: NixValue): never => {
|
||||
throw new Error("Not implemented: convertHash");
|
||||
export const convertHash = (args: NixValue): string => {
|
||||
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_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_add_path(
|
||||
|
||||
@@ -58,6 +58,9 @@ fn runtime_extension<Ctx: RuntimeContext>() -> Extension {
|
||||
op_make_placeholder(),
|
||||
op_store_path::<Ctx>(),
|
||||
|
||||
op_convert_hash(),
|
||||
op_hash_string(),
|
||||
op_hash_file(),
|
||||
op_parse_hash(),
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[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!(context);
|
||||
eval_okay_test!(context_introspection);
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: convertHash"]
|
||||
convertHash
|
||||
);
|
||||
eval_okay_test!(convertHash);
|
||||
eval_okay_test!(curpos);
|
||||
eval_okay_test!(deepseq);
|
||||
eval_okay_test!(delayed_with);
|
||||
@@ -158,24 +155,15 @@ eval_okay_test!(
|
||||
fromTOML_timestamps
|
||||
);
|
||||
eval_okay_test!(functionargs);
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: hashFile"]
|
||||
hashfile
|
||||
);
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: hashString"]
|
||||
hashstring
|
||||
);
|
||||
eval_okay_test!(hashfile);
|
||||
eval_okay_test!(hashstring);
|
||||
eval_okay_test!(getattrpos);
|
||||
eval_okay_test!(getattrpos_functionargs);
|
||||
eval_okay_test!(getattrpos_undefined);
|
||||
eval_okay_test!(getenv, || {
|
||||
unsafe { std::env::set_var("TEST_VAR", "foo") };
|
||||
});
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: hashString"]
|
||||
groupBy
|
||||
);
|
||||
eval_okay_test!(groupBy);
|
||||
eval_okay_test!(r#if);
|
||||
eval_okay_test!(ind_string);
|
||||
eval_okay_test!(import);
|
||||
@@ -265,10 +253,7 @@ eval_okay_test!(tryeval);
|
||||
eval_okay_test!(types);
|
||||
eval_okay_test!(versions);
|
||||
eval_okay_test!(with);
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: hashString"]
|
||||
zipAttrsWith
|
||||
);
|
||||
eval_okay_test!(zipAttrsWith);
|
||||
|
||||
eval_fail_test!(fail_abort);
|
||||
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