mirror of
https://github.com/rust-lang/cargo
synced 2024-08-28 11:50:23 +00:00
Auto merge of #7375 - ehuss:extract-platform, r=alexcrichton
Extract Platform to a separate crate. This moves the `Platform`, `Cfg`, `CfgExpr` types to a new crate named "cargo-platform". The intent here is to give users of `cargo_metadata` a way of parsing and inspecting cargo's platform values. Along the way, I rewrote the error handling to remove `failure`, and to slightly improve the output. I'm having doubts whether or not this is a good idea. As you can see from the `examples/matches.rs` example, it is nontrivial to use this (which also misses cargo's config values and environment variables). I don't know if anyone will actually use this. If this doesn't seem to have value, I would suggest closing it. I've also included a sample script, `publish.py`, for publishing cargo itself. I suspect it will need tweaking, but I figure it would be a start and open for feedback.
This commit is contained in:
commit
7ab477866e
|
@ -21,6 +21,7 @@ path = "src/cargo/lib.rs"
|
|||
[dependencies]
|
||||
atty = "0.2"
|
||||
bytesize = "1.0"
|
||||
cargo-platform = { path = "crates/cargo-platform", version = "0.1" }
|
||||
crates-io = { path = "crates/crates-io", version = "0.28" }
|
||||
crossbeam-utils = "0.6"
|
||||
crypto-hash = "0.3.1"
|
||||
|
|
|
@ -61,6 +61,8 @@ jobs:
|
|||
displayName: "Check rustfmt (crates-io)"
|
||||
- bash: cd crates/resolver-tests && cargo fmt --all -- --check
|
||||
displayName: "Check rustfmt (resolver-tests)"
|
||||
- bash: cd crates/cargo-platform && cargo fmt --all -- --check
|
||||
displayName: "Check rustfmt (cargo-platform)"
|
||||
variables:
|
||||
TOOLCHAIN: stable
|
||||
|
||||
|
|
|
@ -29,3 +29,6 @@ steps:
|
|||
|
||||
- bash: cargo test -p cargo-test-support
|
||||
displayName: "cargo test -p cargo-test-support"
|
||||
|
||||
- bash: cargo test -p cargo-platform
|
||||
displayName: "cargo test -p cargo-platform"
|
||||
|
|
13
crates/cargo-platform/Cargo.toml
Normal file
13
crates/cargo-platform/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.0"
|
||||
authors = ["The Cargo Project Developers"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
homepage = "https://github.com/rust-lang/cargo"
|
||||
repository = "https://github.com/rust-lang/cargo"
|
||||
documentation = "https://docs.rs/cargo-platform"
|
||||
description = "Cargo's representation of a target platform."
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.82", features = ['derive'] }
|
55
crates/cargo-platform/examples/matches.rs
Normal file
55
crates/cargo-platform/examples/matches.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
//! This example demonstrates how to filter a Platform based on the current
|
||||
//! host target.
|
||||
|
||||
use cargo_platform::{Cfg, Platform};
|
||||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
|
||||
static EXAMPLES: &[&str] = &[
|
||||
"cfg(windows)",
|
||||
"cfg(unix)",
|
||||
"cfg(target_os=\"macos\")",
|
||||
"cfg(target_os=\"linux\")",
|
||||
"cfg(any(target_arch=\"x86\", target_arch=\"x86_64\"))",
|
||||
];
|
||||
|
||||
fn main() {
|
||||
let target = get_target();
|
||||
let cfgs = get_cfgs();
|
||||
println!("host target={} cfgs:", target);
|
||||
for cfg in &cfgs {
|
||||
println!(" {}", cfg);
|
||||
}
|
||||
let mut examples: Vec<&str> = EXAMPLES.iter().copied().collect();
|
||||
examples.push(target.as_str());
|
||||
for example in examples {
|
||||
let p = Platform::from_str(example).unwrap();
|
||||
println!("{:?} matches: {:?}", example, p.matches(&target, &cfgs));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_target() -> String {
|
||||
let output = Command::new("rustc")
|
||||
.arg("-Vv")
|
||||
.output()
|
||||
.expect("rustc failed to run");
|
||||
let stdout = String::from_utf8(output.stdout).unwrap();
|
||||
for line in stdout.lines() {
|
||||
if line.starts_with("host: ") {
|
||||
return String::from(&line[6..]);
|
||||
}
|
||||
}
|
||||
panic!("Failed to find host: {}", stdout);
|
||||
}
|
||||
|
||||
fn get_cfgs() -> Vec<Cfg> {
|
||||
let output = Command::new("rustc")
|
||||
.arg("--print=cfg")
|
||||
.output()
|
||||
.expect("rustc failed to run");
|
||||
let stdout = String::from_utf8(output.stdout).unwrap();
|
||||
stdout
|
||||
.lines()
|
||||
.map(|line| Cfg::from_str(line).unwrap())
|
||||
.collect()
|
||||
}
|
|
@ -1,15 +1,9 @@
|
|||
use crate::error::{ParseError, ParseErrorKind::*};
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::str::{self, FromStr};
|
||||
|
||||
use crate::util::CargoResult;
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)]
|
||||
pub enum Cfg {
|
||||
Name(String),
|
||||
KeyPair(String, String),
|
||||
}
|
||||
|
||||
/// A cfg expression.
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)]
|
||||
pub enum CfgExpr {
|
||||
Not(Box<CfgExpr>),
|
||||
|
@ -18,6 +12,15 @@ pub enum CfgExpr {
|
|||
Value(Cfg),
|
||||
}
|
||||
|
||||
/// A cfg value.
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)]
|
||||
pub enum Cfg {
|
||||
/// A named cfg value, like `unix`.
|
||||
Name(String),
|
||||
/// A key/value cfg pair, like `target_os = "linux"`.
|
||||
KeyPair(String, String),
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Token<'a> {
|
||||
LeftParen,
|
||||
|
@ -28,23 +31,27 @@ enum Token<'a> {
|
|||
String(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Tokenizer<'a> {
|
||||
s: iter::Peekable<str::CharIndices<'a>>,
|
||||
orig: &'a str,
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
t: iter::Peekable<Tokenizer<'a>>,
|
||||
t: Tokenizer<'a>,
|
||||
}
|
||||
|
||||
impl FromStr for Cfg {
|
||||
type Err = failure::Error;
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> CargoResult<Cfg> {
|
||||
fn from_str(s: &str) -> Result<Cfg, Self::Err> {
|
||||
let mut p = Parser::new(s);
|
||||
let e = p.cfg()?;
|
||||
if p.t.next().is_some() {
|
||||
failure::bail!("malformed cfg value or key/value pair: `{}`", s)
|
||||
if let Some(rest) = p.rest() {
|
||||
return Err(ParseError::new(
|
||||
p.t.orig,
|
||||
UnterminatedExpression(rest.to_string()),
|
||||
));
|
||||
}
|
||||
Ok(e)
|
||||
}
|
||||
|
@ -85,16 +92,16 @@ impl CfgExpr {
|
|||
}
|
||||
|
||||
impl FromStr for CfgExpr {
|
||||
type Err = failure::Error;
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> CargoResult<CfgExpr> {
|
||||
fn from_str(s: &str) -> Result<CfgExpr, Self::Err> {
|
||||
let mut p = Parser::new(s);
|
||||
let e = p.expr()?;
|
||||
if p.t.next().is_some() {
|
||||
failure::bail!(
|
||||
"can only have one cfg-expression, consider using all() or \
|
||||
any() explicitly"
|
||||
)
|
||||
if let Some(rest) = p.rest() {
|
||||
return Err(ParseError::new(
|
||||
p.t.orig,
|
||||
UnterminatedExpression(rest.to_string()),
|
||||
));
|
||||
}
|
||||
Ok(e)
|
||||
}
|
||||
|
@ -131,14 +138,13 @@ impl<'a> Parser<'a> {
|
|||
t: Tokenizer {
|
||||
s: s.char_indices().peekable(),
|
||||
orig: s,
|
||||
}
|
||||
.peekable(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn expr(&mut self) -> CargoResult<CfgExpr> {
|
||||
match self.t.peek() {
|
||||
Some(&Ok(Token::Ident(op @ "all"))) | Some(&Ok(Token::Ident(op @ "any"))) => {
|
||||
fn expr(&mut self) -> Result<CfgExpr, ParseError> {
|
||||
match self.peek() {
|
||||
Some(Ok(Token::Ident(op @ "all"))) | Some(Ok(Token::Ident(op @ "any"))) => {
|
||||
self.t.next();
|
||||
let mut e = Vec::new();
|
||||
self.eat(&Token::LeftParen)?;
|
||||
|
@ -155,31 +161,41 @@ impl<'a> Parser<'a> {
|
|||
Ok(CfgExpr::Any(e))
|
||||
}
|
||||
}
|
||||
Some(&Ok(Token::Ident("not"))) => {
|
||||
Some(Ok(Token::Ident("not"))) => {
|
||||
self.t.next();
|
||||
self.eat(&Token::LeftParen)?;
|
||||
let e = self.expr()?;
|
||||
self.eat(&Token::RightParen)?;
|
||||
Ok(CfgExpr::Not(Box::new(e)))
|
||||
}
|
||||
Some(&Ok(..)) => self.cfg().map(CfgExpr::Value),
|
||||
Some(&Err(..)) => Err(self.t.next().unwrap().err().unwrap()),
|
||||
None => failure::bail!(
|
||||
"expected start of a cfg expression, \
|
||||
found nothing"
|
||||
),
|
||||
Some(Ok(..)) => self.cfg().map(CfgExpr::Value),
|
||||
Some(Err(..)) => Err(self.t.next().unwrap().err().unwrap()),
|
||||
None => Err(ParseError::new(
|
||||
self.t.orig,
|
||||
IncompleteExpr("start of a cfg expression"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn cfg(&mut self) -> CargoResult<Cfg> {
|
||||
fn cfg(&mut self) -> Result<Cfg, ParseError> {
|
||||
match self.t.next() {
|
||||
Some(Ok(Token::Ident(name))) => {
|
||||
let e = if self.r#try(&Token::Equals) {
|
||||
let val = match self.t.next() {
|
||||
Some(Ok(Token::String(s))) => s,
|
||||
Some(Ok(t)) => failure::bail!("expected a string, found {}", t.classify()),
|
||||
Some(Ok(t)) => {
|
||||
return Err(ParseError::new(
|
||||
self.t.orig,
|
||||
UnexpectedToken {
|
||||
expected: "a string",
|
||||
found: t.classify(),
|
||||
},
|
||||
))
|
||||
}
|
||||
Some(Err(e)) => return Err(e),
|
||||
None => failure::bail!("expected a string, found nothing"),
|
||||
None => {
|
||||
return Err(ParseError::new(self.t.orig, IncompleteExpr("a string")))
|
||||
}
|
||||
};
|
||||
Cfg::KeyPair(name.to_string(), val.to_string())
|
||||
} else {
|
||||
|
@ -187,35 +203,66 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
Ok(e)
|
||||
}
|
||||
Some(Ok(t)) => failure::bail!("expected identifier, found {}", t.classify()),
|
||||
Some(Ok(t)) => Err(ParseError::new(
|
||||
self.t.orig,
|
||||
UnexpectedToken {
|
||||
expected: "identifier",
|
||||
found: t.classify(),
|
||||
},
|
||||
)),
|
||||
Some(Err(e)) => Err(e),
|
||||
None => failure::bail!("expected identifier, found nothing"),
|
||||
None => Err(ParseError::new(self.t.orig, IncompleteExpr("identifier"))),
|
||||
}
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> Option<Result<Token<'a>, ParseError>> {
|
||||
self.t.clone().next()
|
||||
}
|
||||
|
||||
fn r#try(&mut self, token: &Token<'a>) -> bool {
|
||||
match self.t.peek() {
|
||||
Some(&Ok(ref t)) if token == t => {}
|
||||
match self.peek() {
|
||||
Some(Ok(ref t)) if token == t => {}
|
||||
_ => return false,
|
||||
}
|
||||
self.t.next();
|
||||
true
|
||||
}
|
||||
|
||||
fn eat(&mut self, token: &Token<'a>) -> CargoResult<()> {
|
||||
fn eat(&mut self, token: &Token<'a>) -> Result<(), ParseError> {
|
||||
match self.t.next() {
|
||||
Some(Ok(ref t)) if token == t => Ok(()),
|
||||
Some(Ok(t)) => failure::bail!("expected {}, found {}", token.classify(), t.classify()),
|
||||
Some(Ok(t)) => Err(ParseError::new(
|
||||
self.t.orig,
|
||||
UnexpectedToken {
|
||||
expected: token.classify(),
|
||||
found: t.classify(),
|
||||
},
|
||||
)),
|
||||
Some(Err(e)) => Err(e),
|
||||
None => failure::bail!("expected {}, but cfg expr ended", token.classify()),
|
||||
None => Err(ParseError::new(
|
||||
self.t.orig,
|
||||
IncompleteExpr(token.classify()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the rest of the input from the current location.
|
||||
fn rest(&self) -> Option<&str> {
|
||||
let mut s = self.t.s.clone();
|
||||
loop {
|
||||
match s.next() {
|
||||
Some((_, ' ')) => {}
|
||||
Some((start, _ch)) => return Some(&self.t.orig[start..]),
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Tokenizer<'a> {
|
||||
type Item = CargoResult<Token<'a>>;
|
||||
type Item = Result<Token<'a>, ParseError>;
|
||||
|
||||
fn next(&mut self) -> Option<CargoResult<Token<'a>>> {
|
||||
fn next(&mut self) -> Option<Result<Token<'a>, ParseError>> {
|
||||
loop {
|
||||
match self.s.next() {
|
||||
Some((_, ' ')) => {}
|
||||
|
@ -229,7 +276,7 @@ impl<'a> Iterator for Tokenizer<'a> {
|
|||
return Some(Ok(Token::String(&self.orig[start + 1..end])));
|
||||
}
|
||||
}
|
||||
return Some(Err(failure::format_err!("unterminated string in cfg")));
|
||||
return Some(Err(ParseError::new(self.orig, UnterminatedString)));
|
||||
}
|
||||
Some((start, ch)) if is_ident_start(ch) => {
|
||||
while let Some(&(end, ch)) = self.s.peek() {
|
||||
|
@ -242,13 +289,7 @@ impl<'a> Iterator for Tokenizer<'a> {
|
|||
return Some(Ok(Token::Ident(&self.orig[start..])));
|
||||
}
|
||||
Some((_, ch)) => {
|
||||
return Some(Err(failure::format_err!(
|
||||
"unexpected character in \
|
||||
cfg `{}`, expected parens, \
|
||||
a comma, an identifier, or \
|
||||
a string",
|
||||
ch
|
||||
)));
|
||||
return Some(Err(ParseError::new(self.orig, UnexpectedChar(ch))));
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
|
@ -265,7 +306,7 @@ fn is_ident_rest(ch: char) -> bool {
|
|||
}
|
||||
|
||||
impl<'a> Token<'a> {
|
||||
fn classify(&self) -> &str {
|
||||
fn classify(&self) -> &'static str {
|
||||
match *self {
|
||||
Token::LeftParen => "`(`",
|
||||
Token::RightParen => "`)`",
|
70
crates/cargo-platform/src/error.rs
Normal file
70
crates/cargo-platform/src/error.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseError {
|
||||
kind: ParseErrorKind,
|
||||
orig: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseErrorKind {
|
||||
UnterminatedString,
|
||||
UnexpectedChar(char),
|
||||
UnexpectedToken {
|
||||
expected: &'static str,
|
||||
found: &'static str,
|
||||
},
|
||||
IncompleteExpr(&'static str),
|
||||
UnterminatedExpression(String),
|
||||
InvalidTarget(String),
|
||||
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"failed to parse `{}` as a cfg expression: {}",
|
||||
self.orig, self.kind
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseErrorKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use ParseErrorKind::*;
|
||||
match self {
|
||||
UnterminatedString => write!(f, "unterminated string in cfg"),
|
||||
UnexpectedChar(ch) => write!(
|
||||
f,
|
||||
"unexpected character `{}` in cfg, expected parens, a comma, \
|
||||
an identifier, or a string",
|
||||
ch
|
||||
),
|
||||
UnexpectedToken { expected, found } => {
|
||||
write!(f, "expected {}, found {}", expected, found)
|
||||
}
|
||||
IncompleteExpr(expected) => {
|
||||
write!(f, "expected {}, but cfg expression ended", expected)
|
||||
}
|
||||
UnterminatedExpression(s) => {
|
||||
write!(f, "unexpected content `{}` found after cfg expression", s)
|
||||
}
|
||||
InvalidTarget(s) => write!(f, "invalid target specifier: {}", s),
|
||||
__Nonexhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseError {}
|
||||
|
||||
impl ParseError {
|
||||
pub fn new(orig: &str, kind: ParseErrorKind) -> ParseError {
|
||||
ParseError {
|
||||
kind,
|
||||
orig: orig.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
106
crates/cargo-platform/src/lib.rs
Normal file
106
crates/cargo-platform/src/lib.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
//! Platform definition used by Cargo.
|
||||
//!
|
||||
//! This defines a [`Platform`] type which is used in Cargo to specify a target platform.
|
||||
//! There are two kinds, a named target like `x86_64-apple-darwin`, and a "cfg expression"
|
||||
//! like `cfg(any(target_os = "macos", target_os = "ios"))`.
|
||||
//!
|
||||
//! See `examples/matches.rs` for an example of how to match against a `Platform`.
|
||||
//!
|
||||
//! [`Platform`]: enum.Platform.html
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
mod cfg;
|
||||
mod error;
|
||||
|
||||
pub use cfg::{Cfg, CfgExpr};
|
||||
pub use error::{ParseError, ParseErrorKind};
|
||||
|
||||
/// Platform definition.
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)]
|
||||
pub enum Platform {
|
||||
/// A named platform, like `x86_64-apple-darwin`.
|
||||
Name(String),
|
||||
/// A cfg expression, like `cfg(windows)`.
|
||||
Cfg(CfgExpr),
|
||||
}
|
||||
|
||||
impl Platform {
|
||||
/// Returns whether the Platform matches the given target and cfg.
|
||||
///
|
||||
/// The named target and cfg values should be obtained from `rustc`.
|
||||
pub fn matches(&self, name: &str, cfg: &[Cfg]) -> bool {
|
||||
match *self {
|
||||
Platform::Name(ref p) => p == name,
|
||||
Platform::Cfg(ref p) => p.matches(cfg),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_named_platform(name: &str) -> Result<(), ParseError> {
|
||||
if let Some(ch) = name
|
||||
.chars()
|
||||
.find(|&c| !(c.is_alphanumeric() || c == '_' || c == '-' || c == '.'))
|
||||
{
|
||||
if name.chars().any(|c| c == '(') {
|
||||
return Err(ParseError::new(
|
||||
name,
|
||||
ParseErrorKind::InvalidTarget(
|
||||
"unexpected `(` character, cfg expressions must start with `cfg(`"
|
||||
.to_string(),
|
||||
),
|
||||
));
|
||||
}
|
||||
return Err(ParseError::new(
|
||||
name,
|
||||
ParseErrorKind::InvalidTarget(format!(
|
||||
"unexpected character {} in target name",
|
||||
ch
|
||||
)),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for Platform {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.to_string().serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Platform {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
FromStr::from_str(&s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Platform {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Platform, ParseError> {
|
||||
if s.starts_with("cfg(") && s.ends_with(')') {
|
||||
let s = &s[4..s.len() - 1];
|
||||
s.parse().map(Platform::Cfg)
|
||||
} else {
|
||||
Platform::validate_named_platform(s)?;
|
||||
Ok(Platform::Name(s.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Platform {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Platform::Name(ref n) => n.fmt(f),
|
||||
Platform::Cfg(ref e) => write!(f, "cfg({})", e),
|
||||
}
|
||||
}
|
||||
}
|
178
crates/cargo-platform/tests/test_cfg.rs
Normal file
178
crates/cargo-platform/tests/test_cfg.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
use cargo_platform::{Cfg, CfgExpr, Platform};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
macro_rules! c {
|
||||
($a:ident) => {
|
||||
Cfg::Name(stringify!($a).to_string())
|
||||
};
|
||||
($a:ident = $e:expr) => {
|
||||
Cfg::KeyPair(stringify!($a).to_string(), $e.to_string())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! e {
|
||||
(any($($t:tt),*)) => (CfgExpr::Any(vec![$(e!($t)),*]));
|
||||
(all($($t:tt),*)) => (CfgExpr::All(vec![$(e!($t)),*]));
|
||||
(not($($t:tt)*)) => (CfgExpr::Not(Box::new(e!($($t)*))));
|
||||
(($($t:tt)*)) => (e!($($t)*));
|
||||
($($t:tt)*) => (CfgExpr::Value(c!($($t)*)));
|
||||
}
|
||||
|
||||
fn good<T>(s: &str, expected: T)
|
||||
where
|
||||
T: FromStr + PartialEq + fmt::Debug,
|
||||
T::Err: fmt::Display,
|
||||
{
|
||||
let c = match T::from_str(s) {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("failed to parse `{}`: {}", s, e),
|
||||
};
|
||||
assert_eq!(c, expected);
|
||||
}
|
||||
|
||||
fn bad<T>(s: &str, err: &str)
|
||||
where
|
||||
T: FromStr + fmt::Display,
|
||||
T::Err: fmt::Display,
|
||||
{
|
||||
let e = match T::from_str(s) {
|
||||
Ok(cfg) => panic!("expected `{}` to not parse but got {}", s, cfg),
|
||||
Err(e) => e.to_string(),
|
||||
};
|
||||
assert!(
|
||||
e.contains(err),
|
||||
"when parsing `{}`,\n\"{}\" not contained \
|
||||
inside: {}",
|
||||
s,
|
||||
err,
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_syntax() {
|
||||
good("foo", c!(foo));
|
||||
good("_bar", c!(_bar));
|
||||
good(" foo", c!(foo));
|
||||
good(" foo ", c!(foo));
|
||||
good(" foo = \"bar\"", c!(foo = "bar"));
|
||||
good("foo=\"\"", c!(foo = ""));
|
||||
good(" foo=\"3\" ", c!(foo = "3"));
|
||||
good("foo = \"3 e\"", c!(foo = "3 e"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_syntax_bad() {
|
||||
bad::<Cfg>("", "but cfg expression ended");
|
||||
bad::<Cfg>(" ", "but cfg expression ended");
|
||||
bad::<Cfg>("\t", "unexpected character");
|
||||
bad::<Cfg>("7", "unexpected character");
|
||||
bad::<Cfg>("=", "expected identifier");
|
||||
bad::<Cfg>(",", "expected identifier");
|
||||
bad::<Cfg>("(", "expected identifier");
|
||||
bad::<Cfg>("foo (", "unexpected content `(` found after cfg expression");
|
||||
bad::<Cfg>("bar =", "expected a string");
|
||||
bad::<Cfg>("bar = \"", "unterminated string");
|
||||
bad::<Cfg>(
|
||||
"foo, bar",
|
||||
"unexpected content `, bar` found after cfg expression",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_expr() {
|
||||
good("foo", e!(foo));
|
||||
good("_bar", e!(_bar));
|
||||
good(" foo", e!(foo));
|
||||
good(" foo ", e!(foo));
|
||||
good(" foo = \"bar\"", e!(foo = "bar"));
|
||||
good("foo=\"\"", e!(foo = ""));
|
||||
good(" foo=\"3\" ", e!(foo = "3"));
|
||||
good("foo = \"3 e\"", e!(foo = "3 e"));
|
||||
|
||||
good("all()", e!(all()));
|
||||
good("all(a)", e!(all(a)));
|
||||
good("all(a, b)", e!(all(a, b)));
|
||||
good("all(a, )", e!(all(a)));
|
||||
good("not(a = \"b\")", e!(not(a = "b")));
|
||||
good("not(all(a))", e!(not(all(a))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_expr_bad() {
|
||||
bad::<CfgExpr>(" ", "but cfg expression ended");
|
||||
bad::<CfgExpr>(" all", "expected `(`");
|
||||
bad::<CfgExpr>("all(a", "expected `)`");
|
||||
bad::<CfgExpr>("not", "expected `(`");
|
||||
bad::<CfgExpr>("not(a", "expected `)`");
|
||||
bad::<CfgExpr>("a = ", "expected a string");
|
||||
bad::<CfgExpr>("all(not())", "expected identifier");
|
||||
bad::<CfgExpr>(
|
||||
"foo(a)",
|
||||
"unexpected content `(a)` found after cfg expression",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_matches() {
|
||||
assert!(e!(foo).matches(&[c!(bar), c!(foo), c!(baz)]));
|
||||
assert!(e!(any(foo)).matches(&[c!(bar), c!(foo), c!(baz)]));
|
||||
assert!(e!(any(foo, bar)).matches(&[c!(bar)]));
|
||||
assert!(e!(any(foo, bar)).matches(&[c!(foo)]));
|
||||
assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
|
||||
assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
|
||||
assert!(e!(not(foo)).matches(&[c!(bar)]));
|
||||
assert!(e!(not(foo)).matches(&[]));
|
||||
assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(bar)]));
|
||||
assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo), c!(bar)]));
|
||||
|
||||
assert!(!e!(foo).matches(&[]));
|
||||
assert!(!e!(foo).matches(&[c!(bar)]));
|
||||
assert!(!e!(foo).matches(&[c!(fo)]));
|
||||
assert!(!e!(any(foo)).matches(&[]));
|
||||
assert!(!e!(any(foo)).matches(&[c!(bar)]));
|
||||
assert!(!e!(any(foo)).matches(&[c!(bar), c!(baz)]));
|
||||
assert!(!e!(all(foo)).matches(&[c!(bar), c!(baz)]));
|
||||
assert!(!e!(all(foo, bar)).matches(&[c!(bar)]));
|
||||
assert!(!e!(all(foo, bar)).matches(&[c!(foo)]));
|
||||
assert!(!e!(all(foo, bar)).matches(&[]));
|
||||
assert!(!e!(not(bar)).matches(&[c!(bar)]));
|
||||
assert!(!e!(not(bar)).matches(&[c!(baz), c!(bar)]));
|
||||
assert!(!e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_target_name() {
|
||||
bad::<Platform>(
|
||||
"any(cfg(unix), cfg(windows))",
|
||||
"failed to parse `any(cfg(unix), cfg(windows))` as a cfg expression: \
|
||||
invalid target specifier: unexpected `(` character, \
|
||||
cfg expressions must start with `cfg(`",
|
||||
);
|
||||
bad::<Platform>(
|
||||
"!foo",
|
||||
"failed to parse `!foo` as a cfg expression: \
|
||||
invalid target specifier: unexpected character ! in target name",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_platform() {
|
||||
fn rt(s: &str) {
|
||||
let p = Platform::from_str(s).unwrap();
|
||||
let s2 = p.to_string();
|
||||
let p2 = Platform::from_str(&s2).unwrap();
|
||||
assert_eq!(p, p2);
|
||||
}
|
||||
rt("x86_64-apple-darwin");
|
||||
rt("foo");
|
||||
rt("cfg(windows)");
|
||||
rt("cfg(target_os = \"windows\")");
|
||||
rt(
|
||||
"cfg(any(all(any(target_os = \"android\", target_os = \"linux\"), \
|
||||
any(target_arch = \"aarch64\", target_arch = \"arm\", target_arch = \"powerpc64\", \
|
||||
target_arch = \"x86\", target_arch = \"x86_64\")), \
|
||||
all(target_os = \"freebsd\", target_arch = \"x86_64\")))",
|
||||
);
|
||||
}
|
50
publish.py
Executable file
50
publish.py
Executable file
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# This script is used to publish Cargo to crates.io.
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import urllib.request
|
||||
from urllib.error import HTTPError
|
||||
|
||||
|
||||
TO_PUBLISH = [
|
||||
'crates/cargo-platform',
|
||||
'crates/crates-io',
|
||||
'.',
|
||||
]
|
||||
|
||||
|
||||
def already_published(name, version):
|
||||
try:
|
||||
urllib.request.urlopen('https://crates.io/api/v1/crates/%s/%s/download' % (name, version))
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
return False
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def maybe_publish(path):
|
||||
content = open(os.path.join(path, 'Cargo.toml')).read()
|
||||
name = re.search('^name = "([^"]+)"', content, re.M).group(1)
|
||||
version = re.search('^version = "([^"]+)"', content, re.M).group(1)
|
||||
if already_published(name, version):
|
||||
print('%s %s is already published, skipping' % (name, version))
|
||||
return
|
||||
subprocess.check_call(['cargo', 'publish', '--no-verify'], cwd=path)
|
||||
|
||||
|
||||
def main():
|
||||
print('Doing dry run first...')
|
||||
for path in TO_PUBLISH:
|
||||
subprocess.check_call(['cargo', 'publish', '--no-verify', '--dry-run'], cwd=path)
|
||||
print('Starting publish...')
|
||||
for path in TO_PUBLISH:
|
||||
maybe_publish(path)
|
||||
print('Publish complete!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
|
||||
use cargo_platform::Cfg;
|
||||
use log::debug;
|
||||
|
||||
use crate::core::compiler::unit::UnitInterner;
|
||||
|
@ -10,7 +11,7 @@ use crate::core::profiles::Profiles;
|
|||
use crate::core::{Dependency, Workspace};
|
||||
use crate::core::{PackageId, PackageSet};
|
||||
use crate::util::errors::CargoResult;
|
||||
use crate::util::{profile, Cfg, Config, Rustc};
|
||||
use crate::util::{profile, Config, Rustc};
|
||||
|
||||
mod target_info;
|
||||
pub use self::target_info::{FileFlavor, TargetInfo};
|
||||
|
|
|
@ -6,8 +6,8 @@ use std::str::{self, FromStr};
|
|||
|
||||
use crate::core::compiler::Kind;
|
||||
use crate::core::TargetKind;
|
||||
use crate::util::CfgExpr;
|
||||
use crate::util::{CargoResult, CargoResultExt, Cfg, Config, ProcessBuilder, Rustc};
|
||||
use crate::util::{CargoResult, CargoResultExt, Config, ProcessBuilder, Rustc};
|
||||
use cargo_platform::{Cfg, CfgExpr};
|
||||
|
||||
/// Information about the platform target gleaned from querying rustc.
|
||||
///
|
||||
|
@ -171,7 +171,7 @@ impl TargetInfo {
|
|||
};
|
||||
|
||||
let cfg = lines
|
||||
.map(Cfg::from_str)
|
||||
.map(|line| Ok(Cfg::from_str(line)?))
|
||||
.collect::<CargoResult<Vec<_>>>()
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
|
|
|
@ -3,13 +3,12 @@ use std::env;
|
|||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use cargo_platform::CfgExpr;
|
||||
use semver::Version;
|
||||
|
||||
use super::BuildContext;
|
||||
use crate::core::{Edition, InternedString, Package, PackageId, Target};
|
||||
use crate::util::{
|
||||
self, join_paths, process, rustc::Rustc, CargoResult, CfgExpr, Config, ProcessBuilder,
|
||||
};
|
||||
use crate::util::{self, join_paths, process, rustc::Rustc, CargoResult, Config, ProcessBuilder};
|
||||
|
||||
pub struct Doctest {
|
||||
/// The package being doc-tested.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use cargo_platform::Cfg;
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -8,7 +9,6 @@ use crate::core::compiler::job_queue::JobState;
|
|||
use crate::core::PackageId;
|
||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||
use crate::util::machine_message::{self, Message};
|
||||
use crate::util::Cfg;
|
||||
use crate::util::{self, internal, paths, profile};
|
||||
|
||||
use super::job::{Freshness, Job, Work};
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use cargo_platform::Platform;
|
||||
use log::trace;
|
||||
use semver::ReqParseError;
|
||||
use semver::VersionReq;
|
||||
use serde::ser;
|
||||
use serde::Serialize;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::core::interning::InternedString;
|
||||
use crate::core::{PackageId, SourceId, Summary};
|
||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||
use crate::util::{Cfg, CfgExpr, Config};
|
||||
use crate::util::Config;
|
||||
|
||||
/// Information about a dependency requested by a Cargo manifest.
|
||||
/// Cheap to copy.
|
||||
|
@ -48,12 +46,6 @@ struct Inner {
|
|||
platform: Option<Platform>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)]
|
||||
pub enum Platform {
|
||||
Name(String),
|
||||
Cfg(CfgExpr),
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SerializedDependency<'a> {
|
||||
name: &'a str,
|
||||
|
@ -459,46 +451,3 @@ impl Dependency {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Platform {
|
||||
pub fn matches(&self, name: &str, cfg: &[Cfg]) -> bool {
|
||||
match *self {
|
||||
Platform::Name(ref p) => p == name,
|
||||
Platform::Cfg(ref p) => p.matches(cfg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Serialize for Platform {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ser::Serializer,
|
||||
{
|
||||
self.to_string().serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Platform {
|
||||
type Err = failure::Error;
|
||||
|
||||
fn from_str(s: &str) -> CargoResult<Platform> {
|
||||
if s.starts_with("cfg(") && s.ends_with(')') {
|
||||
let s = &s[4..s.len() - 1];
|
||||
let p = s.parse().map(Platform::Cfg).chain_err(|| {
|
||||
failure::format_err!("failed to parse `{}` as a cfg expression", s)
|
||||
})?;
|
||||
Ok(p)
|
||||
} else {
|
||||
Ok(Platform::Name(s.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Platform {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Platform::Name(ref n) => n.fmt(f),
|
||||
Platform::Cfg(ref e) => write!(f, "cfg({})", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
pub use self::canonical_url::CanonicalUrl;
|
||||
pub use self::cfg::{Cfg, CfgExpr};
|
||||
pub use self::config::{homedir, Config, ConfigValue};
|
||||
pub use self::dependency_queue::DependencyQueue;
|
||||
pub use self::diagnostic_server::RustfixDiagnosticServer;
|
||||
|
@ -30,7 +29,6 @@ pub use self::workspace::{
|
|||
};
|
||||
|
||||
mod canonical_url;
|
||||
mod cfg;
|
||||
pub mod command_prelude;
|
||||
pub mod config;
|
||||
pub mod cpu;
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
|
|||
use std::rc::Rc;
|
||||
use std::str;
|
||||
|
||||
use cargo_platform::Platform;
|
||||
use failure::bail;
|
||||
use log::{debug, trace};
|
||||
use semver::{self, VersionReq};
|
||||
|
@ -13,7 +14,7 @@ use serde::ser;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::core::dependency::{Kind, Platform};
|
||||
use crate::core::dependency::Kind;
|
||||
use crate::core::manifest::{LibKind, ManifestMetadata, TargetSourcePath, Warnings};
|
||||
use crate::core::profiles::Profiles;
|
||||
use crate::core::{Dependency, InternedString, Manifest, PackageId, Summary, Target};
|
||||
|
|
|
@ -1,145 +1,7 @@
|
|||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use cargo::util::{Cfg, CfgExpr};
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::rustc_host;
|
||||
use cargo_test_support::{basic_manifest, project};
|
||||
|
||||
macro_rules! c {
|
||||
($a:ident) => {
|
||||
Cfg::Name(stringify!($a).to_string())
|
||||
};
|
||||
($a:ident = $e:expr) => {
|
||||
Cfg::KeyPair(stringify!($a).to_string(), $e.to_string())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! e {
|
||||
(any($($t:tt),*)) => (CfgExpr::Any(vec![$(e!($t)),*]));
|
||||
(all($($t:tt),*)) => (CfgExpr::All(vec![$(e!($t)),*]));
|
||||
(not($($t:tt)*)) => (CfgExpr::Not(Box::new(e!($($t)*))));
|
||||
(($($t:tt)*)) => (e!($($t)*));
|
||||
($($t:tt)*) => (CfgExpr::Value(c!($($t)*)));
|
||||
}
|
||||
|
||||
fn good<T>(s: &str, expected: T)
|
||||
where
|
||||
T: FromStr + PartialEq + fmt::Debug,
|
||||
T::Err: fmt::Display,
|
||||
{
|
||||
let c = match T::from_str(s) {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("failed to parse `{}`: {}", s, e),
|
||||
};
|
||||
assert_eq!(c, expected);
|
||||
}
|
||||
|
||||
fn bad<T>(s: &str, err: &str)
|
||||
where
|
||||
T: FromStr + fmt::Display,
|
||||
T::Err: fmt::Display,
|
||||
{
|
||||
let e = match T::from_str(s) {
|
||||
Ok(cfg) => panic!("expected `{}` to not parse but got {}", s, cfg),
|
||||
Err(e) => e.to_string(),
|
||||
};
|
||||
assert!(
|
||||
e.contains(err),
|
||||
"when parsing `{}`,\n\"{}\" not contained \
|
||||
inside: {}",
|
||||
s,
|
||||
err,
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cfg_syntax() {
|
||||
good("foo", c!(foo));
|
||||
good("_bar", c!(_bar));
|
||||
good(" foo", c!(foo));
|
||||
good(" foo ", c!(foo));
|
||||
good(" foo = \"bar\"", c!(foo = "bar"));
|
||||
good("foo=\"\"", c!(foo = ""));
|
||||
good(" foo=\"3\" ", c!(foo = "3"));
|
||||
good("foo = \"3 e\"", c!(foo = "3 e"));
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cfg_syntax_bad() {
|
||||
bad::<Cfg>("", "found nothing");
|
||||
bad::<Cfg>(" ", "found nothing");
|
||||
bad::<Cfg>("\t", "unexpected character");
|
||||
bad::<Cfg>("7", "unexpected character");
|
||||
bad::<Cfg>("=", "expected identifier");
|
||||
bad::<Cfg>(",", "expected identifier");
|
||||
bad::<Cfg>("(", "expected identifier");
|
||||
bad::<Cfg>("foo (", "malformed cfg value");
|
||||
bad::<Cfg>("bar =", "expected a string");
|
||||
bad::<Cfg>("bar = \"", "unterminated string");
|
||||
bad::<Cfg>("foo, bar", "malformed cfg value");
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cfg_expr() {
|
||||
good("foo", e!(foo));
|
||||
good("_bar", e!(_bar));
|
||||
good(" foo", e!(foo));
|
||||
good(" foo ", e!(foo));
|
||||
good(" foo = \"bar\"", e!(foo = "bar"));
|
||||
good("foo=\"\"", e!(foo = ""));
|
||||
good(" foo=\"3\" ", e!(foo = "3"));
|
||||
good("foo = \"3 e\"", e!(foo = "3 e"));
|
||||
|
||||
good("all()", e!(all()));
|
||||
good("all(a)", e!(all(a)));
|
||||
good("all(a, b)", e!(all(a, b)));
|
||||
good("all(a, )", e!(all(a)));
|
||||
good("not(a = \"b\")", e!(not(a = "b")));
|
||||
good("not(all(a))", e!(not(all(a))));
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cfg_expr_bad() {
|
||||
bad::<CfgExpr>(" ", "found nothing");
|
||||
bad::<CfgExpr>(" all", "expected `(`");
|
||||
bad::<CfgExpr>("all(a", "expected `)`");
|
||||
bad::<CfgExpr>("not", "expected `(`");
|
||||
bad::<CfgExpr>("not(a", "expected `)`");
|
||||
bad::<CfgExpr>("a = ", "expected a string");
|
||||
bad::<CfgExpr>("all(not())", "expected identifier");
|
||||
bad::<CfgExpr>("foo(a)", "consider using all() or any() explicitly");
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cfg_matches() {
|
||||
assert!(e!(foo).matches(&[c!(bar), c!(foo), c!(baz)]));
|
||||
assert!(e!(any(foo)).matches(&[c!(bar), c!(foo), c!(baz)]));
|
||||
assert!(e!(any(foo, bar)).matches(&[c!(bar)]));
|
||||
assert!(e!(any(foo, bar)).matches(&[c!(foo)]));
|
||||
assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
|
||||
assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
|
||||
assert!(e!(not(foo)).matches(&[c!(bar)]));
|
||||
assert!(e!(not(foo)).matches(&[]));
|
||||
assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(bar)]));
|
||||
assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo), c!(bar)]));
|
||||
|
||||
assert!(!e!(foo).matches(&[]));
|
||||
assert!(!e!(foo).matches(&[c!(bar)]));
|
||||
assert!(!e!(foo).matches(&[c!(fo)]));
|
||||
assert!(!e!(any(foo)).matches(&[]));
|
||||
assert!(!e!(any(foo)).matches(&[c!(bar)]));
|
||||
assert!(!e!(any(foo)).matches(&[c!(bar), c!(baz)]));
|
||||
assert!(!e!(all(foo)).matches(&[c!(bar), c!(baz)]));
|
||||
assert!(!e!(all(foo, bar)).matches(&[c!(bar)]));
|
||||
assert!(!e!(all(foo, bar)).matches(&[c!(foo)]));
|
||||
assert!(!e!(all(foo, bar)).matches(&[]));
|
||||
assert!(!e!(not(bar)).matches(&[c!(bar)]));
|
||||
assert!(!e!(not(bar)).matches(&[c!(baz), c!(bar)]));
|
||||
assert!(!e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo)]));
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cfg_easy() {
|
||||
let p = project()
|
||||
|
@ -311,10 +173,7 @@ fn bad_target_spec() {
|
|||
[ERROR] failed to parse manifest at `[..]`
|
||||
|
||||
Caused by:
|
||||
failed to parse `4` as a cfg expression
|
||||
|
||||
Caused by:
|
||||
unexpected character in cfg `4`, [..]
|
||||
failed to parse `4` as a cfg expression: unexpected character `4` in cfg, [..]
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
@ -345,10 +204,7 @@ fn bad_target_spec2() {
|
|||
[ERROR] failed to parse manifest at `[..]`
|
||||
|
||||
Caused by:
|
||||
failed to parse `bar =` as a cfg expression
|
||||
|
||||
Caused by:
|
||||
expected a string, found nothing
|
||||
failed to parse `bar =` as a cfg expression: expected a string, but cfg expression ended
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
@ -576,7 +432,8 @@ command was: `[..]compiler[..]--crate-type [..]`
|
|||
|
||||
|
||||
Caused by:
|
||||
unexpected character in cfg `1`, expected parens, a comma, an identifier, or a string
|
||||
failed to parse `123` as a cfg expression: unexpected character `1` in cfg, \
|
||||
expected parens, a comma, an identifier, or a string
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
|
Loading…
Reference in a new issue