Skip to content

Commit e18d034

Browse files
GuillaumeGomezsyphar
authored andcommitted
Add search alias for Rust official crates
1 parent 7603408 commit e18d034

File tree

4 files changed

+238
-44
lines changed

4 files changed

+238
-44
lines changed

src/test/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ impl AxumRouterTestExt for axum::Router {
289289
// }
290290

291291
if redirect_target != expected_target {
292-
anyhow::bail!("got redirect to {redirect_target}");
292+
anyhow::bail!(
293+
"got redirect to `{redirect_target}`, expected redirect to `{expected_target}`",
294+
);
293295
}
294296

295297
Ok(response)

src/web/releases.rs

Lines changed: 93 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,38 @@ 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+
if let Some(super::rustdoc::OfficialCrateDescription {
238+
name,
239+
href,
240+
description,
241+
}) = super::rustdoc::DOC_RUST_LANG_ORG_REDIRECTS.get(query)
242+
{
243+
results.push(rust_lib_release(name, description, href))
244+
}
245+
215246
let names: Vec<String> =
216247
Arc::into_inner(names).expect("Arc still borrowed in `get_search_results`");
248+
results.extend(names.into_iter().map(|name| {
249+
if let Some(release) = crates.remove(&name) {
250+
ReleaseStatus::Available(release)
251+
} else {
252+
ReleaseStatus::NotAvailable(name)
253+
}
254+
}));
255+
217256
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(),
257+
results,
231258
prev_page: meta.prev_page,
232259
next_page: meta.next_page,
233260
})
@@ -589,15 +616,15 @@ pub(crate) async fn search_handler(
589616
}
590617
}
591618

592-
get_search_results(&mut conn, &registry, query_params).await?
619+
get_search_results(&mut conn, &registry, query_params, "").await?
593620
} else if !query.is_empty() {
594621
let query_params: String = form_urlencoded::Serializer::new(String::new())
595622
.append_pair("q", &query)
596623
.append_pair("sort", &sort_by)
597624
.append_pair("per_page", &RELEASES_IN_RELEASES.to_string())
598625
.finish();
599626

600-
get_search_results(&mut conn, &registry, &query_params).await?
627+
get_search_results(&mut conn, &registry, &query_params, &query).await?
601628
} else {
602629
return Err(AxumNope::NoResults);
603630
};
@@ -2231,4 +2258,55 @@ mod tests {
22312258
Ok(())
22322259
});
22332260
}
2261+
2262+
#[test]
2263+
fn test_search_std() {
2264+
async_wrapper(|env| async move {
2265+
let web = env.web_app().await;
2266+
2267+
async fn inner(web: &axum::Router, krate: &str) -> Result<(), anyhow::Error> {
2268+
let full = kuchikiki::parse_html().one(
2269+
web.get(&format!("/releases/search?query={krate}"))
2270+
.await?
2271+
.text()
2272+
.await?,
2273+
);
2274+
let items = full
2275+
.select("ul a.release")
2276+
.expect("missing list items")
2277+
.collect::<Vec<_>>();
2278+
2279+
// empty because expand_rebuild_queue is not set
2280+
let item_element = items.first().unwrap();
2281+
let item = item_element.as_node();
2282+
assert_eq!(
2283+
item.select(".name")
2284+
.unwrap()
2285+
.next()
2286+
.unwrap()
2287+
.text_contents(),
2288+
"std"
2289+
);
2290+
assert_eq!(
2291+
item.select(".description")
2292+
.unwrap()
2293+
.next()
2294+
.unwrap()
2295+
.text_contents(),
2296+
"Rust standard library",
2297+
);
2298+
assert_eq!(
2299+
item_element.attributes.borrow().get("href").unwrap(),
2300+
"https://doc.rust-lang.org/stable/std/"
2301+
);
2302+
2303+
Ok(())
2304+
}
2305+
2306+
inner(&web, "std").await?;
2307+
inner(&web, "libstd").await?;
2308+
2309+
Ok(())
2310+
});
2311+
}
22342312
}

src/web/rustdoc.rs

Lines changed: 125 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,129 @@ use tracing::{Instrument, debug, error, info_span, instrument, trace};
4444

4545
use super::extractors::PathFileExtension;
4646

