Skip to content

Commit

Permalink
Use standard cache directories for nce cache. (#49)
Browse files Browse the repository at this point in the history
Fixes #47
  • Loading branch information
jsirois authored Nov 29, 2022
1 parent 5e12d2b commit f13033b
Show file tree
Hide file tree
Showing 18 changed files with 43 additions and 50 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ re-executes itself using that command. In general, the command will run an inter
contained in one of the files it extracts (say a CPython distribution) against another set of
interpreted files it extracts (say `.py` files). As such, a `scie-jump` is the launcher stub for a
self-contained interpreted executable. It extracts the needed files into a base directory that is
traditionally located at `~/.nce`. This is where the self-contained interpreted executable is
transformed by the `scie-jump` into a non-compact executable.
traditionally located in the local user cache subdirectory `nce` (`~/.cache/nce` on Linux,
`~/Library/Caches/nce` on macOS and `~\AppData\Local\nce` on Windows). This is where the
self-contained interpreted executable is transformed by the `scie-jump` into a non-compact
executable.

## Format

Expand Down
23 changes: 11 additions & 12 deletions docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ In the "lift" manifest, there are 3 required fields:
command and have done that so that it runs by default (More on adding more commands and selecting
them at runtime below). Each command object requires an "exe" that is the path of the executable
to run. Since your scie will be packaged as a single file executable, it will need to unpack the
files you have added to it on first boot. By default, it will do this in the `~/.nce` directory
of the user running the scie, but your command should insulate itself from the details of exactly
where things are unpacked by using placeholders. Placeholders come in a few varieties, but the
most common is a file placeholder. This is just the name of a file in the "files" section
files you have added to it on first boot. By default, it will do this in the `nce` cache
directory of the user running the scie, but your command should insulate itself from the details
of exactly where things are unpacked by using placeholders. Placeholders come in a few varieties,
but the most common is a file placeholder. This is just the name of a file in the "files" section
surrounded by brackets, e.g.: `{amazon-corretto-11.0.17.8.1-linux-x64.tar.gz}`. That placeholder
will be expanded to the full path of the unpacked tarball on the local system when the command
runs. If the name is a bit unwieldy, as it is in this case, you can add a "key" field to the file
Expand Down Expand Up @@ -146,13 +146,13 @@ user of the scie. Instead, they serve the role of performing 1-time installation
requested by other commands that rely upon them via a `{scie.bindings.<binding command name>}`
placeholder. The named binding command will be run (successfully) exactly once as tracked by a lock
file maintained by the scie jump. The binding command will generally want to use the
`{scie.bindings}` to request the path of a directory (housed in the `~/.nce` and namespaced by the
lift manifest hash) set aside for that scie alone. The binding command is guaranteed it will be the
only command operating against that directory when it is invoked.
`{scie.bindings}` to request the path of a directory (housed in the `nce` cache and namespaced by
the lift manifest hash) set aside for that scie alone. The binding command is guaranteed it will be
the only command operating against that directory when it is invoked.

N.B.: Since the scie-jump only maintains cooperative control over the contents of the `~/.nce`, care
should be taken when designing boot binding commands. If the scie is run in a Docker container build
step, you have a wider guaranty of non-interference. If the scie is run in an open environment
N.B.: Since the scie-jump only maintains cooperative control over the contents of the `nce` cache,
care should be taken when designing boot binding commands. If the scie is run in a Docker container
build step, you have a wider guaranty of non-interference. If the scie is run in an open environment
though, you may need to account for conflicting processes running in parallel to your binding
command and invalidating its work or assumptions about the state of the wider filesystem.

Expand Down Expand Up @@ -215,7 +215,7 @@ And you can also inspect the lift manifest with basic tools since the boot-pack
`--single-lift-line` by default:
```
$ tail -1 coursier
{"scie":{"lift":{"name":"coursier","base":"~/.nce","files":[{"name":"amazon-corretto-11.0.17.8.1-linux-x64.tar.gz","key":"jdk","size":194998805,"hash":"9628b1c1ec298a6e0f277afe383b342580086cfd7eee2be567b8d00529ca9449","type":"tar.gz"},{"name":"coursier.jar","size":42284054,"hash":"a1799d6418fbcbad47ac9e388affc751b4fc2d8678f89c332df9592d2dd3a202","type":"blob"}],"boot":{"commands":{"":{"exe":"{jdk}/amazon-corretto-11.0.17.8.1-linux-x64/bin/java","args":["-jar","{coursier.jar}"],"env":{"=JAVA_HOME":"{jdk}/amazon-corretto-11.0.17.8.1-linux-x64","=PATH":"{jdk}/amazon-corretto-11.0.17.8.1-linux-x64/bin:{scie.env.PATH}"}}}}},"jump":{"size":1557952,"version":"0.1.10"}}}
{"scie":{"lift":{"name":"coursier","files":[{"name":"amazon-corretto-11.0.17.8.1-linux-x64.tar.gz","key":"jdk","size":194998805,"hash":"9628b1c1ec298a6e0f277afe383b342580086cfd7eee2be567b8d00529ca9449","type":"tar.gz"},{"name":"coursier.jar","size":42284054,"hash":"a1799d6418fbcbad47ac9e388affc751b4fc2d8678f89c332df9592d2dd3a202","type":"blob"}],"boot":{"commands":{"":{"exe":"{jdk}/amazon-corretto-11.0.17.8.1-linux-x64/bin/java","args":["-jar","{coursier.jar}"],"env":{"=JAVA_HOME":"{jdk}/amazon-corretto-11.0.17.8.1-linux-x64","=PATH":"{jdk}/amazon-corretto-11.0.17.8.1-linux-x64/bin:{scie.env.PATH}"}}}}},"jump":{"size":1557952,"version":"0.1.10"}}}
```

You can also inspect the lift manifest with the built in `inspect` tool by setting the `SCIE`
Expand All @@ -225,7 +225,6 @@ environment variable, e.g.: `SCIE=inspect ./coursier`
"scie": {
"lift": {
"name": "coursier",
"base": "~/.nce",
"files": [
{
"name": "amazon-corretto-11.0.17.8.1-linux-x64.tar.gz",
Expand Down
1 change: 0 additions & 1 deletion examples/cat/lift.linux-aarch64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "java",
"base": "~/.nce",
"files": [
{
"name": "openjdk-19.0.1_linux-aarch64_bin.tar.gz",
Expand Down
1 change: 0 additions & 1 deletion examples/cat/lift.linux-x86_64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "java",
"base": "~/.nce",
"files": [
{
"name": "openjdk-19.0.1_linux-x64_bin.tar.gz",
Expand Down
1 change: 0 additions & 1 deletion examples/cat/lift.macos-aarch64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "java",
"base": "~/.nce",
"files": [
{
"name": "openjdk-19.0.1_macos-aarch64_bin.tar.gz",
Expand Down
1 change: 0 additions & 1 deletion examples/cat/lift.macos-x86_64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "java",
"base": "~/.nce",
"files": [
{
"name": "openjdk-19.0.1_macos-x64_bin.tar.gz",
Expand Down
1 change: 0 additions & 1 deletion examples/cat/lift.windows-x86_64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "java",
"base": "~/.nce",
"files": [
{
"name": "openjdk-19.0.1_windows-x64_bin.zip",
Expand Down
1 change: 0 additions & 1 deletion examples/load/lift.linux-aarch64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "cowsay",
"base": "~/.nce",
"files": [
{
"name": "get.sh"
Expand Down
1 change: 0 additions & 1 deletion examples/load/lift.linux-x86_64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "cowsay",
"base": "~/.nce",
"files": [
{
"name": "get.sh"
Expand Down
1 change: 0 additions & 1 deletion examples/load/lift.macos-aarch64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "cowsay",
"base": "~/.nce",
"files": [
{
"name": "get.sh"
Expand Down
1 change: 0 additions & 1 deletion examples/load/lift.macos-x86_64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "cowsay",
"base": "~/.nce",
"files": [
{
"name": "get.sh"
Expand Down
1 change: 0 additions & 1 deletion examples/load/lift.windows-x86_64.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"scie": {
"lift": {
"name": "cowsay",
"base": "~/.nce",
"files": [
{
"name": "get.sh"
Expand Down
2 changes: 1 addition & 1 deletion examples/load/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ check_cmd mktemp
gc "${PWD}/cowsay"
"${SCIE_JUMP}" "${LIFT}"

# Force downloads to occur to exercise the load functionality even if ~/.nce has the JDK and the
# Force downloads to occur to exercise the load functionality even if nce cache has the JDK and the
# cowsay jars already from other examples.
SCIE_BASE="$(mktemp -d)"
gc "${SCIE_BASE}"
Expand Down
2 changes: 1 addition & 1 deletion examples/ptex/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ check_cmd mktemp
gc "${PWD}/cowsay"
"${SCIE_JUMP}" "${LIFT}"

# Force downloads to occur to exercise the load functionality even if ~/.nce has the JDK and the
# Force downloads to occur to exercise the load functionality even if nce cache has the JDK and the
# cowsay jars already from other examples.
SCIE_BASE="$(mktemp -d)"
gc "${SCIE_BASE}"
Expand Down
19 changes: 10 additions & 9 deletions jump/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The core logic of the scie-jump binary.

Most modules are self-explanatory but the relationship between [config](src/config.rs) and [lift](
src/lift.rs), the overall scie-jump execution flow and the `~/.nce` [CAS](
src/lift.rs), the overall scie-jump execution flow and the `nce` [CAS](
https://en.wikipedia.org/wiki/Content-addressable_storage) deserve to be fleshed out a bit since
they are key aspects of operation.

Expand Down Expand Up @@ -61,7 +61,6 @@ That is reified to this fully specified lift manifest on ingestion via the scie-
"version": "0.1.9"
},
"lift": {
"base": "~/.nce",
"boot": {
"commands": {
"": {
Expand Down Expand Up @@ -119,14 +118,16 @@ scie-jump intrinsic command. The checking proceeds in order:
any files not yet extracted and substituting their paths into placeholders in the command
definition.

## The `~/.nce` CAS
## The `nce` CAS

Step 5 in the execution flow described above critically relies on an atomic content addressable
store for scie file artifacts to ensure the work of extracting scie files is performed exactly once
on any given machine. The `scie-jump` uses a file-system based [CAS](
https://en.wikipedia.org/wiki/Content-addressable_storage) rooted in the `~/.nce` directory by
default, but overridable at scie construction time with the `scie.lift.base` lift manifest field and
at runtime via the `SCIE_BASE` environment variable. The sha256 hash of each file is used as a
directory name key under the `~/.nce` and a cooperative file locking scheme implemented in
[atomic.rs](src/atomic.rs) is used to ensure the CAS directory containing the extracted file is
created exactly once by a single process in the face of parallel scie execution on a host.
https://en.wikipedia.org/wiki/Content-addressable_storage) rooted in the `nce` subdirectory of the
User's cache directory by default (`~/Library/Caches/nce` by default on macOS, `~\AppData\Local\nce`
by default on Windows and `~/.cache/nce` by default on all other Unix systems), but overridable at
scie construction time with the `scie.lift.base` lift manifest field and at runtime via the
`SCIE_BASE` environment variable. The sha256 hash of each file is used as a directory name key under
the `nce` cache directory and a cooperative file locking scheme implemented in [atomic.rs](
src/atomic.rs) is used to ensure the CAS directory containing the extracted file is created exactly
once by a single process in the face of parallel scie execution on a host.
11 changes: 4 additions & 7 deletions jump/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,16 @@ pub struct Boot {
pub bindings: BTreeMap<String, Cmd>,
}

fn default_base() -> PathBuf {
PathBuf::from("~/.nce")
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Lift {
pub name: String,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default = "default_base")]
pub base: PathBuf,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub base: Option<PathBuf>,
pub files: Vec<File>,
pub boot: Boot,
}
Expand Down Expand Up @@ -373,7 +370,7 @@ mod tests {
size: 37,
},
Lift {
base: "~/.nce".into(),
base: None,
files: vec![
File {
name: "pants-client".to_string(),
Expand Down
11 changes: 10 additions & 1 deletion jump/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,20 @@ impl<'a> Context<'a> {
files_by_name.insert(key.as_str(), file);
}
}
let base = if let Ok(base) = env::var("SCIE_BASE") {
PathBuf::from(base)
} else if let Some(base) = &lift.base {
base.clone()
} else if let Some(dir) = dirs::cache_dir() {
dir.join("nce")
} else {
PathBuf::from("~/.nce")
};
Ok(Context {
scie,
jump,
lift,
base: expanduser(&lift.base)?,
base: expanduser(base.as_path())?,
files_by_name,
replacements: HashSet::new(),
bindings: IndexMap::new(),
Expand Down
9 changes: 2 additions & 7 deletions jump/src/lift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl From<File> for crate::config::File {
pub struct Lift {
pub name: String,
pub description: Option<String>,
pub base: PathBuf,
pub base: Option<PathBuf>,
pub size: usize,
pub hash: String,
pub boot: Boot,
Expand Down Expand Up @@ -259,17 +259,12 @@ fn load(
.unwrap_or_else(|| Path::new(""));
let lift = config.scie.lift;
let files = assemble(resolve_base, lift.files, reconstitute)?;
let base = if let Ok(base) = std::env::var("SCIE_BASE") {
PathBuf::from(base)
} else {
lift.base
};
Ok((
config.scie.jump,
Lift {
name: lift.name,
description: lift.description,
base,
base: lift.base,
boot: lift.boot,
size: data.len(),
hash: fingerprint::digest(data),
Expand Down

0 comments on commit f13033b

Please sign in to comment.