feat: add timestamp metadata to generated zip file (#204)
parent
fb5b50f059
commit
652f836c23
|
@ -127,6 +127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2105142db9c6203b9dadc83b0553394589a6cb31b1449a3b46b42f47c3434d0"
|
checksum = "b2105142db9c6203b9dadc83b0553394589a6cb31b1449a3b46b42f47c3434d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
|
"chrono",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"log",
|
"log",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
|
|
|
@ -22,7 +22,7 @@ serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
base64 = "0.21"
|
base64 = "0.21"
|
||||||
async_zip = { version = "0.0.12", default-features = false, features = ["deflate"] }
|
async_zip = { version = "0.0.12", default-features = false, features = ["deflate", "chrono"] }
|
||||||
headers = "0.3"
|
headers = "0.3"
|
||||||
mime_guess = "2.0"
|
mime_guess = "2.0"
|
||||||
if-addrs = "0.10.1"
|
if-addrs = "0.10.1"
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use crate::streamer::Streamer;
|
use crate::streamer::Streamer;
|
||||||
use crate::utils::{decode_uri, encode_uri, get_file_name, glob, try_get_file_name};
|
use crate::utils::{
|
||||||
|
decode_uri, encode_uri, get_file_mtime_and_mode, get_file_name, glob, try_get_file_name,
|
||||||
|
};
|
||||||
use crate::Args;
|
use crate::Args;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use xml::escape::escape_str_pcdata;
|
use xml::escape::escape_str_pcdata;
|
||||||
|
|
||||||
use async_zip::write::ZipFileWriter;
|
use async_zip::write::ZipFileWriter;
|
||||||
use async_zip::{Compression, ZipEntryBuilder};
|
use async_zip::{Compression, ZipDateTime, ZipEntryBuilder};
|
||||||
use chrono::{LocalResult, TimeZone, Utc};
|
use chrono::{LocalResult, TimeZone, Utc};
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use headers::{
|
use headers::{
|
||||||
|
@ -1286,8 +1288,10 @@ async fn zip_dir<W: AsyncWrite + Unpin>(
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
let builder =
|
let (datetime, mode) = get_file_mtime_and_mode(&zip_path).await?;
|
||||||
ZipEntryBuilder::new(filename.into(), Compression::Deflate).unix_permissions(0o644);
|
let builder = ZipEntryBuilder::new(filename.into(), Compression::Deflate)
|
||||||
|
.unix_permissions(mode)
|
||||||
|
.last_modification_date(ZipDateTime::from_chrono(&datetime));
|
||||||
let mut file = File::open(&zip_path).await?;
|
let mut file = File::open(&zip_path).await?;
|
||||||
let mut file_writer = writer.write_entry_stream(builder).await?;
|
let mut file_writer = writer.write_entry_stream(builder).await?;
|
||||||
io::copy(&mut file, &mut file_writer).await?;
|
io::copy(&mut file, &mut file_writer).await?;
|
||||||
|
|
16
src/utils.rs
16
src/utils.rs
|
@ -1,4 +1,5 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
path::Path,
|
path::Path,
|
||||||
|
@ -28,6 +29,21 @@ pub fn get_file_name(path: &Path) -> &str {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub async fn get_file_mtime_and_mode(path: &Path) -> Result<(DateTime<Utc>, u16)> {
|
||||||
|
use std::os::unix::prelude::MetadataExt;
|
||||||
|
let meta = tokio::fs::metadata(path).await?;
|
||||||
|
let datetime: DateTime<Utc> = meta.modified()?.into();
|
||||||
|
Ok((datetime, meta.mode() as u16))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
pub async fn get_file_mtime_and_mode(path: &Path) -> Result<(DateTime<Utc>, u16)> {
|
||||||
|
let meta = tokio::fs::metadata(&path).await?;
|
||||||
|
let datetime: DateTime<Utc> = meta.modified()?.into();
|
||||||
|
Ok((datetime, 0o644))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_get_file_name(path: &Path) -> Result<&str> {
|
pub fn try_get_file_name(path: &Path) -> Result<&str> {
|
||||||
path.file_name()
|
path.file_name()
|
||||||
.and_then(|v| v.to_str())
|
.and_then(|v| v.to_str())
|
||||||
|
|
Loading…
Reference in New Issue