Skip to content

Split up the about page #924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Aug 6, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,14 @@ fn main() {
env::var("TARGET").unwrap()
);

// Don't rerun anytime a single change is made
println!("cargo:rerun-if-changed=templates/style.scss");
println!("cargo:rerun-if-changed=templates/menu.js");
println!("cargo:rerun-if-changed=templates/index.js");
// TODO: are these right?
println!("cargo:rerun-if-changed=.git/HEAD");
println!("cargo:rerun-if-changed=.git/index");

write_git_version();
compile_sass();
copy_js();
2 changes: 1 addition & 1 deletion src/web/page/mod.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ mod templates;
mod web_page;

pub(crate) use templates::TemplateData;
pub(crate) use web_page::WebPage;
pub(super) use web_page::WebPage;

use serde::Serialize;

14 changes: 10 additions & 4 deletions src/web/page/web_page.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
use super::TemplateData;
use iron::{headers::ContentType, response::Response, status::Status, IronResult, Request};
use serde::Serialize;
use std::borrow::Cow;
use tera::Context;

/// When making using a custom status, use a closure that coerces to a `fn(&Self) -> Status`
#[macro_export]
macro_rules! impl_webpage {
($page:ty = $template:literal $(, status = $status:expr)? $(, content_type = $content_type:expr)? $(,)?) => {
impl_webpage!($page = |_| ::std::borrow::Cow::Borrowed($template) $(, status = $status)? $(, content_type = $content_type)?);
};
($page:ty = $template:expr $(, status = $status:expr)? $(, content_type = $content_type:expr)? $(,)?) => {
impl $crate::web::page::WebPage for $page {
const TEMPLATE: &'static str = $template;
fn template(&self) -> ::std::borrow::Cow<'static, str> {
let template: fn(&Self) -> ::std::borrow::Cow<'static, str> = $template;
template(self)
}

$(
fn get_status(&self) -> ::iron::status::Status {
@@ -32,14 +39,13 @@ pub trait WebPage: Serialize + Sized {
// TODO: We could cache similar pages using the `&Context`
fn into_response(self, req: &Request) -> IronResult<Response> {
let ctx = Context::from_serialize(&self).unwrap();

let rendered = req
.extensions
.get::<TemplateData>()
.expect("missing TemplateData from the request extensions")
.templates
.load()
.render(Self::TEMPLATE, &ctx)
.render(&self.template(), &ctx)
.unwrap();

let mut response = Response::with((self.get_status(), rendered));
@@ -49,7 +55,7 @@ pub trait WebPage: Serialize + Sized {
}

/// The name of the template to be rendered
const TEMPLATE: &'static str;
fn template(&self) -> Cow<'static, str>;

/// Gets the status of the request, defaults to `Ok`
fn get_status(&self) -> Status {
2 changes: 2 additions & 0 deletions src/web/routes.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ pub(super) fn build_routes() -> Routes {

routes.internal_page("/about", super::sitemap::about_handler);
routes.internal_page("/about/metrics", super::metrics::metrics_handler);
routes.internal_page("/about/builds", super::sitemap::about_builds_handler);
routes.internal_page("/about/:subpage", super::sitemap::about_handler);

routes.internal_page("/releases", super::releases::recent_releases_handler);
routes.static_resource("/releases/feed", super::releases::releases_feed_handler);
59 changes: 55 additions & 4 deletions src/web/sitemap.rs
Original file line number Diff line number Diff line change
@@ -56,16 +56,18 @@ pub fn robots_txt_handler(_: &mut Request) -> IronResult<Response> {
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
struct About {
struct AboutBuilds {
/// The current version of rustc that docs.rs is using to build crates
rustc_version: Option<String>,
/// The default crate build limits
limits: Limits,
/// Just for the template, since this isn't shared with AboutPage
active_tab: &'static str,
}

impl_webpage!(About = "core/about.html");
impl_webpage!(AboutBuilds = "core/about/builds.html");

pub fn about_handler(req: &mut Request) -> IronResult<Response> {
pub fn about_builds_handler(req: &mut Request) -> IronResult<Response> {
let mut conn = extension!(req, Pool).get()?;
let res = ctry!(
req,
@@ -80,9 +82,45 @@ pub fn about_handler(req: &mut Request) -> IronResult<Response> {
}
});

About {
AboutBuilds {
rustc_version,
limits: Limits::default(),
active_tab: "builds",
}
.into_response(req)
}

#[derive(Serialize)]
struct AboutPage<'a> {
#[serde(skip)]
template: String,
active_tab: &'a str,
}

impl_webpage!(AboutPage<'_> = |this: &AboutPage| this.template.clone().into());

pub fn about_handler(req: &mut Request) -> IronResult<Response> {
use super::ErrorPage;
use iron::status::Status;

let name = match *req.url.path().last().expect("iron is broken") {
"about" | "index" => "index",
x @ "badges" | x @ "metadata" | x @ "redirections" => x,
_ => {
let msg = "This /about page does not exist. \
Perhaps you are interested in <a href=\"https://github.com/rust-lang/docs.rs/tree/master/templates/core/about\">creating</a> it?";
let page = ErrorPage {
title: "The requested page does not exist",
message: Some(msg.into()),
status: Status::NotFound,
};
return page.into_response(req);
}
};
let template = format!("core/about/{}.html", name);
AboutPage {
template,
active_tab: name,
}
.into_response(req)
}
@@ -110,6 +148,19 @@ mod tests {
fn about_page() {
wrapper(|env| {
let web = env.frontend();
for file in std::fs::read_dir("templates/core/about")? {
use std::ffi::OsStr;

let file_path = file?.path();
if file_path.extension() != Some(OsStr::new("html"))
|| file_path.file_stem() == Some(OsStr::new("index"))
{
continue;
}
let filename = file_path.file_stem().unwrap().to_str().unwrap();
let path = format!("/about/{}", filename);
assert_success(&path, web)?;
}
assert_success("/about", web)
})
}
23 changes: 23 additions & 0 deletions templates/about-base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends "base.html" %}

{% block header %}
<div class="cratesfyi-package-container">
<div class="container about">
<h3 id="crate-title">Docs.rs documentation</h3>
<div class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
{% set text = '<i class="fa fa-fw fa-info-circle"></i> <span class="title">About</span>' %}
{{ macros::active_link(expected="index", href="/about", text=text) }}
{% set text = '<i class="fa fa-fw fa-fonticons"></i> <span class="title">Badges</span>' %}
{{ macros::active_link(expected="badges", href="/about/badges", text=text) }}
{% set text = '<i class="fa fa-fw fa-cogs"></i> <span class="title">Builds</span>' %}
{{ macros::active_link(expected="builds", href="/about/builds", text=text) }}
{% set text = '<i class="fa fa-fw fa-table"></i> <span class="title">Metadata</span>' %}
{{ macros::active_link(expected="metadata", href="/about/metadata", text=text) }}
{% set text = '<i class="fa fa-fw fa-road"></i> <span class="title">Shorthand URLs</span>' %}
{{ macros::active_link(expected="redirections", href="/about/redirections", text=text) }}
</ul>
</div>
</div>
</div>
{% endblock %}
201 changes: 0 additions & 201 deletions templates/core/about.html

This file was deleted.

53 changes: 53 additions & 0 deletions templates/core/about/badges.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{% extends "about-base.html" -%}

{%- block title -%} Badges {%- endblock title -%}

{%- block body -%}
<h1>Badges</h1>

<div class="container about">
<p>
You can use badges to show state of your documentation to your users.
The default badge will be pointed at the latest version of a crate.
You can use <code>version</code> parameter to show status of documentation for
any version you want.
</p>

<p>
Badge will display in blue if docs.rs is successfully hosting your crate
documentation, and red if building documentation failing.
</p>

<p>Example badges for mio crate:</p>
<table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>URL</th>
<th>Badge</th>
</tr>
</thead>

<tbody>
{%- set mio_badge = "https://docs.rs/mio/badge.svg" -%}
<tr>
<td>Latest version: <a href="{{ mio_badge | safe }}">{{ mio_badge }}</a></td>
<td><img src="{{ mio_badge | safe }}" alt="mio" /></td>
</tr>

<tr>
<td>
Version 0.4.4: <a href="{{ mio_badge | safe }}?version=0.4.4">{{ mio_badge }}?version=0.4.4</a>
</td>
<td><img src="{{ mio_badge | safe }}?version=0.4.4" alt="mio" /></td>
</tr>

<tr>
<td>
Version 0.1.0: <a href="{{ mio_badge | safe }}?version=0.1.0">{{ mio_badge }}?version=0.1.0</a>
</td>
<td><img src="{{ mio_badge | safe }}?version=0.1.0" alt="mio" /></td>
</tr>
</tbody>
</table>
</div>
{%- endblock body %}
85 changes: 85 additions & 0 deletions templates/core/about/builds.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{% extends "about-base.html" -%}

{%- block title -%} Builds {%- endblock title -%}

{%- block body -%}
{%- set docsrs_repo = "https://github.com/rust-lang/docs.rs" -%}
<h1>Builds</h1>
<div class="container about">
<p>
Docs.rs automatically builds crates' documentation released on
<a href="https://crates.io/">crates.io</a>
using the nightly release of the Rust compiler.
Builds can take a while depending how many crates are in <a href="/releases/queue">the queue</a>.
</p>

<p>
{%- if rustc_version %}
The current version of the Rust compiler in use is <code>{{ rustc_version }}</code>.
{%- endif -%}
</p>

<p>
The README of a crate is taken from the <code>readme</code> field defined in
<code>Cargo.toml</code>. If a crate doesn't have this field,
no README will be displayed.
</p>

<h3>Diagnosing a failed build</h3>

<h4>Missing dependencies</h4>
<p>
Missing dependencies are a common reason for a failed build.
Docs.rs dependencies are managed through
<a href="https://github.com/rust-lang/crates-build-env">crates-build-env</a>;
see <a href="https://forge.rust-lang.org/docs-rs/add-dependencies.html">Forge</a> for instructions
on how to make a PR. You can always <a href="{{ docsrs_repo | safe }}/issues">file an issue</a>
if you're having trouble.
</p>

<h4>Detecting Docs.rs from <code>build.rs</code></h4>
<p>
Docs.rs builds crates with the environment variable <code>DOCS_RS</code> set to
<code>1</code>, which enables the crate to detect docs.rs and build the
crate differently. This can be helpful if you need
dependencies for building the library, but not for building the documentation.
</p>

<h4>Detecting Docs.rs from <code>#[cfg]</code> attributes</h4>
<p>
You can detect Docs.rs by having a <a href="https://doc.rust-lang.org/cargo/reference/features.html">feature</a>
which is only set by Docs.rs. See <a href="metadata">Metadata</a> for more information.
</p>

<h4>Global sandbox limits</h4>

<p>
All the builds on docs.rs are executed inside a sandbox with limited
resources. The current limits are the following:
</p>

{{ macros::crate_limits(limits=limits) }}

<p>
If a build fails because it hit one of those limits please
<a href="{{ docsrs_repo | safe }}/issues/new/choose">open an issue</a>
to get them increased for your crate.
Note that network access will not be enabled for any crate.
</p>

<h4>Test crate documentation build locally</h4>
{%- set build_subcommand = docsrs_repo ~ "/blob/master/README.md#build-subcommand" -%}
<p>
The <a href="{{ build_subcommand | safe }}">docs.rs README</a> describes how to build an
unpublished crate's documentation locally using the same build environment as the build agent.
</p>
</div>
{%- endblock body %}

{% block css -%}
{{ macros::highlight_css() }}
{%- endblock css %}

{% block javascript -%}
{{ macros::highlight_js(languages=["ini"]) }}
{%- endblock javascript %}
47 changes: 47 additions & 0 deletions templates/core/about/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{% extends "about-base.html" -%}

{%- block title -%} About Docs.rs {%- endblock title -%}

{%- block body -%}
{%- set docsrs_repo = "https://github.com/rust-lang/docs.rs" -%}

<h1 id="crate-title">About Docs.rs</h1>
<div class="container about">
<p>
Docs.rs is an
<a href="{{ docsrs_repo | safe }}">open source</a>
documentation host for crates of the
<a href="https://www.rust-lang.org/">Rust Programming Language</a>.
All libraries published to <a href="https://crates.io">crates.io</a>
are documented. If you just published a crate, your crate is likely
still in <a href="/releases/queue">the queue</a>.
</p>

<p>
The source code of Docs.rs is available on
<a href="{{ docsrs_repo | safe }}">GitHub</a>. If
you ever encounter an issue, don't hesitate to report it! (And
thanks in advance!)
</p>


<h2>More about Docs.rs</h2>
<ol>
<li><a href="/about/badges">Badges</a>: How to use badges generated by Docs.rs</li>
<li><a href="/about/builds">Builds</a>: How Docs.rs builds documentation for a crate</li>
<li><a href="/about/metadata">Metadata</a>: How you can configure a build</li>
<li><a href="/about/redirections">Redirections</a>: How Docs.rs uses semantic versioning in URLs</li>
</ol>

<h3>Version</h3>
<p>Currently running Docs.rs version is: <strong>{{ docsrs_version() }}</strong></p>

<h3>Contact</h3>
{%- set governance_link = "https://www.rust-lang.org/governance/teams/dev-tools#docs-rs" -%}
<p>
Docs.rs is run and maintained by the <a href="{{ governance_link | safe }}">Docs.rs team</a>.
You can find us in #docs-rs on <a href="https://discordapp.com/invite/f7mTXPW/">Discord</a>.
</p>

</div>
{%- endblock body %}
18 changes: 18 additions & 0 deletions templates/core/about/metadata.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "about-base.html" -%}

{%- block title -%} Metadata {%- endblock title -%}

{%- block body -%}
<h1>Metadata for custom builds</h1>

<div class="container about">
<p>
You can customize docs.rs builds by defining <code>[package.metadata.docs.rs]</code>
table in your crates' <code>Cargo.toml</code>.
</p>

<p>The available configuration flags you can customize are:</p>

<pre><code>{%- include "core/Cargo.toml.example" -%}</code></pre>
</div>
{%- endblock body %}
60 changes: 60 additions & 0 deletions templates/core/about/redirections.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{% extends "about-base.html" -%}

{%- block title -%} Shorthand URLs {%- endblock title -%}

{%- block body -%}
<h1>Shorthand URLs</h1>
<div class="container about">

<p>
Docs.rs uses semver to parse URLs. You can use this feature to access
crates' documentation easily. Example of URL redirections for
<code>clap</code> crate:
</p>

<table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>URL</th>
<th>Redirects to documentation of</th>
</tr>
</thead>

<tbody>
<tr>
<td><a href="https://docs.rs/clap">docs.rs/clap</a></td>
<td>Latest version of clap</td>
</tr>

<tr>
<td><a href="https://docs.rs/clap/%7E2">docs.rs/clap/~2</a></td>
<td>2.* version</td>
</tr>

<tr>
<td><a href="https://docs.rs/clap/%7E2.9">docs.rs/clap/~2.9</a></td>
<td>2.9.* version</td>
</tr>

<tr>
<td>
<a href="https://docs.rs/clap/2.9.3">docs.rs/clap/2.9.3</a>
</td>
<td>
2.9.3 version (you don't need <code>=</code> unlike semver)
</td>
</tr>

<tr>
<td>
<a href="https://docs.rs/clap/*/clap/struct.App.html">docs.rs/clap/*/clap/struct.App.html</a>
</td>
<td>
Latest version of this page (if it still exists). "latest" or "newest" work as well as
<code>*</code>.
</td>
</tr>
</tbody>
</table>
</div>
{%- endblock body %}
12 changes: 9 additions & 3 deletions templates/crate/details.html
Original file line number Diff line number Diff line change
@@ -147,9 +147,15 @@
{%- else -%}
{# Display a warning telling the user we failed to build the docs #}
<div class="warning">
docs.rs failed to build {{ details.name }}-{{ details.version }}<br>Please check the
<a href="/crate/{{ details.name }}/{{ details.version }}/builds">build logs</a> and, if you believe this is
docs.rs' fault, <a href="https://github.com/rust-lang/docs.rs/issues/new/choose">open an issue</a>.
docs.rs failed to build {{ details.name }}-{{ details.version }}
<br>
Please check the
<a href="/crate/{{ details.name }}/{{ details.version }}/builds">build logs</a> for more information.
<br>
See <a href="/about/builds">Builds</a> for ideas on how to fix a failed build,
or <a href="/about/metadata">Metadata</a> for how to configure docs.rs builds.
<br>
If you believe this is docs.rs' fault, <a href="https://github.com/rust-lang/docs.rs/issues/new/choose">open an issue</a>.
</div>

{# If there is one, display the most next most recent successful build #}
12 changes: 6 additions & 6 deletions templates/header/topbar.html
Original file line number Diff line number Diff line change
@@ -24,6 +24,12 @@
</a>

<ul class="pure-menu-list">
<li class="pure-menu-item">
<a href="/about" class="pure-menu-link">
About
</a>
</li>

<li class="pure-menu-item">
<a href="/releases" class="pure-menu-link">
Releases
@@ -78,12 +84,6 @@
The Cargo Guide
</a>
</li>

<li class="pure-menu-item">
<a href="/about" class="pure-menu-link">
About Docs.rs
</a>
</li>
</ul>
</li>

15 changes: 15 additions & 0 deletions templates/macros.html
Original file line number Diff line number Diff line change
@@ -26,6 +26,21 @@
type="text/css" media="all" />
{% endmacro highlight_css %}

{#
Creates a list entry for active tabs. When the active tab is the same as `expected`, it will show the current tab as active.
* `expected` A string that represents the current tab, when `active_tab == expected` the current will be shown as active
* `href` A string used as the tab's link
* `text` A string used as the tab's text
#}
{% macro active_link(expected, href, text) %}
<li class="pure-menu-item">
<a class="pure-menu-link {% if active_tab == expected %} pure-menu-active {% endif %}" href="{{ href }}">
{# safe: allow passing in HTML #}
{{ text | safe }}
</a>
</li>
{% endmacro active_link %}

{#
Creates a formatted table showing the resource limits of a crate
* `limits` A non-null `Limits` struct