-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate from file content #3
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* text=auto | ||
LICENSE text eol=lf |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,17 @@ | ||
use std::fs; | ||
use std::fs::{File}; | ||
use std::io::{BufReader, Read}; | ||
use std::iter::*; | ||
use std::error::{Error}; | ||
use std::path::Path; | ||
|
||
use hex::*; | ||
use regex::Regex; | ||
use semver::Version; | ||
use std::iter::*; | ||
use std::error::{Error}; | ||
use sha2::Sha256; | ||
use sha2::Digest; | ||
use url::{Url}; | ||
use url::percent_encoding::{percent_decode}; | ||
use url::percent_encoding::{percent_decode, utf8_percent_encode, DEFAULT_ENCODE_SET}; | ||
|
||
/* Example lines: | ||
|
||
|
@@ -19,21 +26,103 @@ pub struct ReleaseEntry { | |
pub sha256: [u8; 32], | ||
pub filename_or_url: String, | ||
pub version: Version, | ||
pub length: i64, | ||
pub length: u64, | ||
pub is_delta: bool, | ||
pub percentage: i32, | ||
} | ||
|
||
impl Default for ReleaseEntry { | ||
fn default() -> ReleaseEntry { | ||
ReleaseEntry { | ||
filename_or_url: "Foobdar".to_owned(), | ||
version: Version::parse("1.0.0").unwrap(), | ||
is_delta: true, | ||
length: 42, | ||
static HEADER: &'static str = "# SHA256 of the file Name Version Size [delta/full] release%"; | ||
|
||
// | ||
// Create new release entries | ||
impl ReleaseEntry { | ||
pub fn from_file(path: &str) -> Result<ReleaseEntry, Box<Error>> { | ||
let mut sha256_sum = Sha256::new(); | ||
{ | ||
let file = try!(File::open(path)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a So this line could be |
||
let mut content: [u8; 65536] = [0; 65536]; | ||
let mut buf = BufReader::new(file); | ||
|
||
loop { | ||
let count = try!(buf.read(&mut content)); | ||
if count == 0 { break; } | ||
|
||
sha256_sum.input(&content[..count]); | ||
} | ||
} | ||
|
||
let p = Path::new(path); | ||
let stat = try!(fs::metadata(path)); | ||
let file = p.file_name().unwrap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be able to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
|
||
let mut ret = ReleaseEntry { | ||
sha256: [0; 32], | ||
filename_or_url: file.to_str().unwrap().to_owned(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use |
||
length: stat.len(), | ||
version: Version::parse("0.0.0").unwrap(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use |
||
is_delta: false, | ||
percentage: 100, | ||
}; | ||
|
||
let sha = sha256_sum.result(); | ||
for i in 0..32 { | ||
ret.sha256[i] = sha[i]; | ||
} | ||
|
||
return Ok(ret); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Rust, the last expression statement in a block is the return. If that statement doesn't end with So this could simply be If it was |
||
} | ||
} | ||
|
||
// | ||
// Write release files | ||
// | ||
|
||
impl ReleaseEntry { | ||
fn sha256_to_string(&self) -> String { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this could be Because |
||
return self.sha256.into_iter().fold( | ||
"".to_owned(), | ||
|mut acc, x| { | ||
let byte = format!("{:02x}", x); | ||
acc.push_str(&byte); | ||
return acc; | ||
}); | ||
} | ||
|
||
fn escape_filename(&self) -> String { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how much you care about allocations here, but you might find the It would basically look like: fn escape_filename(&self) -> Cow<str> {
if match {
Cow::Borrowed(&self.filename_or_url)
} else {
Cow::Owned(utf8_percent_encode(&self.filename_or_url))
}
} |
||
if SCHEME.is_match(&self.filename_or_url) { | ||
return self.filename_or_url.to_owned(); | ||
} else { | ||
return utf8_percent_encode(&self.filename_or_url, DEFAULT_ENCODE_SET).to_string(); | ||
} | ||
} | ||
|
||
pub fn to_release_entry(&self) -> String { | ||
if self.percentage == 100 { | ||
return format!("{} {} {} {} {}", | ||
self.sha256_to_string(), | ||
self.escape_filename(), | ||
self.version, | ||
self.length, | ||
if self.is_delta { "delta" } else { "full" }); | ||
} else { | ||
return format!("{} {} {} {} {} {}%", | ||
self.sha256_to_string(), | ||
self.escape_filename(), | ||
self.version, | ||
self.length, | ||
if self.is_delta { "delta" } else { "full" }, | ||
self.percentage); | ||
} | ||
} | ||
|
||
pub fn to_releases_file(entries: &Vec<ReleaseEntry>) -> String { | ||
let ret = entries.into_iter() | ||
.fold("".to_owned(), |mut acc, x| { | ||
acc.push_str(&format!("{}\n", x.to_release_entry())); | ||
return acc; | ||
}); | ||
|
||
return format!("{}\n{}", HEADER, ret.trim_right_matches("\n")); | ||
} | ||
} | ||
|
||
|
@@ -45,6 +134,10 @@ lazy_static! { | |
static ref COMMENT: Regex = Regex::new(r"#.*$").unwrap(); | ||
} | ||
|
||
// | ||
// Parse release entries | ||
// | ||
|
||
impl ReleaseEntry { | ||
fn parse_sha256(sha256: &str, to_fill: &mut ReleaseEntry) -> Result<bool, Box<Error>> { | ||
let ret = try!(sha256.from_hex()); | ||
|
@@ -97,7 +190,7 @@ impl ReleaseEntry { | |
is_delta: try!(ReleaseEntry::parse_delta_full(delta_or_full)), | ||
filename_or_url: try!(ReleaseEntry::parse_name(name)), | ||
version: try!(Version::parse(version)), | ||
length: try!(size.parse::<i64>()), | ||
length: try!(size.parse::<u64>()), | ||
percentage: 100, | ||
}; | ||
|
||
|
@@ -111,7 +204,7 @@ impl ReleaseEntry { | |
is_delta: try!(ReleaseEntry::parse_delta_full(delta_or_full)), | ||
filename_or_url: try!(ReleaseEntry::parse_name(name)).to_owned(), | ||
version: try!(Version::parse(version)), | ||
length: try!(size.parse::<i64>()), | ||
length: try!(size.parse::<u64>()), | ||
percentage: try!(ReleaseEntry::parse_percentage(percent)) | ||
}; | ||
|
||
|
@@ -149,21 +242,51 @@ impl ReleaseEntry { | |
|
||
#[cfg(test)] | ||
mod tests { | ||
use sha2::Sha256; | ||
use sha2::Digest; | ||
use std::env; | ||
use std::path::Path; | ||
use super::ReleaseEntry; | ||
|
||
fn print_result(sum: &[u8], name: &str) { | ||
for byte in sum { | ||
print!("{:02x}", byte); | ||
} | ||
println!("\t{}", name); | ||
const ENTRIES_EXAMPLE_1: &'static str = "# SHA256 of the file Name Version Size [delta/full] release% | ||
e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full | ||
a4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-delta.7z 1.2.3 555 delta | ||
b4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-beta.7z 2.0.0-beta.1 34567 full 5%"; | ||
|
||
// | ||
// Generate from file | ||
// | ||
|
||
#[test] | ||
fn generate_from_license_file() { | ||
let expected = "afb11426e09da40a1ae4f8fa17ddcc6b6a52d14df04c29bc5bcd06eb8730624d LICENSE 0.0.0 1057 full"; | ||
let dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||
let input = Path::new(&dir).join("LICENSE"); | ||
|
||
let result = ReleaseEntry::from_file(input.to_str().unwrap()) | ||
.unwrap() | ||
.to_release_entry(); | ||
|
||
assert_eq!(result, expected); | ||
} | ||
|
||
// | ||
// Parse release entries | ||
// | ||
|
||
#[test] | ||
fn roundtrip_parse_and_generate() { | ||
let entry = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full"; | ||
let input = ReleaseEntry::parse(entry).unwrap(); | ||
|
||
let result = input.to_release_entry(); | ||
assert_eq!(entry, &result); | ||
} | ||
|
||
#[test] | ||
fn create_a_release_entry() { | ||
let f = ReleaseEntry::default(); | ||
assert_eq!(f.length, 42); | ||
fn roundtrip_parse_and_generate_all() { | ||
let entries = ReleaseEntry::parse_entries(ENTRIES_EXAMPLE_1).unwrap(); | ||
let result = ReleaseEntry::to_releases_file(&entries); | ||
|
||
assert_eq!(ENTRIES_EXAMPLE_1, &result); | ||
} | ||
|
||
#[test] | ||
|
@@ -236,23 +359,7 @@ mod tests { | |
|
||
#[test] | ||
fn parse_all_entries() { | ||
let input = " | ||
# SHA256 of the file Name Version Size [delta/full] release% | ||
e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full | ||
a4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-delta.7z 1.2.3 555 delta | ||
b4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-beta.7z 2.0.0-beta.1 34567 full 5%"; | ||
|
||
let result = ReleaseEntry::parse_entries(input).unwrap(); | ||
let result = ReleaseEntry::parse_entries(ENTRIES_EXAMPLE_1).unwrap(); | ||
assert_eq!(result.len(), 3); | ||
} | ||
|
||
#[test] | ||
fn stringify_a_sha256() { | ||
let mut sha = Sha256::default(); | ||
sha.input("This is a test".as_bytes()); | ||
|
||
let hash = sha.result(); | ||
print_result(&hash, "SHA256"); | ||
println!("Wat."); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be
fn from_file<P: AsRef<std::path::Path>>(path: P)
. That way we can accept anything that can be referenced as aPath
, which includes owned and borrowed strings, paths and OS strings.For reference, that's what the sig for
File::open
looks like.