47-
static DOC_RUST_LANG_ORG_REDIRECTS: Lazy<HashMap<&str, &str>> = Lazy::new(|| {
48-
HashMap::from([
49-
("alloc", "stable/alloc"),
50-
("core", "stable/core"),
51-
("proc_macro", "stable/proc_macro"),
52-
("proc-macro", "stable/proc_macro"),
53-
("std", "stable/std"),
54-
("test", "stable/test"),
55-
("rustc", "nightly/nightly-rustc"),
56-
("rustdoc", "nightly/nightly-rustc/rustdoc"),
57-
])
58-
});
47+
pub(crate) struct OfficialCrateDescription {
48+
pub(crate) name: &'static str,
49+
pub(crate) href: &'static str,
50+
pub(crate) description: &'static str,
51+
}
52+
53+
pub(crate) static DOC_RUST_LANG_ORG_REDIRECTS: Lazy<HashMap<&str, OfficialCrateDescription>> =
54+
Lazy::new(|| {
55+
HashMap::from([
56+
(
57+
"alloc",
58+
OfficialCrateDescription {
59+
name: "alloc",
60+
href: "https://doc.rust-lang.org/stable/alloc/",
61+
description: "Rust alloc library",
62+
},
63+
),
64+
(
65+
"liballoc",
66+
OfficialCrateDescription {
67+
name: "alloc",
68+
href: "https://doc.rust-lang.org/stable/alloc/",
69+
description: "Rust alloc library",
70+
},
71+
),
72+
(
73+
"core",
74+
OfficialCrateDescription {
75+
name: "core",
76+
href: "https://doc.rust-lang.org/stable/core/",
77+
description: "Rust core library",
78+
},
79+
),
80+
(
81+
"libcore",
82+
OfficialCrateDescription {
83+
name: "core",
84+
href: "https://doc.rust-lang.org/stable/core/",
85+
description: "Rust core library",
86+
},
87+
),
88+
(
89+
"proc_macro",
90+
OfficialCrateDescription {
91+
name: "proc_macro",
92+
href: "https://doc.rust-lang.org/stable/proc_macro/",
93+
description: "Rust proc_macro library",
94+
},
95+
),
96+
(
97+
"libproc_macro",
98+
OfficialCrateDescription {
99+
name: "proc_macro",
100+
href: "https://doc.rust-lang.org/stable/proc_macro/",
101+
description: "Rust proc_macro library",
102+
},
103+
),
104+
(
105+
"proc-macro",
106+
OfficialCrateDescription {
107+
name: "proc_macro",
108+
href: "https://doc.rust-lang.org/stable/proc_macro/",
109+
description: "Rust proc_macro library",
110+
},
111+
),
112+
(
113+
"libproc-macro",
114+
OfficialCrateDescription {
115+
name: "proc_macro",
116+
href: "https://doc.rust-lang.org/stable/proc_macro/",
117+
description: "Rust proc_macro library",
118+
},
119+
),
120+
(
121+
"std",
122+
OfficialCrateDescription {
123+
name: "std",
124+
href: "https://doc.rust-lang.org/stable/std/",
125+
description: "Rust standard library",
126+
},
127+
),
128+
(
129+
"libstd",
130+
OfficialCrateDescription {
131+
name: "std",
132+
href: "https://doc.rust-lang.org/stable/std/",
133+
description: "Rust standard library",
134+
},
135+
),
136+
(
137+
"test",
138+
OfficialCrateDescription {
139+
name: "test",
140+
href: "https://doc.rust-lang.org/stable/test/",
141+
description: "Rust test library",
142+
},
143+
),
144+
(
145+
"libtest",
146+
OfficialCrateDescription {
147+
name: "test",
148+
href: "https://doc.rust-lang.org/stable/test/",
149+
description: "Rust test library",
150+
},
151+
),
152+
(
153+
"rustc",
154+
OfficialCrateDescription {
155+
name: "rustc",
156+
href: "https://doc.rust-lang.org/nightly/nightly-rustc/",
157+
description: "rustc API",
158+
},
159+
),
160+
(
161+
"rustdoc",
162+
OfficialCrateDescription {
163+
name: "rustdoc",
164+
href: "https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/",
165+
description: "rustdoc API",
166+
},
167+
),
168+
])
169+
});
59170

60171
#[derive(Debug, Clone, Deserialize)]
61172
pub(crate) struct RustdocRedirectorParams {
@@ -152,10 +263,10 @@ pub(crate) async fn rustdoc_redirector_handler(
152263
None => (params.name.to_string(), None),
153264
};
154265

155-
if let Some(inner_path) = DOC_RUST_LANG_ORG_REDIRECTS.get(crate_name.as_str()) {
266+
if let Some(description) = DOC_RUST_LANG_ORG_REDIRECTS.get(crate_name.as_str()) {
156267
return Ok(redirect_to_doc(
157268
&query_pairs,
158-
format!("https://doc.rust-lang.org/{inner_path}/"),
269+
description.href.to_string(),
159270
CachePolicy::ForeverInCdnAndStaleInBrowser,
160271
path_in_crate.as_deref(),
161272
)?

0 commit comments

Comments
 (0)