mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Move design documents
This commit is contained in:
parent
3316e85ab5
commit
8bc5b96a55
152
DESIGN/DESIGN.md
Normal file
152
DESIGN/DESIGN.md
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
## Subcommands
|
||||||
|
|
||||||
|
The top-level `cargo` command delegates to sub-commands named
|
||||||
|
`cargo-foo`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cargo compile
|
||||||
|
# delegates to cargo-compile
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, Cargo will come with a set of built-in commands that don't
|
||||||
|
need to be on the `$PATH`, but additional commands can be added to the
|
||||||
|
`$PATH`.
|
||||||
|
|
||||||
|
There will also be an additional configuration for locating Cargo
|
||||||
|
subcommands that are not on the `$PATH`.
|
||||||
|
|
||||||
|
### Input/Output
|
||||||
|
|
||||||
|
By default, Cargo subcommands are built by implementing the
|
||||||
|
`CargoCommand` trait. This trait will pass structured data to the
|
||||||
|
command.
|
||||||
|
|
||||||
|
By default, commands will communicate with each other via JSON data, and
|
||||||
|
the `CargoCommand` trait will convert the JSON data into the structured
|
||||||
|
data needed by the command. All commands must implement JSON data
|
||||||
|
output.
|
||||||
|
|
||||||
|
Commands must also implement human-readable output, and may implement
|
||||||
|
additional output forms (such as tab- or space-separated output) for use
|
||||||
|
in other scripting languages.
|
||||||
|
|
||||||
|
```rs
|
||||||
|
// The main entry point for new commands to implement
|
||||||
|
trait CargoCommand<T, U> {
|
||||||
|
fn execute<L: CargoLogger>(input: T, logger: L) -> Result<U, CargoErr>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, the raw IPC communication is represented as JSON primitive
|
||||||
|
// values. The ConvertToRaw trait below converts a string protocol into the
|
||||||
|
// Raw format. Obviously, the JSON string protocol can trivially be
|
||||||
|
// converted, but other line protocols need to be defined on a
|
||||||
|
// case-by-case basis.
|
||||||
|
type Raw = serialize::json::Json;
|
||||||
|
type Flags = Map<~str, serialize::json::Json>
|
||||||
|
|
||||||
|
// This is a list of available IPC String protocols. To start, we'll
|
||||||
|
// support JSON and an (optional) arbitrary type-defined line protocol.
|
||||||
|
enum Input {
|
||||||
|
JSONString(~str),
|
||||||
|
LineOrientedString(~str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This trait supports converting any supported input form into Raw.
|
||||||
|
trait ConvertToRaw<Input> {
|
||||||
|
fn convert(input: Input) -> Raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the runner implementation. It will not need to be implemented
|
||||||
|
// by individual commands.
|
||||||
|
fn execute_command<Config, Output, C: CargoCommand, L: Logger>(command: C, config: Config, logger: L) -> Output {
|
||||||
|
match command.execute(input, logger) {
|
||||||
|
Ok(success) => {
|
||||||
|
// serialize success
|
||||||
|
},
|
||||||
|
Err(failure) => {
|
||||||
|
// error handling/output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an example configuration. It is the combination of the Raw
|
||||||
|
// input from a previous command and any flags passed to this command.
|
||||||
|
// Top-level commands will mostly be configured via flags -- plumbing
|
||||||
|
// commands will be mostly configured via Raw.
|
||||||
|
//
|
||||||
|
// Note that because configurations serve as both input and output, and
|
||||||
|
// the ConvertToRaw trait handles both sides of the pipe, these definitions
|
||||||
|
// are not part of an individual command. Some configuration structures
|
||||||
|
// may even be used by multiple different commands.
|
||||||
|
struct CompileConfig {
|
||||||
|
flags: ~[~str],
|
||||||
|
path: ~[~str],
|
||||||
|
lib_path: ~str
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CompileConfigBuilder {
|
||||||
|
flags: Option<~[~str]>,
|
||||||
|
path: Option<~[~str]>,
|
||||||
|
lib_path: Option<~str>
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, configurations manually convert the Flags and Raw into a
|
||||||
|
// single configuration object. This is the main point where a failure
|
||||||
|
// can occur that is not type-checked. All other functions receive the
|
||||||
|
// structured type and will get compiler help.
|
||||||
|
impl CompileConfig {
|
||||||
|
pub fn deserialize(flags: Flags, raw: Raw) -> CompileConfig {
|
||||||
|
CompileConfig{ flags: raw.at("flags"), path: raw.at("path"), lib_path: flags.at("lib_path") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configurations must implement ConvertIntoRaw<JSONString> and may
|
||||||
|
// implement other ConvertIntoRaw converters.
|
||||||
|
impl ConvertToRaw<JSONString> for CompileConfig {
|
||||||
|
fn convert(input: JSONString) -> Raw {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertToRaw<LineOrientedString> for CompileConfig {
|
||||||
|
fn convert(input: LineOrientedString) -> Raw {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertFlags for CompileConfig {
|
||||||
|
fn convert(input: FlagDefinition) -> Flags {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commands are simple objects that implement CargoCommand for a given
|
||||||
|
struct CompileCommand;
|
||||||
|
|
||||||
|
impl CompileCommand {
|
||||||
|
fn new() -> CompileCommand { CompileCommand }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CargoCommand<CompileConfig, CompileOutput> for CompileCommand {
|
||||||
|
fn execute<L: CargoLogger>(input: CompileConfig, logger: L) -> Result<CompileOutput, CargoErr>;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = parse_arguments(f);
|
||||||
|
let config = process_args_and_stdin(args); // { "flags": [ ... ] }
|
||||||
|
let command = CompileCommand::new()
|
||||||
|
let logger = CargoLogger::for(config);
|
||||||
|
let result = execute_command(command, config, logger);
|
||||||
|
|
||||||
|
// deal with serialized output or error
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_args_and_stdin(args: Flags) -> CompileConfig {
|
||||||
|
// delegate to other generic function; Flags tells us which serializer
|
||||||
|
// to use
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
142
DESIGN/MANIFEST.md
Normal file
142
DESIGN/MANIFEST.md
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
The manifest file (`Cargo.toml`) is still under active development. This document captures the current thinking on the design.
|
||||||
|
|
||||||
|
## Sections
|
||||||
|
|
||||||
|
The `Cargo.toml` file contains several top-level sections:
|
||||||
|
|
||||||
|
* `[project]`: project-specific details, such as name, version and author
|
||||||
|
* `[[lib]]`: information about the main library file, if one exists. By
|
||||||
|
default, the main library file is `src/<package-name>.rs`
|
||||||
|
* `[[executable]]`: optionally repeated information about executables
|
||||||
|
that the project is generating. This can both be used for projects
|
||||||
|
that primarily build executables, as well as projects that contain
|
||||||
|
utility executables (such as an HTTP library that comes with a web
|
||||||
|
server executable).
|
||||||
|
|
||||||
|
## Extensibility
|
||||||
|
|
||||||
|
In general, any unknown attributes are ignored for future extensibility.
|
||||||
|
Future plugins may also use this capability.
|
||||||
|
|
||||||
|
The project uses the `Decoder` in `rust-toml` to decode the manifest
|
||||||
|
into Rust structs that are used throughout the built-in commands.
|
||||||
|
|
||||||
|
## The `[project]` Section
|
||||||
|
|
||||||
|
* `name`: the name of the project (`~str`)
|
||||||
|
* `version`: the version of the project, (`~str` that can be parsed
|
||||||
|
via `semver::parse`)
|
||||||
|
* `readme`: a Markdown-formatted file in the project that can be used as
|
||||||
|
a description of the document in indexes (`Option<Path>`, relative to
|
||||||
|
the project root, defaults to "./README.md", if found).
|
||||||
|
* `tags`: an array of tags that can be used in indexes (`~[~str]`)
|
||||||
|
* `authors`: a list of authors in `name <email>` format (`~[~str]`). At
|
||||||
|
least one `author` with email will probably be required to submit to
|
||||||
|
the Cargo repository.
|
||||||
|
* `src`: the root directory containing source files (`Option<Path>`,
|
||||||
|
relative to the project root, defaults to `src`)
|
||||||
|
|
||||||
|
## The `[[lib]]` Section
|
||||||
|
|
||||||
|
At the moment, Cargo only supports a single lib per package. We use the
|
||||||
|
array format for future extensibility.
|
||||||
|
|
||||||
|
We only plan to support a single lib at the moment because if you have
|
||||||
|
multiple libs, you would want projects to be able to depend on them
|
||||||
|
separately. If you don't care about that, why do you have separate libs?
|
||||||
|
|
||||||
|
* `name`: the name of the library (`~str`, `hammer` would create a `libhammer`)
|
||||||
|
* `path`: the location of the main crate file (`Option<Path>`, defaults to
|
||||||
|
`src/<name>.rs`)
|
||||||
|
|
||||||
|
Note that we plan to support multiple `Cargo.toml` files in Cargo's git
|
||||||
|
support, so you don't have to have a separate git repository per
|
||||||
|
library.
|
||||||
|
|
||||||
|
## The `[[executable]]` Section
|
||||||
|
|
||||||
|
The `executable` section is optionally repeated. It is designed for
|
||||||
|
projects whose main raison d'être is a single executable, or for projects
|
||||||
|
that want to provide utility executables alongside a primary library.
|
||||||
|
|
||||||
|
If an executable has a different set of flags or dependencies from the
|
||||||
|
main library, it should be shipped as a separate package with a
|
||||||
|
dependency on the main library to keep the usage requirements of the
|
||||||
|
standalone library limited to the bare minimum requirements.
|
||||||
|
|
||||||
|
* `name`: the name of the executable (`~str`, `hammer` would create a
|
||||||
|
`hammer` executable)
|
||||||
|
* `path`: the location of the main crate file for the executable
|
||||||
|
(`Option<Path>`, defaults to `src/<name>.rs` if the project has only
|
||||||
|
an executable, `src/bin/<name>.rs` if the project has both a lib and
|
||||||
|
executable, see below)
|
||||||
|
|
||||||
|
## Projects Containing Both `lib` and `executable`
|
||||||
|
|
||||||
|
Most projects will primarily produce either a library or an executable.
|
||||||
|
Such projects should name the main crate file `<projectname>.rs` and
|
||||||
|
omit the optional `path` from the `lib` or `executable` sections.
|
||||||
|
|
||||||
|
Projects that contain both a library and one or more executables should
|
||||||
|
generally use `<projectname>.rs` for their library, and `bin/*.rs`
|
||||||
|
for the executables.
|
||||||
|
|
||||||
|
These rules are also the default behavior if `path` is left off of `lib`
|
||||||
|
or `executable` sections.
|
||||||
|
|
||||||
|
## Example Manifests
|
||||||
|
|
||||||
|
Simple `lib`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
|
||||||
|
name = "hammer"
|
||||||
|
version = "0.1.0"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = ["Yehuda Katz <wycats@gmail.com>"]
|
||||||
|
|
||||||
|
[[lib]]
|
||||||
|
|
||||||
|
name = "hammer"
|
||||||
|
```
|
||||||
|
|
||||||
|
Simple `executable`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
|
||||||
|
name = "skylight"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = ["Tom Dale <tom@tomdale.net>", "Carl Lerche <me@carllerche.com>"]
|
||||||
|
tags = ["performance", "profiling"]
|
||||||
|
|
||||||
|
[[executable]]
|
||||||
|
|
||||||
|
name = "skylight"
|
||||||
|
path = "bin/skylight.rs" # supports existing project structures
|
||||||
|
```
|
||||||
|
|
||||||
|
A project with both a lib and an `executable`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
|
||||||
|
name = "skylight"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = ["Tom Dale <tom@tomdale.net>", "Carl Lerche <me@carllerche.com>"]
|
||||||
|
tags = ["performance", "profiling"]
|
||||||
|
|
||||||
|
[[lib]]
|
||||||
|
|
||||||
|
name = "skylight" # path defaults to src/skylight.rs
|
||||||
|
|
||||||
|
[[executable]]
|
||||||
|
|
||||||
|
name = "skylight" # path defaults to src/bin/skylight.rs
|
||||||
|
|
||||||
|
[[executable]]
|
||||||
|
|
||||||
|
name = "skylight-setup" # path defaults to src/bin/skylight-setup.rs
|
||||||
|
```
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user