diff --git a/.sqlx/query-31b24e2e5aea1c5dcd742343aa18e4b1806f0926d3494747854a036421399546.json b/.sqlx/query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json similarity index 63% rename from .sqlx/query-31b24e2e5aea1c5dcd742343aa18e4b1806f0926d3494747854a036421399546.json rename to .sqlx/query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json index 20c1dd68b..384e3bbed 100644 --- a/.sqlx/query-31b24e2e5aea1c5dcd742343aa18e4b1806f0926d3494747854a036421399546.json +++ b/.sqlx/query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n crates.id AS crate_id,\n releases.id AS release_id,\n crates.name,\n releases.version,\n releases.description,\n releases.dependencies,\n releases.readme,\n releases.description_long,\n releases.release_time,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n (\n -- this is the latest build ID that generated content\n -- it's used to invalidate some blob storage related caches.\n SELECT id\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY build_finished DESC\n LIMIT 1\n ) AS latest_build_id,\n releases.rustdoc_status,\n releases.archive_storage,\n releases.repository_url,\n releases.homepage_url,\n releases.keywords,\n releases.have_examples,\n releases.target_name,\n repositories.host as \"repo_host?\",\n repositories.stars as \"repo_stars?\",\n repositories.forks as \"repo_forks?\",\n repositories.issues as \"repo_issues?\",\n repositories.name as \"repo_name?\",\n releases.is_library,\n releases.yanked,\n releases.doc_targets,\n releases.license,\n releases.documentation_url,\n releases.default_target,\n (\n -- we're using the rustc version here to set the correct CSS file\n -- in the metadata.\n -- So we're only interested in successful builds here.\n SELECT rustc_version\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY builds.build_finished\n DESC LIMIT 1\n ) as \"rustc_version?\",\n doc_coverage.total_items,\n doc_coverage.documented_items,\n doc_coverage.total_items_needing_examples,\n doc_coverage.items_with_examples\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id\n LEFT JOIN repositories ON releases.repository_id = repositories.id\n WHERE crates.name = $1 AND releases.version = $2;", + "query": "SELECT\n crates.id AS crate_id,\n releases.id AS release_id,\n crates.name,\n releases.version,\n releases.description,\n releases.dependencies,\n releases.readme,\n releases.description_long,\n releases.release_time,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n -- this is the latest build ID that generated content\n -- it's used to invalidate some blob storage related caches.\n builds.id as \"latest_build_id?\",\n releases.rustdoc_status,\n releases.archive_storage,\n releases.repository_url,\n releases.homepage_url,\n releases.keywords,\n releases.have_examples,\n releases.target_name,\n repositories.host as \"repo_host?\",\n repositories.stars as \"repo_stars?\",\n repositories.forks as \"repo_forks?\",\n repositories.issues as \"repo_issues?\",\n repositories.name as \"repo_name?\",\n releases.is_library,\n releases.yanked,\n releases.doc_targets,\n releases.license,\n releases.documentation_url,\n releases.default_target,\n releases.source_size as \"source_size?\",\n builds.documentation_size as \"documentation_size?\",\n -- we're using the rustc version here to set the correct CSS file\n -- in the metadata.\n -- So we're only interested in successful builds here.\n builds.rustc_version as \"rustc_version?\",\n doc_coverage.total_items,\n doc_coverage.documented_items,\n doc_coverage.total_items_needing_examples,\n doc_coverage.items_with_examples\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id\n LEFT JOIN repositories ON releases.repository_id = repositories.id\n LEFT JOIN LATERAL (\n SELECT rustc_version, documentation_size, id\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY builds.build_finished\n DESC LIMIT 1\n ) AS builds ON true\n WHERE crates.name = $1 AND releases.version = $2;", "describe": { "columns": [ { @@ -66,7 +66,7 @@ }, { "ordinal": 10, - "name": "latest_build_id", + "name": "latest_build_id?", "type_info": "Int4" }, { @@ -161,26 +161,36 @@ }, { "ordinal": 29, + "name": "source_size?", + "type_info": "Int8" + }, + { + "ordinal": 30, + "name": "documentation_size?", + "type_info": "Int8" + }, + { + "ordinal": 31, "name": "rustc_version?", "type_info": "Varchar" }, { - "ordinal": 30, + "ordinal": 32, "name": "total_items", "type_info": "Int4" }, { - "ordinal": 31, + "ordinal": 33, "name": "documented_items", "type_info": "Int4" }, { - "ordinal": 32, + "ordinal": 34, "name": "total_items_needing_examples", "type_info": "Int4" }, { - "ordinal": 33, + "ordinal": 35, "name": "items_with_examples", "type_info": "Int4" } @@ -202,7 +212,7 @@ true, true, false, - null, + false, true, false, true, @@ -221,12 +231,14 @@ true, true, true, - null, + true, + true, + true, true, true, true, true ] }, - "hash": "31b24e2e5aea1c5dcd742343aa18e4b1806f0926d3494747854a036421399546" + "hash": "1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87" } diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index d10e3c653..4606d7eed 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -65,6 +65,8 @@ pub(crate) struct CrateDetails { pub(crate) crate_id: i32, /// Database id for this release pub(crate) release_id: i32, + source_size: Option, + documentation_size: Option, } #[derive(Debug, Clone, PartialEq)] @@ -134,17 +136,9 @@ impl CrateDetails { releases.description_long, releases.release_time, release_build_status.build_status as "build_status!: BuildStatus", - ( - -- this is the latest build ID that generated content - -- it's used to invalidate some blob storage related caches. - SELECT id - FROM builds - WHERE - builds.rid = releases.id AND - builds.build_status = 'success' - ORDER BY build_finished DESC - LIMIT 1 - ) AS latest_build_id, + -- this is the latest build ID that generated content + -- it's used to invalidate some blob storage related caches. + builds.id as "latest_build_id?", releases.rustdoc_status, releases.archive_storage, releases.repository_url, @@ -163,18 +157,12 @@ impl CrateDetails { releases.license, releases.documentation_url, releases.default_target, - ( - -- we're using the rustc version here to set the correct CSS file - -- in the metadata. - -- So we're only interested in successful builds here. - SELECT rustc_version - FROM builds - WHERE - builds.rid = releases.id AND - builds.build_status = 'success' - ORDER BY builds.build_finished - DESC LIMIT 1 - ) as "rustc_version?", + releases.source_size as "source_size?", + builds.documentation_size as "documentation_size?", + -- we're using the rustc version here to set the correct CSS file + -- in the metadata. + -- So we're only interested in successful builds here. + builds.rustc_version as "rustc_version?", doc_coverage.total_items, doc_coverage.documented_items, doc_coverage.total_items_needing_examples, @@ -184,6 +172,15 @@ impl CrateDetails { INNER JOIN crates ON releases.crate_id = crates.id LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id LEFT JOIN repositories ON releases.repository_id = repositories.id + LEFT JOIN LATERAL ( + SELECT rustc_version, documentation_size, id + FROM builds + WHERE + builds.rid = releases.id AND + builds.build_status = 'success' + ORDER BY builds.build_finished + DESC LIMIT 1 + ) AS builds ON true WHERE crates.name = $1 AND releases.version = $2;"#, name, version.to_string(), @@ -258,6 +255,8 @@ impl CrateDetails { items_with_examples: krate.items_with_examples, crate_id: krate.crate_id, release_id: krate.release_id, + documentation_size: krate.documentation_size, + source_size: krate.source_size, }; // get owners @@ -442,6 +441,8 @@ struct CrateDetailsPage { last_successful_build: Option, rustdoc: Option, // this is description_long in database csp_nonce: String, + source_size: Option, + documentation_size: Option, } impl CrateDetailsPage { @@ -513,6 +514,8 @@ pub(crate) async fn crate_details_handler( is_library, last_successful_build, rustdoc, + source_size, + documentation_size, .. } = details; @@ -538,6 +541,8 @@ pub(crate) async fn crate_details_handler( last_successful_build, rustdoc, csp_nonce: String::new(), + source_size, + documentation_size, } .into_response(); res.extensions_mut() @@ -2160,4 +2165,35 @@ mod tests { Ok(()) }) } + + #[test] + fn test_sizes_display() { + wrapper(|env| { + env.fake_release() + .name("dummy") + .version("0.4.0") + .rustdoc_file("dummy/index.html") + .create()?; + + let response = env.frontend().get("/crate/dummy/0.4.0").send()?; + assert!(response.status().is_success()); + + let mut has_source_code_size = false; + let mut has_doc_size = false; + for span in kuchikiki::parse_html() + .one(response.text()?) + .select(r#".pure-menu-item span.documented-info"#) + .expect("invalid selector") + { + if span.text_contents().starts_with("Source code size:") { + has_source_code_size = true; + } else if span.text_contents().starts_with("Documentation size:") { + has_doc_size = true; + } + } + assert!(has_source_code_size); + assert!(has_doc_size); + Ok(()) + }); + } } diff --git a/templates/crate/details.html b/templates/crate/details.html index b2a83d2b8..9752cd9f6 100644 --- a/templates/crate/details.html +++ b/templates/crate/details.html @@ -37,8 +37,19 @@ {%- endif -%} {%- endif -%} -
  • Links
  • + {%- if let Some(source_size) = source_size -%} +
  • Size
  • +
  • + Source code size: {{(*source_size)|filesizeformat}} +
  • + {%- if let Some(doc_size) = documentation_size -%} +
  • + Documentation size: {{(*doc_size)|filesizeformat}} +
  • + {%- endif -%} + {%- endif -%} +
  • Links
  • {# If the crate has a homepage, show it #} {%- if let Some(homepage_url) = homepage_url -%}