From 6fa43f7a4739f3c7f1bb49bd4ff074f24f314c39 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 01:11:49 +0200 Subject: [PATCH 01/35] Add server-side rendering of the crate's READMEs --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + src/krate.rs | 9 ++++-- src/lib.rs | 2 ++ src/render.rs | 12 +++++++ src/uploaders.rs | 81 +++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 src/render.rs diff --git a/Cargo.lock b/Cargo.lock index 0357fe946e..2604a88d59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,6 +133,7 @@ dependencies = [ "postgres 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2-diesel 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_postgres 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -865,6 +866,14 @@ dependencies = [ "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pulldown-cmark" +version = "0.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quine-mc_cluskey" version = "0.2.4" @@ -1328,6 +1337,7 @@ dependencies = [ "checksum postgres-protocol 0.3.0 (git+https://github.com/sfackler/rust-postgres.git)" = "" "checksum postgres-shared 0.3.0 (git+https://github.com/sfackler/rust-postgres.git)" = "" "checksum pq-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfb5e575ef93a1b7b2a381d47ba7c5d4e4f73bff37cee932195de769aad9a54" +"checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c665a538b218e1620093be6643b375d3321837bfc1b30aa18757b7c6546d2ca" diff --git a/Cargo.toml b/Cargo.toml index bb275efbb5..ae2e02d80b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ serde_derive = "1.0.0" serde = "1.0.0" clippy = { version = "=0.0.142", optional = true } chrono = "0.4.0" +pulldown-cmark = { version = "0.0.15", default-features = false } conduit = "0.8" conduit-conditional-get = "0.8" diff --git a/src/krate.rs b/src/krate.rs index 0e4d2d5141..95d0b18eb2 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -31,6 +31,7 @@ use git; use keyword::{EncodableKeyword, CrateKeyword}; use owner::{EncodableOwner, Owner, Rights, OwnerKind, Team, rights, CrateOwner}; use pagination::Paginate; +use render; use schema::*; use upload; use user::RequestUser; @@ -1189,10 +1190,13 @@ pub fn new(req: &mut Request) -> CargoResult { let ignored_invalid_badges = Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?; let max_version = krate.max_version(&conn)?; + // Render the README for this crate + let readme = render::markdown_to_html(new_crate.readme.as_ref().map(|s| &**s))?; + // Upload the crate, return way to delete the crate from the server // If the git commands fail below, we shouldn't keep the crate on the // server. - let (cksum, mut bomb) = app.config.uploader.upload(req, &krate, max, vers)?; + let (cksum, mut crate_bomb, mut readme_bomb) = app.config.uploader.upload(req, &krate, readme, max, vers)?; // Register this crate in our local git repo. let git_crate = git::Crate { @@ -1211,7 +1215,8 @@ pub fn new(req: &mut Request) -> CargoResult { })?; // Now that we've come this far, we're committed! - bomb.path = None; + crate_bomb.path = None; + readme_bomb.path = None; #[derive(Serialize)] struct Warnings<'a> { diff --git a/src/lib.rs b/src/lib.rs index bf446745b9..5850dfb3e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ extern crate license_exprs; extern crate oauth2; extern crate openssl; extern crate postgres as pg; +extern crate pulldown_cmark; extern crate r2d2; extern crate r2d2_diesel; extern crate r2d2_postgres; @@ -85,6 +86,7 @@ pub mod keyword; pub mod krate; pub mod model; pub mod owner; +pub mod render; pub mod schema; pub mod token; pub mod upload; diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000000..ab86034e88 --- /dev/null +++ b/src/render.rs @@ -0,0 +1,12 @@ +use pulldown_cmark::Parser; +use pulldown_cmark::html; + +use util::CargoResult; + +pub fn markdown_to_html(raw: Option<&str>) -> CargoResult { + let text = raw.unwrap_or(""); + let mut rendered = String::with_capacity(text.len() * 3 / 2); + let parser = Parser::new(&text); + html::push_html(&mut rendered, parser); + Ok(rendered) +} diff --git a/src/uploaders.rs b/src/uploaders.rs index fa8b11bcbb..0653fe62e8 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -59,17 +59,22 @@ impl Uploader { format!("crates/{}/{}-{}.crate", name, name, version) } + fn readme_path(name: &str, version: &str) -> String { + format!("readmes/{}/{}-{}.html", name, name, version) + } + pub fn upload( &self, req: &mut Request, krate: &Crate, + readme: String, max: u64, vers: &semver::Version, - ) -> CargoResult<(Vec, Bomb)> { + ) -> CargoResult<(Vec, Bomb, Bomb)> { match *self { Uploader::S3 { ref bucket, .. } => { let mut handle = req.app().handle(); - let path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); + let crate_path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); let (response, cksum) = { let length = read_le_u32(req.body())?; let body = LimitErrorReader::new(req.body(), max); @@ -78,7 +83,7 @@ impl Uploader { { let mut s3req = bucket.put( &mut handle, - &path, + &crate_path, &mut body, "application/x-tar", length as u64, @@ -90,7 +95,7 @@ impl Uploader { }) .unwrap(); s3req.perform().chain_error(|| { - internal(&format_args!("failed to upload to S3: `{}`", path)) + internal(&format_args!("failed to upload to S3: `{}`", crate_path)) })?; } (response, body.finalize()) @@ -103,21 +108,62 @@ impl Uploader { ))); } + let mut handle = req.app().handle(); + let readme_path = format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string())); + let response = { + let mut response = Vec::new(); + { + let readme_len = readme.len(); + let mut cursor = io::Cursor::new(readme.into_bytes()); + let mut s3req = bucket.put( + &mut handle, + &readme_path, + &mut cursor, + "text/html", + readme_len as u64, + ); + s3req.write_function(|data| { + response.extend(data); + Ok(data.len()) + }).unwrap(); + s3req.perform().chain_error(|| { + internal(&format_args!("failed to upload readme to S3: `{}`", readme_path)) + })?; + } + response + }; + if handle.response_code().unwrap() != 200 { + if let Err(e) = self.delete(req.app().clone(), &crate_path) { + println!("failed to delete crate from S3: `{}`, {:?}", crate_path, e); + } + let response = String::from_utf8_lossy(&response); + return Err(internal(&format_args!( + "failed to get a 200 response from S3: {}", + response + ))); + } + Ok(( cksum, Bomb { app: req.app().clone(), - path: Some(path), + path: Some(crate_path), + }, + Bomb { + app: req.app().clone(), + path: Some(readme_path), }, )) } Uploader::Local => { - let path = Uploader::crate_path(&krate.name, &vers.to_string()); + use std::io::Write; + + let crate_path = Uploader::crate_path(&krate.name, &vers.to_string()); let crate_filename = env::current_dir() .unwrap() .join("dist") .join("local_uploads") - .join(path); + .join(crate_path); let crate_dir = crate_filename.parent().unwrap(); fs::create_dir_all(crate_dir)?; @@ -133,12 +179,29 @@ impl Uploader { body.finalize() }; + let readme_path = Uploader::readme_path(&krate.name, &vers.to_string()); + let readme_filename = env::current_dir() + .unwrap() + .join("dist") + .join("local_uploads") + .join(readme_path); + + let readme_dir = readme_filename.parent().unwrap(); + fs::create_dir_all(readme_dir)?; + + let mut readme_file = File::create(&readme_filename)?; + readme_file.write_all(readme.as_ref())?; + Ok(( cksum, Bomb { app: req.app().clone(), path: crate_filename.to_str().map(String::from), }, + Bomb { + app: req.app().clone(), + path: readme_filename.to_str().map(String::from), + }, )) } Uploader::NoOp => { @@ -148,6 +211,10 @@ impl Uploader { app: req.app().clone(), path: None, }, + Bomb { + app: req.app().clone(), + path: None + }, )) } } From b15403b24524c4aee981ceb0a930c3d464fdc0af Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 03:34:54 +0200 Subject: [PATCH 02/35] Add readme_path to EncodableVersion & create associated route --- src/krate.rs | 22 ++++++++++++++++++++++ src/lib.rs | 1 + src/uploaders.rs | 19 +++++++++++++++++++ src/version.rs | 2 ++ 4 files changed, 44 insertions(+) diff --git a/src/krate.rs b/src/krate.rs index 95d0b18eb2..2d6c806baf 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -1317,6 +1317,28 @@ pub fn download(req: &mut Request) -> CargoResult { } } +/// Handles the `GET /crates/:crate_id/:version/readme` route. +pub fn readme(req: &mut Request) -> CargoResult { + let crate_name = &req.params()["crate_id"]; + let version = &req.params()["version"]; + + let redirect_url = req.app() + .config + .uploader + .readme_location(crate_name, version) + .ok_or_else(|| human("crate readme not found"))?; + + if req.wants_json() { + #[derive(Serialize)] + struct R { + url: String, + } + Ok(req.json(&R { url: redirect_url })) + } else { + Ok(req.redirect(redirect_url)) + } +} + fn increment_download_counts(req: &Request, crate_name: &str, version: &str) -> CargoResult<()> { use self::versions::dsl::*; diff --git a/src/lib.rs b/src/lib.rs index 5850dfb3e0..6548df70fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,6 +120,7 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { api_router.put("/crates/new", C(krate::new)); api_router.get("/crates/:crate_id/:version", C(version::show)); api_router.get("/crates/:crate_id/:version/download", C(krate::download)); + api_router.get("/crates/:crate_id/:version/readme", C(krate::readme)); api_router.get( "/crates/:crate_id/:version/dependencies", C(version::dependencies), diff --git a/src/uploaders.rs b/src/uploaders.rs index 0653fe62e8..40718d1c0e 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -54,6 +54,25 @@ impl Uploader { } } + pub fn readme_location(&self, crate_name: &str, version: &str) -> Option { + match *self { + Uploader::S3 { ref bucket, .. } => { + Some(format!( + "https://{}/{}", + bucket.host(), + Uploader::readme_path(crate_name, version) + )) + } + Uploader::Local => { + Some(format!( + "/local_uploads/{}", + Uploader::readme_path(crate_name, version) + )) + } + Uploader::NoOp => None, + } + } + fn crate_path(name: &str, version: &str) -> String { // No slash in front so we can use join format!("crates/{}/{}-{}.crate", name, name, version) diff --git a/src/version.rs b/src/version.rs index e30cf45b6c..c2e3e04a83 100644 --- a/src/version.rs +++ b/src/version.rs @@ -56,6 +56,7 @@ pub struct EncodableVersion { pub krate: String, pub num: String, pub dl_path: String, + pub readme_path: String, pub updated_at: String, pub created_at: String, pub downloads: i32, @@ -127,6 +128,7 @@ impl Version { let num = num.to_string(); EncodableVersion { dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num), + readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num), num: num.clone(), id: id, krate: crate_name.to_string(), From ed9e4139f706a0117d9ed337ac7e726176bc02df Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 03:35:35 +0200 Subject: [PATCH 03/35] Display README content on crate page if it's available --- app/models/version.js | 1 + app/routes/crate/version.js | 19 ++++++++++++++++++- app/styles/crate.scss | 5 +++++ app/templates/crate/version.hbs | 5 +++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/models/version.js b/app/models/version.js index fec6f6c3f3..3da95b4300 100644 --- a/app/models/version.js +++ b/app/models/version.js @@ -4,6 +4,7 @@ import DS from 'ember-data'; export default DS.Model.extend({ num: DS.attr('string'), dl_path: DS.attr('string'), + readme_path: DS.attr('string'), created_at: DS.attr('date'), updated_at: DS.attr('date'), downloads: DS.attr('number'), diff --git a/app/routes/crate/version.js b/app/routes/crate/version.js index e6a0be8e29..6003a6c8cc 100644 --- a/app/routes/crate/version.js +++ b/app/routes/crate/version.js @@ -99,9 +99,26 @@ export default Route.extend({ `Version '${params.version_num}' of crate '${crate.get('name')}' does not exist`); } - return version || + const result = version || versions.find(version => version.get('num') === maxVersion) || versions.objectAt(0); + if (result.get('readme_path')) { + this.get('ajax').request(result.get('readme_path')) + .then((r) => this.get('ajax').raw(r.url, { + method: 'GET', + dataType: 'html', + headers: { + Accept: '*/*', + }, + })) + .then((r) => { + crate.set('readme', r.payload); + }) + .catch((r) => { + console.error(r); + }) + } + return result; }); }, diff --git a/app/styles/crate.scss b/app/styles/crate.scss index 9a39f5c60e..9ef11fed27 100644 --- a/app/styles/crate.scss +++ b/app/styles/crate.scss @@ -208,6 +208,11 @@ .docs { @include flex(7); padding-right: 40px; + max-width: 600px; + + pre { + overflow-x: scroll; + } } .authorship { @include flex(3); diff --git a/app/templates/crate/version.hbs b/app/templates/crate/version.hbs index 9cc4528b7f..db08bf118c 100644 --- a/app/templates/crate/version.hbs +++ b/app/templates/crate/version.hbs @@ -85,6 +85,11 @@ {{/if}} + {{#if crate.readme}} +
+ {{{crate.readme}}} +
+ {{/if}}
From c938b0f2d5a912636c6c54a4c2fc0834dc0f3cfe Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 12:51:02 +0200 Subject: [PATCH 04/35] Don't upload rendered README to S3 if crate has no README file --- src/krate.rs | 8 +++- src/render.rs | 5 +-- src/uploaders.rs | 112 +++++++++++++++++++++++++++-------------------- 3 files changed, 72 insertions(+), 53 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 2d6c806baf..ee77322dc5 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -1191,12 +1191,16 @@ pub fn new(req: &mut Request) -> CargoResult { let max_version = krate.max_version(&conn)?; // Render the README for this crate - let readme = render::markdown_to_html(new_crate.readme.as_ref().map(|s| &**s))?; + let readme = match new_crate.readme.as_ref() { + Some(readme) => Some(render::markdown_to_html(&**readme)?), + None => None, + }; // Upload the crate, return way to delete the crate from the server // If the git commands fail below, we shouldn't keep the crate on the // server. - let (cksum, mut crate_bomb, mut readme_bomb) = app.config.uploader.upload(req, &krate, readme, max, vers)?; + let (cksum, mut crate_bomb, mut readme_bomb) = + app.config.uploader.upload(req, &krate, readme, max, vers)?; // Register this crate in our local git repo. let git_crate = git::Crate { diff --git a/src/render.rs b/src/render.rs index ab86034e88..d782d2dafc 100644 --- a/src/render.rs +++ b/src/render.rs @@ -3,10 +3,9 @@ use pulldown_cmark::html; use util::CargoResult; -pub fn markdown_to_html(raw: Option<&str>) -> CargoResult { - let text = raw.unwrap_or(""); +pub fn markdown_to_html(text: &str) -> CargoResult { let mut rendered = String::with_capacity(text.len() * 3 / 2); - let parser = Parser::new(&text); + let parser = Parser::new(text); html::push_html(&mut rendered, parser); Ok(rendered) } diff --git a/src/uploaders.rs b/src/uploaders.rs index 40718d1c0e..4421f15515 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -86,14 +86,15 @@ impl Uploader { &self, req: &mut Request, krate: &Crate, - readme: String, + readme: Option, max: u64, vers: &semver::Version, ) -> CargoResult<(Vec, Bomb, Bomb)> { match *self { Uploader::S3 { ref bucket, .. } => { let mut handle = req.app().handle(); - let crate_path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); + let crate_path = + format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); let (response, cksum) = { let length = read_le_u32(req.body())?; let body = LimitErrorReader::new(req.body(), max); @@ -126,41 +127,51 @@ impl Uploader { response ))); } - - let mut handle = req.app().handle(); - let readme_path = format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string())); - let response = { - let mut response = Vec::new(); - { - let readme_len = readme.len(); - let mut cursor = io::Cursor::new(readme.into_bytes()); - let mut s3req = bucket.put( - &mut handle, - &readme_path, - &mut cursor, - "text/html", - readme_len as u64, - ); - s3req.write_function(|data| { - response.extend(data); - Ok(data.len()) - }).unwrap(); - s3req.perform().chain_error(|| { - internal(&format_args!("failed to upload readme to S3: `{}`", readme_path)) - })?; + let readme_path = if let Some(rendered) = readme { + let mut handle = req.app().handle(); + let readme_path = + format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string())); + let response = { + let mut response = Vec::new(); + { + let readme_len = rendered.len(); + let mut cursor = io::Cursor::new(rendered.into_bytes()); + let mut s3req = bucket.put( + &mut handle, + &readme_path, + &mut cursor, + "text/html", + readme_len as u64, + ); + s3req + .write_function(|data| { + response.extend(data); + Ok(data.len()) + }) + .unwrap(); + s3req.perform().chain_error(|| { + internal(&format_args!( + "failed to upload readme to S3: `{}`", + readme_path + )) + })?; + } + response + }; + if handle.response_code().unwrap() != 200 { + if let Err(e) = self.delete(req.app().clone(), &crate_path) { + println!("failed to delete crate from S3: `{}`, {:?}", crate_path, e); + } + let response = String::from_utf8_lossy(&response); + return Err(internal(&format_args!( + "failed to get a 200 response from S3: {}", + response + ))); } - response + Some(readme_path) + } else { + None }; - if handle.response_code().unwrap() != 200 { - if let Err(e) = self.delete(req.app().clone(), &crate_path) { - println!("failed to delete crate from S3: `{}`, {:?}", crate_path, e); - } - let response = String::from_utf8_lossy(&response); - return Err(internal(&format_args!( - "failed to get a 200 response from S3: {}", - response - ))); - } Ok(( cksum, @@ -170,7 +181,7 @@ impl Uploader { }, Bomb { app: req.app().clone(), - path: Some(readme_path), + path: readme_path, }, )) } @@ -198,18 +209,23 @@ impl Uploader { body.finalize() }; - let readme_path = Uploader::readme_path(&krate.name, &vers.to_string()); - let readme_filename = env::current_dir() - .unwrap() - .join("dist") - .join("local_uploads") - .join(readme_path); + let readme_filename = if let Some(rendered) = readme { + let readme_path = Uploader::readme_path(&krate.name, &vers.to_string()); + let readme_filename = env::current_dir() + .unwrap() + .join("dist") + .join("local_uploads") + .join(readme_path); - let readme_dir = readme_filename.parent().unwrap(); - fs::create_dir_all(readme_dir)?; + let readme_dir = readme_filename.parent().unwrap(); + fs::create_dir_all(readme_dir)?; - let mut readme_file = File::create(&readme_filename)?; - readme_file.write_all(readme.as_ref())?; + let mut readme_file = File::create(&readme_filename)?; + readme_file.write_all(rendered.as_ref())?; + readme_filename.to_str().map(String::from) + } else { + None + }; Ok(( cksum, @@ -219,7 +235,7 @@ impl Uploader { }, Bomb { app: req.app().clone(), - path: readme_filename.to_str().map(String::from), + path: readme_filename, }, )) } @@ -232,7 +248,7 @@ impl Uploader { }, Bomb { app: req.app().clone(), - path: None + path: None, }, )) } From 501cef8ad839238f70ca22b45cd9674589158022 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 12:55:32 +0200 Subject: [PATCH 05/35] Fix ESLint complains & add proper error handling if no readme --- app/routes/crate/version.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/routes/crate/version.js b/app/routes/crate/version.js index 6003a6c8cc..393e1a9d3f 100644 --- a/app/routes/crate/version.js +++ b/app/routes/crate/version.js @@ -114,9 +114,9 @@ export default Route.extend({ .then((r) => { crate.set('readme', r.payload); }) - .catch((r) => { - console.error(r); - }) + .catch(() => { + crate.set('readme', null); + }); } return result; }); From 827ff653e3783dedd19cdfac972cbb656e08b94d Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 20:28:53 +0200 Subject: [PATCH 06/35] Sanitize rendered html with ammonia --- Cargo.lock | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 1 + src/render.rs | 7 ++- 4 files changed, 167 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 2604a88d59..c9e4b53fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,17 @@ dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ammonia" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maplit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "antidote" version = "1.0.0" @@ -102,6 +113,7 @@ dependencies = [ name = "cargo-registry" version = "0.1.0" dependencies = [ + "ammonia 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cargo-registry-s3 0.1.0", "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -397,6 +409,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "debug_unreachable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "derive-error-chain" version = "0.10.1" @@ -523,6 +543,15 @@ name = "foreign-types" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.51" @@ -565,6 +594,18 @@ dependencies = [ "generic-array 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "html5ever" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.1.2" @@ -664,6 +705,29 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "maplit" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "markup5ever" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "matches" version = "0.1.6" @@ -794,6 +858,24 @@ dependencies = [ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "phf_codegen" +version = "0.7.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_generator" +version = "0.7.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "phf_shared" version = "0.7.21" @@ -866,6 +948,11 @@ dependencies = [ "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "precomputed-hash" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pulldown-cmark" version = "0.0.15" @@ -1081,6 +1168,36 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "string_cache" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "string_cache_codegen" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "string_cache_shared" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stringprep" version = "0.1.0" @@ -1108,6 +1225,16 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tendril" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf-8 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread-id" version = "2.0.0" @@ -1184,6 +1311,14 @@ name = "unicode-xid" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unreachable" version = "1.0.0" @@ -1202,6 +1337,14 @@ dependencies = [ "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "utf-8" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "0.1.3" @@ -1244,6 +1387,7 @@ dependencies = [ [metadata] "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" +"checksum ammonia 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84d348f2d98bb52f7e8d896c3ce5b6bbf66a040dd334c9cfe1503b6d8e7d15e" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" "checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76" "checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff" @@ -1280,6 +1424,7 @@ dependencies = [ "checksum curl 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6689276ab61f97c660669a5ecc117c36875dfc1ba301c986b16c653415bdf9d7" "checksum curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d5481162dc4f424d088581db2f979fa7d4c238fe9794595de61d8d7522e277de" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" "checksum derive-error-chain 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9ca9ade651388daad7c993f005d0d20c4f6fe78c1cdc93e95f161c6f5ede4a" "checksum diesel 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7302a01c06bd94e619661c44528375a068e34717608d0d1c93bf75428da142a" "checksum diesel_codegen 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "044abc50a0ee67e195b0ae95c9ffe6903748434294636dd67808301b7df1902f" @@ -1296,11 +1441,13 @@ dependencies = [ "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" +"checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3" "checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" "checksum generic-array 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "330920f60726e8a1ca0129a40f0f0df0b8ee773945bf34895d578f35f31dc660" "checksum git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa01936ac96555c083c0e8553f672616274408d9d3fc5b8696603fbf63ff43ee" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hmac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb5aa9647ba4711e9d6968dc1c810cd23989ed435443ca962e1bf6d8b8b83ff" +"checksum html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a49d5001dd1bddf042ea41ed4e0a671d50b1bf187e66b349d7ec613bdce4ad90" "checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37" "checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be" "checksum itertools 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "772a0928a97246167d59a2a4729df5871f1327ab8b36fd24c4224b229cb47b99" @@ -1313,6 +1460,9 @@ dependencies = [ "checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8" "checksum license-exprs 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20e170a9f8785c9bb07576397a605ac453332e833a5eb5686cd4dcbb39cc1a66" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +"checksum maplit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "be384c560e0c3ad868b590ffb88d2c0a1effde6f59885234e4ea811c1202bfea" +"checksum markup5ever 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5050cc22c1d567a9b99bcbe9ffbd8f3127b3d146994105480240dc8ba4f4f2ef" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum md5 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "11f2f3240857d306c26118e2e92a5eaf8990df379e3d96573ee6c92cdbf58a81" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" @@ -1330,6 +1480,8 @@ dependencies = [ "checksum openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "236c718c2e2c2b58a546d86ffea5194400bb15dbe01ca85325ffd357b03cf66c" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" +"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" +"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum postgres 0.14.2 (git+https://github.com/sfackler/rust-postgres.git)" = "" @@ -1337,6 +1489,7 @@ dependencies = [ "checksum postgres-protocol 0.3.0 (git+https://github.com/sfackler/rust-postgres.git)" = "" "checksum postgres-shared 0.3.0 (git+https://github.com/sfackler/rust-postgres.git)" = "" "checksum pq-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfb5e575ef93a1b7b2a381d47ba7c5d4e4f73bff37cee932195de769aad9a54" +"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150" "checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" @@ -1365,9 +1518,13 @@ dependencies = [ "checksum sha2 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84920f9ac881e94e33ec89e1b3dcd36040523a308a92548e01217ce35d8cf6a8" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum socket2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12cdbddbaa27bf94cc194b8e37f5811db6fe83cea96cf99cf1f8e92b65a41371" +"checksum string_cache 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2fa69b90c5398217fb0414706d1becea9325ad21ed5d87bd6dda82127911f324" +"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7" +"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" "checksum stringprep 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c5ff9d098c000a75bb827d6d0d7c45082dfa0372467d29237f9590a3f87867d0" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1b72f8e2f5b73b65c315b1a70c730f24b9d7a25f39e98de8acbe2bb795caea" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" @@ -1378,8 +1535,10 @@ dependencies = [ "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" +"checksum utf-8 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6f923c601c7ac48ef1d66f7d5b5b2d9a7ba9c51333ab75a3ddf8d0309185a56" "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" diff --git a/Cargo.toml b/Cargo.toml index ae2e02d80b..353cdfa39f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ serde = "1.0.0" clippy = { version = "=0.0.142", optional = true } chrono = "0.4.0" pulldown-cmark = { version = "0.0.15", default-features = false } +ammonia = "0.5.0" conduit = "0.8" conduit-conditional-get = "0.8" diff --git a/src/lib.rs b/src/lib.rs index 6548df70fd..5c3e4f09ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ extern crate log; extern crate serde_json; #[macro_use] extern crate serde_derive; +extern crate ammonia; extern crate chrono; extern crate curl; extern crate diesel_full_text_search; diff --git a/src/render.rs b/src/render.rs index d782d2dafc..51bb21ed7c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,3 +1,4 @@ +use ammonia::Ammonia; use pulldown_cmark::Parser; use pulldown_cmark::html; @@ -5,7 +6,11 @@ use util::CargoResult; pub fn markdown_to_html(text: &str) -> CargoResult { let mut rendered = String::with_capacity(text.len() * 3 / 2); + let cleaner = Ammonia { + keep_cleaned_elements: true, + ..Ammonia::default() + }; let parser = Parser::new(text); html::push_html(&mut rendered, parser); - Ok(rendered) + Ok(cleaner.clean(&rendered)) } From 59e92adf288c604d69eab4a67cdc9d83aa0efd9d Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 22:38:39 +0200 Subject: [PATCH 07/35] Styling issues --- app/styles/crate.scss | 7 +++---- app/templates/crate/version.hbs | 6 ------ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/app/styles/crate.scss b/app/styles/crate.scss index 9ef11fed27..efd1e75c87 100644 --- a/app/styles/crate.scss +++ b/app/styles/crate.scss @@ -209,10 +209,6 @@ @include flex(7); padding-right: 40px; max-width: 600px; - - pre { - overflow-x: scroll; - } } .authorship { @include flex(3); @@ -307,6 +303,9 @@ color: red; } } + .docs pre { + overflow-x: scroll; + } .last-update { color: $main-color-light; font-size: 90%; diff --git a/app/templates/crate/version.hbs b/app/templates/crate/version.hbs index db08bf118c..bf7904c7e2 100644 --- a/app/templates/crate/version.hbs +++ b/app/templates/crate/version.hbs @@ -57,12 +57,6 @@ {{else}}
- {{#if crate.description}} -
-

About This Package

-

{{ crate.description }}

-
- {{/if}}
Cargo.toml
{{ crate.name }} = "{{ currentVersion.num }}" From 14e6b3e2c6ed232b08572ae9b1a74113f8dc80f6 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 9 Jul 2017 22:40:18 +0200 Subject: [PATCH 08/35] Minimal documentation --- app/routes/crate/version.js | 2 ++ src/render.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/routes/crate/version.js b/app/routes/crate/version.js index 393e1a9d3f..e6c2f18985 100644 --- a/app/routes/crate/version.js +++ b/app/routes/crate/version.js @@ -108,6 +108,8 @@ export default Route.extend({ method: 'GET', dataType: 'html', headers: { + // We need to force the Accept header, otherwise crates.io won't return + // the readme file when not using S3. Accept: '*/*', }, })) diff --git a/src/render.rs b/src/render.rs index 51bb21ed7c..10f5a953bd 100644 --- a/src/render.rs +++ b/src/render.rs @@ -4,6 +4,8 @@ use pulldown_cmark::html; use util::CargoResult; +/// Renders a markdown text to sanitized HTML. The returned text should not contain any harmful +/// HTML tag or attribute (such as iframe, onclick, onmouseover, etc.). pub fn markdown_to_html(text: &str) -> CargoResult { let mut rendered = String::with_capacity(text.len() * 3 / 2); let cleaner = Ammonia { From 61f6431dac6c296edc1f07467d132bfd8c7c9abc Mon Sep 17 00:00:00 2001 From: Louis Person Date: Mon, 10 Jul 2017 00:16:23 +0200 Subject: [PATCH 09/35] Test readme upload --- .../http-data/krate_new_krate_with_readme | 42 +++++++++++++++++++ src/tests/krate.rs | 13 ++++++ 2 files changed, 55 insertions(+) create mode 100644 src/tests/http-data/krate_new_krate_with_readme diff --git a/src/tests/http-data/krate_new_krate_with_readme b/src/tests/http-data/krate_new_krate_with_readme new file mode 100644 index 0000000000..75f1ae26ff --- /dev/null +++ b/src/tests/http-data/krate_new_krate_with_readme @@ -0,0 +1,42 @@ +===REQUEST 345 +PUT http://alexcrichton-test.s3.amazonaws.com/crates/foo_readme/foo_readme-1.0.0.crate HTTP/1.1 +Accept: */* +Proxy-Connection: Keep-Alive +Authorization: AWS AKIAJF3GEK7N44BACDZA:GDxGb6r3SIqo9wXuzHrgMNWekwk= +Content-Length: 0 +Host: alexcrichton-test.s3.amazonaws.com +Content-Type: application/x-tar +Date: Sun, 28 Jun 2015 14:07:17 -0700 + + +===RESPONSE 258 +HTTP/1.1 200 +x-amz-request-id: CB0E925D8E3AB3E8 +x-amz-id-2: SiaMwszM1p2TzXlLauvZ6kRKcUCg7HoyBW29vts42w9ArrLwkJWl8vuvPuGFkpM6XGH+YXN852g= +date: Sun, 28 Jun 2015 21:07:51 GMT +etag: "d41d8cd98f00b204e9800998ecf8427e" +content-length: 0 +server: AmazonS3 + + +===REQUEST 337 +PUT http://alexcrichton-test.s3.amazonaws.com/readmes/foo_readme/foo_readme-1.0.0.html HTTP/1.1 +Accept: */* +Proxy-Connection: Keep-Alive +Authorization: AWS AKIAJF3GEK7N44BACDZA:GDxGb6r3SIqo9wXuzHrgMNWekwk= +Content-Length: 0 +Host: alexcrichton-test.s3.amazonaws.com +Content-Type: text/html +Date: Sun, 28 Jun 2015 14:07:17 -0700 + + +===RESPONSE 258 +HTTP/1.1 200 +x-amz-request-id: CB0E925D8E3AB3E8 +x-amz-id-2: SiaMwszM1p2TzXlLauvZ6kRKcUCg7HoyBW29vts42w9ArrLwkJWl8vuvPuGFkpM6XGH+YXN852g= +date: Sun, 28 Jun 2015 21:07:51 GMT +etag: "d41d8cd98f00b204e9800998ecf8427e" +content-length: 0 +server: AmazonS3 + + diff --git a/src/tests/krate.rs b/src/tests/krate.rs index d36fd42887..6df10f8e66 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -1000,6 +1000,19 @@ fn new_krate_dependency_missing() { )); } +#[test] +fn new_krate_with_readme() { + let (_b, app, middle) = ::app(); + let mut krate = ::krate("foo_readme"); + krate.readme = Some("".to_owned()); + let mut req = ::new_req_full(app.clone(), krate, "1.0.0", vec![]); + ::sign_in(&mut req, &app); + let mut response = ok_resp!(middle.call(&mut req)); + let json: GoodCrate = ::json(&mut response); + assert_eq!(json.krate.name, "foo_readme"); + assert_eq!(json.krate.max_version, "1.0.0"); +} + #[test] fn summary_doesnt_die() { let (_b, app, middle) = ::app(); From e56b118b57a5e25cbc148362bc870656467723bb Mon Sep 17 00:00:00 2001 From: Louis Person Date: Mon, 10 Jul 2017 02:22:08 +0200 Subject: [PATCH 10/35] Add tests for the new render module --- src/tests/all.rs | 1 + src/tests/render.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/tests/render.rs diff --git a/src/tests/all.rs b/src/tests/all.rs index d53a1379e1..2a72a00922 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -92,6 +92,7 @@ mod git; mod keyword; mod krate; mod record; +mod render; mod schema_details; mod team; mod token; diff --git a/src/tests/render.rs b/src/tests/render.rs new file mode 100644 index 0000000000..4b313177e0 --- /dev/null +++ b/src/tests/render.rs @@ -0,0 +1,57 @@ +use cargo_registry::render; + +#[test] +fn empty_text() { + let text = ""; + let result = render::markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered, ""); +} + +#[test] +fn text_with_script_tag() { + let text = "foo_readme\n\n"; + let result = render::markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("script"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); +} + +#[test] +fn text_with_iframe_tag() { + let text = "foo_readme\n\n"; + let result = render::markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("iframe"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); +} + +#[test] +fn text_with_unknwon_tag() { + let text = "foo_readme\n\nalert('Hello World')"; + let result = render::markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("unknown"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); +} + +#[test] +fn text_with_inline_javascript() { + let text = r#"foo_readme\n\nCrate page"#; + let result = render::markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains(" Date: Fri, 14 Jul 2017 16:55:01 +0200 Subject: [PATCH 11/35] Extracted file upload into its own method upload is now named upload_crate, and the new upload method is now only responsible for the upload of a single file. --- src/krate.rs | 9 +- src/uploaders.rs | 212 +++++++++++++++++------------------------------ 2 files changed, 81 insertions(+), 140 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index ee77322dc5..0c271253f8 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -1199,8 +1199,13 @@ pub fn new(req: &mut Request) -> CargoResult { // Upload the crate, return way to delete the crate from the server // If the git commands fail below, we shouldn't keep the crate on the // server. - let (cksum, mut crate_bomb, mut readme_bomb) = - app.config.uploader.upload(req, &krate, readme, max, vers)?; + let (cksum, mut crate_bomb, mut readme_bomb) = app.config.uploader.upload_crate( + req, + &krate, + readme, + max, + vers, + )?; // Register this crate in our local git repo. let git_crate = git::Crate { diff --git a/src/uploaders.rs b/src/uploaders.rs index 4421f15515..2cac2ba147 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -82,32 +82,26 @@ impl Uploader { format!("readmes/{}/{}-{}.html", name, name, version) } + /// Uploads a file using the configured uploader (either S3, Local or NoOp). + /// It returns a a tuple containing the path of the uploaded file + /// and its checksum. pub fn upload( &self, - req: &mut Request, - krate: &Crate, - readme: Option, - max: u64, - vers: &semver::Version, - ) -> CargoResult<(Vec, Bomb, Bomb)> { + app: Arc, + path: &str, + body: &mut io::Read, + content_type: &str, + content_length: u64, + ) -> CargoResult<(Option, Vec)> { match *self { Uploader::S3 { ref bucket, .. } => { - let mut handle = req.app().handle(); - let crate_path = - format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); + let mut handle = app.handle(); let (response, cksum) = { - let length = read_le_u32(req.body())?; - let body = LimitErrorReader::new(req.body(), max); let mut body = HashingReader::new(body); let mut response = Vec::new(); { - let mut s3req = bucket.put( - &mut handle, - &crate_path, - &mut body, - "application/x-tar", - length as u64, - ); + let mut s3req = + bucket.put(&mut handle, &path, &mut body, content_type, content_length); s3req .write_function(|data| { response.extend(data); @@ -115,7 +109,7 @@ impl Uploader { }) .unwrap(); s3req.perform().chain_error(|| { - internal(&format_args!("failed to upload to S3: `{}`", crate_path)) + internal(&format_args!("failed to upload to S3: `{}`", path)) })?; } (response, body.finalize()) @@ -127,134 +121,76 @@ impl Uploader { response ))); } - let readme_path = if let Some(rendered) = readme { - let mut handle = req.app().handle(); - let readme_path = - format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string())); - let response = { - let mut response = Vec::new(); - { - let readme_len = rendered.len(); - let mut cursor = io::Cursor::new(rendered.into_bytes()); - let mut s3req = bucket.put( - &mut handle, - &readme_path, - &mut cursor, - "text/html", - readme_len as u64, - ); - s3req - .write_function(|data| { - response.extend(data); - Ok(data.len()) - }) - .unwrap(); - s3req.perform().chain_error(|| { - internal(&format_args!( - "failed to upload readme to S3: `{}`", - readme_path - )) - })?; - } - response - }; - if handle.response_code().unwrap() != 200 { - if let Err(e) = self.delete(req.app().clone(), &crate_path) { - println!("failed to delete crate from S3: `{}`, {:?}", crate_path, e); - } - let response = String::from_utf8_lossy(&response); - return Err(internal(&format_args!( - "failed to get a 200 response from S3: {}", - response - ))); - } - Some(readme_path) - } else { - None - }; - - Ok(( - cksum, - Bomb { - app: req.app().clone(), - path: Some(crate_path), - }, - Bomb { - app: req.app().clone(), - path: readme_path, - }, - )) + Ok((Some(String::from(path)), cksum)) } Uploader::Local => { - use std::io::Write; - - let crate_path = Uploader::crate_path(&krate.name, &vers.to_string()); - let crate_filename = env::current_dir() + let filename = env::current_dir() .unwrap() .join("dist") .join("local_uploads") - .join(crate_path); - - let crate_dir = crate_filename.parent().unwrap(); - fs::create_dir_all(crate_dir)?; - - let mut crate_file = File::create(&crate_filename)?; - - let cksum = { - read_le_u32(req.body())?; - let body = LimitErrorReader::new(req.body(), max); - let mut body = HashingReader::new(body); - - io::copy(&mut body, &mut crate_file)?; - body.finalize() - }; - - let readme_filename = if let Some(rendered) = readme { - let readme_path = Uploader::readme_path(&krate.name, &vers.to_string()); - let readme_filename = env::current_dir() - .unwrap() - .join("dist") - .join("local_uploads") - .join(readme_path); - - let readme_dir = readme_filename.parent().unwrap(); - fs::create_dir_all(readme_dir)?; - - let mut readme_file = File::create(&readme_filename)?; - readme_file.write_all(rendered.as_ref())?; - readme_filename.to_str().map(String::from) - } else { - None - }; - - Ok(( - cksum, - Bomb { - app: req.app().clone(), - path: crate_filename.to_str().map(String::from), - }, - Bomb { - app: req.app().clone(), - path: readme_filename, - }, - )) - } - Uploader::NoOp => { - Ok(( - vec![], - Bomb { - app: req.app().clone(), - path: None, - }, - Bomb { - app: req.app().clone(), - path: None, - }, - )) + .join(path); + let dir = filename.parent().unwrap(); + fs::create_dir_all(dir)?; + let mut file = File::create(&filename)?; + let mut body = HashingReader::new(body); + io::copy(&mut body, &mut file)?; + Ok((filename.to_str().map(String::from), body.finalize())) } + Uploader::NoOp => Ok((None, vec![])), } } + /// Uploads a crate and its readme. Returns the checksum of the uploaded crate + /// file, and bombs for the uploaded crate and the uploaded readme. + pub fn upload_crate( + &self, + req: &mut Request, + krate: &Crate, + readme: Option, + max: u64, + vers: &semver::Version, + ) -> CargoResult<(Vec, Bomb, Bomb)> { + let app = req.app().clone(); + let (crate_path, checksum) = { + let path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); + let length = read_le_u32(req.body())?; + let mut body = LimitErrorReader::new(req.body(), max); + self.upload( + app.clone(), + &path, + &mut body, + "application/x-tar", + length as u64, + )? + }; + let crate_bomb = Bomb { + app: app.clone(), + path: crate_path, + }; + let (readme_path, _) = if let Some(rendered) = readme { + let path = format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string())); + let length = rendered.len(); + let mut body = io::Cursor::new(rendered.into_bytes()); + self.upload( + app.clone(), + &path, + &mut body, + "text/html", + length as u64, + )? + } else { + (None, vec![]) + }; + Ok(( + checksum, + crate_bomb, + Bomb { + app: app.clone(), + path: readme_path, + }, + )) + } + fn delete(&self, app: Arc, path: &str) -> CargoResult<()> { match *self { Uploader::S3 { ref bucket, .. } => { From 756505e602820c284ecfaf07ebcb5059f4aa1821 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sat, 15 Jul 2017 01:13:08 +0200 Subject: [PATCH 12/35] Add a render-readmes script This script renders the README of every published crate and uploads it to S3. --- Cargo.lock | 66 +++++--- Cargo.toml | 1 + src/bin/render-readmes.rs | 330 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 375 insertions(+), 22 deletions(-) create mode 100644 src/bin/render-readmes.rs diff --git a/Cargo.lock b/Cargo.lock index c9e4b53fe3..059bfe126b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,15 +143,17 @@ dependencies = [ "oauth2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "postgres 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2-diesel 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_postgres 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -159,11 +161,11 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -202,7 +204,7 @@ name = "clippy" version = "0.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cargo_metadata 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.142 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -217,8 +219,8 @@ dependencies = [ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -608,7 +610,7 @@ dependencies = [ [[package]] name = "idna" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1009,7 +1011,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1106,12 +1108,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1136,7 +1138,7 @@ dependencies = [ "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1177,7 +1179,7 @@ dependencies = [ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1225,6 +1227,16 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tar" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tendril" version = "0.3.1" @@ -1268,7 +1280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1277,7 +1289,7 @@ name = "toml" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1332,7 +1344,7 @@ name = "url" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1384,6 +1396,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xattr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" @@ -1398,7 +1418,7 @@ dependencies = [ "checksum byte-tools 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0919189ba800c7ffe8778278116b7e0de3905ab81c72abb69c85cbfef7991279" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24f16593f445422331a5eed46b72f7f171f910fead4f2ea8f17e727e9c5c14" -"checksum cargo_metadata 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d84cb53c78e573aa126a4b9f963fdb2629f8183b26e235da08bb36dc7381162" +"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum civet 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6263e7af767a5bf9e4d3d0a6c3ceb5f3940ec85cf2fbfee59024b8a264be180f" @@ -1448,7 +1468,7 @@ dependencies = [ "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hmac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb5aa9647ba4711e9d6968dc1c810cd23989ed435443ca962e1bf6d8b8b83ff" "checksum html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a49d5001dd1bddf042ea41ed4e0a671d50b1bf187e66b349d7ec613bdce4ad90" -"checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37" +"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be" "checksum itertools 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "772a0928a97246167d59a2a4729df5871f1327ab8b36fd24c4224b229cb47b99" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" @@ -1497,7 +1517,7 @@ dependencies = [ "checksum r2d2-diesel 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ca2d40462e2ddaf9d448f1aa0251ac37310ff0adf6da2eba36a49dd7fd6f034" "checksum r2d2_postgres 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00aae18ea6279c73dea01c5816fcd7ee1d0369e957f9445aebcbcb2927dd2b5c" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum redox_syscall 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "9aa093607d28cfd65f317edeeefb6749be428eacc8decd1c5f8c0fbcc327aff5" +"checksum redox_syscall 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "9df6a71a1e67be2104410736b2389fb8e383c1d7e9e792d629ff13c02867147a" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" @@ -1511,8 +1531,8 @@ dependencies = [ "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver-parser 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fff3c9c5a54636ab95acd8c1349926e04cb1eb8cd70b5adced8a1d1f703a67" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a" -"checksum serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639" +"checksum serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "433d7d9f8530d5a939ad5e0e72a6243d2e42a24804f70bf592c679363dcacb2f" +"checksum serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7b707cf0d4cab852084f573058def08879bb467fda89d99052485e7d00edd624" "checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b" "checksum sha2 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84920f9ac881e94e33ec89e1b3dcd36040523a308a92548e01217ce35d8cf6a8" @@ -1524,6 +1544,7 @@ dependencies = [ "checksum stringprep 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c5ff9d098c000a75bb827d6d0d7c45082dfa0372467d29237f9590a3f87867d0" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b" "checksum tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1b72f8e2f5b73b65c315b1a70c730f24b9d7a25f39e98de8acbe2bb795caea" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" @@ -1546,3 +1567,4 @@ dependencies = [ "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" diff --git a/Cargo.toml b/Cargo.toml index 353cdfa39f..fdeadb5913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ git2 = "0.6.4" flate2 = "0.2" semver = "0.5" url = "1.2.1" +tar = "0.4.13" postgres = { version = "0.14.0", features = ["with-time", "with-openssl", "with-serde_json", "with-chrono"] } r2d2 = "0.7.0" diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs new file mode 100644 index 0000000000..1ab0bb4c7d --- /dev/null +++ b/src/bin/render-readmes.rs @@ -0,0 +1,330 @@ +// Iterates over every crate versions ever uploaded and (re-)renders their +// readme using the Markdown renderer from the cargo_registry crate. +// +// Warning: this can take a lot of time. +// +// Usage: +// cargo run --bin render-readmes [page-size: optional = 25] +// The page-size argument dictate how much versions should be queried and processed at once. + +#![deny(warnings)] + +#[macro_use] +extern crate serde_derive; + +extern crate cargo_registry; +extern crate curl; +extern crate diesel; +extern crate flate2; +extern crate postgres; +extern crate s3; +extern crate tar; +extern crate time; +extern crate toml; +extern crate url; + +use curl::easy::List; +use diesel::prelude::*; +use flate2::read::GzDecoder; +use std::env; +use std::io::{Cursor, Read}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::thread; +use tar::Archive; +use url::Url; + +use cargo_registry::{App, env, Env, Replica, Uploader, Version}; +use cargo_registry::version::EncodableVersion; +use cargo_registry::schema::*; +use cargo_registry::render::markdown_to_html; + +const DEFAULT_PAGE_SIZE: i64 = 25; + +fn main() { + let app = make_app(); + let conn = app.diesel_database.get().unwrap(); + let versions_count = versions::table + .select(versions::all_columns) + .count() + .get_result::(&*conn) + .expect("error counting versions"); + let page_size = match env::args().nth(1) { + None => DEFAULT_PAGE_SIZE, + Some(s) => s.parse::().unwrap_or(DEFAULT_PAGE_SIZE), + }; + let pages = if versions_count % page_size == 0 { + versions_count / page_size + } else { + versions_count / page_size + 1 + }; + for current_page in 0..pages { + let versions: Vec = versions::table + .inner_join(crates::table) + .select((versions::all_columns, crates::name)) + .limit(page_size) + .offset(current_page * page_size) + .load::<(Version, String)>(&*conn) + .expect("error loading versions") + .into_iter() + .map(|(version, crate_name)| version.encodable(&crate_name)) + .collect(); + let mut tasks = Vec::with_capacity(page_size as usize); + for version in versions { + let app = app.clone(); + let handle = thread::spawn(move || { + println!("[{}-{}] Rendering README...", version.krate, version.num); + let readme = get_readme(app.clone(), &version); + if readme.is_none() { + return; + } + let readme = readme.unwrap(); + let readme_path = format!( + "readmes/{}/{}-{}.html", + version.krate, + version.krate, + version.num + ); + let readme_len = readme.len(); + let mut body = Cursor::new(readme.into_bytes()); + app.config + .uploader + .upload( + app.clone(), + &readme_path, + &mut body, + "text/html", + readme_len as u64, + ) + .expect(&format!( + "[{}-{}] Couldn't upload file to S3", + version.krate, + version.num + )); + }); + tasks.push(handle); + } + for handle in tasks { + if let Err(err) = handle.join() { + println!("Thead panicked: {:?}", err); + } + } + } +} + +/// Renders the readme of an uploaded crate version. +fn get_readme(app: Arc, version: &EncodableVersion) -> Option { + let mut handle = app.handle(); + let location = match app.config.uploader.crate_location( + &version.krate, + &version.num, + ) { + Some(l) => l, + None => return None, + }; + let date = time::now().rfc822z().to_string(); + let url = Url::parse(&location).expect(&format!( + "[{}-{}] Couldn't parse crate URL", + version.krate, + version.num + )); + + let mut headers = List::new(); + headers + .append(&format!("Host: {}", url.host().unwrap())) + .unwrap(); + headers.append(&format!("Date: {}", date)).unwrap(); + + handle.url(url.as_str()).unwrap(); + handle.get(true).unwrap(); + handle.http_headers(headers).unwrap(); + + let mut response = Vec::new(); + { + let mut req = handle.transfer(); + req.write_function(|data| { + response.extend(data); + Ok(data.len()) + }).unwrap(); + if let Err(err) = req.perform() { + println!( + "[{}-{}] Unable to fetch crate: {}", + version.krate, + version.num, + err + ); + return None; + } + } + if handle.response_code().unwrap() != 200 { + let response = String::from_utf8_lossy(&response); + println!( + "[{}-{}] Failed to get a 200 response: {}", + version.krate, + version.num, + response + ); + return None; + } + let reader = Cursor::new(response); + let reader = GzDecoder::new(reader).expect(&format!( + "[{}-{}] Invalid gzip header", + version.krate, + version.num + )); + let mut archive = Archive::new(reader); + let mut entries = archive.entries().expect(&format!( + "[{}-{}] Invalid tar archive entries", + version.krate, + version.num + )); + let manifest: Manifest = { + let path = format!("{}-{}/Cargo.toml", version.krate, version.num); + let contents = find_file_by_path(&mut entries, Path::new(&path), &version).unwrap(); + toml::from_str(&contents).expect(&format!( + "[{}-{}] Syntax error in manifest file", + version.krate, + version.num + )) + }; + if manifest.package.readme.is_none() { + return None; + } + let rendered = { + let path = format!( + "{}-{}/{}", + version.krate, + version.num, + manifest.package.readme.unwrap() + ); + let contents = find_file_by_path(&mut entries, Path::new(&path), &version).unwrap(); + markdown_to_html(&contents).expect(&format!( + "[{}-{}] Couldn't render README", + version.krate, + version.num + )) + }; + return Some(rendered); + #[derive(Deserialize)] + struct Package { + readme: Option, + } + #[derive(Deserialize)] + struct Manifest { + package: Package, + } +} + +/// Search an entry by its path in a Tar archive. +fn find_file_by_path( + mut entries: &mut tar::Entries, + path: &Path, + version: &EncodableVersion, +) -> Option { + let mut file = entries + .find(|entry| match *entry { + Err(_) => false, + Ok(ref file) => { + let filepath = match file.path() { + Ok(p) => p, + Err(_) => return false, + }; + return filepath == path; + } + }) + .expect(&format!( + "[{}-{}] file is not present: {}", + version.krate, + version.num, + path.display() + )); + match file { + Err(_) => None, + Ok(ref mut f) => { + let mut contents = String::new(); + f.read_to_string(&mut contents).expect(&format!( + "[{}-{}] Couldn't read file contents", + version.krate, + version.num + )); + return Some(contents); + } + } +} + +/// Creates and Arc over an App instance. +fn make_app() -> Arc { + let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT")); + let api_protocol = String::from("https"); + let mirror = if env::var("MIRROR").is_ok() { + Replica::ReadOnlyMirror + } else { + Replica::Primary + }; + let heroku = env::var("HEROKU").is_ok(); + let cargo_env = if heroku { + Env::Production + } else { + Env::Development + }; + let uploader = match (cargo_env, mirror) { + (Env::Production, Replica::Primary) => { + // `env` panics if these vars are not set + Uploader::S3 { + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env("S3_ACCESS_KEY"), + env("S3_SECRET_KEY"), + &api_protocol, + ), + proxy: None, + } + } + (Env::Production, Replica::ReadOnlyMirror) => { + // Read-only mirrors don't need access key or secret key, + // but they might have them. Definitely need bucket though. + Uploader::S3 { + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env::var("S3_ACCESS_KEY").unwrap_or(String::new()), + env::var("S3_SECRET_KEY").unwrap_or(String::new()), + &api_protocol, + ), + proxy: None, + } + } + _ => { + if env::var("S3_BUCKET").is_ok() { + println!("Using S3 uploader"); + Uploader::S3 { + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env::var("S3_ACCESS_KEY").unwrap_or(String::new()), + env::var("S3_SECRET_KEY").unwrap_or(String::new()), + &api_protocol, + ), + proxy: None, + } + } else { + println!("Using local uploader, crate files will be in the dist directory"); + Uploader::Local + } + } + }; + let config = cargo_registry::Config { + uploader: uploader, + session_key: env("SESSION_KEY"), + git_repo_checkout: checkout, + gh_client_id: env("GH_CLIENT_ID"), + gh_client_secret: env("GH_CLIENT_SECRET"), + db_url: env("DATABASE_URL"), + env: cargo_env, + max_upload_size: 10 * 1024 * 1024, + mirror: mirror, + api_protocol: api_protocol, + }; + Arc::new(cargo_registry::App::new(&config)) +} From 425439e0149fa640740be560a4c50e5a31af5c91 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sat, 15 Jul 2017 01:44:40 +0200 Subject: [PATCH 13/35] Remove needless borrow --- src/uploaders.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uploaders.rs b/src/uploaders.rs index 2cac2ba147..603ea34f1c 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -101,7 +101,7 @@ impl Uploader { let mut response = Vec::new(); { let mut s3req = - bucket.put(&mut handle, &path, &mut body, content_type, content_length); + bucket.put(&mut handle, path, &mut body, content_type, content_length); s3req .write_function(|data| { response.extend(data); From 8e2729756b2ded61fded1b05b515747d0bf9d8df Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sat, 15 Jul 2017 19:51:12 +0200 Subject: [PATCH 14/35] Add syntax highlighting to markdown rendering The feature tries to work as much as possible like GitHub's rendering. Syntax highlighting is done with Sublime syntax files using syntect. Also made some changes to the config used with the HTML sanitizer to be more flexible with the allowed tags & attributes. --- Cargo.lock | 133 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 1 + src/render.rs | 174 +++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 300 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 059bfe126b..4442dd52e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,26 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bincode" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "0.9.1" @@ -153,6 +173,7 @@ dependencies = [ "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syntect 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -174,6 +195,15 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "chrono" version = "0.4.0" @@ -540,6 +570,11 @@ dependencies = [ "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fnv" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "foreign-types" version = "0.2.0" @@ -820,6 +855,27 @@ name = "odds" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "onig" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", + "onig_sys 64.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "onig_sys" +version = "64.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "openssl" version = "0.9.14" @@ -891,6 +947,18 @@ name = "pkg-config" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "plist" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "postgres" version = "0.14.2" @@ -1068,6 +1136,15 @@ name = "safemem" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scheduled-thread-pool" version = "0.1.0" @@ -1227,6 +1304,26 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syntect" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "onig 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "plist 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tar" version = "0.4.13" @@ -1377,6 +1474,16 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -1404,6 +1511,19 @@ dependencies = [ "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xml-rs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "yaml-rust" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" @@ -1413,6 +1533,9 @@ dependencies = [ "checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff" "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" "checksum byte-tools 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0919189ba800c7ffe8778278116b7e0de3905ab81c72abb69c85cbfef7991279" @@ -1420,6 +1543,7 @@ dependencies = [ "checksum bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24f16593f445422331a5eed46b72f7f171f910fead4f2ea8f17e727e9c5c14" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "158b0bd7d75cbb6bf9c25967a48a2e9f77da95876b858eadfabaa99cd069de6e" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum civet 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6263e7af767a5bf9e4d3d0a6c3ceb5f3940ec85cf2fbfee59024b8a264be180f" "checksum civet-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "958d15372bf28b7983cb35e1d4bf36dd843b0d42e507c1c73aad7150372c5936" @@ -1460,6 +1584,7 @@ dependencies = [ "checksum fallible-iterator 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5d48ab1bc11a086628e8cc0cc2c2dc200b884ac05c4b48fb71d6036b6999ff1d" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" +"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" "checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3" "checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" @@ -1495,6 +1620,8 @@ dependencies = [ "checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6" "checksum oauth2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fcd990d45681b9eba5f4f3fa7d0371ec277f4e4380a94104d26aa4fae386fc" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" +"checksum onig 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0da8cd0eff000f68698dd3f773a0e580a68aa1959e999eed5eec53e23ded89d7" +"checksum onig_sys 64.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4401b2ffbef83c7f16578d477689c2b9ab114204651da4efcb626efe603ca9f4" "checksum openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11ba043cb65fc9af71a431b8a36ffe8686cd4751cdf70a473ec1d01066ac7e41" "checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf" "checksum openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "236c718c2e2c2b58a546d86ffea5194400bb15dbe01ca85325ffd357b03cf66c" @@ -1504,6 +1631,7 @@ dependencies = [ "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum plist 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e2f7e9574aabcf57bc5e9f602caabdffffa8179b0c130a039f7895fea3dbdb5" "checksum postgres 0.14.2 (git+https://github.com/sfackler/rust-postgres.git)" = "" "checksum postgres 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b51f9f4b74a0d3a475fe272f5acc72761d750fd67af90cd2241bce49639ca395" "checksum postgres-protocol 0.3.0 (git+https://github.com/sfackler/rust-postgres.git)" = "" @@ -1526,6 +1654,7 @@ dependencies = [ "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d9fbe48ead32343b76f544c85953bf260ed39219a8bbbb62cd85f6a00f9644f" "checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" @@ -1544,6 +1673,7 @@ dependencies = [ "checksum stringprep 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c5ff9d098c000a75bb827d6d0d7c45082dfa0372467d29237f9590a3f87867d0" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum syntect 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06aec79102600f6f53dbe3a9e294cb356783cfe0476628efaf0d34f3298c07d8" "checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b" "checksum tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1b72f8e2f5b73b65c315b1a70c730f24b9d7a25f39e98de8acbe2bb795caea" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" @@ -1564,7 +1694,10 @@ dependencies = [ "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" +"checksum xml-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b46ee689ba7a669c08a1170c2348d2516c62dc461135c9e86b2f1f476e07be4a" +"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/Cargo.toml b/Cargo.toml index fdeadb5913..270d1fd7dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ clippy = { version = "=0.0.142", optional = true } chrono = "0.4.0" pulldown-cmark = { version = "0.0.15", default-features = false } ammonia = "0.5.0" +syntect = "1.7.1" conduit = "0.8" conduit-conditional-get = "0.8" diff --git a/src/lib.rs b/src/lib.rs index 5c3e4f09ec..b59b2cc3b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ extern crate rand; extern crate s3; extern crate semver; extern crate serde; +extern crate syntect; extern crate time; extern crate toml; extern crate url; diff --git a/src/render.rs b/src/render.rs index 10f5a953bd..8dd20b7804 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,18 +1,174 @@ use ammonia::Ammonia; -use pulldown_cmark::Parser; +use pulldown_cmark::{Event, Parser, Tag}; use pulldown_cmark::html; +use std::borrow::Cow; +use syntect::easy::HighlightLines; +use syntect::highlighting::{Color, ThemeSet}; +use syntect::html::{IncludeBackground, styles_to_coloured_html}; +use syntect::parsing::SyntaxSet; use util::CargoResult; +/// Context for markdown to HTML rendering. +pub struct MarkdownRenderer<'a> { + html_sanitizer: Ammonia<'a>, + syntax_set: SyntaxSet, + theme_set: ThemeSet, +} + +impl<'a> MarkdownRenderer<'a> { + /// Creates a new renderer instance. + pub fn new() -> MarkdownRenderer<'a> { + let tags = [ + "a", + "b", + "blockquote", + "br", + "code", + "dd", + "del", + "dl", + "dt", + "em", + "i", + "h1", + "h2", + "h3", + "hr", + "img", + "kbd", + "li", + "ol", + "p", + "pre", + "s", + "strike", + "strong", + "sub", + "sup", + "table", + "tbody", + "td", + "th", + "thead", + "tr", + "ul", + "hr", + "span", + ].iter() + .cloned() + .collect(); + let tag_attributes = [ + ("a", ["href", "target"].iter().cloned().collect()), + ( + "img", + ["width", "height", "src", "alt", "align", "width"] + .iter() + .cloned() + .collect(), + ), + ("pre", ["style"].iter().cloned().collect()), + ("span", ["style"].iter().cloned().collect()), + ].iter() + .cloned() + .collect(); + let html_sanitizer = Ammonia { + keep_cleaned_elements: true, + tags: tags, + tag_attributes: tag_attributes, + ..Ammonia::default() + }; + MarkdownRenderer { + html_sanitizer: html_sanitizer, + syntax_set: SyntaxSet::load_defaults_newlines(), + theme_set: ThemeSet::load_defaults(), + } + } + + /// Renders the given markdown to HTML using the current settings. + pub fn to_html(&self, text: &str) -> CargoResult { + let mut rendered = String::with_capacity(text.len() * 3 / 2); + let mut codeblock = false; + let mut sample = String::new(); + let parser = Parser::new(text).map(|event| match event.clone() { + Event::Start(tag) => { + match tag { + Tag::CodeBlock(_) => { + codeblock = true; + Event::Text(Cow::Borrowed("")) + } + _ => event, + } + } + Event::End(tag) => { + match tag { + Tag::CodeBlock(s) => { + let snippet = self.highlight(&s, &sample); + codeblock = false; + sample.clear(); + Event::Html(Cow::Owned(snippet)) + } + _ => event, + } + } + Event::Text(t) => { + if codeblock { + sample.push_str(&t); + Event::Text(Cow::Borrowed("")) + } else { + event + } + } + _ => event, + }); + html::push_html(&mut rendered, parser); + Ok(self.html_sanitizer.clean(&rendered)) + } + + /// Highlights to given code sample, using the syntax_hint parameter in order to choose the + /// syntax it will use. Defaults to plain text. + fn highlight(&self, syntax_hint: &str, sample: &str) -> String { + use std::fmt::Write; + + let theme = &self.theme_set.themes["InspiredGitHub"]; + let syntax = self.syntax_set + .find_syntax_by_token(syntax_hint) + .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()); + let mut output = String::new(); + let mut highlighter = HighlightLines::new(syntax, theme); + let c = Color { + r: 249, + g: 247, + b: 236, + a: 255, + }; + write!( + output, + "
\n",
+            c.r,
+            c.g,
+            c.b
+        ).unwrap();
+        for line in sample.lines() {
+            let regions = highlighter.highlight(line);
+            let html = styles_to_coloured_html(®ions[..], IncludeBackground::No);
+            output.push_str(&html);
+            output.push('\n');
+        }
+        output.push_str("
\n"); + output + } +} + +impl<'a> Default for MarkdownRenderer<'a> { + fn default() -> Self { + Self::new() + } +} + /// Renders a markdown text to sanitized HTML. The returned text should not contain any harmful /// HTML tag or attribute (such as iframe, onclick, onmouseover, etc.). pub fn markdown_to_html(text: &str) -> CargoResult { - let mut rendered = String::with_capacity(text.len() * 3 / 2); - let cleaner = Ammonia { - keep_cleaned_elements: true, - ..Ammonia::default() - }; - let parser = Parser::new(text); - html::push_html(&mut rendered, parser); - Ok(cleaner.clean(&rendered)) + let renderer = MarkdownRenderer::new(); + renderer.to_html(text) } From 40b1d0dfdc118dfa3afcfd7d2c2d4f8264b7de94 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Wed, 26 Jul 2017 13:24:10 +0200 Subject: [PATCH 15/35] Remove syntax highlighting from the render module --- Cargo.lock | 134 -------------------------------------------------- Cargo.toml | 1 - src/lib.rs | 1 - src/render.rs | 83 ++----------------------------- 4 files changed, 3 insertions(+), 216 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4442dd52e9..b858587fb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,26 +80,6 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bincode" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "0.9.1" @@ -166,14 +146,12 @@ dependencies = [ "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2-diesel 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_postgres 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syntect 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -195,15 +173,6 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "chrono" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "chrono" version = "0.4.0" @@ -570,11 +539,6 @@ dependencies = [ "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fnv" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "foreign-types" version = "0.2.0" @@ -855,27 +819,6 @@ name = "odds" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "onig" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", - "onig_sys 64.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "onig_sys" -version = "64.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "openssl" version = "0.9.14" @@ -947,18 +890,6 @@ name = "pkg-config" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "plist" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "postgres" version = "0.14.2" @@ -1136,15 +1067,6 @@ name = "safemem" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "same-file" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "scheduled-thread-pool" version = "0.1.0" @@ -1304,26 +1226,6 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntect" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "onig 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "plist 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tar" version = "0.4.13" @@ -1474,16 +1376,6 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "walkdir" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" version = "0.2.8" @@ -1511,19 +1403,6 @@ dependencies = [ "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "xml-rs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "yaml-rust" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" @@ -1533,9 +1412,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff" "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" "checksum byte-tools 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0919189ba800c7ffe8778278116b7e0de3905ab81c72abb69c85cbfef7991279" @@ -1543,7 +1419,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24f16593f445422331a5eed46b72f7f171f910fead4f2ea8f17e727e9c5c14" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "158b0bd7d75cbb6bf9c25967a48a2e9f77da95876b858eadfabaa99cd069de6e" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum civet 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6263e7af767a5bf9e4d3d0a6c3ceb5f3940ec85cf2fbfee59024b8a264be180f" "checksum civet-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "958d15372bf28b7983cb35e1d4bf36dd843b0d42e507c1c73aad7150372c5936" @@ -1584,7 +1459,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fallible-iterator 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5d48ab1bc11a086628e8cc0cc2c2dc200b884ac05c4b48fb71d6036b6999ff1d" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" -"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" "checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3" "checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" @@ -1620,8 +1494,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6" "checksum oauth2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fcd990d45681b9eba5f4f3fa7d0371ec277f4e4380a94104d26aa4fae386fc" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" -"checksum onig 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0da8cd0eff000f68698dd3f773a0e580a68aa1959e999eed5eec53e23ded89d7" -"checksum onig_sys 64.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4401b2ffbef83c7f16578d477689c2b9ab114204651da4efcb626efe603ca9f4" "checksum openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11ba043cb65fc9af71a431b8a36ffe8686cd4751cdf70a473ec1d01066ac7e41" "checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf" "checksum openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "236c718c2e2c2b58a546d86ffea5194400bb15dbe01ca85325ffd357b03cf66c" @@ -1631,7 +1503,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" -"checksum plist 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e2f7e9574aabcf57bc5e9f602caabdffffa8179b0c130a039f7895fea3dbdb5" "checksum postgres 0.14.2 (git+https://github.com/sfackler/rust-postgres.git)" = "" "checksum postgres 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b51f9f4b74a0d3a475fe272f5acc72761d750fd67af90cd2241bce49639ca395" "checksum postgres-protocol 0.3.0 (git+https://github.com/sfackler/rust-postgres.git)" = "" @@ -1654,7 +1525,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d9fbe48ead32343b76f544c85953bf260ed39219a8bbbb62cd85f6a00f9644f" "checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" @@ -1673,7 +1543,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stringprep 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c5ff9d098c000a75bb827d6d0d7c45082dfa0372467d29237f9590a3f87867d0" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum syntect 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06aec79102600f6f53dbe3a9e294cb356783cfe0476628efaf0d34f3298c07d8" "checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b" "checksum tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1b72f8e2f5b73b65c315b1a70c730f24b9d7a25f39e98de8acbe2bb795caea" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" @@ -1694,10 +1563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" -"checksum xml-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b46ee689ba7a669c08a1170c2348d2516c62dc461135c9e86b2f1f476e07be4a" -"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/Cargo.toml b/Cargo.toml index 270d1fd7dd..fdeadb5913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ clippy = { version = "=0.0.142", optional = true } chrono = "0.4.0" pulldown-cmark = { version = "0.0.15", default-features = false } ammonia = "0.5.0" -syntect = "1.7.1" conduit = "0.8" conduit-conditional-get = "0.8" diff --git a/src/lib.rs b/src/lib.rs index b59b2cc3b2..5c3e4f09ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,6 @@ extern crate rand; extern crate s3; extern crate semver; extern crate serde; -extern crate syntect; extern crate time; extern crate toml; extern crate url; diff --git a/src/render.rs b/src/render.rs index 8dd20b7804..5625ca9f99 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,19 +1,12 @@ use ammonia::Ammonia; -use pulldown_cmark::{Event, Parser, Tag}; +use pulldown_cmark::Parser; use pulldown_cmark::html; -use std::borrow::Cow; -use syntect::easy::HighlightLines; -use syntect::highlighting::{Color, ThemeSet}; -use syntect::html::{IncludeBackground, styles_to_coloured_html}; -use syntect::parsing::SyntaxSet; use util::CargoResult; /// Context for markdown to HTML rendering. pub struct MarkdownRenderer<'a> { html_sanitizer: Ammonia<'a>, - syntax_set: SyntaxSet, - theme_set: ThemeSet, } impl<'a> MarkdownRenderer<'a> { @@ -78,86 +71,16 @@ impl<'a> MarkdownRenderer<'a> { tag_attributes: tag_attributes, ..Ammonia::default() }; - MarkdownRenderer { - html_sanitizer: html_sanitizer, - syntax_set: SyntaxSet::load_defaults_newlines(), - theme_set: ThemeSet::load_defaults(), - } + MarkdownRenderer { html_sanitizer: html_sanitizer } } /// Renders the given markdown to HTML using the current settings. pub fn to_html(&self, text: &str) -> CargoResult { let mut rendered = String::with_capacity(text.len() * 3 / 2); - let mut codeblock = false; - let mut sample = String::new(); - let parser = Parser::new(text).map(|event| match event.clone() { - Event::Start(tag) => { - match tag { - Tag::CodeBlock(_) => { - codeblock = true; - Event::Text(Cow::Borrowed("")) - } - _ => event, - } - } - Event::End(tag) => { - match tag { - Tag::CodeBlock(s) => { - let snippet = self.highlight(&s, &sample); - codeblock = false; - sample.clear(); - Event::Html(Cow::Owned(snippet)) - } - _ => event, - } - } - Event::Text(t) => { - if codeblock { - sample.push_str(&t); - Event::Text(Cow::Borrowed("")) - } else { - event - } - } - _ => event, - }); + let parser = Parser::new(text); html::push_html(&mut rendered, parser); Ok(self.html_sanitizer.clean(&rendered)) } - - /// Highlights to given code sample, using the syntax_hint parameter in order to choose the - /// syntax it will use. Defaults to plain text. - fn highlight(&self, syntax_hint: &str, sample: &str) -> String { - use std::fmt::Write; - - let theme = &self.theme_set.themes["InspiredGitHub"]; - let syntax = self.syntax_set - .find_syntax_by_token(syntax_hint) - .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()); - let mut output = String::new(); - let mut highlighter = HighlightLines::new(syntax, theme); - let c = Color { - r: 249, - g: 247, - b: 236, - a: 255, - }; - write!( - output, - "
\n",
-            c.r,
-            c.g,
-            c.b
-        ).unwrap();
-        for line in sample.lines() {
-            let regions = highlighter.highlight(line);
-            let html = styles_to_coloured_html(®ions[..], IncludeBackground::No);
-            output.push_str(&html);
-            output.push('\n');
-        }
-        output.push_str("
\n"); - output - } } impl<'a> Default for MarkdownRenderer<'a> { From 08f62a75ae64e51c74877a798df629373d63c1a4 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Wed, 26 Jul 2017 15:08:49 +0200 Subject: [PATCH 16/35] Factor out config initialization into a Default implementation --- src/bin/render-readmes.rs | 84 ++----------------------------- src/bin/server.rs | 96 +++++------------------------------ src/config.rs | 102 +++++++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 164 deletions(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index 1ab0bb4c7d..2e495648dc 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -28,13 +28,13 @@ use diesel::prelude::*; use flate2::read::GzDecoder; use std::env; use std::io::{Cursor, Read}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::sync::Arc; use std::thread; use tar::Archive; use url::Url; -use cargo_registry::{App, env, Env, Replica, Uploader, Version}; +use cargo_registry::{App, Config, Version}; use cargo_registry::version::EncodableVersion; use cargo_registry::schema::*; use cargo_registry::render::markdown_to_html; @@ -42,7 +42,8 @@ use cargo_registry::render::markdown_to_html; const DEFAULT_PAGE_SIZE: i64 = 25; fn main() { - let app = make_app(); + let config: Config = Default::default(); + let app = Arc::new(App::new(&config)); let conn = app.diesel_database.get().unwrap(); let versions_count = versions::table .select(versions::all_columns) @@ -251,80 +252,3 @@ fn find_file_by_path( } } } - -/// Creates and Arc over an App instance. -fn make_app() -> Arc { - let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT")); - let api_protocol = String::from("https"); - let mirror = if env::var("MIRROR").is_ok() { - Replica::ReadOnlyMirror - } else { - Replica::Primary - }; - let heroku = env::var("HEROKU").is_ok(); - let cargo_env = if heroku { - Env::Production - } else { - Env::Development - }; - let uploader = match (cargo_env, mirror) { - (Env::Production, Replica::Primary) => { - // `env` panics if these vars are not set - Uploader::S3 { - bucket: s3::Bucket::new( - env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env("S3_ACCESS_KEY"), - env("S3_SECRET_KEY"), - &api_protocol, - ), - proxy: None, - } - } - (Env::Production, Replica::ReadOnlyMirror) => { - // Read-only mirrors don't need access key or secret key, - // but they might have them. Definitely need bucket though. - Uploader::S3 { - bucket: s3::Bucket::new( - env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), - &api_protocol, - ), - proxy: None, - } - } - _ => { - if env::var("S3_BUCKET").is_ok() { - println!("Using S3 uploader"); - Uploader::S3 { - bucket: s3::Bucket::new( - env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), - &api_protocol, - ), - proxy: None, - } - } else { - println!("Using local uploader, crate files will be in the dist directory"); - Uploader::Local - } - } - }; - let config = cargo_registry::Config { - uploader: uploader, - session_key: env("SESSION_KEY"), - git_repo_checkout: checkout, - gh_client_id: env("GH_CLIENT_ID"), - gh_client_secret: env("GH_CLIENT_SECRET"), - db_url: env("DATABASE_URL"), - env: cargo_env, - max_upload_size: 10 * 1024 * 1024, - mirror: mirror, - api_protocol: api_protocol, - }; - Arc::new(cargo_registry::App::new(&config)) -} diff --git a/src/bin/server.rs b/src/bin/server.rs index 8cf6099e56..1dc0a4489f 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -7,32 +7,31 @@ extern crate git2; extern crate env_logger; extern crate s3; -use cargo_registry::{env, Env, Uploader, Replica}; +use cargo_registry::{env, Env}; use civet::Server; use std::env; use std::fs::{self, File}; -use std::path::PathBuf; use std::sync::Arc; use std::sync::mpsc::channel; #[allow(dead_code)] fn main() { env_logger::init().unwrap(); - let url = env("GIT_REPO_URL"); - let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT")); + let config: cargo_registry::Config = Default::default(); - let repo = match git2::Repository::open(&checkout) { + let url = env("GIT_REPO_URL"); + let repo = match git2::Repository::open(&config.git_repo_checkout) { Ok(r) => r, Err(..) => { - let _ = fs::remove_dir_all(&checkout); - fs::create_dir_all(&checkout).unwrap(); + let _ = fs::remove_dir_all(&config.git_repo_checkout); + fs::create_dir_all(&config.git_repo_checkout).unwrap(); let mut cb = git2::RemoteCallbacks::new(); cb.credentials(cargo_registry::git::credentials); let mut opts = git2::FetchOptions::new(); opts.remote_callbacks(cb); git2::build::RepoBuilder::new() .fetch_options(opts) - .clone(&url, &checkout) + .clone(&url, &config.git_repo_checkout) .unwrap() } }; @@ -40,85 +39,12 @@ fn main() { cfg.set_str("user.name", "bors").unwrap(); cfg.set_str("user.email", "bors@rust-lang.org").unwrap(); - let api_protocol = String::from("https"); - let mirror = if env::var("MIRROR").is_ok() { - Replica::ReadOnlyMirror - } else { - Replica::Primary - }; - - let heroku = env::var("HEROKU").is_ok(); - let cargo_env = if heroku { - Env::Production - } else { - Env::Development - }; - - let uploader = match (cargo_env, mirror) { - (Env::Production, Replica::Primary) => { - // `env` panics if these vars are not set - Uploader::S3 { - bucket: s3::Bucket::new( - env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env("S3_ACCESS_KEY"), - env("S3_SECRET_KEY"), - &api_protocol, - ), - proxy: None, - } - } - (Env::Production, Replica::ReadOnlyMirror) => { - // Read-only mirrors don't need access key or secret key, - // but they might have them. Definitely need bucket though. - Uploader::S3 { - bucket: s3::Bucket::new( - env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), - &api_protocol, - ), - proxy: None, - } - } - _ => { - if env::var("S3_BUCKET").is_ok() { - println!("Using S3 uploader"); - Uploader::S3 { - bucket: s3::Bucket::new( - env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), - &api_protocol, - ), - proxy: None, - } - } else { - println!("Using local uploader, crate files will be in the dist directory"); - Uploader::Local - } - } - }; - - let config = cargo_registry::Config { - uploader: uploader, - session_key: env("SESSION_KEY"), - git_repo_checkout: checkout, - gh_client_id: env("GH_CLIENT_ID"), - gh_client_secret: env("GH_CLIENT_SECRET"), - db_url: env("DATABASE_URL"), - env: cargo_env, - max_upload_size: 10 * 1024 * 1024, - mirror: mirror, - api_protocol: api_protocol, - }; let app = cargo_registry::App::new(&config); let app = cargo_registry::middleware(Arc::new(app)); cargo_registry::categories::sync().unwrap(); + let heroku = env::var("HEROKU").is_ok(); let port = if heroku { 8888 } else { @@ -127,7 +53,11 @@ fn main() { .and_then(|s| s.parse().ok()) .unwrap_or(8888) }; - let threads = if cargo_env == Env::Development { 1 } else { 50 }; + let threads = if config.env == Env::Development { + 1 + } else { + 50 + }; let mut cfg = civet::Config::new(); cfg.port(port).threads(threads).keep_alive(true); let _a = Server::start(cfg, app); diff --git a/src/config.rs b/src/config.rs index 30890add68..8df2655fbd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,9 @@ +use s3; + +use std::env; use std::path::PathBuf; -use {Uploader, Replica}; + +use {Env, env, Uploader, Replica}; #[derive(Clone, Debug)] pub struct Config { @@ -14,3 +18,99 @@ pub struct Config { pub mirror: Replica, pub api_protocol: String, } + +impl Default for Config { + /// Returns a default value for the application's config + /// + /// Sets the following default values: + /// - `Config::max_upload_size`: 10MiB + /// - `Config::api_protocol`: `https` + /// + /// Pulls values from the following environment variables: + /// - `GIT_REPO_CHECKOUT`: The directory where the registry index was cloned. + /// - `MIRROR`: Is this instance of cargo_registry a mirror of crates.io. + /// - `HEROKU`: Is this instance of cargo_registry currently running on Heroku. + /// - `S3_BUCKET`: The S3 bucket used to store crate files. If not present during development, + /// cargo_registry will fall back to a local uploader. + /// - `S3_REGION`: The region in which the bucket was created. Optional if US standard. + /// - `S3_ACCESS_KEY`: The access key to interact with S3. Optional if running a mirror. + /// - `S3_SECRET_KEY`: The secret key to interact with S3. Optional if running a mirror. + /// - `SESSION_KEY`: The key used to sign and encrypt session cookies. + /// - `GH_CLIENT_ID`: The client ID of the associated GitHub application. + /// - `GH_CLIENT_SECRET`: The client secret of the associated GitHub application. + /// - `DATABASE_URL`: The URL of the postgres database to use. + fn default() -> Config { + let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT")); + let api_protocol = String::from("https"); + let mirror = if env::var("MIRROR").is_ok() { + Replica::ReadOnlyMirror + } else { + Replica::Primary + }; + let heroku = env::var("HEROKU").is_ok(); + let cargo_env = if heroku { + Env::Production + } else { + Env::Development + }; + let uploader = match (cargo_env, mirror) { + (Env::Production, Replica::Primary) => { + // `env` panics if these vars are not set + Uploader::S3 { + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env("S3_ACCESS_KEY"), + env("S3_SECRET_KEY"), + &api_protocol, + ), + proxy: None, + } + } + (Env::Production, Replica::ReadOnlyMirror) => { + // Read-only mirrors don't need access key or secret key, + // but they might have them. Definitely need bucket though. + Uploader::S3 { + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env::var("S3_ACCESS_KEY").unwrap_or(String::new()), + env::var("S3_SECRET_KEY").unwrap_or(String::new()), + &api_protocol, + ), + proxy: None, + } + } + _ => { + if env::var("S3_BUCKET").is_ok() { + println!("Using S3 uploader"); + Uploader::S3 { + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env::var("S3_ACCESS_KEY").unwrap_or(String::new()), + env::var("S3_SECRET_KEY").unwrap_or(String::new()), + &api_protocol, + ), + proxy: None, + } + } else { + println!("Using local uploader, crate files will be in the dist directory"); + Uploader::Local + } + } + }; + Config { + uploader: uploader, + session_key: env("SESSION_KEY"), + git_repo_checkout: checkout, + gh_client_id: env("GH_CLIENT_ID"), + gh_client_secret: env("GH_CLIENT_SECRET"), + db_url: env("DATABASE_URL"), + env: cargo_env, + max_upload_size: 10 * 1024 * 1024, + mirror: mirror, + api_protocol: api_protocol, + } + } +} From 738be0ac34af070af3e6d64776ed86aa8b87be75 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Wed, 26 Jul 2017 15:10:00 +0200 Subject: [PATCH 17/35] Documentation comments in the uploaders and render modules --- src/render.rs | 15 +++++++++++++-- src/uploaders.rs | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/render.rs b/src/render.rs index 5625ca9f99..d57a9c7885 100644 --- a/src/render.rs +++ b/src/render.rs @@ -89,8 +89,19 @@ impl<'a> Default for MarkdownRenderer<'a> { } } -/// Renders a markdown text to sanitized HTML. The returned text should not contain any harmful -/// HTML tag or attribute (such as iframe, onclick, onmouseover, etc.). +/// Renders a markdown text to sanitized HTML. +/// +/// The returned text should not contain any harmful HTML tag or attribute (such as iframe, +/// onclick, onmouseover, etc.). +/// +/// # Examples +/// +/// ``` +/// use render::markdown_to_html; +/// +/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!"; +/// let rendered = markdown_to_html(text)?; +/// ``` pub fn markdown_to_html(text: &str) -> CargoResult { let renderer = MarkdownRenderer::new(); renderer.to_html(text) diff --git a/src/uploaders.rs b/src/uploaders.rs index 603ea34f1c..da197ebca1 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -35,6 +35,10 @@ impl Uploader { } } + /// Returns the URL of an uploaded crate's version archive. + /// + /// The function doesn't check for the existence of the file. + /// It returns `None` if the current `Uploader` is `NoOp`. pub fn crate_location(&self, crate_name: &str, version: &str) -> Option { match *self { Uploader::S3 { ref bucket, .. } => { @@ -54,6 +58,10 @@ impl Uploader { } } + /// Returns the URL of an uploaded crate's version readme. + /// + /// The function doesn't check for the existence of the file. + /// It returns `None` if the current `Uploader` is `NoOp`. pub fn readme_location(&self, crate_name: &str, version: &str) -> Option { match *self { Uploader::S3 { ref bucket, .. } => { @@ -73,16 +81,19 @@ impl Uploader { } } + /// Returns the interna path of an uploaded crate's version archive. fn crate_path(name: &str, version: &str) -> String { // No slash in front so we can use join format!("crates/{}/{}-{}.crate", name, name, version) } + /// Returns the interna path of an uploaded crate's version readme. fn readme_path(name: &str, version: &str) -> String { format!("readmes/{}/{}-{}.html", name, name, version) } - /// Uploads a file using the configured uploader (either S3, Local or NoOp). + /// Uploads a file using the configured uploader (either `S3`, `Local` or `NoOp`). + /// /// It returns a a tuple containing the path of the uploaded file /// and its checksum. pub fn upload( @@ -163,6 +174,8 @@ impl Uploader { length as u64, )? }; + // We create the bomb for the crate file before uploading the readme so that if the + // readme upload fails, the uploaded crate file is automatically deleted. let crate_bomb = Bomb { app: app.clone(), path: crate_path, @@ -191,6 +204,7 @@ impl Uploader { )) } + /// Deletes an uploaded file. fn delete(&self, app: Arc, path: &str) -> CargoResult<()> { match *self { Uploader::S3 { ref bucket, .. } => { From 27c6c4208614a578534a64fb203c8a540649b083 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Wed, 26 Jul 2017 15:25:03 +0200 Subject: [PATCH 18/35] Move render unit tests out of the integration tests module --- src/render.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ src/tests/all.rs | 1 - src/tests/render.rs | 57 ----------------------------------------- 3 files changed, 62 insertions(+), 58 deletions(-) delete mode 100644 src/tests/render.rs diff --git a/src/render.rs b/src/render.rs index d57a9c7885..ab462e3128 100644 --- a/src/render.rs +++ b/src/render.rs @@ -106,3 +106,65 @@ pub fn markdown_to_html(text: &str) -> CargoResult { let renderer = MarkdownRenderer::new(); renderer.to_html(text) } + +#[cfg(test)] +mod tests { +use super::*; + +#[test] +fn empty_text() { + let text = ""; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered, ""); +} + +#[test] +fn text_with_script_tag() { + let text = "foo_readme\n\n"; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("script"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); +} + +#[test] +fn text_with_iframe_tag() { + let text = "foo_readme\n\n"; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("iframe"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); +} + +#[test] +fn text_with_unknwon_tag() { + let text = "foo_readme\n\nalert('Hello World')"; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("unknown"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); +} + +#[test] +fn text_with_inline_javascript() { + let text = r#"foo_readme\n\nCrate page"#; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("Crate page"#; - let result = render::markdown_to_html(text); - assert_eq!(result.is_ok(), true); - let rendered = result.unwrap(); - assert_eq!(rendered.contains("foo_readme"), true); - assert_eq!(rendered.contains(" Date: Wed, 26 Jul 2017 15:45:02 +0200 Subject: [PATCH 19/35] Replace unwrap_or by unwrap_or_default Reported by clippy --- src/config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 8df2655fbd..29816f1718 100644 --- a/src/config.rs +++ b/src/config.rs @@ -74,8 +74,8 @@ impl Default for Config { bucket: s3::Bucket::new( env("S3_BUCKET"), env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), + env::var("S3_ACCESS_KEY").unwrap_or_default(), + env::var("S3_SECRET_KEY").unwrap_or_default(), &api_protocol, ), proxy: None, @@ -88,8 +88,8 @@ impl Default for Config { bucket: s3::Bucket::new( env("S3_BUCKET"), env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), + env::var("S3_ACCESS_KEY").unwrap_or_default(), + env::var("S3_SECRET_KEY").unwrap_or_default(), &api_protocol, ), proxy: None, From 88990e7a4153d0677d9afd7715d8fc9fba72696a Mon Sep 17 00:00:00 2001 From: Louis Person Date: Thu, 27 Jul 2017 13:03:00 +0200 Subject: [PATCH 20/35] Remove leading slash in the path of the uploaded file --- src/uploaders.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uploaders.rs b/src/uploaders.rs index da197ebca1..58430506c4 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -163,7 +163,7 @@ impl Uploader { ) -> CargoResult<(Vec, Bomb, Bomb)> { let app = req.app().clone(); let (crate_path, checksum) = { - let path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string())); + let path = Uploader::crate_path(&krate.name, &vers.to_string()); let length = read_le_u32(req.body())?; let mut body = LimitErrorReader::new(req.body(), max); self.upload( @@ -181,7 +181,7 @@ impl Uploader { path: crate_path, }; let (readme_path, _) = if let Some(rendered) = readme { - let path = format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string())); + let path = Uploader::readme_path(&krate.name, &vers.to_string()); let length = rendered.len(); let mut body = io::Cursor::new(rendered.into_bytes()); self.upload( From 82e4a13b914805bef4c94a18036cc2ca4370211b Mon Sep 17 00:00:00 2001 From: Louis Person Date: Thu, 27 Jul 2017 13:56:27 +0200 Subject: [PATCH 21/35] Tests formatting --- src/render.rs | 105 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/render.rs b/src/render.rs index ab462e3128..aa7e7f0c51 100644 --- a/src/render.rs +++ b/src/render.rs @@ -109,62 +109,61 @@ pub fn markdown_to_html(text: &str) -> CargoResult { #[cfg(test)] mod tests { -use super::*; + use super::*; -#[test] -fn empty_text() { - let text = ""; - let result = markdown_to_html(text); - assert_eq!(result.is_ok(), true); - let rendered = result.unwrap(); - assert_eq!(rendered, ""); -} - -#[test] -fn text_with_script_tag() { - let text = "foo_readme\n\n"; - let result = markdown_to_html(text); - assert_eq!(result.is_ok(), true); - let rendered = result.unwrap(); - assert_eq!(rendered.contains("foo_readme"), true); - assert_eq!(rendered.contains("script"), false); - assert_eq!(rendered.contains("alert('Hello World')"), true); -} + #[test] + fn empty_text() { + let text = ""; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered, ""); + } -#[test] -fn text_with_iframe_tag() { - let text = "foo_readme\n\n"; - let result = markdown_to_html(text); - assert_eq!(result.is_ok(), true); - let rendered = result.unwrap(); - assert_eq!(rendered.contains("foo_readme"), true); - assert_eq!(rendered.contains("iframe"), false); - assert_eq!(rendered.contains("alert('Hello World')"), true); -} + #[test] + fn text_with_script_tag() { + let text = "foo_readme\n\n"; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("script"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); + } -#[test] -fn text_with_unknwon_tag() { - let text = "foo_readme\n\nalert('Hello World')"; - let result = markdown_to_html(text); - assert_eq!(result.is_ok(), true); - let rendered = result.unwrap(); - assert_eq!(rendered.contains("foo_readme"), true); - assert_eq!(rendered.contains("unknown"), false); - assert_eq!(rendered.contains("alert('Hello World')"), true); -} + #[test] + fn text_with_iframe_tag() { + let text = "foo_readme\n\n"; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains("iframe"), false); + assert_eq!(rendered.contains("alert('Hello World')"), true); + } -#[test] -fn text_with_inline_javascript() { - let text = r#"foo_readme\n\nCrate page"#; - let result = markdown_to_html(text); - assert_eq!(result.is_ok(), true); - let rendered = result.unwrap(); - assert_eq!(rendered.contains("foo_readme"), true); - assert_eq!(rendered.contains("Crate page"#; + let result = markdown_to_html(text); + assert_eq!(result.is_ok(), true); + let rendered = result.unwrap(); + assert_eq!(rendered.contains("foo_readme"), true); + assert_eq!(rendered.contains(" Date: Sun, 30 Jul 2017 18:11:08 +0200 Subject: [PATCH 22/35] Syntax highlighting is now done client-side --- app/components/crate-readme.js | 11 + app/styles/crate.scss | 8 +- app/templates/components/crate-readme.hbs | 1 + app/templates/crate/version.hbs | 2 +- ember-cli-build.js | 21 + package-lock.json | 1453 +++++---------------- package.json | 1 + src/render.rs | 2 +- 8 files changed, 348 insertions(+), 1151 deletions(-) create mode 100644 app/components/crate-readme.js create mode 100644 app/templates/components/crate-readme.hbs diff --git a/app/components/crate-readme.js b/app/components/crate-readme.js new file mode 100644 index 0000000000..eb18c70bc3 --- /dev/null +++ b/app/components/crate-readme.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + rendered: '', + didRender() { + this._super(...arguments); + this.$('pre > code').each(function() { + window.Prism.highlightElement(this); + }); + } +}); diff --git a/app/styles/crate.scss b/app/styles/crate.scss index efd1e75c87..b590aef5cf 100644 --- a/app/styles/crate.scss +++ b/app/styles/crate.scss @@ -303,8 +303,12 @@ color: red; } } - .docs pre { - overflow-x: scroll; + .crate-readme { + line-height: 1.5; + + pre { + overflow-x: scroll; + } } .last-update { color: $main-color-light; diff --git a/app/templates/components/crate-readme.hbs b/app/templates/components/crate-readme.hbs new file mode 100644 index 0000000000..624ded4c91 --- /dev/null +++ b/app/templates/components/crate-readme.hbs @@ -0,0 +1 @@ +{{{rendered}}} diff --git a/app/templates/crate/version.hbs b/app/templates/crate/version.hbs index bf7904c7e2..fb9f27064f 100644 --- a/app/templates/crate/version.hbs +++ b/app/templates/crate/version.hbs @@ -81,7 +81,7 @@
{{#if crate.readme}}
- {{{crate.readme}}} + {{crate-readme rendered=crate.readme}}
{{/if}}
diff --git a/ember-cli-build.js b/ember-cli-build.js index 427a8da274..5e987af7ed 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -5,10 +5,31 @@ const EmberApp = require('ember-cli/lib/broccoli/ember-app'); module.exports = function(defaults) { + const highlightedLanguages = [ + 'bash', + 'clike', + 'glsl', + 'go', + 'ini', + 'javascript', + 'json', + 'markup', + 'protobuf', + 'ruby', + 'rust', + 'scss', + 'sql', + 'yaml' + ]; + let app = new EmberApp(defaults, { babel6: { plugins: ['transform-object-rest-spread'], }, + 'ember-prism': { + theme: 'twilight', + components: highlightedLanguages, + } }); // Use `app.import` to add additional libraries to the generated diff --git a/package-lock.json b/package-lock.json index 88024e3203..37c5f7207c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2311,7 +2311,6 @@ "requires": { "anymatch": "1.3.0", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -6372,6 +6371,56 @@ "ember-cli-htmlbars": "2.0.2" } }, + "ember-prism": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ember-prism/-/ember-prism-0.1.0.tgz", + "integrity": "sha1-JWz25nDj/9B4OXa58nSuhLU8ExQ=", + "dev": true, + "requires": { + "ember-cli-babel": "6.6.0", + "ember-cli-htmlbars": "1.3.4", + "ember-cli-node-assets": "0.2.2", + "prismjs": "1.6.0" + }, + "dependencies": { + "ember-cli-htmlbars": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.4.tgz", + "integrity": "sha512-5lycG6z35QHr3WZF1OkVvT+N/GGAVuemtM6m8NUgBWoeA2TqOgPFRcI0eRqoLA0HAfe0R2MReKmMI7y1LEM1+w==", + "dev": true, + "requires": { + "broccoli-persistent-filter": "1.4.2", + "ember-cli-version-checker": "1.3.1", + "hash-for-dep": "1.1.2", + "json-stable-stringify": "1.0.1", + "strip-bom": "2.0.0" + } + }, + "ember-cli-node-assets": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-cli-node-assets/-/ember-cli-node-assets-0.2.2.tgz", + "integrity": "sha1-0tVWJufMZhn4gtf+VXUfkmYCJwg=", + "dev": true, + "requires": { + "broccoli-funnel": "1.2.0", + "broccoli-merge-trees": "1.2.4", + "broccoli-source": "1.1.0", + "debug": "2.6.8", + "lodash": "4.17.4", + "resolve": "1.3.3" + } + }, + "ember-cli-version-checker": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz", + "integrity": "sha1-C8LRNMgwFC2mS/lieg7e0QthrnI=", + "dev": true, + "requires": { + "semver": "5.3.0" + } + } + } + }, "ember-qunit": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/ember-qunit/-/ember-qunit-2.1.4.tgz", @@ -8109,1161 +8158,262 @@ "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", "dev": true, "requires": { - "ansi-regex": "0.2.1" - } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", - "dev": true - } - } - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": "0.6.5" - } - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "1.2.2", - "object-assign": "4.1.1" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "filesize": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz", - "integrity": "sha1-/I+iPdtO+eXgq24eZPZ5okpWdh8=", - "dev": true - }, - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - } - }, - "finalhandler": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz", - "integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=", - "dev": true, - "requires": { - "debug": "2.6.7", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.1", - "statuses": "1.3.1", - "unpipe": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "find-index": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz", - "integrity": "sha1-UwB8ec0wBA1oFteUWOiDfVxXBe8=", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "2.0.0" - } - }, - "findup-sync": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz", - "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=", - "dev": true, - "requires": { - "detect-file": "0.1.0", - "is-glob": "2.0.1", - "micromatch": "2.3.11", - "resolve-dir": "0.1.1" - } - }, - "fireworm": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz", - "integrity": "sha1-zPIPeUHxCIg/zduZOD2+bhhhx1g=", - "dev": true, - "requires": { - "async": "0.2.10", - "is-type": "0.0.1", - "lodash.debounce": "3.1.1", - "lodash.flatten": "3.0.2", - "minimatch": "3.0.4" - }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", - "dev": true - } - } - }, - "flat-cache": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", - "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", - "dev": true, - "requires": { - "circular-json": "0.3.1", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "forwarded": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", - "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=", - "dev": true - }, - "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=", - "dev": true - }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", - "dev": true - }, - "fs-extra": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", - "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "3.0.1", - "universalify": "0.1.0" - }, - "dependencies": { - "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11" - } - } - } - }, - "fs-readdir-recursive": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz", - "integrity": "sha1-MVtPuMHKW4xH3v7zGdBz2tNWgFk=", - "dev": true - }, - "fs-tree-diff": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz", - "integrity": "sha1-NCZldJ6NykBoALZyJoyPUHPz5iM=", - "dev": true, - "requires": { - "heimdalljs-logger": "0.1.9", - "object-assign": "4.1.1", - "path-posix": "1.0.0", - "symlink-or-copy": "1.1.8" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.6.2", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" + "ansi-regex": "0.2.1" } }, - "wide-align": { - "version": "1.1.2", - "bundled": true, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", + "dev": true + } + } + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": "0.6.5" + } + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "2.0.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.2.2", + "object-assign": "4.1.1" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "filesize": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz", + "integrity": "sha1-/I+iPdtO+eXgq24eZPZ5okpWdh8=", + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "finalhandler": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz", + "integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=", + "dev": true, + "requires": { + "debug": "2.6.7", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.1", + "statuses": "1.3.1", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", "dev": true, - "optional": true, "requires": { - "string-width": "1.0.2" + "ms": "2.0.0" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, + } + } + }, + "find-index": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz", + "integrity": "sha1-UwB8ec0wBA1oFteUWOiDfVxXBe8=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "findup-sync": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz", + "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=", + "dev": true, + "requires": { + "detect-file": "0.1.0", + "is-glob": "2.0.1", + "micromatch": "2.3.11", + "resolve-dir": "0.1.1" + } + }, + "fireworm": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz", + "integrity": "sha1-zPIPeUHxCIg/zduZOD2+bhhhx1g=", + "dev": true, + "requires": { + "async": "0.2.10", + "is-type": "0.0.1", + "lodash.debounce": "3.1.1", + "lodash.flatten": "3.0.2", + "minimatch": "3.0.4" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", "dev": true } } }, + "flat-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true, + "requires": { + "circular-json": "0.3.1", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "forwarded": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=", + "dev": true + }, + "fresh": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", + "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=", + "dev": true + }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "dev": true + }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "3.0.1", + "universalify": "0.1.0" + }, + "dependencies": { + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + } + } + }, + "fs-readdir-recursive": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz", + "integrity": "sha1-MVtPuMHKW4xH3v7zGdBz2tNWgFk=", + "dev": true + }, + "fs-tree-diff": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz", + "integrity": "sha1-NCZldJ6NykBoALZyJoyPUHPz5iM=", + "dev": true, + "requires": { + "heimdalljs-logger": "0.1.9", + "object-assign": "4.1.1", + "path-posix": "1.0.0", + "symlink-or-copy": "1.1.8" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -11584,6 +10734,15 @@ "integrity": "sha1-xDjKLKM+OSdnHbSracDlL5NqTw8=", "dev": true }, + "prismjs": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.6.0.tgz", + "integrity": "sha1-EY2V+3pm26InLjQ7NF9SNmWds2U=", + "dev": true, + "requires": { + "clipboard": "1.7.1" + } + }, "private": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", diff --git a/package.json b/package.json index 4090f476cb..8e9a8251a7 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "ember-moment": "^7.3.1", "ember-normalize": "^1.0.0", "ember-page-title": "^3.2.1", + "ember-prism": "^0.1.0", "ember-resolver": "^4.1.0", "ember-router-scroll": "^0.2.0", "ember-source": "~2.13.3", diff --git a/src/render.rs b/src/render.rs index aa7e7f0c51..5f319b8587 100644 --- a/src/render.rs +++ b/src/render.rs @@ -60,7 +60,7 @@ impl<'a> MarkdownRenderer<'a> { .cloned() .collect(), ), - ("pre", ["style"].iter().cloned().collect()), + ("code", ["class"].iter().cloned().collect()), ("span", ["style"].iter().cloned().collect()), ].iter() .cloned() From 143f98737a8570c561a04877a0dfd29fed0a5476 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Sun, 30 Jul 2017 20:09:46 +0200 Subject: [PATCH 23/35] Replace pattern matcing by expect in find_file_by_path --- src/bin/render-readmes.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index 2e495648dc..7719b34504 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -181,7 +181,7 @@ fn get_readme(app: Arc, version: &EncodableVersion) -> Option { )); let manifest: Manifest = { let path = format!("{}-{}/Cargo.toml", version.krate, version.num); - let contents = find_file_by_path(&mut entries, Path::new(&path), &version).unwrap(); + let contents = find_file_by_path(&mut entries, Path::new(&path), &version); toml::from_str(&contents).expect(&format!( "[{}-{}] Syntax error in manifest file", version.krate, @@ -198,7 +198,7 @@ fn get_readme(app: Arc, version: &EncodableVersion) -> Option { version.num, manifest.package.readme.unwrap() ); - let contents = find_file_by_path(&mut entries, Path::new(&path), &version).unwrap(); + let contents = find_file_by_path(&mut entries, Path::new(&path), &version); markdown_to_html(&contents).expect(&format!( "[{}-{}] Couldn't render README", version.krate, @@ -221,7 +221,7 @@ fn find_file_by_path( mut entries: &mut tar::Entries, path: &Path, version: &EncodableVersion, -) -> Option { +) -> String { let mut file = entries .find(|entry| match *entry { Err(_) => false, @@ -233,22 +233,23 @@ fn find_file_by_path( return filepath == path; } }) + .expect(&format!( + "[{}-{}] couldn't open file: {}", + version.krate, + version.num, + path.display() + )) .expect(&format!( "[{}-{}] file is not present: {}", version.krate, version.num, path.display() )); - match file { - Err(_) => None, - Ok(ref mut f) => { - let mut contents = String::new(); - f.read_to_string(&mut contents).expect(&format!( - "[{}-{}] Couldn't read file contents", - version.krate, - version.num - )); - return Some(contents); - } - } + let mut contents = String::new(); + file.read_to_string(&mut contents).expect(&format!( + "[{}-{}] Couldn't read file contents", + version.krate, + version.num + )); + contents } From 067537820729f556c1696433484c930cc4751df0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 4 Aug 2017 22:11:26 -0400 Subject: [PATCH 24/35] Allow a missing debug; the Ammonia type doesn't implement debug --- src/render.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render.rs b/src/render.rs index 5f319b8587..96659be002 100644 --- a/src/render.rs +++ b/src/render.rs @@ -5,6 +5,7 @@ use pulldown_cmark::html; use util::CargoResult; /// Context for markdown to HTML rendering. +#[allow(missing_debug_implementations)] pub struct MarkdownRenderer<'a> { html_sanitizer: Ammonia<'a>, } From 5e0968a607f34bda5486bc3ef2996e2db024dfae Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 9 Aug 2017 18:59:24 -0400 Subject: [PATCH 25/35] Commit package-lock.json changes --- package-lock.json | 900 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 900 insertions(+) diff --git a/package-lock.json b/package-lock.json index 37c5f7207c..f6ccc2e7b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2311,6 +2311,7 @@ "requires": { "anymatch": "1.3.0", "async-each": "1.0.1", + "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -8414,6 +8415,905 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.6.2", + "node-pre-gyp": "0.6.36" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", From c72d11b481040ced01c6e8a0eab70b87d65bb00c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 10 Aug 2017 10:57:05 -0400 Subject: [PATCH 26/35] Switch to sudo: required to get more memory --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 66ee18221f..25a941ad08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -sudo: false +sudo: required dist: trusty branches: From 65c0bd65f565709a4dbf5c0efbd22d5f8ed9d7a4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 13 Aug 2017 15:18:54 -0400 Subject: [PATCH 27/35] Include the s3 URL as a whitelisted value in the CSP headers --- src/http.rs | 97 ++++++++++++++++++++++++++++++++++------------------- src/lib.rs | 2 +- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/http.rs b/src/http.rs index 552bca7891..3f066e2295 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,14 +1,21 @@ use conduit::{Request, Response}; use conduit_middleware::Middleware; + use curl; use curl::easy::{Easy, List}; + use oauth2::*; -use app::App; -use util::{CargoResult, internal, ChainError, human}; + use serde_json; use serde::Deserialize; + use std::str; use std::error::Error; +use std::collections::HashMap; + +use app::App; +use util::{CargoResult, internal, ChainError, human}; +use Uploader; /// Does all the nonsense for sending a GET to Github. Doesn't handle parsing /// because custom error-code handling may be desirable. Use @@ -91,8 +98,59 @@ pub fn token(token: String) -> Token { } } -#[derive(Clone, Copy, Debug)] -pub struct SecurityHeadersMiddleware; +#[derive(Clone, Debug)] +pub struct SecurityHeadersMiddleware { + headers: HashMap>, +} + +impl SecurityHeadersMiddleware { + pub fn new(uploader: &Uploader) -> Self { + let mut headers = HashMap::new(); + + headers.insert( + "X-Content-Type-Options".into(), + vec!["nosniff".into()], + ); + + headers.insert( + "X-Frame-Options".into(), + vec!["SAMEORIGIN".into()], + ); + + headers.insert( + "X-XSS-Protection".into(), + vec!["1; mode=block".into()], + ); + + let s3_host = match *uploader { + Uploader::S3 { ref bucket, .. } => bucket.host(), + _ => unreachable!("This middleware should only be used in the production environment, \ + which should also require an S3 uploader, QED"), + }; + + // It would be better if we didn't have to have 'unsafe-eval' in the `script-src` + // policy, but google charts (used for the download graph on crate pages) uses `eval` + // to load scripts. Remove 'unsafe-eval' if google fixes the issue: + // https://github.com/google/google-visualization-issues/issues/1356 + // or if we switch to a different graph generation library. + headers.insert( + "Content-Security-Policy".into(), + vec![ + format!("default-src 'self'; \ + connect-src 'self' https://docs.rs {}; \ + script-src 'self' 'unsafe-eval' \ + https://www.google-analytics.com https://www.google.com; \ + style-src 'self' https://www.google.com https://ajax.googleapis.com; \ + img-src *; \ + object-src 'none'", + s3_host + ), + ], + ); + + SecurityHeadersMiddleware { headers } + } +} impl Middleware for SecurityHeadersMiddleware { fn after( @@ -101,36 +159,7 @@ impl Middleware for SecurityHeadersMiddleware { mut res: Result>, ) -> Result> { if let Ok(ref mut response) = res { - // It would be better if we didn't have to have 'unsafe-eval' in the `script-src` - // policy, but google charts (used for the download graph on crate pages) uses `eval` - // to load scripts. Remove 'unsafe-eval' if google fixes the issue: - // https://github.com/google/google-visualization-issues/issues/1356 - // or if we switch to a different graph generation library. - response.headers.insert( - "Content-Security-Policy".into(), - vec![ - "default-src 'self'; \ - connect-src 'self' https://docs.rs; \ - script-src 'self' 'unsafe-eval' \ - https://www.google-analytics.com https://www.google.com; \ - style-src 'self' https://www.google.com https://ajax.googleapis.com; \ - img-src *; \ - object-src 'none'" - .into(), - ], - ); - response.headers.insert( - "X-Content-Type-Options".into(), - vec!["nosniff".into()], - ); - response.headers.insert( - "X-Frame-Options".into(), - vec!["SAMEORIGIN".into()], - ); - response.headers.insert( - "X-XSS-Protection".into(), - vec!["1; mode=block".into()], - ); + response.headers.extend(self.headers.clone()); } res } diff --git a/src/lib.rs b/src/lib.rs index 9d682c95dc..ded097e2a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -232,7 +232,7 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { env == Env::Production, )); if env == Env::Production { - m.add(http::SecurityHeadersMiddleware); + m.add(http::SecurityHeadersMiddleware::new(&app.config.uploader)); } m.add(app::AppMiddleware::new(app)); From 24da2e20e56ce561b4d425a2c9851909c032cac3 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 13 Aug 2017 15:33:50 -0400 Subject: [PATCH 28/35] Oops this really is only the host and doesn't include the protocol --- src/http.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http.rs b/src/http.rs index 3f066e2295..f188defa47 100644 --- a/src/http.rs +++ b/src/http.rs @@ -137,7 +137,7 @@ impl SecurityHeadersMiddleware { "Content-Security-Policy".into(), vec![ format!("default-src 'self'; \ - connect-src 'self' https://docs.rs {}; \ + connect-src 'self' https://docs.rs https://{}; \ script-src 'self' 'unsafe-eval' \ https://www.google-analytics.com https://www.google.com; \ style-src 'self' https://www.google.com https://ajax.googleapis.com; \ From 6babc00f1f2bcda3fa32279cdacb2880b7f7dabf Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 13 Aug 2017 19:28:48 -0400 Subject: [PATCH 29/35] cargo fmt --- src/http.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/http.rs b/src/http.rs index f188defa47..13a7cc234c 100644 --- a/src/http.rs +++ b/src/http.rs @@ -107,25 +107,20 @@ impl SecurityHeadersMiddleware { pub fn new(uploader: &Uploader) -> Self { let mut headers = HashMap::new(); - headers.insert( - "X-Content-Type-Options".into(), - vec!["nosniff".into()], - ); + headers.insert("X-Content-Type-Options".into(), vec!["nosniff".into()]); - headers.insert( - "X-Frame-Options".into(), - vec!["SAMEORIGIN".into()], - ); + headers.insert("X-Frame-Options".into(), vec!["SAMEORIGIN".into()]); - headers.insert( - "X-XSS-Protection".into(), - vec!["1; mode=block".into()], - ); + headers.insert("X-XSS-Protection".into(), vec!["1; mode=block".into()]); let s3_host = match *uploader { Uploader::S3 { ref bucket, .. } => bucket.host(), - _ => unreachable!("This middleware should only be used in the production environment, \ - which should also require an S3 uploader, QED"), + _ => { + unreachable!( + "This middleware should only be used in the production environment, \ + which should also require an S3 uploader, QED" + ) + } }; // It would be better if we didn't have to have 'unsafe-eval' in the `script-src` @@ -136,14 +131,15 @@ impl SecurityHeadersMiddleware { headers.insert( "Content-Security-Policy".into(), vec![ - format!("default-src 'self'; \ + format!( + "default-src 'self'; \ connect-src 'self' https://docs.rs https://{}; \ script-src 'self' 'unsafe-eval' \ https://www.google-analytics.com https://www.google.com; \ style-src 'self' https://www.google.com https://ajax.googleapis.com; \ img-src *; \ object-src 'none'", - s3_host + s3_host ), ], ); From 8c4c43378aba61f766052a6e157dd82356153ab8 Mon Sep 17 00:00:00 2001 From: Louis Person Date: Mon, 14 Aug 2017 23:01:15 +0200 Subject: [PATCH 30/35] Try new layout for crate version page --- app/templates/crate/version.hbs | 147 ++++++++++++++------------------ 1 file changed, 64 insertions(+), 83 deletions(-) diff --git a/app/templates/crate/version.hbs b/app/templates/crate/version.hbs index f6075a2327..ea0a568db3 100644 --- a/app/templates/crate/version.hbs +++ b/app/templates/crate/version.hbs @@ -28,13 +28,28 @@ @@ -165,88 +180,54 @@ {{/each}}
-
-
- - - {{/if}} - -
-

Versions

-
    - {{#each smallSortedVersions as |version|}} -
  • - {{#link-to 'crate.version' version.num}} - {{ version.num }} - {{/link-to}} - {{moment-format version.created_at 'll'}} - {{#if version.yanked}} - yanked - {{/if}} -
  • - {{/each}} -
- - {{#if hasMoreVersions}} - {{#link-to 'crate.versions' crate}} - show all {{ crate.versions.length }} versions - {{/link-to}} - {{/if}} - -
@@ -255,14 +236,14 @@
{{svg-jar "download"}} - {{ format-num downloadsContext.downloads }} + {{format-num downloadsContext.downloads}} Downloads all time
{{svg-jar "crate"}} - {{ crate.versions.length }} + {{crate.versions.length}} Versions published
From 578c5bf411a7ba5fb9e734578108cc4e2e494ebc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 16 Aug 2017 19:33:09 -0400 Subject: [PATCH 31/35] Have uploader take a curl::Easy handle instead of an App --- src/bin/render-readmes.rs | 6 +++--- src/uploaders.rs | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index 7719b34504..d5bd8a414e 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -23,7 +23,7 @@ extern crate time; extern crate toml; extern crate url; -use curl::easy::List; +use curl::easy::{Easy, List}; use diesel::prelude::*; use flate2::read::GzDecoder; use std::env; @@ -91,7 +91,7 @@ fn main() { app.config .uploader .upload( - app.clone(), + Easy::new(), &readme_path, &mut body, "text/html", @@ -115,7 +115,7 @@ fn main() { /// Renders the readme of an uploaded crate version. fn get_readme(app: Arc, version: &EncodableVersion) -> Option { - let mut handle = app.handle(); + let mut handle = Easy::new(); let location = match app.config.uploader.crate_location( &version.krate, &version.num, diff --git a/src/uploaders.rs b/src/uploaders.rs index eda826a958..d86c8afcef 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -1,9 +1,11 @@ use conduit::Request; +use curl::easy::Easy; use krate::Crate; use util::{CargoResult, internal, ChainError}; use util::{LimitErrorReader, HashingReader, read_le_u32}; use s3; use semver; + use app::{App, RequestApp}; use std::sync::Arc; use std::fs::{self, File}; @@ -98,7 +100,7 @@ impl Uploader { /// and its checksum. pub fn upload( &self, - app: Arc, + mut handle: Easy, path: &str, body: &mut io::Read, content_type: &str, @@ -106,7 +108,6 @@ impl Uploader { ) -> CargoResult<(Option, Vec)> { match *self { Uploader::S3 { ref bucket, .. } => { - let mut handle = app.handle(); let (response, cksum) = { let mut body = HashingReader::new(body); let mut response = Vec::new(); @@ -167,7 +168,7 @@ impl Uploader { let length = read_le_u32(req.body())?; let mut body = LimitErrorReader::new(req.body(), max); self.upload( - app.clone(), + app.handle(), &path, &mut body, "application/x-tar", @@ -185,7 +186,7 @@ impl Uploader { let length = rendered.len(); let mut body = io::Cursor::new(rendered.into_bytes()); self.upload( - app.clone(), + app.handle(), &path, &mut body, "text/html", From b0f014d734db2f78846d3fc69d156481133cc764 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 16 Aug 2017 19:50:19 -0400 Subject: [PATCH 32/35] Get a diesel connection from connect_now instead of app --- src/bin/render-readmes.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index d5bd8a414e..a1c970311f 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -44,11 +44,11 @@ const DEFAULT_PAGE_SIZE: i64 = 25; fn main() { let config: Config = Default::default(); let app = Arc::new(App::new(&config)); - let conn = app.diesel_database.get().unwrap(); + let conn = cargo_registry::db::connect_now().unwrap(); let versions_count = versions::table .select(versions::all_columns) .count() - .get_result::(&*conn) + .get_result::(&conn) .expect("error counting versions"); let page_size = match env::args().nth(1) { None => DEFAULT_PAGE_SIZE, @@ -65,7 +65,7 @@ fn main() { .select((versions::all_columns, crates::name)) .limit(page_size) .offset(current_page * page_size) - .load::<(Version, String)>(&*conn) + .load::<(Version, String)>(&conn) .expect("error loading versions") .into_iter() .map(|(version, crate_name)| version.encodable(&crate_name)) From f25fbd61b1246a007ae6971cde1bac4d0a995981 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 16 Aug 2017 19:58:09 -0400 Subject: [PATCH 33/35] Get uploader from config instead of app This removes the need for an app instance in the render-readmes script --- src/bin/render-readmes.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index a1c970311f..2eae64ad19 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -29,12 +29,11 @@ use flate2::read::GzDecoder; use std::env; use std::io::{Cursor, Read}; use std::path::Path; -use std::sync::Arc; use std::thread; use tar::Archive; use url::Url; -use cargo_registry::{App, Config, Version}; +use cargo_registry::{Config, Version}; use cargo_registry::version::EncodableVersion; use cargo_registry::schema::*; use cargo_registry::render::markdown_to_html; @@ -43,7 +42,6 @@ const DEFAULT_PAGE_SIZE: i64 = 25; fn main() { let config: Config = Default::default(); - let app = Arc::new(App::new(&config)); let conn = cargo_registry::db::connect_now().unwrap(); let versions_count = versions::table .select(versions::all_columns) @@ -72,10 +70,10 @@ fn main() { .collect(); let mut tasks = Vec::with_capacity(page_size as usize); for version in versions { - let app = app.clone(); + let config = config.clone(); let handle = thread::spawn(move || { println!("[{}-{}] Rendering README...", version.krate, version.num); - let readme = get_readme(app.clone(), &version); + let readme = get_readme(&config, &version); if readme.is_none() { return; } @@ -88,7 +86,7 @@ fn main() { ); let readme_len = readme.len(); let mut body = Cursor::new(readme.into_bytes()); - app.config + config .uploader .upload( Easy::new(), @@ -114,9 +112,9 @@ fn main() { } /// Renders the readme of an uploaded crate version. -fn get_readme(app: Arc, version: &EncodableVersion) -> Option { +fn get_readme(config: &Config, version: &EncodableVersion) -> Option { let mut handle = Easy::new(); - let location = match app.config.uploader.crate_location( + let location = match config.uploader.crate_location( &version.krate, &version.num, ) { From 79ba3aeb21cee39482b7230e08e43ac71d70d88d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 16 Aug 2017 21:50:22 -0400 Subject: [PATCH 34/35] cargo fmt --- src/bin/render-readmes.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index 2eae64ad19..f800242c30 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -114,10 +114,7 @@ fn main() { /// Renders the readme of an uploaded crate version. fn get_readme(config: &Config, version: &EncodableVersion) -> Option { let mut handle = Easy::new(); - let location = match config.uploader.crate_location( - &version.krate, - &version.num, - ) { + let location = match config.uploader.crate_location(&version.krate, &version.num) { Some(l) => l, None => return None, }; From e28e48f25e7f5470b2920ba0f9f5747c6a26441b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 16 Aug 2017 23:18:39 -0400 Subject: [PATCH 35/35] No more postgres crate --- src/bin/render-readmes.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index f800242c30..00000dc384 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -16,7 +16,6 @@ extern crate cargo_registry; extern crate curl; extern crate diesel; extern crate flate2; -extern crate postgres; extern crate s3; extern crate tar; extern crate time;