Skip to content

Commit

Permalink
feat: also generate integrity attributes for snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
ctron committed Nov 24, 2023
1 parent 67f1cea commit 3c11f00
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
23 changes: 14 additions & 9 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
//! Common functionality and types.
use anyhow::{anyhow, bail, Context, Result};
use async_recursion::async_recursion;
use console::Emoji;
use once_cell::sync::Lazy;
use std::collections::HashSet;
use std::convert::Infallible;
use std::ffi::OsStr;
use std::fmt::Debug;
use std::fs::Metadata;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use std::process::Stdio;

use anyhow::{anyhow, bail, Context, Result};
use async_recursion::async_recursion;
use console::Emoji;
use once_cell::sync::Lazy;
use tokio::fs;
use tokio::process::Command;

Expand All @@ -34,7 +34,7 @@ pub fn parse_public_url(val: &str) -> Result<String, Infallible> {

/// A utility function to recursively copy a directory.
#[async_recursion]
pub async fn copy_dir_recursive<F, T>(from_dir: F, to_dir: T) -> Result<()>
pub async fn copy_dir_recursive<F, T>(from_dir: F, to_dir: T) -> Result<HashSet<PathBuf>>
where
F: AsRef<Path> + Debug + Send + 'static,
T: AsRef<Path> + Send + 'static,
Expand All @@ -59,6 +59,8 @@ where
.with_context(|| format!("Unable to create target directory '{to:?}'."))?;
}

let mut collector = HashSet::new();

// Copy files and recursively handle nested directories.
let mut read_dir = tokio::fs::read_dir(from)
.await
Expand All @@ -69,14 +71,17 @@ where
.context(anyhow!("Unable to read next dir entry"))?
{
if entry.file_type().await?.is_dir() {
copy_dir_recursive(entry.path(), to.join(entry.file_name())).await?;
let files = copy_dir_recursive(entry.path(), to.join(entry.file_name())).await?;
collector.extend(files);
} else {
let to = to.join(entry.file_name());
// Does overwrite!
tokio::fs::copy(entry.path(), to.join(entry.file_name())).await?;
tokio::fs::copy(entry.path(), &to).await?;
collector.insert(to);
}
}

Ok(())
Ok(collector)
}

/// A utility function to recursively delete a directory.
Expand Down
36 changes: 31 additions & 5 deletions src/pipelines/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cargo_metadata::camino::Utf8PathBuf;
use minify_js::TopLevelMode;
use nipper::Document;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::iter::Iterator;
use std::path::{Path, PathBuf};
use std::process::Stdio;
Expand Down Expand Up @@ -550,20 +550,31 @@ impl RustApp {

// Check for any snippets, and copy them over.
let snippets_dir_src = bindgen_out.join(SNIPPETS_DIR);
if path_exists(&snippets_dir_src).await? {
let snippets = if path_exists(&snippets_dir_src).await? {
let snippets_dir_dest = self.cfg.staging_dist.join(SNIPPETS_DIR);
tracing::debug!(
"recursively copying from '{snippets_dir_src}' to '{}'",
snippets_dir_dest.to_string_lossy()
);
copy_dir_recursive(snippets_dir_src, snippets_dir_dest)
.await
.context("error copying snippets dir to stage dir")?;
}
.context("error copying snippets dir to stage dir")?
} else {
HashSet::new()
};

integrity.js =
OutputDigest::generate(self.integrity, || std::fs::read(js_loader_path_dist))?;

let mut snippet_integrities = HashMap::new();
for snippet in snippets {
let integrity = OutputDigest::generate(self.integrity, || std::fs::read(&snippet))?;

if let Ok(name) = snippet.strip_prefix(&self.cfg.staging_dist) {
snippet_integrities.insert(name.to_string_lossy().to_string(), integrity);
}
}

Ok(RustAppOutput {
id: self.id,
cfg: self.cfg.clone(),
Expand All @@ -574,6 +585,7 @@ impl RustApp {
r#type: self.app_type,
cross_origin: self.cross_origin,
integrity,
snippet_integrities,
})
}

Expand Down Expand Up @@ -726,6 +738,8 @@ pub struct RustAppOutput {
pub cross_origin: CrossOrigin,
/// The integrity and digest of the output, ignored in case of [`IntegrityType::None`]
pub integrity: IntegrityOutput,
/// The output digests for the discovered snippets
pub snippet_integrities: HashMap<String, OutputDigest>,
}

pub fn pattern_evaluate(template: &str, params: &HashMap<String, String>) -> String {
Expand Down Expand Up @@ -792,11 +806,23 @@ impl RustAppOutput {
};
dom.select(head).append_html(preload);

for (name, integrity) in self.snippet_integrities {
if let Some(integrity) = integrity.to_integrity_value() {
let preload = format!(
r#"
<link rel="modulepreload" href="{base}{name}" crossorigin={cross_origin} integrity="{integrity}">"#,
cross_origin = self.cross_origin,
);
dom.select(head).append_html(preload);
}
}

let script = match pattern_script {
Some(pattern) => pattern_evaluate(pattern, &params),
None => {
format!(
r#"<script type="module">import init from '{base}{js}';init('{base}{wasm}');</script>"#,
r#"
<script type="module">import init from '{base}{js}';init('{base}{wasm}');</script>"#,
)
}
};
Expand Down

0 comments on commit 3c11f00

Please sign in to comment.