Skip to content

Show versions of tools. #398

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 1 commit into from Sep 14, 2018
Merged
Show file tree
Hide file tree
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
39 changes: 34 additions & 5 deletions ui/frontend/ToolsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,27 @@ import { connect } from 'react-redux';
import ButtonMenuItem from './ButtonMenuItem';
import MenuGroup from './MenuGroup';

import {
clippyVersionDetailsText,
clippyVersionText,
miriVersionText,
rustfmtVersionDetailsText,
rustfmtVersionText,
} from './selectors';
import State from './state';

import {
performClippy,
performFormat,
performMiri,
} from './actions';

interface ToolsMenuProps {
rustfmtVersion: string;
rustfmtVersionDetails: string;
clippyVersion: string;
clippyVersionDetails: string;
miriVersion: string;
clippy: () => any;
miri: () => any;
format: () => any;
Expand All @@ -22,26 +36,41 @@ const ToolsMenu: React.SFC<ToolsMenuProps> = props => (
<ButtonMenuItem
name="Rustfmt"
onClick={() => { props.format(); props.close(); }}>
Format this code with Rustfmt.
<div>Format this code with Rustfmt.</div>
<div className="tools-menu__aside">{props.rustfmtVersion} ({props.rustfmtVersionDetails})</div>
</ButtonMenuItem>
<ButtonMenuItem
name="Clippy"
onClick={() => { props.clippy(); props.close(); }}>
Catch common mistakes and improve the code using the Clippy linter.
<div>Catch common mistakes and improve the code using the Clippy linter.</div>
<div className="tools-menu__aside">{props.clippyVersion} ({props.clippyVersionDetails})</div>
</ButtonMenuItem>
<ButtonMenuItem
name="Miri"
onClick={() => { props.miri(); props.close(); }}>
Execute this program in the Miri interpreter to detect certain
cases of undefined behavior (like out-of-bounds memory access).
<div>
Execute this program in the Miri interpreter to detect certain
cases of undefined behavior (like out-of-bounds memory access).
</div>
<div className="tools-menu__aside">{props.miriVersion}</div>
</ButtonMenuItem>
</MenuGroup>
);

const mapStateToProps = (state: State) => {
return {
rustfmtVersion: rustfmtVersionText(state),
rustfmtVersionDetails: rustfmtVersionDetailsText(state),
clippyVersionDetails: clippyVersionDetailsText(state),
clippyVersion: clippyVersionText(state),
miriVersion: miriVersionText(state),
};
};

const mapDispatchToProps = ({
clippy: performClippy,
miri: performMiri,
format: performFormat,
});

export default connect(undefined, mapDispatchToProps)(ToolsMenu);
export default connect(mapStateToProps, mapDispatchToProps)(ToolsMenu);
17 changes: 13 additions & 4 deletions ui/frontend/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const routes = {
stable: '/meta/version/stable',
beta: '/meta/version/beta',
nightly: '/meta/version/nightly',
rustfmt: '/meta/version/rustfmt',
clippy: '/meta/version/clippy',
miri: '/meta/version/miri',
},
gist: { pathname: '/meta/gist/' },
},
Expand Down Expand Up @@ -575,8 +578,8 @@ export function performCratesLoad(): ThunkAction {
const requestVersionsLoad = () =>
createAction(ActionType.RequestVersionsLoad);

const receiveVersionsLoadSuccess = ({ stable, beta, nightly }) =>
createAction(ActionType.VersionsLoadSucceeded, { stable, beta, nightly });
const receiveVersionsLoadSuccess = ({ stable, beta, nightly, rustfmt, clippy, miri }) =>
createAction(ActionType.VersionsLoadSucceeded, { stable, beta, nightly, rustfmt, clippy, miri });

export function performVersionsLoad(): ThunkAction {
return function(dispatch) {
Expand All @@ -585,14 +588,20 @@ export function performVersionsLoad(): ThunkAction {
const stable = jsonGet(routes.meta.version.stable);
const beta = jsonGet(routes.meta.version.beta);
const nightly = jsonGet(routes.meta.version.nightly);
const rustfmt = jsonGet(routes.meta.version.rustfmt);
const clippy = jsonGet(routes.meta.version.clippy);
const miri = jsonGet(routes.meta.version.miri);

const all = Promise.all([stable, beta, nightly]);
const all = Promise.all([stable, beta, nightly, rustfmt, clippy, miri]);

return all
.then(([stable, beta, nightly]) => dispatch(receiveVersionsLoadSuccess({
.then(([stable, beta, nightly, rustfmt, clippy, miri]) => dispatch(receiveVersionsLoadSuccess({
stable,
beta,
nightly,
rustfmt,
clippy,
miri,
})));
// TODO: Failure case
};
Expand Down
7 changes: 7 additions & 0 deletions ui/frontend/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,13 @@ $header-transition: 0.2s ease-in-out;
}
}

.tools-menu {
&__aside {
margin: 0.25em 0 0 0;
color: #888;
}
}

.config-element {
display: flex;
align-items: center;
Expand Down
10 changes: 8 additions & 2 deletions ui/frontend/reducers/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ const DEFAULT: State = {
stable: null,
beta: null,
nightly: null,
rustfmt: null,
clippy: null,
miri: null,
};

export interface State {
stable?: Version;
beta?: Version;
nightly?: Version;
rustfmt?: Version;
clippy?: Version;
miri?: Version;
}

export default function crates(state = DEFAULT, action: Action) {
switch (action.type) {
case ActionType.VersionsLoadSucceeded: {
const { stable, beta, nightly } = action;
return { stable, beta, nightly };
const { stable, beta, nightly, rustfmt, clippy, miri } = action;
return { stable, beta, nightly, rustfmt, clippy, miri };
}
default:
return state;
Expand Down
8 changes: 8 additions & 0 deletions ui/frontend/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,23 @@ export const getExecutionLabel = createSelector(primaryActionSelector, primaryAc
const getStable = (state: State) => state.versions && state.versions.stable;
const getBeta = (state: State) => state.versions && state.versions.beta;
const getNightly = (state: State) => state.versions && state.versions.nightly;
const getRustfmt = (state: State) => state.versions && state.versions.rustfmt;
const getClippy = (state: State) => state.versions && state.versions.clippy;
const getMiri = (state: State) => state.versions && state.versions.miri;

const versionNumber = v => v ? v.version : '';
export const stableVersionText = createSelector([getStable], versionNumber);
export const betaVersionText = createSelector([getBeta], versionNumber);
export const nightlyVersionText = createSelector([getNightly], versionNumber);
export const clippyVersionText = createSelector([getClippy], versionNumber);
export const rustfmtVersionText = createSelector([getRustfmt], versionNumber);
export const miriVersionText = createSelector([getMiri], versionNumber);

const versionDetails = v => v ? `${v.date} ${v.hash.slice(0, 20)}` : '';
export const betaVersionDetailsText = createSelector([getBeta], versionDetails);
export const nightlyVersionDetailsText = createSelector([getNightly], versionDetails);
export const clippyVersionDetailsText = createSelector([getClippy], versionDetails);
export const rustfmtVersionDetailsText = createSelector([getRustfmt], versionDetails);

export const isWasmAvailable = (state: State) => (
state.configuration.channel === Channel.Nightly
Expand Down
48 changes: 48 additions & 0 deletions ui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ fn main() {
mount.mount("/meta/version/stable", meta_version_stable);
mount.mount("/meta/version/beta", meta_version_beta);
mount.mount("/meta/version/nightly", meta_version_nightly);
mount.mount("/meta/version/rustfmt", meta_version_rustfmt);
mount.mount("/meta/version/clippy", meta_version_clippy);
mount.mount("/meta/version/miri", meta_version_miri);
mount.mount("/meta/gist", gist_router);
mount.mount("/evaluate.json", evaluate);

Expand Down Expand Up @@ -236,6 +239,30 @@ fn meta_version_nightly(_req: &mut Request) -> IronResult<Response> {
})
}

fn meta_version_rustfmt(_req: &mut Request) -> IronResult<Response> {
with_sandbox_no_request(|sandbox| {
cached(sandbox)
.version_rustfmt()
.map(MetaVersionResponse::from)
})
}

fn meta_version_clippy(_req: &mut Request) -> IronResult<Response> {
with_sandbox_no_request(|sandbox| {
cached(sandbox)
.version_clippy()
.map(MetaVersionResponse::from)
})
}

fn meta_version_miri(_req: &mut Request) -> IronResult<Response> {
with_sandbox_no_request(|sandbox| {
cached(sandbox)
.version_miri()
.map(MetaVersionResponse::from)
})
}

fn meta_gist_create(req: &mut Request) -> IronResult<Response> {
let token = req.extensions.get::<GhToken>().unwrap().0.as_ref().clone();
serialize_to_response(deserialize_from_request(req, |r: MetaGistCreateRequest| {
Expand Down Expand Up @@ -401,6 +428,9 @@ struct SandboxCache {
version_stable: SandboxCacheOne<sandbox::Version>,
version_beta: SandboxCacheOne<sandbox::Version>,
version_nightly: SandboxCacheOne<sandbox::Version>,
version_clippy: SandboxCacheOne<sandbox::Version>,
version_rustfmt: SandboxCacheOne<sandbox::Version>,
version_miri: SandboxCacheOne<sandbox::Version>,
}

/// Provides a similar API to the Sandbox that caches the successful results.
Expand Down Expand Up @@ -431,6 +461,24 @@ impl<'a> CachedSandbox<'a> {
self.sandbox.version(sandbox::Channel::Nightly)
})
}

fn version_clippy(&self) -> Result<sandbox::Version> {
self.cache.version_clippy.clone_or_populate(|| {
self.sandbox.version_clippy()
})
}

fn version_rustfmt(&self) -> Result<sandbox::Version> {
self.cache.version_rustfmt.clone_or_populate(|| {
self.sandbox.version_rustfmt()
})
}

fn version_miri(&self) -> Result<sandbox::Version> {
self.cache.version_miri.clone_or_populate(|| {
self.sandbox.version_miri()
})
}
}

/// A convenience constructor
Expand Down
40 changes: 40 additions & 0 deletions ui/src/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,46 @@ impl Sandbox {
Ok(Version { release, commit_hash, commit_date })
}


pub fn version_rustfmt(&self) -> Result<Version> {
let mut command = basic_secure_docker_command();
command.args(&["rustfmt", "cargo", "fmt", "--version"]);
self.cargo_tool_version(command)
}

pub fn version_clippy(&self) -> Result<Version> {
let mut command = basic_secure_docker_command();
command.args(&["clippy", "cargo", "clippy", "--version"]);
self.cargo_tool_version(command)
}

pub fn version_miri(&self) -> Result<Version> {
let mut command = basic_secure_docker_command();
command.args(&["miri", "cargo", "miri", "--version"]);

let output = command.output().map_err(Error::UnableToExecuteCompiler)?;
let version_output = vec_to_str(output.stdout)?;

let release = version_output.trim().into();
let commit_hash = String::new();
let commit_date = String::new();

Ok(Version { release, commit_hash, commit_date })
}

// Parses versions of the shape `toolname 0.0.0 (0000000 0000-00-00)`
fn cargo_tool_version(&self, mut command: Command) -> Result<Version> {
let output = command.output().map_err(Error::UnableToExecuteCompiler)?;
let version_output = vec_to_str(output.stdout)?;
let mut parts = version_output.split_whitespace().fuse().skip(1);

let release = parts.next().unwrap_or("").into();
let commit_hash = parts.next().unwrap_or("").trim_left_matches('(').into();
let commit_date = parts.next().unwrap_or("").trim_right_matches(')').into();

Ok(Version { release, commit_hash, commit_date })
}

fn write_source_code(&self, code: &str) -> Result<()> {
let data = code.as_bytes();

Expand Down