Build a gzipped tar layer from a directory's contents (recursive). Paths inside the tar are relative to `dir`. Regular files and symlinks are included; directory entries themselves are omitted (their paths are implied by the files within). Entries are emitted in a deterministic (sorted) order. Computes `diff_id` (sha256 of the uncompressed tar stream) and `digest` (sha256 of the gzipped bytes).
(dir: &Path)
| 80 | /// Computes `diff_id` (sha256 of the uncompressed tar stream) and `digest` |
| 81 | /// (sha256 of the gzipped bytes). |
| 82 | pub fn layer_from_dir(dir: &Path) -> std::io::Result<OciLayer> { |
| 83 | let mut entries: Vec<(String, PathBuf, bool)> = Vec::new(); |
| 84 | for entry in WalkDir::new(dir) { |
| 85 | let entry = entry.map_err(std::io::Error::from)?; |
| 86 | let file_type = entry.file_type(); |
| 87 | if file_type.is_dir() { |
| 88 | continue; |
| 89 | } |
| 90 | let rel = match entry.path().strip_prefix(dir) { |
| 91 | Ok(r) => r, |
| 92 | Err(_) => continue, |
| 93 | }; |
| 94 | if rel.as_os_str().is_empty() { |
| 95 | continue; |
| 96 | } |
| 97 | entries.push(( |
| 98 | rel.to_string_lossy().into_owned(), |
| 99 | entry.path().to_path_buf(), |
| 100 | file_type.is_symlink(), |
| 101 | )); |
| 102 | } |
| 103 | entries.sort_by(|a, b| a.0.cmp(&b.0)); |
| 104 | |
| 105 | let mut tar_buf = Vec::new(); |
| 106 | { |
| 107 | let mut builder = Builder::new(&mut tar_buf); |
| 108 | for (rel, full, is_symlink) in &entries { |
| 109 | if *is_symlink { |
| 110 | let target = std::fs::read_link(full)?; |
| 111 | let mut header = Header::new_gnu(); |
| 112 | header.set_entry_type(EntryType::Symlink); |
| 113 | header.set_size(0); |
| 114 | header.set_mode(0o777); |
| 115 | header.set_mtime(0); |
| 116 | builder.append_link(&mut header, rel, &target)?; |
| 117 | } else { |
| 118 | let data = std::fs::read(full)?; |
| 119 | let mut header = Header::new_gnu(); |
| 120 | header.set_entry_type(EntryType::Regular); |
| 121 | header.set_size(data.len() as u64); |
| 122 | header.set_mode(0o644); |
| 123 | header.set_mtime(0); |
| 124 | builder.append_data(&mut header, rel, data.as_slice())?; |
| 125 | } |
| 126 | } |
| 127 | builder.finish()?; |
| 128 | } |
| 129 | |
| 130 | finish_layer(tar_buf) |
| 131 | } |
| 132 | |
| 133 | /// Build a single layer from an in-memory set of `(relative_path, bytes)` files |
| 134 | /// plus optional whiteouts. |