feat: Make the rename effect (#1669)

* feat: Make the rename effect

* chore: Change to dst and src

* chore: update the remove file to use dst src
This commit is contained in:
J M
2022-07-20 13:42:54 -06:00
committed by GitHub
parent 0f027fefb8
commit 5fa743755d
4 changed files with 204 additions and 28 deletions

View File

@@ -1,6 +1,10 @@
import Deno from "/deno_global.js";
import * as mainModule from "/embassy.js";
function requireParam(param) {
throw new Error(`Missing required parameter ${param}`);
}
/**
* This is using the simplified json pointer spec, using no escapes and arrays
* @param {object} obj
@@ -20,52 +24,83 @@ function jsonPointerValue(obj, pointer) {
function maybeDate(value) {
if (!value) return value;
return new Date(value)
return new Date(value);
}
const writeFile = ({ path, volumeId, toWrite }) => Deno.core.opAsync("write_file", volumeId, path, toWrite);
const writeFile = (
{
path = requireParam("path"),
volumeId = requireParam("volumeId"),
toWrite = requireParam("toWrite"),
} = requireParam("options"),
) => Deno.core.opAsync("write_file", volumeId, path, toWrite);
const readFile = ({ volumeId, path }) => Deno.core.opAsync("read_file", volumeId, path);
const metadata = async ({ volumeId, path }) => {
const data = await Deno.core.opAsync("metadata", volumeId, path)
const readFile = (
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
) => Deno.core.opAsync("read_file", volumeId, path);
const rename = (
{
srcVolume = requireParam("srcVolume"),
dstVolume = requireParam("dstVolume"),
srcPath = requireParam("srcPath"),
dstPath = requireParam("dstPath"),
} = requireParam("options"),
) => Deno.core.opAsync("rename", srcVolume, srcPath, dstVolume, dstPath);
const metadata = async (
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
) => {
const data = await Deno.core.opAsync("metadata", volumeId, path);
return {
...data,
modified: maybeDate(data.modified),
created: maybeDate(data.created),
accessed: maybeDate(data.accessed),
}
};
};
const removeFile = ({ volumeId, path }) => Deno.core.opAsync("remove_file", volumeId, path);
const removeFile = (
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
) => Deno.core.opAsync("remove_file", volumeId, path);
const isSandboxed = () => Deno.core.opSync("is_sandboxed");
const writeJsonFile = ({ volumeId, path, toWrite }) =>
const writeJsonFile = (
{
volumeId = requireParam("volumeId"),
path = requireParam("path"),
toWrite = requireParam("toWrite"),
} = requireParam("options"),
) =>
writeFile({
volumeId,
path,
toWrite: JSON.stringify(toWrite),
});
const readJsonFile = async ({ volumeId, path }) => JSON.parse(await readFile({ volumeId, path }));
const createDir = ({ volumeId, path }) => Deno.core.opAsync("create_dir", volumeId, path);
const removeDir = ({ volumeId, path }) => Deno.core.opAsync("remove_dir", volumeId, path);
const trace = (x) => Deno.core.opSync("log_trace", x);
const warn = (x) => Deno.core.opSync("log_warn", x);
const error = (x) => Deno.core.opSync("log_error", x);
const debug = (x) => Deno.core.opSync("log_debug", x);
const info = (x) => Deno.core.opSync("log_info", x);
const fetch = async (url, options = null) => {
const {body, ...response} = await Deno.core.opAsync("fetch", url, options);
const textValue = Promise.resolve(body)
const readJsonFile = async (
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
) => JSON.parse(await readFile({ volumeId, path }));
const createDir = (
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
) => Deno.core.opAsync("create_dir", volumeId, path);
const removeDir = (
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
) => Deno.core.opAsync("remove_dir", volumeId, path);
const trace = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opSync("log_trace", whatToTrace);
const warn = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opSync("log_warn", whatToTrace);
const error = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opSync("log_error", whatToTrace);
const debug = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opSync("log_debug", whatToTrace);
const info = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opSync("log_info", whatToTrace);
const fetch = async (url = requireParam ('url'), options = null) => {
const { body, ...response } = await Deno.core.opAsync("fetch", url, options);
const textValue = Promise.resolve(body);
return {
...response,
text() {
return textValue
return textValue;
},
json() {
return textValue.then(x => JSON.parse(x))
}
}
return textValue.then((x) => JSON.parse(x));
},
};
};
const currentFunction = Deno.core.opSync("current_function");
const input = Deno.core.opSync("get_input");
const variable_args = Deno.core.opSync("get_variable_args");
@@ -85,14 +120,15 @@ const effects = {
removeFile,
createDir,
removeDir,
metadata
metadata,
rename,
};
const runFunction = jsonPointerValue(mainModule, currentFunction);
(async () => {
if (typeof runFunction !== "function") {
error(`Expecting ${ currentFunction } to be a function`);
throw new Error(`Expecting ${ currentFunction } to be a function`);
error(`Expecting ${currentFunction} to be a function`);
throw new Error(`Expecting ${currentFunction} to be a function`);
}
const answer = await runFunction(effects, input, ...variable_args);
setState(answer);

View File

@@ -259,6 +259,7 @@ impl JsExecutionEnvironment {
fns::read_file::decl(),
fns::metadata::decl(),
fns::write_file::decl(),
fns::rename::decl(),
fns::remove_file::decl(),
fns::create_dir::decl(),
fns::remove_dir::decl(),
@@ -529,6 +530,56 @@ mod fns {
Ok(())
}
#[op]
async fn rename(
state: Rc<RefCell<OpState>>,
src_volume: VolumeId,
src_path: PathBuf,
dst_volume: VolumeId,
dst_path: PathBuf,
) -> Result<(), AnyError> {
let state = state.borrow();
let ctx: &JsContext = state.borrow();
let volume_path = ctx
.volumes
.path_for(&ctx.datadir, &ctx.package_id, &ctx.version, &src_volume)
.ok_or_else(|| anyhow!("There is no {} in volumes", src_volume))?;
let volume_path_out = ctx
.volumes
.path_for(&ctx.datadir, &ctx.package_id, &ctx.version, &dst_volume)
.ok_or_else(|| anyhow!("There is no {} in volumes", dst_volume))?;
if ctx.volumes.readonly(&dst_volume) {
bail!("Volume {} is readonly", dst_volume);
}
let old_file = volume_path.join(src_path);
let parent_old_file = old_file
.parent()
.ok_or_else(|| anyhow!("Expecting that file is not root"))?;
// With the volume check
if !is_subset(&volume_path, &parent_old_file).await? {
bail!(
"Path '{}' has broken away from parent '{}'",
old_file.to_string_lossy(),
volume_path.to_string_lossy(),
);
}
let new_file = volume_path_out.join(dst_path);
let parent_new_file = new_file
.parent()
.ok_or_else(|| anyhow!("Expecting that file is not root"))?;
// With the volume check
if !is_subset(&volume_path_out, &parent_new_file).await? {
bail!(
"Path '{}' has broken away from parent '{}'",
new_file.to_string_lossy(),
volume_path_out.to_string_lossy(),
);
}
tokio::fs::rename(old_file, new_file).await?;
Ok(())
}
#[op]
async fn remove_file(
state: Rc<RefCell<OpState>>,
volume_id: VolumeId,