Skip to content

Commit 8751acf

Browse files
Add search alias for Rust official crates
1 parent f96cd52 commit 8751acf

File tree

2 files changed

+140
-29
lines changed

2 files changed

+140
-29
lines changed

src/web/releases.rs

Lines changed: 123 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub struct Release {
5050
pub(crate) build_time: Option<DateTime<Utc>>,
5151
pub(crate) stars: i32,
5252
pub(crate) has_unyanked_releases: Option<bool>,
53+
pub(crate) href: Option<&'static str>,
5354
}
5455

5556
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -124,6 +125,7 @@ pub(crate) async fn get_releases(
124125
build_time: row.get(5),
125126
stars: row.get::<Option<i32>, _>(6).unwrap_or(0),
126127
has_unyanked_releases: None,
128+
href: None,
127129
})
128130
.try_collect()
129131
.await?)
@@ -142,13 +144,28 @@ struct SearchResult {
142144
pub next_page: Option<String>,
143145
}
144146

147+
fn rust_lib_release(name: &str, description: &str, href: &'static str) -> ReleaseStatus {
148+
ReleaseStatus::Available(Release {
149+
name: name.to_string(),
150+
version: String::new(),
151+
description: Some(description.to_string()),
152+
build_time: None,
153+
target_name: None,
154+
rustdoc_status: false,
155+
stars: 0,
156+
has_unyanked_releases: None,
157+
href: Some(href),
158+
})
159+
}
160+
145161
/// Get the search results for a crate search query
146162
///
147163
/// This delegates to the crates.io search API.
148164
async fn get_search_results(
149165
conn: &mut sqlx::PgConnection,
150166
registry: &RegistryApi,
151167
query_params: &str,
168+
query: &str,
152169
) -> Result<SearchResult, anyhow::Error> {
153170
let crate::registry_api::Search { crates, meta } = registry.search(query_params).await?;
154171

@@ -206,28 +223,68 @@ async fn get_search_results(
206223
rustdoc_status: row.rustdoc_status.unwrap_or(false),
207224
stars: row.stars.unwrap_or(0),
208225
has_unyanked_releases: row.has_unyanked_releases,
226+
href: None,
209227
},
210228
)
211229
})
212230
.try_collect()
213231
.await?;
214232

233+
// start with the original names from crates.io to keep the original ranking,
234+
// extend with the release/build information from docs.rs
235+
// Crates that are not on docs.rs yet will not be returned.
236+
let mut results = Vec::new();
237+
match query {
238+
"std" | "libstd" => {
239+
results.push(rust_lib_release(
240+
"std",
241+
"Rust standard library",
242+
"https://doc.rust-lang.org/stable/std",
243+
));
244+
}
245+
"core" | "libcore" => {
246+
results.push(rust_lib_release(
247+
"core",
248+
"Rust core library",
249+
"https://doc.rust-lang.org/stable/core",
250+
));
251+
}
252+
"alloc" | "liballoc" => {
253+
results.push(rust_lib_release(
254+
"core",
255+
"Rust alloc library",
256+
"https://doc.rust-lang.org/stable/alloc",
257+
));
258+
}
259+
"proc_macro" | "proc-macro" | "libproc_macro" | "libproc-macro" => {
260+
results.push(rust_lib_release(
261+
"proc_macro",
262+
"Rust proc_macro library",
263+
"https://doc.rust-lang.org/stable/proc_macro",
264+
));
265+
}
266+
"test" | "libtest" => {
267+
results.push(rust_lib_release(
268+
"test",
269+
"Rust test library",
270+
"https://doc.rust-lang.org/stable/test",
271+
));
272+
}
273+
_ => {}
274+
}
275+
215276
let names: Vec<String> =
216277
Arc::into_inner(names).expect("Arc still borrowed in `get_search_results`");
278+
results.extend(names.into_iter().map(|name| {
279+
if let Some(release) = crates.remove(&name) {
280+
ReleaseStatus::Available(release)
281+
} else {
282+
ReleaseStatus::NotAvailable(name)
283+
}
284+
}));
285+
217286
Ok(SearchResult {
218-
// start with the original names from crates.io to keep the original ranking,
219-
// extend with the release/build information from docs.rs
220-
// Crates that are not on docs.rs yet will not be returned.
221-
results: names
222-
.into_iter()
223-
.map(|name| {
224-
if let Some(release) = crates.remove(&name) {
225-
ReleaseStatus::Available(release)
226-
} else {
227-
ReleaseStatus::NotAvailable(name)
228-
}
229-
})
230-
.collect(),
287+
results,
231288
prev_page: meta.prev_page,
232289
next_page: meta.next_page,
233290
})
@@ -589,15 +646,15 @@ pub(crate) async fn search_handler(
589646
}
590647
}
591648

