diff --git a/build.rs b/build.rs index 5465bdef4..907df3ff0 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,7 @@ fn main() { fn write_git_version() { let maybe_hash = get_git_hash(); let git_hash = maybe_hash.as_deref().unwrap_or("???????"); + let build_date = time::strftime("%Y-%m-%d", &time::now_utc()).unwrap(); let dest_path = Path::new(&env::var("OUT_DIR").unwrap()).join("git_version"); diff --git a/src/db/add_package.rs b/src/db/add_package.rs index 365b7f5da..88512eca2 100644 --- a/src/db/add_package.rs +++ b/src/db/add_package.rs @@ -410,6 +410,7 @@ fn add_keywords_into_database( .get(0) } }; + // add releationship let _ = conn.query( "INSERT INTO keyword_rels (rid, kid) VALUES ($1, $2)", diff --git a/src/db/file.rs b/src/db/file.rs index aaa6c1695..ccd1916cf 100644 --- a/src/db/file.rs +++ b/src/db/file.rs @@ -126,6 +126,7 @@ pub(super) fn s3_client() -> Option { if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() && std::env::var_os("FORCE_S3").is_none() { return None; } + let creds = match DefaultCredentialsProvider::new() { Ok(creds) => creds, Err(err) => { @@ -133,6 +134,7 @@ pub(super) fn s3_client() -> Option { return None; } }; + Some(S3Client::new_with( rusoto_core::request::HttpClient::new().unwrap(), creds, diff --git a/src/docbuilder/crates.rs b/src/docbuilder/crates.rs index b9268698f..0c3a8db71 100644 --- a/src/docbuilder/crates.rs +++ b/src/docbuilder/crates.rs @@ -18,13 +18,16 @@ where for line in reader.lines() { // some crates have invalid UTF-8 (nanny-sys-0.0.7) // skip them - let line = match line { - Ok(l) => l, - Err(_) => continue, + let line = if let Ok(line) = line { + line + } else { + continue; }; - let data = match Json::from_str(line.trim()) { - Ok(d) => d, - Err(_) => continue, + + let data = if let Ok(data) = Json::from_str(line.trim()) { + data + } else { + continue; }; let obj = data diff --git a/src/docbuilder/mod.rs b/src/docbuilder/mod.rs index 4f47a796f..8fb38c0e0 100644 --- a/src/docbuilder/mod.rs +++ b/src/docbuilder/mod.rs @@ -37,6 +37,7 @@ impl DocBuilder { /// Loads build cache pub fn load_cache(&mut self) -> Result<()> { debug!("Loading cache"); + let path = PathBuf::from(&self.options.prefix).join("cache"); let reader = fs::File::open(path).map(BufReader::new); @@ -53,6 +54,7 @@ impl DocBuilder { fn load_database_cache(&mut self) -> Result<()> { debug!("Loading database cache"); + use crate::db::connect_db; let conn = connect_db()?; @@ -63,6 +65,7 @@ impl DocBuilder { )? { let name: String = row.get(0); let version: String = row.get(1); + self.db_cache.insert(format!("{}-{}", name, version)); } @@ -72,11 +75,14 @@ impl DocBuilder { /// Saves build cache pub fn save_cache(&self) -> Result<()> { debug!("Saving cache"); + let path = PathBuf::from(&self.options.prefix).join("cache"); let mut file = fs::OpenOptions::new().write(true).create(true).open(path)?; + for krate in &self.cache { writeln!(file, "{}", krate)?; } + Ok(()) } @@ -90,6 +96,7 @@ impl DocBuilder { if !path.exists() { fs::OpenOptions::new().write(true).create(true).open(path)?; } + Ok(()) } @@ -99,6 +106,7 @@ impl DocBuilder { if path.exists() { fs::remove_file(path)?; } + Ok(()) } @@ -120,6 +128,7 @@ impl DocBuilder { let name = format!("{}-{}", name, version); let local = self.options.skip_if_log_exists && self.cache.contains(&name); let db = self.options.skip_if_exists && self.db_cache.contains(&name); + !(local || db) } } diff --git a/src/docbuilder/options.rs b/src/docbuilder/options.rs index a883e137e..668a2f20d 100644 --- a/src/docbuilder/options.rs +++ b/src/docbuilder/options.rs @@ -55,6 +55,7 @@ impl DocBuilderOptions { /// Creates new DocBuilderOptions from prefix pub fn from_prefix(prefix: PathBuf) -> DocBuilderOptions { let (prefix, crates_io_index_path) = generate_paths(prefix); + DocBuilderOptions { prefix, crates_io_index_path, @@ -69,6 +70,7 @@ impl DocBuilderOptions { self.crates_io_index_path.display() ); } + Ok(()) } } diff --git a/src/docbuilder/rustwide_builder.rs b/src/docbuilder/rustwide_builder.rs index 2f113b25d..845e5aa60 100644 --- a/src/docbuilder/rustwide_builder.rs +++ b/src/docbuilder/rustwide_builder.rs @@ -122,8 +122,9 @@ impl RustwideBuilder { let mut targets_to_install = TARGETS .iter() - .map(|&t| t.to_string()) + .map(|&t| t.to_string()) // &str has a specialized ToString impl, while &&str goes through Display .collect::>(); + let installed_targets = match self.toolchain.installed_targets(&self.workspace) { Ok(targets) => targets, Err(err) => { diff --git a/src/utils/daemon.rs b/src/utils/daemon.rs index ffc7b2b0f..48bfc653a 100644 --- a/src/utils/daemon.rs +++ b/src/utils/daemon.rs @@ -18,16 +18,16 @@ use time; use ::{libc::fork, std::fs::File, std::io::Write, std::process::exit}; pub fn start_daemon(background: bool) { - // first check required environment variables - for v in [ + const CRATE_VARIABLES: [&str; 3] = [ "CRATESFYI_PREFIX", "CRATESFYI_GITHUB_USERNAME", "CRATESFYI_GITHUB_ACCESSTOKEN", - ] - .iter() - { + ]; + + // first check required environment variables + for v in CRATE_VARIABLES.iter() { if env::var(v).is_err() { - panic!("Environment variable {} not found", v); + panic!("Environment variable {} not found", v) } } @@ -41,6 +41,7 @@ pub fn start_daemon(background: bool) { { panic!("running in background not supported on windows"); } + #[cfg(not(target_os = "windows"))] { // fork the process @@ -86,6 +87,7 @@ pub fn start_daemon(background: bool) { .unwrap(); // build new crates every minute + // REFACTOR: Break this into smaller functions thread::Builder::new().name("build queue reader".to_string()).spawn(move || { let opts = opts(); let mut doc_builder = DocBuilder::new(opts); @@ -145,6 +147,7 @@ pub fn start_daemon(background: bool) { error!("Failed to read the number of crates in the queue: {}", e); continue; } + Ok(0) => { if status.count() > 0 { // ping the hubs before continuing @@ -161,6 +164,7 @@ pub fn start_daemon(background: bool) { status = BuilderState::EmptyQueue; continue; } + Ok(queue_count) => { info!("Starting build with {} crates in queue (currently on a {} crate streak)", queue_count, status.count()); @@ -184,7 +188,6 @@ pub fn start_daemon(background: bool) { Ok(crate_built) => if crate_built { status.increment(); } - } })); @@ -256,6 +259,7 @@ pub fn start_daemon(background: bool) { // at least start web server info!("Starting web server"); + crate::Server::start(None); } diff --git a/src/utils/github_updater.rs b/src/utils/github_updater.rs index 2c882a6aa..0a80ba808 100644 --- a/src/utils/github_updater.rs +++ b/src/utils/github_updater.rs @@ -136,16 +136,16 @@ fn get_github_path(url: &str) -> Option { Some(cap) => { let username = cap.get(1).unwrap().as_str(); let reponame = cap.get(2).unwrap().as_str(); - Some(format!( - "{}/{}", - username, - if reponame.ends_with(".git") { - reponame.split(".git").next().unwrap() - } else { - reponame - } - )) + + let reponame = if reponame.ends_with(".git") { + reponame.split(".git").next().unwrap() + } else { + reponame + }; + + Some(format!("{}/{}", username, reponame)) } + None => None, } } diff --git a/src/utils/html.rs b/src/utils/html.rs index 55602dae9..a217b7069 100644 --- a/src/utils/html.rs +++ b/src/utils/html.rs @@ -32,6 +32,7 @@ fn extract_from_rcdom(dom: &RcDom) -> Result<(Handle, Handle)> { head = Some(handle.clone()); } } + "body" => { if body.is_some() { return Err(err_msg("duplicate tag")); @@ -39,6 +40,7 @@ fn extract_from_rcdom(dom: &RcDom) -> Result<(Handle, Handle)> { body = Some(handle.clone()); } } + _ => {} // do nothing } } @@ -68,6 +70,7 @@ fn extract_class(node: &Handle) -> String { .find(|a| &a.name.local == "class") .map_or(String::new(), |a| a.value.to_string()) } + _ => String::new(), } } @@ -79,6 +82,7 @@ mod test { let (head, body, class) = super::extract_head_and_body( r#"

hello

"# ).unwrap(); + assert_eq!(head, r#""#); assert_eq!(body, "

hello

"); assert_eq!(class, "rustdoc struct"); @@ -91,6 +95,7 @@ mod test { let expected_head = std::fs::read_to_string("tests/regex/head.html").unwrap(); let expected_body = std::fs::read_to_string("tests/regex/body.html").unwrap(); let (head, body, class) = super::extract_head_and_body(&original).unwrap(); + assert_eq!(head, expected_head.trim()); assert_eq!(&body, &expected_body.trim()); assert_eq!(class, "rustdoc struct"); diff --git a/src/utils/release_activity_updater.rs b/src/utils/release_activity_updater.rs index 5bc931da5..1d1b9ac84 100644 --- a/src/utils/release_activity_updater.rs +++ b/src/utils/release_activity_updater.rs @@ -6,17 +6,17 @@ use time::{now, Duration}; pub fn update_release_activity() -> Result<()> { let conn = connect_db()?; - let mut dates = Vec::new(); - let mut crate_counts = Vec::new(); - let mut failure_counts = Vec::new(); + let mut dates = Vec::with_capacity(30); + let mut crate_counts = Vec::with_capacity(30); + let mut failure_counts = Vec::with_capacity(30); for day in 0..30 { let rows = conn.query( &format!( "SELECT COUNT(*) - FROM releases - WHERE release_time < NOW() - INTERVAL '{} day' AND - release_time > NOW() - INTERVAL '{} day'", + FROM releases + WHERE release_time < NOW() - INTERVAL '{} day' AND + release_time > NOW() - INTERVAL '{} day'", day, day + 1 ), @@ -25,22 +25,24 @@ pub fn update_release_activity() -> Result<()> { let failures_count_rows = conn.query( &format!( "SELECT COUNT(*) - FROM releases - WHERE is_library = TRUE AND - build_status = FALSE AND - release_time < NOW() - INTERVAL '{} day' AND - release_time > NOW() - INTERVAL '{} day'", + FROM releases + WHERE is_library = TRUE AND + build_status = FALSE AND + release_time < NOW() - INTERVAL '{} day' AND + release_time > NOW() - INTERVAL '{} day'", day, day + 1 ), &[], )?; + let release_count: i64 = rows.get(0).get(0); let failure_count: i64 = failures_count_rows.get(0).get(0); let now = now(); let date = now - Duration::days(day); + + // unwrap is fine here, as our date format is always valid dates.push(format!("{}", date.strftime("%d %b").unwrap())); - // unwrap is fine here, ~~~~~~~~~~~~^ our date format is always valid crate_counts.push(release_count); failure_counts.push(failure_count); } @@ -54,6 +56,7 @@ pub fn update_release_activity() -> Result<()> { map.insert("dates".to_owned(), dates.to_json()); map.insert("counts".to_owned(), crate_counts.to_json()); map.insert("failures".to_owned(), failure_counts.to_json()); + map.to_json() }; diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 69c9bfdda..87fa0737a 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -163,10 +163,10 @@ impl CrateDetails { if let Some(version) = version.as_string() { if let Ok(sem_ver) = semver::Version::parse(&version) { versions.push(sem_ver); - }; - }; + } + } } - }; + } versions.sort(); versions.reverse(); diff --git a/src/web/mod.rs b/src/web/mod.rs index df165514e..ee519bef4 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -523,34 +523,31 @@ pub(crate) struct MetaData { impl MetaData { fn from_crate(conn: &Connection, name: &str, version: &str) -> Option { - if let Some(row) = &conn + let rows = conn .query( "SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.rustdoc_status, - releases.default_target - FROM releases - INNER JOIN crates ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", + releases.version, + releases.description, + releases.target_name, + releases.rustdoc_status, + releases.default_target + FROM releases + INNER JOIN crates ON crates.id = releases.crate_id + WHERE crates.name = $1 AND releases.version = $2", &[&name, &version], ) - .unwrap() - .iter() - .next() - { - return Some(MetaData { - name: row.get(0), - version: row.get(1), - description: row.get(2), - target_name: row.get(3), - rustdoc_status: row.get(4), - default_target: row.get(5), - }); - } + .unwrap(); - None + let row = rows.iter().next()?; + + Some(MetaData { + name: row.get(0), + version: row.get(1), + description: row.get(2), + target_name: row.get(3), + rustdoc_status: row.get(4), + default_target: row.get(5), + }) } } diff --git a/src/web/page.rs b/src/web/page.rs index e3b8f74a0..46b8f0615 100644 --- a/src/web/page.rs +++ b/src/web/page.rs @@ -114,6 +114,7 @@ impl Page { let status = self.status; let temp = Template::new(template, self); resp.set_mut(temp).set_mut(status); + Ok(resp) } } diff --git a/src/web/releases.rs b/src/web/releases.rs index 0640c5f03..0287cd4d3 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -447,6 +447,7 @@ pub fn author_handler(req: &mut Request) -> IronResult { let (author_name, packages) = if author.starts_with('@') { let mut author = author.split('@'); + get_releases_by_owner( &conn, page_number, @@ -572,7 +573,7 @@ pub fn search_handler(req: &mut Request) -> IronResult { let search_query = query.replace(" ", " & "); #[allow(clippy::or_fun_call)] get_search_results(&conn, &search_query, 1, RELEASES_IN_RELEASES) - .ok_or(IronError::new(Nope::NoResults, status::NotFound)) + .ok_or_else(|| IronError::new(Nope::NoResults, status::NotFound)) .and_then(|(_, results)| { // FIXME: There is no pagination Page::new(results) diff --git a/src/web/routes.rs b/src/web/routes.rs index 840bc15df..25727ab2f 100644 --- a/src/web/routes.rs +++ b/src/web/routes.rs @@ -6,6 +6,7 @@ use std::collections::HashSet; const DOC_RUST_LANG_ORG_REDIRECTS: &[&str] = &["alloc", "core", "proc_macro", "std", "test"]; +// REFACTOR: Break this into smaller initialization functions pub(super) fn build_routes() -> Routes { let mut routes = Routes::new(); diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index b7ab03ab3..7efbdcd95 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -402,6 +402,7 @@ pub fn badge_handler(req: &mut Request) -> IronResult { } } } + Some(MatchSemver::Semver((version, _))) => { let base_url = format!("{}/{}/badge.svg", redirect_base(req), name); let url = ctry!(url::Url::parse_with_params( @@ -411,6 +412,7 @@ pub fn badge_handler(req: &mut Request) -> IronResult { let iron_url = ctry!(Url::from_generic_url(url)); return Ok(super::redirect(iron_url)); } + None => BadgeOptions { subject: "docs".to_owned(), status: "no builds".to_owned(), diff --git a/src/web/source.rs b/src/web/source.rs index 2784cb7ed..de10c7cb4 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -42,16 +42,14 @@ impl ToJson for FileList { let mut file_m: BTreeMap = BTreeMap::new(); file_m.insert("name".to_string(), file.name.to_json()); - file_m.insert( - match file.file_type { - FileType::Dir => "file_type_dir".to_string(), - FileType::Text => "file_type_text".to_string(), - FileType::Binary => "file_type_binary".to_string(), - FileType::RustSource => "file_type_rust_source".to_string(), - }, - true.to_json(), - ); - + let file_type = match file.file_type { + FileType::Dir => "file_type_dir", + FileType::Text => "file_type_text", + FileType::Binary => "file_type_binary", + FileType::RustSource => "file_type_rust_source", + }; + + file_m.insert(file_type.to_string(), true.to_json()); file_vec.push(file_m.to_json()); } @@ -141,9 +139,9 @@ impl FileList { file_list.push(file); } } - }; + } } - }; + } if file_list.is_empty() { return None;