mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +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