592-
get_search_results(&mut conn, &registry, query_params).await?
649+
get_search_results(&mut conn, &registry, query_params, "").await?
593650
} else if !query.is_empty() {
594651
let query_params: String = form_urlencoded::Serializer::new(String::new())
595652
.append_pair("q", &query)
596653
.append_pair("sort", &sort_by)
597654
.append_pair("per_page", &RELEASES_IN_RELEASES.to_string())
598655
.finish();
599656

600-
get_search_results(&mut conn, &registry, &query_params).await?
657+
get_search_results(&mut conn, &registry, &query_params, &query).await?
601658
} else {
602659
return Err(AxumNope::NoResults);
603660
};
@@ -2231,4 +2288,55 @@ mod tests {
22312288
Ok(())
22322289
});
22332290
}
2291+
2292+
#[test]
2293+
fn test_search_std() {
2294+
async_wrapper(|env| async move {
2295+
let web = env.web_app().await;
2296+
2297+
async fn inner(web: &axum::Router, krate: &str) -> Result<(), anyhow::Error> {
2298+
let full = kuchikiki::parse_html().one(
2299+
web.get(&format!("/releases/search?query={krate}"))
2300+
.await?
2301+
.text()
2302+
.await?,
2303+
);
2304+
let items = full
2305+
.select("ul a.release")
2306+
.expect("missing list items")
2307+
.collect::<Vec<_>>();
2308+
2309+
// empty because expand_rebuild_queue is not set
2310+
let item_element = items.first().unwrap();
2311+
let item = item_element.as_node();
2312+
assert_eq!(
2313+
item.select(".name")
2314+
.unwrap()
2315+
.next()
2316+
.unwrap()
2317+
.text_contents(),
2318+
"std"
2319+
);
2320+
assert_eq!(
2321+
item.select(".description")
2322+
.unwrap()
2323+
.next()
2324+
.unwrap()
2325+
.text_contents(),
2326+
"Rust standard library",
2327+
);
2328+
assert_eq!(
2329+
item_element.attributes.borrow().get("href").unwrap(),
2330+
"https://doc.rust-lang.org/stable/std"
2331+
);
2332+
2333+
Ok(())
2334+
}
2335+
2336+
inner(&web, "std").await?;
2337+
inner(&web, "libstd").await?;
2338+
2339+
Ok(())
2340+
});
2341+
}
22342342
}

templates/releases/releases.html

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,26 @@
4747
{%- else -%}
4848
{%- set release_version = release.version -%}
4949
{%- endif -%}
50-
{% set link %}
51-
{%- if release.rustdoc_status -%}
50+
{%- set link -%}
51+
{%- if let Some(href) = release.href -%}
52+
{% set link = href.to_string() -%}
53+
{%- elif release.rustdoc_status -%}
5254
{% set link = "/{}/{}/{}/"|format(release.name, release_version, release.target_name.as_deref().unwrap_or_default()) -%}
5355
{%- else -%}
5456
{% set link = "/crate/{}/{}"|format(release.name, release_version) -%}
5557
{%- endif -%}
56-
<a href="{{ link|safe }}" class="release">
57-
<div class="pure-g">
58+
<a href="{{ link|safe }}" class="release"> {#- -#}
59+
<div class="pure-g"> {#- -#}
5860
<div class="pure-u-1 pure-u-sm-6-24 pure-u-md-5-24 name">
59-
{{- release.name }}-{{ release.version }}
60-
{%+ if !has_unyanked_releases -%}
61+
{{- release.name -}}
62+
{%- if !release.version.is_empty() -%}-{{ release.version }}{% endif -%}
63+
{%- if !has_unyanked_releases ~%}
6164
<span class="yanked" title="all releases of {{ release.name }} have been yanked">
62-
{{- crate::icons::IconTrash.render_solid(false, false, "") +}}
65+
{{- crate::icons::IconTrash.render_solid(false, false, "") ~}}
6366
Yanked
6467
</span>
6568
{%- endif -%}
66-
</div>
69+
</div> {#- -#}
6770

6871
<div class="pure-u-1 pure-u-sm-14-24 pure-u-md-16-24 description">
6972
{{- release.description.as_deref().unwrap_or_default() -}}
@@ -72,25 +75,25 @@
7275
{%- if release_type == "owner" -%}
7376
<div class="pure-u-1 pure-u-sm-4-24 pure-u-md-3-24 date" {% if let Some(build_time) = release.build_time -%}
7477
title="Published {{ build_time|timeformat }}" {%- endif -%}>
75-
{{- release.stars +}}
78+
{{- release.stars ~}}
7679
{{ crate::icons::IconStar.render_solid(false, false, "") -}}
7780
</div>
7881
{%- elif let Some(build_time) = release.build_time -%}
79-
<div class="pure-u-1 pure-u-sm-4-24 pure-u-md-3-24 date"
82+
<div class="pure-u-1 pure-u-sm-4-24 pure-u-md-3-24 date" {#~ -#}
8083
title="{{ build_time.format("%FT%TZ") }}">
8184
{{- build_time|timeformat -}}
8285
</div>
8386
{%- else -%}
8487
<div class="pure-u-1 pure-u-sm-4-24 pure-u-md-3-24 date">
85-
&mdash;
88+
{%- if release.href.is_none() %}&mdash;{% endif -%}
8689
</div>
87-
{%- endif %}
88-
</div>
90+
{%- endif -%}
91+
</div> {#- -#}
8992
</a>
9093
{%- endmatch -%}
9194
</li>
9295
{%- endfor -%}
93-
</ul>
96+
</ul> {#- -#}
9497

9598
<div class="pagination">
9699
{% block pagination %}

0 commit comments

Comments
 (0)