From 95b3689b34035a0c3d7831441c1eae0904903351 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Mon, 5 Aug 2013 21:15:55 +0400 Subject: [PATCH 01/18] Implement FromStr for IpAddr and SocketAddr Better than that in rt::uv::net, because it: * handles invalid input explicitly, without fail!() * parses socket address, not just IP * handles various ipv4-in-ipv6 addresses, like 2001:db8:122:344::192.0.2.33 (see http://tools.ietf.org/html/rfc6052 for example) * rejects output like `127.0000000.0.1` * does not allocate heap memory * have unit tests --- src/libstd/rt/io/net/ip.rs | 365 +++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 815ec9b5c61ec..81269d197d501 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -9,7 +9,11 @@ // except according to those terms. use num::FromStrRadix; +use vec::MutableCloneableVector; use to_str::ToStr; +use from_str::FromStr; +use option::{Option, None, Some}; + type Port = u16; @@ -73,3 +77,364 @@ impl ToStr for SocketAddr { } } } + +struct Parser<'self> { + // parsing as ASCII, so can use byte array + s: &'self [u8], + pos: uint, +} + +impl<'self> Parser<'self> { + fn new(s: &'self str) -> Parser<'self> { + Parser { + s: s.as_bytes(), + pos: 0, + } + } + + fn is_eof(&self) -> bool { + self.pos == self.s.len() + } + + // Commit only if parser returns Some + fn read_atomically(&mut self, cb: &fn(&mut Parser) -> Option) -> Option { + let pos = self.pos; + let r = cb(self); + if r.is_none() { + self.pos = pos; + } + r + } + + // Commit only if parser read till EOF + fn read_till_eof(&mut self, cb: &fn(&mut Parser) -> Option) -> Option { + do self.read_atomically |p| { + cb(p).filtered(|_| p.is_eof()) + } + } + + // Return result of first successful parser + fn read_or(&mut self, parsers: &[&fn(&mut Parser) -> Option]) -> Option { + for pf in parsers.iter() { + match self.read_atomically(|p: &mut Parser| (*pf)(p)) { + Some(r) => return Some(r), + None => {} + } + } + None + } + + // Apply 3 parsers sequentially + fn read_seq_3(&mut self, + pa: &fn(&mut Parser) -> Option, + pb: &fn(&mut Parser) -> Option, + pc: &fn(&mut Parser) -> Option + ) -> Option<(A, B, C)> + { + do self.read_atomically |p| { + let a = pa(p); + let b = if a.is_some() { pb(p) } else { None }; + let c = if b.is_some() { pc(p) } else { None }; + match (a, b, c) { + (Some(a), Some(b), Some(c)) => Some((a, b, c)), + _ => None + } + } + } + + // Read next char + fn read_char(&mut self) -> Option { + if self.is_eof() { + None + } else { + let r = self.s[self.pos] as char; + self.pos += 1; + Some(r) + } + } + + // Return char and advance iff next char is equal to requested + fn read_given_char(&mut self, c: char) -> Option { + do self.read_atomically |p| { + p.read_char().filtered(|&next| next == c) + } + } + + // Read digit + fn read_digit(&mut self, radix: u8) -> Option { + fn parse_digit(c: char, radix: u8) -> Option { + // assuming radix is either 10 or 16 + if c >= '0' && c <= '9' { + Some((c - '0') as u8) + } else if radix > 10 && c >= 'a' && c < 'a' + (radix - 10) as char { + Some((c - 'a' + (10 as char)) as u8) + } else if radix > 10 && c >= 'A' && c < 'A' + (radix - 10) as char { + Some((c - 'A' + (10 as char)) as u8) + } else { + None + } + } + + do self.read_atomically |p| { + p.read_char().chain(|c| parse_digit(c, radix)) + } + } + + fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { + let mut r = 0u32; + let mut digit_count = 0; + loop { + match self.read_digit(radix) { + Some(d) => { + r = r * (radix as u32) + (d as u32); + digit_count += 1; + if digit_count > max_digits || r >= upto { + return None + } + } + None => { + if digit_count == 0 { + return None + } else { + return Some(r) + } + } + }; + } + } + + // Read number, failing if max_digits of number value exceeded + fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { + do self.read_atomically |p| { + p.read_number_impl(radix, max_digits, upto) + } + } + + fn read_ipv4_addr_impl(&mut self) -> Option { + let mut bs = [0u8, ..4]; + let mut i = 0; + while i < 4 { + if i != 0 && self.read_given_char('.').is_none() { + return None; + } + + let octet = self.read_number(10, 3, 0x100).map(|&n| n as u8); + match octet { + Some(d) => bs[i] = d, + None => return None, + }; + i += 1; + } + Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3])) + } + + // Read IPv4 address + fn read_ipv4_addr(&mut self) -> Option { + do self.read_atomically |p| { + p.read_ipv4_addr_impl() + } + } + + fn read_ipv6_addr_impl(&mut self) -> Option { + fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr { + assert!(head.len() + tail.len() <= 8); + let mut gs = [0u16, ..8]; + gs.copy_from(head); + gs.mut_slice(8 - tail.len(), 8).copy_from(tail); + Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) + } + + fn read_groups(p: &mut Parser, groups: &mut [u16, ..8], limit: uint) -> (uint, bool) { + let mut i = 0; + while i < limit { + if i < limit - 1 { + let ipv4 = do p.read_atomically |p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_ipv4_addr() + } else { + None + } + }; + match ipv4 { + Some(Ipv4Addr(a, b, c, d)) => { + groups[i + 0] = (a as u16 << 8) | (b as u16); + groups[i + 1] = (c as u16 << 8) | (d as u16); + return (i + 2, true); + } + _ => {} + } + } + + let group = do p.read_atomically |p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_number(16, 4, 0x10000).map(|&n| n as u16) + } else { + None + } + }; + match group { + Some(g) => groups[i] = g, + None => return (i, false) + } + i += 1; + } + (i, false) + } + + let mut head = [0u16, ..8]; + let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + + if head_size == 8 { + return Some(Ipv6Addr( + head[0], head[1], head[2], head[3], + head[4], head[5], head[6], head[7])) + } + + // IPv4 part is not allowed before `::` + if head_ipv4 { + return None + } + + // read `::` if previous code parsed less than 8 groups + if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { + return None; + } + + let mut tail = [0u16, ..8]; + let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size); + Some(ipv6_addr_from_head_tail(head.slice(0, head_size), tail.slice(0, tail_size))) + } + + fn read_ipv6_addr(&mut self) -> Option { + do self.read_atomically |p| { + p.read_ipv6_addr_impl() + } + } + + fn read_ip_addr(&mut self) -> Option { + let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr(); + let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr(); + self.read_or([ipv4_addr, ipv6_addr]) + } + + fn read_socket_addr(&mut self) -> Option { + let ip_addr = |p: &mut Parser| { + let ipv4_p = |p: &mut Parser| p.read_ip_addr(); + let ipv6_p = |p: &mut Parser| { + let open_br = |p: &mut Parser| p.read_given_char('['); + let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); + let clos_br = |p: &mut Parser| p.read_given_char(']'); + p.read_seq_3::(open_br, ip_addr, clos_br) + .map(|&t| match t { (_, ip, _) => ip }) + }; + p.read_or([ipv4_p, ipv6_p]) + }; + let colon = |p: &mut Parser| p.read_given_char(':'); + let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|&n| n as u16); + + // host, colon, port + self.read_seq_3::(ip_addr, colon, port) + .map(|&t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } }) + } +} + +impl FromStr for IpAddr { + fn from_str(s: &str) -> Option { + do Parser::new(s).read_till_eof |p| { + p.read_ip_addr() + } + } +} + +impl FromStr for SocketAddr { + fn from_str(s: &str) -> Option { + do Parser::new(s).read_till_eof |p| { + p.read_socket_addr() + } + } +} + + +#[cfg(test)] +mod test { + use super::*; + use from_str::FromStr; + use option::{Some, None}; + + #[test] + fn test_from_str_ipv4() { + assert_eq!(Some(Ipv4Addr(127, 0, 0, 1)), FromStr::from_str("127.0.0.1")); + assert_eq!(Some(Ipv4Addr(255, 255, 255, 255)), FromStr::from_str("255.255.255.255")); + assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0")); + + // out of range + assert_eq!(None, FromStr::from_str::("256.0.0.1")); + // too short + assert_eq!(None, FromStr::from_str::("255.0.0")); + // too long + assert_eq!(None, FromStr::from_str::("255.0.0.1.2")); + // no number between dots + assert_eq!(None, FromStr::from_str::("255.0..1")); + } + + #[test] + fn test_from_str_ipv6() { + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("0:0:0:0:0:0:0:0")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("0:0:0:0:0:0:0:1")); + + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("::1")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("::")); + + assert_eq!(Some(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), + FromStr::from_str("2a02:6b8::11:11")); + + // too long group + assert_eq!(None, FromStr::from_str::("::00000")); + // too short + assert_eq!(None, FromStr::from_str::("1:2:3:4:5:6:7")); + // too long + assert_eq!(None, FromStr::from_str::("1:2:3:4:5:6:7:8:9")); + // triple colon + assert_eq!(None, FromStr::from_str::("1:2:::6:7:8")); + // two double colons + assert_eq!(None, FromStr::from_str::("1:2::6::8")); + } + + #[test] + fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)), + FromStr::from_str("::192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + FromStr::from_str("::FFFF:192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + FromStr::from_str("64:ff9b::192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33")); + + // colon after v4 + assert_eq!(None, FromStr::from_str::("::127.0.0.1:")); + // not enought groups + assert_eq!(None, FromStr::from_str::("1.2.3.4.5:127.0.0.1")); + // too many groups + assert_eq!(None, FromStr::from_str::("1.2.3.4.5:6:7:127.0.0.1")); + } + + #[test] + fn test_from_str_socket_addr() { + assert_eq!(Some(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }), + FromStr::from_str("77.88.21.11:80")); + assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }), + FromStr::from_str("[2a02:6b8:0:1::1]:53")); + assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }), + FromStr::from_str("[::127.0.0.1]:22")); + + // without port + assert_eq!(None, FromStr::from_str::("127.0.0.1")); + // without port + assert_eq!(None, FromStr::from_str::("127.0.0.1:")); + // wrong brackets around v4 + assert_eq!(None, FromStr::from_str::("[127.0.0.1]:22")); + // port out of range + assert_eq!(None, FromStr::from_str::("127.0.0.1:123456")); + } +} From 58b11229e563da705e2579821b8c3fe1fa799c52 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Aug 2013 13:35:13 +0400 Subject: [PATCH 02/18] Use FromStr for IpAddr in rt::uv::net --- src/libstd/rt/uv/net.rs | 72 ++--------------------------------------- 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index fd3042899f6bc..c8b3d41a78d79 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -20,7 +20,6 @@ use rt::uv::last_uv_error; use vec; use str; use from_str::{FromStr}; -use num; pub enum UvSocketAddr { UvIpv4SocketAddr(*sockaddr_in), @@ -85,77 +84,10 @@ fn uv_socket_addr_as_socket_addr(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) port as u16 }; let ip_str = str::from_bytes_slice(ip_name).trim_right_chars(&'\x00'); - let ip = match addr { - UvIpv4SocketAddr(*) => { - let ip: ~[u8] = - ip_str.split_iter('.') - .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) - .collect(); - assert_eq!(ip.len(), 4); - SocketAddr { - ip: Ipv4Addr(ip[0], ip[1], ip[2], ip[3]), - port: ip_port - } - }, - UvIpv6SocketAddr(*) => { - let ip: ~[u16] = { - let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] { - let convert_each_segment = |s: &str| -> ~[u16] { - let read_hex_segment = |s: &str| -> u16 { - num::FromStrRadix::from_str_radix(s, 16u).unwrap() - }; - match s { - "" => ~[], - // IPv4-Mapped/Compatible IPv6 Address? - s if s.find('.').is_some() => { - let i = s.rfind(':').unwrap_or_default(-1); - - let b = s.slice(i + 1, s.len()); // the ipv4 part - - let h = b.split_iter('.') - .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) - .transform(|s: u8| -> ~str { fmt!("%02x", s as uint) }) - .collect::<~[~str]>(); - - if i == -1 { - // Ipv4 Compatible Address (::x.x.x.x) - // first 96 bits are zero leaving 32 bits - // for the ipv4 part - // (i.e ::127.0.0.1 == ::7F00:1) - ~[num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), - num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] - } else { - // Ipv4-Mapped Address (::FFFF:x.x.x.x) - // first 80 bits are zero, followed by all ones - // for the next 16 bits, leaving 32 bits for - // the ipv4 part - // (i.e ::FFFF:127.0.0.1 == ::FFFF:7F00:1) - ~[1, - num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), - num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] - } - }, - s => s.split_iter(':').transform(read_hex_segment).collect() - } - }; - s.split_str_iter("::").transform(convert_each_segment).collect() - }; - match expand_shorthand_and_convert(ip_str) { - [x] => x, // no shorthand found - [l, r] => l + vec::from_elem(8 - l.len() - r.len(), 0u16) + r, // fill the gap - _ => fail!(), // impossible. only one shorthand allowed. - } - }; - assert_eq!(ip.len(), 8); - SocketAddr { - ip: Ipv6Addr(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]), - port: ip_port - } - }, - }; + let ip_addr = FromStr::from_str(ip_str).unwrap(); // finally run the closure - f(ip) + f(SocketAddr { ip: ip_addr, port: ip_port }) } pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr { From 8d3c62af9f560866dd8fafc950177b87098bedab Mon Sep 17 00:00:00 2001 From: Dmitry Ermolov Date: Tue, 6 Aug 2013 02:49:01 +0400 Subject: [PATCH 03/18] Better documentation for --emit-llvm option. Document possible use with -S option. --- src/librustc/driver/driver.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 2c642d54253b6..c3c100a89f135 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -822,7 +822,8 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { optmulti("", "cfg", "Configure the compilation environment", "SPEC"), optflag("", "emit-llvm", - "Produce an LLVM bitcode file"), + "Produce an LLVM assembly file if used with -S option; + produce an LLVM bitcode file otherwise"), optflag("h", "help","Display this message"), optmulti("L", "", "Add a directory to the library search path", "PATH"), From 1fa0a8c9db515b96cc85dc23f459539561a955de Mon Sep 17 00:00:00 2001 From: Dmitry Ermolov Date: Tue, 6 Aug 2013 11:08:50 +0400 Subject: [PATCH 04/18] Hide stuff that are not used outside of _match.rs --- src/librustc/middle/trans/_match.rs | 84 ++++++++++++++--------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 9a0dc5f036c76..e5d45d6ca2185 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -183,7 +183,7 @@ use syntax::codemap::{span, dummy_sp}; // An option identifying a literal: either a unit-like struct or an // expression. -pub enum Lit { +enum Lit { UnitLikeStructLit(ast::NodeId), // the node ID of the pattern ExprLit(@ast::expr), ConstLit(ast::def_id), // the def ID of the constant @@ -191,7 +191,7 @@ pub enum Lit { // An option identifying a branch (either a literal, a enum variant or a // range) -pub enum Opt { +enum Opt { lit(Lit), var(/* disr val */ uint, @adt::Repr), range(@ast::expr, @ast::expr), @@ -199,7 +199,7 @@ pub enum Opt { vec_len_ge(uint, /* slice */uint) } -pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { +fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { match (a, b) { (&lit(a), &lit(b)) => { match (a, b) { @@ -258,7 +258,7 @@ pub enum opt_result { lower_bound(Result), range_result(Result, Result), } -pub fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { +fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { let _icx = push_ctxt("match::trans_opt"); let ccx = bcx.ccx(); let bcx = bcx; @@ -292,7 +292,7 @@ pub fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { } } -pub fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId) +fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId) -> Opt { let ccx = bcx.ccx(); match ccx.tcx.def_map.get_copy(&pat_id) { @@ -317,7 +317,7 @@ pub fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId) } #[deriving(Clone)] -pub enum TransBindingMode { +enum TransBindingMode { TrByValue(/*llbinding:*/ ValueRef), TrByRef, } @@ -331,24 +331,24 @@ pub enum TransBindingMode { * - `id` is the node id of the binding * - `ty` is the Rust type of the binding */ #[deriving(Clone)] -pub struct BindingInfo { +struct BindingInfo { llmatch: ValueRef, trmode: TransBindingMode, id: ast::NodeId, ty: ty::t, } -pub type BindingsMap = HashMap; +type BindingsMap = HashMap; #[deriving(Clone)] -pub struct ArmData<'self> { +struct ArmData<'self> { bodycx: @mut Block, arm: &'self ast::arm, bindings_map: @BindingsMap } #[deriving(Clone)] -pub struct Match<'self> { +struct Match<'self> { pats: ~[@ast::pat], data: ArmData<'self> } @@ -364,7 +364,7 @@ impl<'self> Repr for Match<'self> { } } -pub fn has_nested_bindings(m: &[Match], col: uint) -> bool { +fn has_nested_bindings(m: &[Match], col: uint) -> bool { for br in m.iter() { match br.pats[col].node { ast::pat_ident(_, _, Some(_)) => return true, @@ -374,7 +374,7 @@ pub fn has_nested_bindings(m: &[Match], col: uint) -> bool { return false; } -pub fn expand_nested_bindings<'r>(bcx: @mut Block, +fn expand_nested_bindings<'r>(bcx: @mut Block, m: &[Match<'r>], col: uint, val: ValueRef) @@ -409,7 +409,7 @@ pub fn expand_nested_bindings<'r>(bcx: @mut Block, } } -pub fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) { +fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) { if !pat_is_binding_or_wild(bcx.tcx().def_map, p) { bcx.sess().span_bug( p.span, @@ -418,9 +418,9 @@ pub fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) { } } -pub type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>; +type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>; -pub fn enter_match<'r>(bcx: @mut Block, +fn enter_match<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -470,7 +470,7 @@ pub fn enter_match<'r>(bcx: @mut Block, return result; } -pub fn enter_default<'r>(bcx: @mut Block, +fn enter_default<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -516,7 +516,7 @@ pub fn enter_default<'r>(bcx: @mut Block, // so all patterns must either be records (resp. tuples) or // wildcards -pub fn enter_opt<'r>(bcx: @mut Block, +fn enter_opt<'r>(bcx: @mut Block, m: &[Match<'r>], opt: &Opt, col: uint, @@ -628,7 +628,7 @@ pub fn enter_opt<'r>(bcx: @mut Block, } } -pub fn enter_rec_or_struct<'r>(bcx: @mut Block, +fn enter_rec_or_struct<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -663,7 +663,7 @@ pub fn enter_rec_or_struct<'r>(bcx: @mut Block, } } -pub fn enter_tup<'r>(bcx: @mut Block, +fn enter_tup<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -689,7 +689,7 @@ pub fn enter_tup<'r>(bcx: @mut Block, } } -pub fn enter_tuple_struct<'r>(bcx: @mut Block, +fn enter_tuple_struct<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -715,7 +715,7 @@ pub fn enter_tuple_struct<'r>(bcx: @mut Block, } } -pub fn enter_box<'r>(bcx: @mut Block, +fn enter_box<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -742,7 +742,7 @@ pub fn enter_box<'r>(bcx: @mut Block, } } -pub fn enter_uniq<'r>(bcx: @mut Block, +fn enter_uniq<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -769,7 +769,7 @@ pub fn enter_uniq<'r>(bcx: @mut Block, } } -pub fn enter_region<'r>(bcx: @mut Block, +fn enter_region<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -799,7 +799,7 @@ pub fn enter_region<'r>(bcx: @mut Block, // Returns the options in one column of matches. An option is something that // needs to be conditionally matched at runtime; for example, the discriminant // on a set of enum variants or a literal. -pub fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { +fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { let ccx = bcx.ccx(); fn add_to_set(tcx: ty::ctxt, set: &mut ~[Opt], val: Opt) { if set.iter().any(|l| opt_eq(tcx, l, &val)) {return;} @@ -865,12 +865,12 @@ pub fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { return found; } -pub struct ExtractedBlock { +struct ExtractedBlock { vals: ~[ValueRef], bcx: @mut Block } -pub fn extract_variant_args(bcx: @mut Block, +fn extract_variant_args(bcx: @mut Block, repr: &adt::Repr, disr_val: uint, val: ValueRef) @@ -893,7 +893,7 @@ fn match_datum(bcx: @mut Block, val: ValueRef, pat_id: ast::NodeId) -> Datum { } -pub fn extract_vec_elems(bcx: @mut Block, +fn extract_vec_elems(bcx: @mut Block, pat_span: span, pat_id: ast::NodeId, elem_count: uint, @@ -948,7 +948,7 @@ pub fn extract_vec_elems(bcx: @mut Block, } // NB: This function does not collect fields from struct-like enum variants. -pub fn collect_record_or_struct_fields(bcx: @mut Block, +fn collect_record_or_struct_fields(bcx: @mut Block, m: &[Match], col: uint) -> ~[ast::ident] { @@ -976,7 +976,7 @@ pub fn collect_record_or_struct_fields(bcx: @mut Block, } } -pub fn pats_require_rooting(bcx: @mut Block, +fn pats_require_rooting(bcx: @mut Block, m: &[Match], col: uint) -> bool { @@ -987,7 +987,7 @@ pub fn pats_require_rooting(bcx: @mut Block, } } -pub fn root_pats_as_necessary(mut bcx: @mut Block, +fn root_pats_as_necessary(mut bcx: @mut Block, m: &[Match], col: uint, val: ValueRef) @@ -1018,23 +1018,23 @@ macro_rules! any_pat ( ) ) -pub fn any_box_pat(m: &[Match], col: uint) -> bool { +fn any_box_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_box(_)) } -pub fn any_uniq_pat(m: &[Match], col: uint) -> bool { +fn any_uniq_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_uniq(_)) } -pub fn any_region_pat(m: &[Match], col: uint) -> bool { +fn any_region_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_region(_)) } -pub fn any_tup_pat(m: &[Match], col: uint) -> bool { +fn any_tup_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_tup(_)) } -pub fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool { +fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool { do m.iter().any |br| { let pat = br.pats[col]; match pat.node { @@ -1050,9 +1050,9 @@ pub fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool { } } -pub type mk_fail = @fn() -> BasicBlockRef; +type mk_fail = @fn() -> BasicBlockRef; -pub fn pick_col(m: &[Match]) -> uint { +fn pick_col(m: &[Match]) -> uint { fn score(p: &ast::pat) -> uint { match p.node { ast::pat_lit(_) | ast::pat_enum(_, _) | ast::pat_range(_, _) => 1u, @@ -1088,7 +1088,7 @@ pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len, } // Compiles a comparison between two things. // // NB: This must produce an i1, not a Rust bool (i8). -pub fn compare_values(cx: @mut Block, +fn compare_values(cx: @mut Block, lhs: ValueRef, rhs: ValueRef, rhs_t: ty::t) @@ -1204,7 +1204,7 @@ fn insert_lllocals(bcx: @mut Block, return bcx; } -pub fn compile_guard(bcx: @mut Block, +fn compile_guard(bcx: @mut Block, guard_expr: @ast::expr, data: &ArmData, m: &[Match], @@ -1261,7 +1261,7 @@ pub fn compile_guard(bcx: @mut Block, } } -pub fn compile_submatch(bcx: @mut Block, +fn compile_submatch(bcx: @mut Block, m: &[Match], vals: &[ValueRef], chk: Option) { @@ -1670,7 +1670,7 @@ fn create_bindings_map(bcx: @mut Block, pat: @ast::pat) -> BindingsMap { return bindings_map; } -pub fn trans_match_inner(scope_cx: @mut Block, +fn trans_match_inner(scope_cx: @mut Block, discr_expr: @ast::expr, arms: &[ast::arm], dest: Dest) -> @mut Block { @@ -1752,7 +1752,7 @@ pub fn trans_match_inner(scope_cx: @mut Block, } } -pub enum IrrefutablePatternBindingMode { +enum IrrefutablePatternBindingMode { // Stores the association between node ID and LLVM value in `lllocals`. BindLocal, // Stores the association between node ID and LLVM value in `llargs`. From 1710125f673fe8ca2f1ab76074ca26d6f6acd720 Mon Sep 17 00:00:00 2001 From: Dmitry Ermolov Date: Tue, 6 Aug 2013 22:37:27 +0400 Subject: [PATCH 05/18] Added testcases for `match` keyword Added testcases for `match` keyword including test for issue #5625. --- src/test/run-pass/match-enum-struct-0.rs | 26 +++++++++++++++++++++ src/test/run-pass/match-enum-struct-1.rs | 26 +++++++++++++++++++++ src/test/run-pass/match-struct-0.rs | 29 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/test/run-pass/match-enum-struct-0.rs create mode 100644 src/test/run-pass/match-enum-struct-1.rs create mode 100644 src/test/run-pass/match-struct-0.rs diff --git a/src/test/run-pass/match-enum-struct-0.rs b/src/test/run-pass/match-enum-struct-0.rs new file mode 100644 index 0000000000000..5b72eb7aa731c --- /dev/null +++ b/src/test/run-pass/match-enum-struct-0.rs @@ -0,0 +1,26 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-test + +// regression test for issue #5625 + +enum E { + Foo{f : int}, + Bar +} + +pub fn main() { + let e = Bar; + match e { + Foo{f: _f} => fail!(), + _ => (), + } +} diff --git a/src/test/run-pass/match-enum-struct-1.rs b/src/test/run-pass/match-enum-struct-1.rs new file mode 100644 index 0000000000000..15d24c41a3d08 --- /dev/null +++ b/src/test/run-pass/match-enum-struct-1.rs @@ -0,0 +1,26 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { + Foo{f : int}, + Bar +} + +pub fn main() { + let e = Foo{f: 1}; + match e { + Foo{_} => (), + _ => fail!(), + } + match e { + Foo{f: _f} => (), + _ => fail!(), + } +} diff --git a/src/test/run-pass/match-struct-0.rs b/src/test/run-pass/match-struct-0.rs new file mode 100644 index 0000000000000..67e844c519ee8 --- /dev/null +++ b/src/test/run-pass/match-struct-0.rs @@ -0,0 +1,29 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo{ + f : int, +} + +pub fn main() { + let f = Foo{f: 1}; + match f { + Foo{f: 0} => fail!(), + Foo{_} => (), + } + match f { + Foo{f: 0} => fail!(), + Foo{f: _f} => (), + } + match f { + Foo{f: 0} => fail!(), + _ => (), + } +} From 0fadfc5fb7de47f0ffcb55a8bbfe0a75c2a4dbee Mon Sep 17 00:00:00 2001 From: Dmitry Ermolov Date: Tue, 6 Aug 2013 22:43:57 +0400 Subject: [PATCH 06/18] Fix bug in `match`ing struct patterns Code that collects fields in struct-like patterns used to ignore wildcard patterns like `Foo{_}`. But `enter_defaults` considered struct-like patterns as default in order to overcome this (accoring to my understanding of situation). However such behaviour caused code like this: ``` enum E { Foo{f: int}, Bar } let e = Bar; match e { Foo{f: _f} => { /* do something (1) */ } _ => { /* do something (2) */ } } ``` consider pattern `Foo{f: _f}` as default. That caused inproper behaviour and even segfaults while trying to destruct `Bar` as `Foo{f: _f}`. Issues: #5625 , #5530. This patch fixes `collect_record_or_struct_fields` to split cases of single wildcard struct-like pattern and no struct-like pattern at all. Former case resolved with `enter_rec_or_struct` (and not with `enter_defaults`). Closes #5625. Closes #5530. --- src/librustc/middle/trans/_match.rs | 55 +++++++++++++++--------- src/test/run-pass/issue-5530.rs | 2 - src/test/run-pass/match-enum-struct-0.rs | 2 - 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index e5d45d6ca2185..327d2e698c1e1 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -485,7 +485,7 @@ fn enter_default<'r>(bcx: @mut Block, do enter_match(bcx, dm, m, col, val) |p| { match p.node { - ast::pat_wild | ast::pat_tup(_) | ast::pat_struct(*) => Some(~[]), + ast::pat_wild | ast::pat_tup(_) => Some(~[]), ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]), _ => None } @@ -947,24 +947,37 @@ fn extract_vec_elems(bcx: @mut Block, ExtractedBlock { vals: elems, bcx: bcx } } -// NB: This function does not collect fields from struct-like enum variants. +/// Checks every pattern in `m` at `col` column. +/// If there are a struct pattern among them function +/// returns list of all fields that are matched in these patterns. +/// Function returns None if there is no struct pattern. +/// Function doesn't collect fields from struct-like enum variants. +/// Function can return empty list if there is only wildcard struct pattern. fn collect_record_or_struct_fields(bcx: @mut Block, m: &[Match], col: uint) - -> ~[ast::ident] { + -> Option<~[ast::ident]> { let mut fields: ~[ast::ident] = ~[]; + let mut found = false; for br in m.iter() { match br.pats[col].node { ast::pat_struct(_, ref fs, _) => { match ty::get(node_id_type(bcx, br.pats[col].id)).sty { - ty::ty_struct(*) => extend(&mut fields, *fs), + ty::ty_struct(*) => { + extend(&mut fields, *fs); + found = true; + } _ => () } } _ => () } } - return fields; + if found { + return Some(fields); + } else { + return None; + } fn extend(idents: &mut ~[ast::ident], field_pats: &[ast::field_pat]) { for field_pat in field_pats.iter() { @@ -1336,22 +1349,24 @@ fn compile_submatch_continue(mut bcx: @mut Block, // required to root any values. assert!(any_box_pat(m, col) || !pats_require_rooting(bcx, m, col)); - let rec_fields = collect_record_or_struct_fields(bcx, m, col); - if rec_fields.len() > 0 { - let pat_ty = node_id_type(bcx, pat_id); - let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); - do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { - let rec_vals = rec_fields.map(|field_name| { - let ix = ty::field_idx_strict(tcx, *field_name, field_tys); - adt::trans_field_ptr(bcx, pat_repr, val, discr, ix) - }); - compile_submatch( - bcx, - enter_rec_or_struct(bcx, dm, m, col, rec_fields, val), - vec::append(rec_vals, vals_left), - chk); + match collect_record_or_struct_fields(bcx, m, col) { + Some(ref rec_fields) => { + let pat_ty = node_id_type(bcx, pat_id); + let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); + do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { + let rec_vals = rec_fields.map(|field_name| { + let ix = ty::field_idx_strict(tcx, *field_name, field_tys); + adt::trans_field_ptr(bcx, pat_repr, val, discr, ix) + }); + compile_submatch( + bcx, + enter_rec_or_struct(bcx, dm, m, col, *rec_fields, val), + vec::append(rec_vals, vals_left), + chk); + } + return; } - return; + None => {} } if any_tup_pat(m, col) { diff --git a/src/test/run-pass/issue-5530.rs b/src/test/run-pass/issue-5530.rs index 002435fcb36f0..8e55ad90c7044 100644 --- a/src/test/run-pass/issue-5530.rs +++ b/src/test/run-pass/issue-5530.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - enum Enum { Foo { foo: uint }, Bar { bar: uint } diff --git a/src/test/run-pass/match-enum-struct-0.rs b/src/test/run-pass/match-enum-struct-0.rs index 5b72eb7aa731c..365729ec86054 100644 --- a/src/test/run-pass/match-enum-struct-0.rs +++ b/src/test/run-pass/match-enum-struct-0.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - // regression test for issue #5625 enum E { From 0b47b4ccc9a714731112cc49633fc829cf46c95e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 6 Aug 2013 19:35:09 -0700 Subject: [PATCH 07/18] Fix node hashes --- src/librustc/metadata/decoder.rs | 12 ++++----- src/librustc/metadata/encoder.rs | 43 +++++++++++++++++--------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c3097d1aa6657..85f96946aff7a 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -51,20 +51,20 @@ type cmd = @crate_metadata; // what crate that's in and give us a def_id that makes sense for the current // build. -fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: uint) -> +fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: u64) -> Option { let index = reader::get_doc(d, tag_index); let table = reader::get_doc(index, tag_index_table); - let hash_pos = table.start + hash % 256u * 4u; - let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4u) as uint; + let hash_pos = table.start + (hash % 256 * 4) as uint; + let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4) as uint; let tagged_doc = reader::doc_at(d.data, pos); let belt = tag_index_buckets_bucket_elt; let mut ret = None; do reader::tagged_docs(tagged_doc.doc, belt) |elt| { - let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4u) as uint; - if eq_fn(elt.data.slice(elt.start + 4u, elt.end)) { + let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4) as uint; + if eq_fn(elt.data.slice(elt.start + 4, elt.end)) { ret = Some(reader::doc_at(d.data, pos).doc); false } else { @@ -84,7 +84,7 @@ pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option { } lookup_hash(items, |a| eq_item(a, item_id), - item_id.hash() as uint) + (item_id as i64).hash()) } fn find_item(item_id: int, items: ebml::Doc) -> ebml::Doc { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index d847d85112653..c4919e7f26321 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -319,7 +319,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, id: NodeId, variants: &[variant], path: &[ast_map::path_elt], - index: @mut ~[entry], + index: @mut ~[entry], generics: &ast::Generics) { debug!("encode_enum_variant_info(id=%?)", id); @@ -329,7 +329,8 @@ fn encode_enum_variant_info(ecx: &EncodeContext, ast::def_id { crate: LOCAL_CRATE, node: id }); for variant in variants.iter() { let def_id = local_def(variant.node.id); - index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()}); + index.push(entry {val: variant.node.id as i64, + pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'v'); @@ -677,8 +678,8 @@ fn encode_info_for_struct(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], fields: &[@struct_field], - global_index: @mut ~[entry]) - -> ~[entry] { + global_index: @mut ~[entry]) + -> ~[entry] { /* Each class has its own index, since different classes may have fields with the same name */ let mut index = ~[]; @@ -692,8 +693,8 @@ fn encode_info_for_struct(ecx: &EncodeContext, }; let id = field.node.id; - index.push(entry {val: id, pos: ebml_w.writer.tell()}); - global_index.push(entry {val: id, pos: ebml_w.writer.tell()}); + index.push(entry {val: id as i64, pos: ebml_w.writer.tell()}); + global_index.push(entry {val: id as i64, pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); debug!("encode_info_for_struct: doing %s %d", tcx.sess.str_of(nm), id); @@ -712,8 +713,8 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, path: &[ast_map::path_elt], name: ast::ident, ctor_id: NodeId, - index: @mut ~[entry]) { - index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() }); + index: @mut ~[entry]) { + index.push(entry { val: ctor_id as i64, pos: ebml_w.writer.tell() }); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(ctor_id)); @@ -815,13 +816,13 @@ fn should_inline(attrs: &[Attribute]) -> bool { fn encode_info_for_item(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, item: @item, - index: @mut ~[entry], + index: @mut ~[entry], path: &[ast_map::path_elt]) { let tcx = ecx.tcx; fn add_to_index_(item: @item, ebml_w: &writer::Encoder, - index: @mut ~[entry]) { - index.push(entry { val: item.id, pos: ebml_w.writer.tell() }); + index: @mut ~[entry]) { + index.push(entry { val: item.id as i64, pos: ebml_w.writer.tell() }); } let add_to_index: &fn() = || add_to_index_(item, ebml_w, index); @@ -969,7 +970,7 @@ fn encode_info_for_item(ecx: &EncodeContext, /* Each class has its own index -- encode it */ let bkts = create_index(idx); - encode_index(ebml_w, bkts, write_int); + encode_index(ebml_w, bkts, write_i64); ebml_w.end_tag(); // If this is a tuple- or enum-like struct, encode the type of the @@ -1040,7 +1041,8 @@ fn encode_info_for_item(ecx: &EncodeContext, Some(ast_methods[i]) } else { None }; - index.push(entry {val: m.def_id.node, pos: ebml_w.writer.tell()}); + index.push(entry {val: m.def_id.node as i64, + pos: ebml_w.writer.tell()}); encode_info_for_method(ecx, ebml_w, *m, @@ -1086,7 +1088,8 @@ fn encode_info_for_item(ecx: &EncodeContext, let method_ty = ty::method(tcx, method_def_id); - index.push(entry {val: method_def_id.node, pos: ebml_w.writer.tell()}); + index.push(entry {val: method_def_id.node as i64, + pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); @@ -1145,10 +1148,10 @@ fn encode_info_for_item(ecx: &EncodeContext, fn encode_info_for_foreign_item(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, nitem: @foreign_item, - index: @mut ~[entry], + index: @mut ~[entry], path: &ast_map::path, abi: AbiSet) { - index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() }); + index.push(entry { val: nitem.id as i64, pos: ebml_w.writer.tell() }); ebml_w.start_tag(tag_items_data_item); match nitem.node { @@ -1184,10 +1187,10 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, fn encode_info_for_items(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, crate: &Crate) - -> ~[entry] { + -> ~[entry] { let index = @mut ~[]; ebml_w.start_tag(tag_items_data); - index.push(entry { val: CRATE_NODE_ID, pos: ebml_w.writer.tell() }); + index.push(entry { val: CRATE_NODE_ID as i64, pos: ebml_w.writer.tell() }); encode_info_for_mod(ecx, ebml_w, &crate.module, @@ -1304,7 +1307,7 @@ fn write_str(writer: @io::Writer, s: ~str) { writer.write_str(s); } -fn write_int(writer: @io::Writer, &n: &int) { +fn write_i64(writer: @io::Writer, &n: &i64) { assert!(n < 0x7fff_ffff); writer.write_be_u32(n as u32); } @@ -1623,7 +1626,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { i = *wr.pos; let items_buckets = create_index(items_index); - encode_index(&mut ebml_w, items_buckets, write_int); + encode_index(&mut ebml_w, items_buckets, write_i64); ecx.stats.index_bytes = *wr.pos - i; ebml_w.end_tag(); From b32617666a30972f9bcc3c4c619b862f14350d22 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Thu, 18 Jul 2013 17:17:47 +0900 Subject: [PATCH 08/18] std: run test fix for ARM android --- src/libstd/run.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/run.rs b/src/libstd/run.rs index ef3d881c5fead..68986ff11c211 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -1311,11 +1311,11 @@ mod tests { let output = str::from_bytes(prog.finish_with_output().output); let r = os::env(); - for &(k, v) in r.iter() { + for &(ref k, ref v) in r.iter() { // don't check android RANDOM variables - if k != ~"RANDOM" { - assert!(output.contains(fmt!("%s=%s", k, v)) || - output.contains(fmt!("%s=\'%s\'", k, v))); + if *k != ~"RANDOM" { + assert!(output.contains(fmt!("%s=%s", *k, *v)) || + output.contains(fmt!("%s=\'%s\'", *k, *v))); } } } From 492cbcee6dd042913254bf31bf94c4f5c7f5e66a Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Wed, 7 Aug 2013 20:42:44 +0900 Subject: [PATCH 09/18] mk: install.mk fix to specify ADB variables not adb --- mk/install.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/install.mk b/mk/install.mk index 07cb21217ae3f..4b50c5aa7963f 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -199,7 +199,7 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ $(if $(findstring adb,$(CFG_ADB)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(if $(findstring device,$(shell $(CFG_ADB) devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ $(info install: install-runtime-target for $(target) enabled \ $(info install: android device attached) \ $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ From d463f4cb10aeb93bff9c4a376b6c0e46b4abe304 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Wed, 7 Aug 2013 20:43:46 +0900 Subject: [PATCH 10/18] mk: test.mk fix to specify ADB variables not adb --- mk/tests.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/tests.mk b/mk/tests.mk index 682ea3e5f6946..8e921d300b557 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -123,7 +123,7 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ $(if $(findstring adb,$(CFG_ADB)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(if $(findstring device,$(shell $(CFG_ADB) devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ $(info check: $(target) test enabled \ $(info check: android device attached) \ $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ From c3825c835197a97ff4f254802efde80335d3833b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 7 Aug 2013 00:50:23 -0400 Subject: [PATCH 11/18] env! syntax extension changes env! aborts compilation of the specified environment variable is not defined and takes an optional second argument containing a custom error message. option_env! creates an Option<&'static str> containing the value of the environment variable. There are no run-pass tests that check the behavior when the environment variable is defined since the test framework doesn't support setting environment variables at compile time as opposed to runtime. However, both env! and option_env! are used inside of rustc itself, which should act as a sufficient test. Close #2248 --- src/librustc/back/rpath.rs | 9 ++++++ src/librustc/driver/driver.rs | 16 +++++++++- src/librustc/metadata/filesearch.rs | 8 ++++- src/librustc/middle/resolve.rs | 6 ++-- src/librustc/rustc.rs | 11 +++++++ src/libsyntax/ext/asm.rs | 4 +-- src/libsyntax/ext/base.rs | 14 ++++---- src/libsyntax/ext/env.rs | 32 +++++++++++++++---- src/libsyntax/ext/fmt.rs | 4 +-- .../extenv-arg-2-not-string-literal.rs | 11 +++++++ src/test/compile-fail/extenv-no-args.rs | 6 ++-- .../compile-fail/extenv-not-defined-custom.rs | 11 +++++++ .../extenv-not-defined-default.rs | 11 +++++++ .../compile-fail/extenv-not-string-literal.rs | 6 ++-- src/test/compile-fail/extenv-too-many-args.rs | 4 +-- .../compile-fail/extoption_env-no-args.rs | 11 +++++++ .../extoption_env-not-string-literal.rs | 11 +++++++ .../extoption_env-too-many-args.rs | 11 +++++++ .../run-pass/extoption_env-not-defined.rs | 14 ++++++++ 19 files changed, 168 insertions(+), 32 deletions(-) create mode 100644 src/test/compile-fail/extenv-arg-2-not-string-literal.rs create mode 100644 src/test/compile-fail/extenv-not-defined-custom.rs create mode 100644 src/test/compile-fail/extenv-not-defined-default.rs create mode 100644 src/test/compile-fail/extoption_env-no-args.rs create mode 100644 src/test/compile-fail/extoption_env-not-string-literal.rs create mode 100644 src/test/compile-fail/extoption_env-too-many-args.rs create mode 100644 src/test/run-pass/extoption_env-not-defined.rs diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 571721ed40cee..6aac627729c39 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -168,6 +168,7 @@ pub fn get_absolute_rpath(lib: &Path) -> Path { os::make_absolute(lib).dir_path() } +#[cfg(stage0)] pub fn get_install_prefix_rpath(target_triple: &str) -> Path { let install_prefix = env!("CFG_PREFIX"); @@ -179,6 +180,14 @@ pub fn get_install_prefix_rpath(target_triple: &str) -> Path { os::make_absolute(&Path(install_prefix).push_rel(&tlib)) } +#[cfg(not(stage0))] +pub fn get_install_prefix_rpath(target_triple: &str) -> Path { + let install_prefix = env!("CFG_PREFIX"); + + let tlib = filesearch::relative_target_lib_path(target_triple); + os::make_absolute(&Path(install_prefix).push_rel(&tlib)) +} + pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] { let mut set = HashSet::new(); let mut minimized = ~[]; diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 61ab826e9ee51..1cf758b7e6c07 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -578,6 +578,7 @@ pub fn build_target_config(sopts: @session::options, return target_cfg; } +#[cfg(stage0)] pub fn host_triple() -> ~str { // Get the host triple out of the build environment. This ensures that our // idea of the host triple is the same as for the set of libraries we've @@ -595,6 +596,19 @@ pub fn host_triple() -> ~str { }; } +#[cfg(not(stage0))] +pub fn host_triple() -> ~str { + // Get the host triple out of the build environment. This ensures that our + // idea of the host triple is the same as for the set of libraries we've + // actually built. We can't just take LLVM's host triple because they + // normalize all ix86 architectures to i386. + // + // Instead of grabbing the host triple (for the current host), we grab (at + // compile time) the target triple that this rustc is built with and + // calling that (at runtime) the host triple. + (env!("CFG_COMPILER_TRIPLE")).to_owned() +} + pub fn build_session_options(binary: @str, matches: &getopts::Matches, demitter: diagnostic::Emitter) diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 2422be3960b44..e18879464e892 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -186,6 +186,7 @@ fn get_rustpkg_lib_path_nearest() -> Result { // The name of the directory rustc expects libraries to be located. // On Unix should be "lib", on windows "bin" +#[cfg(stage0)] pub fn libdir() -> ~str { let libdir = env!("CFG_LIBDIR"); if libdir.is_empty() { @@ -193,3 +194,8 @@ pub fn libdir() -> ~str { } libdir.to_owned() } + +#[cfg(not(stage0))] +pub fn libdir() -> ~str { + (env!("CFG_LIBDIR")).to_owned() +} diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index da0ba1558c9bd..d17646a95b58a 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -4991,7 +4991,9 @@ impl Resolver { if self.structs.contains(&class_id) => { self.record_def(expr.id, definition); } - _ => { + result => { + debug!("(resolving expression) didn't find struct \ + def: %?", result); self.session.span_err( path.span, fmt!("`%s` does not name a structure", diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 1dfca0ba0e89c..5b4565590b946 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -117,6 +117,7 @@ mod std { } */ +#[cfg(stage0)] pub fn version(argv0: &str) { let mut vers = ~"unknown version"; let env_vers = env!("CFG_VERSION"); @@ -125,6 +126,16 @@ pub fn version(argv0: &str) { printfln!("host: %s", host_triple()); } +#[cfg(not(stage0))] +pub fn version(argv0: &str) { + let vers = match option_env!("CFG_VERSION") { + Some(vers) => vers, + None => "unknown version" + }; + printfln!("%s %s", argv0, vers); + printfln!("host: %s", host_triple()); +} + pub fn usage(argv0: &str) { let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0); printfln!("%s\ diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index ee0ec664e1b9e..b5d97427baf29 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -59,7 +59,7 @@ pub fn expand_asm(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) match state { Asm => { asm = expr_to_str(cx, p.parse_expr(), - ~"inline assembly must be a string literal."); + "inline assembly must be a string literal."); } Outputs => { while *p.token != token::EOF && diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index efaf6b8e001f3..1ba32442d5e6c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -146,7 +146,9 @@ pub fn syntax_expander_table() -> SyntaxEnv { intern(&"auto_decode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_decode))); syntax_expanders.insert(intern(&"env"), - builtin_normal_tt(ext::env::expand_syntax_ext)); + builtin_normal_tt(ext::env::expand_env)); + syntax_expanders.insert(intern(&"option_env"), + builtin_normal_tt(ext::env::expand_option_env)); syntax_expanders.insert(intern("bytes"), builtin_normal_tt(ext::bytes::expand_syntax_ext)); syntax_expanders.insert(intern("concat_idents"), @@ -311,7 +313,7 @@ impl ExtCtxt { } } -pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: ~str) -> @str { +pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: &str) -> @str { match expr.node { ast::expr_lit(l) => match l.node { ast::lit_str(s) => s, @@ -536,8 +538,8 @@ mod test { a.insert (@"abc",@15); let m = MapChain::new(~a); m.insert (@"def",@16); - // FIXME: #4492 (ICE) assert_eq!(m.find(&@"abc"),Some(@15)); - // .... assert_eq!(m.find(&@"def"),Some(@16)); + assert_eq!(m.find(&@"abc"),Some(@15)); + assert_eq!(m.find(&@"def"),Some(@16)); assert_eq!(*(m.find(&@"abc").unwrap()),15); assert_eq!(*(m.find(&@"def").unwrap()),16); let n = m.push_frame(); @@ -549,8 +551,8 @@ mod test { assert_eq!(*(n.find(&@"abc").unwrap()),15); assert_eq!(*(n.find(&@"def").unwrap()),17); // ... but m still has the old ones - // FIXME: #4492: assert_eq!(m.find(&@"abc"),Some(@15)); - // FIXME: #4492: assert_eq!(m.find(&@"def"),Some(@16)); + assert_eq!(m.find(&@"abc"),Some(@15)); + assert_eq!(m.find(&@"def"),Some(@16)); assert_eq!(*(m.find(&@"abc").unwrap()),15); assert_eq!(*(m.find(&@"def").unwrap()),16); } diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index a6cb615587879..c9e01b0f0d596 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -22,17 +22,35 @@ use ext::build::AstBuilder; use std::os; -pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) +pub fn expand_option_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { + let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!"); - let var = get_single_str_from_tts(cx, sp, tts, "env!"); + let e = match os::getenv(var) { + None => quote_expr!(::std::option::None), + Some(s) => quote_expr!(::std::option::Some($s)) + }; + MRExpr(e) +} - // FIXME (#2248): if this was more thorough it would manufacture an - // Option rather than just an maybe-empty string. +pub fn expand_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) + -> base::MacResult { + let exprs = get_exprs_from_tts(ext_cx, sp, tts); + + if exprs.len() == 0 { + ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments"); + } + + let var = expr_to_str(ext_cx, exprs[0], "expected string literal"); + let msg = match exprs.len() { + 1 => fmt!("Environment variable %s not defined", var).to_managed(), + 2 => expr_to_str(ext_cx, exprs[1], "expected string literal"), + _ => ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments") + }; let e = match os::getenv(var) { - None => cx.expr_str(sp, @""), - Some(s) => cx.expr_str(sp, s.to_managed()) + None => ext_cx.span_fatal(sp, msg), + Some(s) => ext_cx.expr_str(sp, s.to_managed()) }; MRExpr(e) } diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 2dbf6887a214e..008545c9729b1 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -32,7 +32,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) } let fmt = expr_to_str(cx, args[0], - ~"first argument to fmt! must be a string literal."); + "first argument to fmt! must be a string literal."); let fmtspan = args[0].span; debug!("Format string: %s", fmt); fn parse_fmt_err_(cx: @ExtCtxt, sp: span, msg: &str) -> ! { diff --git a/src/test/compile-fail/extenv-arg-2-not-string-literal.rs b/src/test/compile-fail/extenv-arg-2-not-string-literal.rs new file mode 100644 index 0000000000000..c2362689721ac --- /dev/null +++ b/src/test/compile-fail/extenv-arg-2-not-string-literal.rs @@ -0,0 +1,11 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { env!("one", 10); } //~ ERROR: expected string literal diff --git a/src/test/compile-fail/extenv-no-args.rs b/src/test/compile-fail/extenv-no-args.rs index 7ff1357dcf3c9..afa47dbe74466 100644 --- a/src/test/compile-fail/extenv-no-args.rs +++ b/src/test/compile-fail/extenv-no-args.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: env! takes 1 argument - -fn main() { env!(); } +fn main() { env!(); } //~ ERROR: env! takes 1 or 2 arguments diff --git a/src/test/compile-fail/extenv-not-defined-custom.rs b/src/test/compile-fail/extenv-not-defined-custom.rs new file mode 100644 index 0000000000000..485b6c09f0a49 --- /dev/null +++ b/src/test/compile-fail/extenv-not-defined-custom.rs @@ -0,0 +1,11 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { env!("__HOPEFULLY_NOT_DEFINED__", "my error message"); } //~ ERROR: my error message diff --git a/src/test/compile-fail/extenv-not-defined-default.rs b/src/test/compile-fail/extenv-not-defined-default.rs new file mode 100644 index 0000000000000..d7a543c045a90 --- /dev/null +++ b/src/test/compile-fail/extenv-not-defined-default.rs @@ -0,0 +1,11 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { env!("__HOPEFULLY_NOT_DEFINED__"); } //~ ERROR: Environment variable __HOPEFULLY_NOT_DEFINED__ not defined diff --git a/src/test/compile-fail/extenv-not-string-literal.rs b/src/test/compile-fail/extenv-not-string-literal.rs index 3f09f81b85bfd..07ce47a14d83d 100644 --- a/src/test/compile-fail/extenv-not-string-literal.rs +++ b/src/test/compile-fail/extenv-not-string-literal.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:requires a string - -fn main() { env!(10); } +fn main() { env!(10, "two"); } //~ ERROR: expected string literal diff --git a/src/test/compile-fail/extenv-too-many-args.rs b/src/test/compile-fail/extenv-too-many-args.rs index b1b2001abc358..c6c4f0ec6b807 100644 --- a/src/test/compile-fail/extenv-too-many-args.rs +++ b/src/test/compile-fail/extenv-too-many-args.rs @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: env! takes 1 argument - -fn main() { env!("one", "two"); } +fn main() { env!("one", "two", "three"); } //~ ERROR: env! takes 1 or 2 arguments diff --git a/src/test/compile-fail/extoption_env-no-args.rs b/src/test/compile-fail/extoption_env-no-args.rs new file mode 100644 index 0000000000000..fd56756584ae3 --- /dev/null +++ b/src/test/compile-fail/extoption_env-no-args.rs @@ -0,0 +1,11 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { option_env!(); } //~ ERROR: option_env! takes 1 argument diff --git a/src/test/compile-fail/extoption_env-not-string-literal.rs b/src/test/compile-fail/extoption_env-not-string-literal.rs new file mode 100644 index 0000000000000..10f6c34980e48 --- /dev/null +++ b/src/test/compile-fail/extoption_env-not-string-literal.rs @@ -0,0 +1,11 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { option_env!(10); } //~ ERROR: requires a string diff --git a/src/test/compile-fail/extoption_env-too-many-args.rs b/src/test/compile-fail/extoption_env-too-many-args.rs new file mode 100644 index 0000000000000..b31e857c14e13 --- /dev/null +++ b/src/test/compile-fail/extoption_env-too-many-args.rs @@ -0,0 +1,11 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { option_env!("one", "two"); } //~ ERROR: option_env! takes 1 argument diff --git a/src/test/run-pass/extoption_env-not-defined.rs b/src/test/run-pass/extoption_env-not-defined.rs new file mode 100644 index 0000000000000..412efcc25a877 --- /dev/null +++ b/src/test/run-pass/extoption_env-not-defined.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let opt: Option<&'static str> = option_env!("__HOPEFULLY_DOESNT_EXIST__"); + assert!(opt.is_none()); +} From 7c1eb830524f404b505d2a0f94e398dbc54c008d Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 30 Jul 2013 14:58:30 -0700 Subject: [PATCH 12/18] rustpkg: Eliminate a copy --- src/librustpkg/path_util.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index fdfa29b2f832b..1c54b6304215f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -163,7 +163,7 @@ pub fn first_pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option

Option { let mut result = workspace.push("build"); // should use a target-specific subdirectory - result = mk_output_path(Main, Build, pkgid, &result); + result = mk_output_path(Main, Build, pkgid, result); debug!("built_executable_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { @@ -191,7 +191,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option { let mut result = workspace.push("build"); // should use a target-specific subdirectory - result = mk_output_path(what, Build, pkgid, &result); + result = mk_output_path(what, Build, pkgid, result); debug!("output_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { @@ -357,7 +357,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, create the %s dir (pkgid=%s, workspace=%s, what=%?, where=%?", subdir, pkgid.to_str(), workspace.to_str(), what, where))); } - mk_output_path(what, where, pkgid, &result) + mk_output_path(what, where, pkgid, result) } /// Return the directory for 's build artifacts in . @@ -380,17 +380,14 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { /// Return the output file for a given directory name, /// given whether we're building a library and whether we're building tests pub fn mk_output_path(what: OutputType, where: Target, - pkg_id: &PkgId, workspace: &Path) -> Path { + pkg_id: &PkgId, workspace: Path) -> Path { let short_name_with_version = fmt!("%s-%s", pkg_id.short_name, pkg_id.version.to_str()); // Not local_path.dir_path()! For package foo/bar/blat/, we want // the executable blat-0.5 to live under blat/ let dir = match where { // If we're installing, it just goes under ... - Install => { - // bad copy, but I just couldn't make the borrow checker happy - (*workspace).clone() - } + Install => workspace, // and if we're just building, it goes in a package-specific subdir Build => workspace.push_rel(&*pkg_id.local_path) }; From e751c90513b3b7948ffab7b449f0758e4225125e Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 30 Jul 2013 14:24:27 -0700 Subject: [PATCH 13/18] Makefiles: make rustpkgtest depend on rustpkg executable --- mk/tests.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/mk/tests.mk b/mk/tests.mk index 682ea3e5f6946..45a6e1447fc07 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -349,6 +349,7 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \ $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) + $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test From b4d6ae5bb8959affdb91a6b6791e725f97787344 Mon Sep 17 00:00:00 2001 From: OGINO Masanori Date: Thu, 8 Aug 2013 10:03:34 +0900 Subject: [PATCH 14/18] Remove redundant Ord method impls. Basically, generic containers should not use the default methods since a type of elements may not guarantees total order. str could use them since u8's Ord guarantees total order. Floating point numbers are also broken with the default methods because of NaN. Thanks for @thestinger. Timespec also guarantees total order AIUI. I'm unsure whether extra::semver::Identifier does so I left it alone. Proof needed. Signed-off-by: OGINO Masanori --- src/libextra/time.rs | 3 --- src/libstd/bool.rs | 6 ------ src/libstd/char.rs | 6 ------ src/libstd/cmp.rs | 9 +++------ src/libstd/nil.rs | 6 ------ src/libstd/num/int_macros.rs | 6 ------ src/libstd/num/uint_macros.rs | 6 ------ src/libstd/str.rs | 18 ------------------ 8 files changed, 3 insertions(+), 57 deletions(-) diff --git a/src/libextra/time.rs b/src/libextra/time.rs index f6a5fd98234b5..cf8ceb463b256 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -57,9 +57,6 @@ impl Ord for Timespec { self.sec < other.sec || (self.sec == other.sec && self.nsec < other.nsec) } - fn le(&self, other: &Timespec) -> bool { !other.lt(self) } - fn ge(&self, other: &Timespec) -> bool { !self.lt(other) } - fn gt(&self, other: &Timespec) -> bool { !self.le(other) } } /** diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index eeaea6a2cffa9..598e808061839 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -284,12 +284,6 @@ impl Not for bool { impl Ord for bool { #[inline] fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) } - #[inline] - fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) } - #[inline] - fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) } - #[inline] - fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) } } #[cfg(not(test))] diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 8505385543213..9c55e22b1f833 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -322,12 +322,6 @@ impl Eq for char { impl Ord for char { #[inline] fn lt(&self, other: &char) -> bool { *self < *other } - #[inline] - fn le(&self, other: &char) -> bool { *self <= *other } - #[inline] - fn gt(&self, other: &char) -> bool { *self > *other } - #[inline] - fn ge(&self, other: &char) -> bool { *self >= *other } } #[cfg(not(test))] diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index b66f89e83415e..28d45abb6881f 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -101,12 +101,6 @@ impl TotalOrd for Ordering { impl Ord for Ordering { #[inline] fn lt(&self, other: &Ordering) -> bool { (*self as int) < (*other as int) } - #[inline] - fn le(&self, other: &Ordering) -> bool { (*self as int) <= (*other as int) } - #[inline] - fn gt(&self, other: &Ordering) -> bool { (*self as int) > (*other as int) } - #[inline] - fn ge(&self, other: &Ordering) -> bool { (*self as int) >= (*other as int) } } macro_rules! totalord_impl( @@ -174,8 +168,11 @@ pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering { #[lang="ord"] pub trait Ord { fn lt(&self, other: &Self) -> bool; + #[inline] fn le(&self, other: &Self) -> bool { !other.lt(self) } + #[inline] fn gt(&self, other: &Self) -> bool { other.lt(self) } + #[inline] fn ge(&self, other: &Self) -> bool { !self.lt(other) } } diff --git a/src/libstd/nil.rs b/src/libstd/nil.rs index 81b7662e58168..3507dc9d2b233 100644 --- a/src/libstd/nil.rs +++ b/src/libstd/nil.rs @@ -33,12 +33,6 @@ impl Eq for () { impl Ord for () { #[inline] fn lt(&self, _other: &()) -> bool { false } - #[inline] - fn le(&self, _other: &()) -> bool { true } - #[inline] - fn ge(&self, _other: &()) -> bool { true } - #[inline] - fn gt(&self, _other: &()) -> bool { false } } #[cfg(not(test))] diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index b692bedebfd54..41da9a6ccbe48 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -130,12 +130,6 @@ impl Num for $T {} impl Ord for $T { #[inline] fn lt(&self, other: &$T) -> bool { return (*self) < (*other); } - #[inline] - fn le(&self, other: &$T) -> bool { return (*self) <= (*other); } - #[inline] - fn ge(&self, other: &$T) -> bool { return (*self) >= (*other); } - #[inline] - fn gt(&self, other: &$T) -> bool { return (*self) > (*other); } } #[cfg(not(test))] diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 29b8f29d87d3f..86b5b4ddfc09f 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -131,12 +131,6 @@ impl Num for $T {} impl Ord for $T { #[inline] fn lt(&self, other: &$T) -> bool { (*self) < (*other) } - #[inline] - fn le(&self, other: &$T) -> bool { (*self) <= (*other) } - #[inline] - fn ge(&self, other: &$T) -> bool { (*self) >= (*other) } - #[inline] - fn gt(&self, other: &$T) -> bool { (*self) > (*other) } } #[cfg(not(test))] diff --git a/src/libstd/str.rs b/src/libstd/str.rs index fa75916fb8640..430eb8544f630 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1050,34 +1050,16 @@ pub mod traits { impl<'self> Ord for &'self str { #[inline] fn lt(&self, other: & &'self str) -> bool { self.cmp(other) == Less } - #[inline] - fn le(&self, other: & &'self str) -> bool { self.cmp(other) != Greater } - #[inline] - fn ge(&self, other: & &'self str) -> bool { self.cmp(other) != Less } - #[inline] - fn gt(&self, other: & &'self str) -> bool { self.cmp(other) == Greater } } impl Ord for ~str { #[inline] fn lt(&self, other: &~str) -> bool { self.cmp(other) == Less } - #[inline] - fn le(&self, other: &~str) -> bool { self.cmp(other) != Greater } - #[inline] - fn ge(&self, other: &~str) -> bool { self.cmp(other) != Less } - #[inline] - fn gt(&self, other: &~str) -> bool { self.cmp(other) == Greater } } impl Ord for @str { #[inline] fn lt(&self, other: &@str) -> bool { self.cmp(other) == Less } - #[inline] - fn le(&self, other: &@str) -> bool { self.cmp(other) != Greater } - #[inline] - fn ge(&self, other: &@str) -> bool { self.cmp(other) != Less } - #[inline] - fn gt(&self, other: &@str) -> bool { self.cmp(other) == Greater } } impl<'self, S: Str> Equiv for &'self str { From d39255616004ea43dfabcf33b20ed2a80cd31dff Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 9 Aug 2013 01:15:31 -0700 Subject: [PATCH 15/18] std: Fix perf of local allocations in newsched Mostly optimizing TLS accesses to bring local heap allocation performance closer to that of oldsched. It's not completely at parity but removing the branches involved in supporting oldsched and optimizing pthread_get/setspecific to instead use our dedicated TCB slot will probably make up for it. --- src/libstd/os.rs | 4 +-- src/libstd/rt/comm.rs | 4 +-- src/libstd/rt/local_heap.rs | 22 +++++++++++----- src/libstd/rt/mod.rs | 51 +++++++++++++++++++++++-------------- src/libstd/sys.rs | 4 +-- src/libstd/task/mod.rs | 15 ++++++----- src/libstd/task/spawn.rs | 17 ++++++------- src/libstd/unstable/lang.rs | 17 +++++-------- src/libstd/unstable/sync.rs | 26 +++++++++++-------- 9 files changed, 92 insertions(+), 68 deletions(-) diff --git a/src/libstd/os.rs b/src/libstd/os.rs index f246a61a4d580..f7bd2aa240d7d 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1142,9 +1142,9 @@ pub fn real_args() -> ~[~str] { #[cfg(target_os = "freebsd")] pub fn real_args() -> ~[~str] { use rt; - use rt::TaskContext; + use rt::NewRtContext; - if rt::context() == TaskContext { + if rt::context() == NewRtContext { match rt::args::clone() { Some(args) => args, None => fail!("process arguments not initialized") diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 936a6526508a9..793e244bec7b9 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -15,6 +15,7 @@ use cast; use ops::Drop; use rt::kill::BlockedTask; use kinds::Send; +use rt; use rt::sched::Scheduler; use rt::local::Local; use rt::select::{Select, SelectPort}; @@ -24,7 +25,6 @@ use util::Void; use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable}; use cell::Cell; use clone::Clone; -use rt::{context, SchedulerContext}; use tuple::ImmutableTuple; /// A combined refcount / BlockedTask-as-uint pointer. @@ -113,7 +113,7 @@ impl ChanOne { // 'do_resched' configures whether the scheduler immediately switches to // the receiving task, or leaves the sending task still running. fn try_send_inner(self, val: T, do_resched: bool) -> bool { - rtassert!(context() != SchedulerContext); + rtassert!(!rt::in_sched_context()); let mut this = self; let mut recvr_active = true; diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index e1e7ceacc3834..8832597f40c45 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -13,6 +13,7 @@ use libc; use libc::{c_void, uintptr_t, size_t}; use ops::Drop; +use option::{Some, None}; use rt; use rt::OldTaskContext; use rt::local::Local; @@ -86,8 +87,12 @@ impl Drop for LocalHeap { // A little compatibility function pub unsafe fn local_free(ptr: *libc::c_char) { - match rt::context() { - OldTaskContext => { + // XXX: Unsafe borrow for speed. Lame. + match Local::try_unsafe_borrow::() { + Some(task) => { + (*task).heap.free(ptr as *libc::c_void); + } + None => { rust_upcall_free_noswitch(ptr); extern { @@ -95,11 +100,6 @@ pub unsafe fn local_free(ptr: *libc::c_char) { fn rust_upcall_free_noswitch(ptr: *libc::c_char); } } - _ => { - do Local::borrow:: |task| { - task.heap.free(ptr as *libc::c_void); - } - } } } @@ -119,20 +119,28 @@ pub fn live_allocs() -> *raw::Box<()> { } extern { + #[fast_ffi] fn rust_new_memory_region(synchronized: uintptr_t, detailed_leaks: uintptr_t, poison_on_free: uintptr_t) -> *MemoryRegion; + #[fast_ffi] fn rust_delete_memory_region(region: *MemoryRegion); + #[fast_ffi] fn rust_new_boxed_region(region: *MemoryRegion, poison_on_free: uintptr_t) -> *BoxedRegion; + #[fast_ffi] fn rust_delete_boxed_region(region: *BoxedRegion); + #[fast_ffi] fn rust_boxed_region_malloc(region: *BoxedRegion, td: *TypeDesc, size: size_t) -> *OpaqueBox; + #[fast_ffi] fn rust_boxed_region_realloc(region: *BoxedRegion, ptr: *OpaqueBox, size: size_t) -> *OpaqueBox; + #[fast_ffi] fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); + #[fast_ffi] fn rust_current_boxed_region() -> *BoxedRegion; } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 01a52892f633b..be71bc651df59 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -407,14 +407,10 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { /// or the old scheduler. #[deriving(Eq)] pub enum RuntimeContext { - // Only the exchange heap is available - GlobalContext, - // The scheduler may be accessed - SchedulerContext, - // Full task services, e.g. local heap, unwinding - TaskContext, // Running in an old-style task - OldTaskContext + OldTaskContext, + // Not old task context + NewRtContext } /// Determine the current RuntimeContext @@ -424,19 +420,8 @@ pub fn context() -> RuntimeContext { if unsafe { rust_try_get_task().is_not_null() } { return OldTaskContext; - } else if Local::exists::() { - // In this case we know it is a new runtime context, but we - // need to check which one. Going to try borrowing task to - // check. Task should always be in TLS, so hopefully this - // doesn't conflict with other ops that borrow. - return do Local::borrow:: |task| { - match task.task_type { - SchedTask => SchedulerContext, - GreenTask(_) => TaskContext - } - }; } else { - return GlobalContext; + return NewRtContext; } extern { @@ -444,3 +429,31 @@ pub fn context() -> RuntimeContext { pub fn rust_try_get_task() -> *rust_task; } } + +pub fn in_sched_context() -> bool { + unsafe { + match Local::try_unsafe_borrow::() { + Some(task) => { + match (*task).task_type { + SchedTask => true, + _ => false + } + } + None => false + } + } +} + +pub fn in_green_task_context() -> bool { + unsafe { + match Local::try_unsafe_borrow::() { + Some(task) => { + match (*task).task_type { + GreenTask(_) => true, + _ => false + } + } + None => false + } + } +} \ No newline at end of file diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 9d853087123e8..15c096ad04fd5 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -136,7 +136,7 @@ impl FailWithCause for &'static str { pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { use either::Left; use option::{Some, None}; - use rt::{context, OldTaskContext, TaskContext}; + use rt::{context, OldTaskContext, in_green_task_context}; use rt::task::Task; use rt::local::Local; use rt::logging::Logger; @@ -158,7 +158,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { // XXX: Logging doesn't work correctly in non-task context because it // invokes the local heap - if context == TaskContext { + if in_green_task_context() { // XXX: Logging doesn't work here - the check to call the log // function never passes - so calling the log function directly. do Local::borrow:: |task| { diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 2e0c9c1d1ad1e..269c828a9845f 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -42,7 +42,7 @@ use cmp::Eq; use comm::{stream, Chan, GenericChan, GenericPort, Port}; use result::Result; use result; -use rt::{context, OldTaskContext, TaskContext}; +use rt::{context, OldTaskContext, in_green_task_context}; use rt::local::Local; use unstable::finally::Finally; use util; @@ -527,14 +527,15 @@ pub fn try(f: ~fn() -> T) -> Result { pub fn with_task_name(blk: &fn(Option<&str>) -> U) -> U { use rt::task::Task; - match context() { - TaskContext => do Local::borrow:: |task| { + if in_green_task_context() { + do Local::borrow:: |task| { match task.name { Some(ref name) => blk(Some(name.as_slice())), None => blk(None) } - }, - _ => fail!("no task name exists in %?", context()), + } + } else { + fail!("no task name exists in %?", context()) } } @@ -614,7 +615,7 @@ pub fn unkillable(f: &fn() -> U) -> U { rt::rust_task_allow_kill(t); } } - TaskContext => { + _ if in_green_task_context() => { // The inhibits/allows might fail and need to borrow the task. let t = Local::unsafe_borrow::(); do (|| { @@ -645,7 +646,7 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { rt::rust_task_inhibit_kill(t); } } - TaskContext => { + _ if in_green_task_context() => { let t = Local::unsafe_borrow::(); do (|| { (*t).death.allow_kill((*t).unwinder.unwinding); diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 05a17f8539c21..314377b8dc9c1 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -91,7 +91,7 @@ use to_bytes::IterBytes; use uint; use util; use unstable::sync::Exclusive; -use rt::{OldTaskContext, TaskContext, SchedulerContext, GlobalContext, context}; +use rt::{OldTaskContext, NewRtContext, context, in_green_task_context}; use rt::local::Local; use rt::task::{Task, Sched}; use rt::kill::KillHandle; @@ -526,7 +526,7 @@ impl RuntimeGlue { let me = rt::rust_get_task(); blk(OldTask(me), rt::rust_task_is_unwinding(me)) }, - TaskContext => unsafe { + NewRtContext if in_green_task_context() => unsafe { // Can't use safe borrow, because the taskgroup destructor needs to // access the scheduler again to send kill signals to other tasks. let me = Local::unsafe_borrow::(); @@ -535,7 +535,7 @@ impl RuntimeGlue { blk(NewTask((*me).death.kill_handle.get_ref().clone()), (*me).unwinder.unwinding) }, - SchedulerContext | GlobalContext => rtabort!("task dying in bad context"), + NewRtContext => rtabort!("task dying in bad context"), } } @@ -563,7 +563,7 @@ impl RuntimeGlue { } } }, - TaskContext => unsafe { + NewRtContext if in_green_task_context() => unsafe { // Can't use safe borrow, because creating new hashmaps for the // tasksets requires an rng, which needs to borrow the sched. let me = Local::unsafe_borrow::(); @@ -588,7 +588,7 @@ impl RuntimeGlue { Some(ref group) => group, }) }, - SchedulerContext | GlobalContext => rtabort!("spawning in bad context"), + NewRtContext => rtabort!("spawning in bad context"), } } } @@ -666,10 +666,9 @@ fn enlist_many(child: TaskHandle, child_arc: &TaskGroupArc, pub fn spawn_raw(opts: TaskOpts, f: ~fn()) { match context() { - OldTaskContext => spawn_raw_oldsched(opts, f), - TaskContext => spawn_raw_newsched(opts, f), - SchedulerContext => fail!("can't spawn from scheduler context"), - GlobalContext => fail!("can't spawn from global context"), + OldTaskContext => spawn_raw_oldsched(opts, f), + _ if in_green_task_context() => spawn_raw_newsched(opts, f), + _ => fail!("can't spawn from this context") } } diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 98c0fe254b697..c5112529aed9f 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -12,9 +12,9 @@ use cast::transmute; use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int}; +use option::{Some, None}; use str; use sys; -use rt::{context, OldTaskContext}; use rt::task::Task; use rt::local::Local; use rt::borrowck; @@ -56,16 +56,13 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, #[lang="malloc"] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - match context() { - OldTaskContext => { - return rustrt::rust_upcall_malloc_noswitch(td, size); + // XXX: Unsafe borrow for speed. Lame. + match Local::try_unsafe_borrow::() { + Some(task) => { + (*task).heap.alloc(td as *c_void, size as uint) as *c_char } - _ => { - let mut alloc = ::ptr::null(); - do Local::borrow:: |task| { - alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char; - } - return alloc; + None => { + rustrt::rust_upcall_malloc_noswitch(td, size) } } } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 225ac5c92adcf..a8d942a46b315 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -282,7 +282,7 @@ pub unsafe fn atomically(f: &fn() -> U) -> U { use rt::task::Task; use task::rt; use rt::local::Local; - use rt::{context, OldTaskContext, TaskContext}; + use rt::{context, OldTaskContext}; match context() { OldTaskContext => { @@ -296,17 +296,23 @@ pub unsafe fn atomically(f: &fn() -> U) -> U { rt::rust_task_allow_kill(t); } } - TaskContext => { - let t = Local::unsafe_borrow::(); - do (|| { - (*t).death.inhibit_yield(); - f() - }).finally { - (*t).death.allow_yield(); + _ => { + let t = Local::try_unsafe_borrow::(); + match t { + Some(t) => { + do (|| { + (*t).death.inhibit_yield(); + f() + }).finally { + (*t).death.allow_yield(); + } + } + None => { + // FIXME(#3095): As in unkillable(). + f() + } } } - // FIXME(#3095): As in unkillable(). - _ => f() } } From ae81151ad63e2db7ec893f90a4e99592cabb6b30 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 9 Aug 2013 13:53:28 +0400 Subject: [PATCH 16/18] Fix Ipv6Addr to_str for ::1:x.x.x.x addresses Reported by luqmana@ --- src/libstd/rt/io/net/ip.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 81269d197d501..77176088801de 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -43,7 +43,7 @@ impl ToStr for IpAddr { } // Ipv4-Mapped address - Ipv6Addr(0, 0, 0, 0, 0, 1, g, h) => { + Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, g, h) => { let a = fmt!("%04x", g as uint); let b = FromStrRadix::from_str_radix(a.slice(2, 4), 16).unwrap(); let a = FromStrRadix::from_str_radix(a.slice(0, 2), 16).unwrap(); @@ -437,4 +437,11 @@ mod test { // port out of range assert_eq!(None, FromStr::from_str::("127.0.0.1:123456")); } + + #[test] + fn ipv6_addr_to_str() { + let a1 = Ipv6Addr(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert!(a1.to_str() == ~"::ffff:192.0.2.128" || a1.to_str() == ~"::FFFF:192.0.2.128"); + } + } From 96fd606dddba6bd4773c41be66c44fc076a96ff8 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 31 Jul 2013 13:47:32 -0700 Subject: [PATCH 17/18] std/rustc/rustpkg/syntax: Support the `extern mod = ...` form This commit allows you to write: extern mod x = "a/b/c"; which means rustc will search in the RUST_PATH for a package with ID a/b/c, and bind it to the name `x` if it's found. Incidentally, move get_relative_to from back::rpath into std::path --- doc/rust.md | 30 ++- mk/tests.mk | 2 +- src/librustc/back/link.rs | 23 ++- src/librustc/back/rpath.rs | 117 +---------- src/librustc/front/std_inject.rs | 2 +- src/librustc/front/test.rs | 2 +- src/librustc/metadata/common.rs | 2 + src/librustc/metadata/creader.rs | 45 +++-- src/librustc/metadata/filesearch.rs | 143 ++++++++------ src/librustc/metadata/loader.rs | 78 ++++---- src/librustc/middle/resolve.rs | 5 +- src/librustpkg/api.rs | 24 +-- src/librustpkg/context.rs | 24 +++ src/librustpkg/installed_packages.rs | 42 +++- src/librustpkg/package_id.rs | 9 +- src/librustpkg/package_source.rs | 21 +- src/librustpkg/path_util.rs | 103 +++------- src/librustpkg/rustpkg.rs | 76 ++++--- src/librustpkg/source_control.rs | 37 +++- src/librustpkg/tests.rs | 283 +++++++++++++++------------ src/librustpkg/util.rs | 106 ++++++---- src/librustpkg/version.rs | 27 ++- src/librustpkg/workspace.rs | 6 +- src/libstd/path.rs | 165 +++++++++++++++- src/libsyntax/ast.rs | 6 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/parse/parser.rs | 23 ++- src/libsyntax/print/pprust.rs | 6 +- src/test/run-pass/extern-mod-url.rs | 16 -- 29 files changed, 821 insertions(+), 604 deletions(-) delete mode 100644 src/test/run-pass/extern-mod-url.rs diff --git a/doc/rust.md b/doc/rust.md index 2f5c310ec8328..d285253ffe200 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -744,7 +744,7 @@ There are several kinds of view item: ##### Extern mod declarations ~~~~~~~~ {.ebnf .gram} -extern_mod_decl : "extern" "mod" ident [ '(' link_attrs ')' ] ? ; +extern_mod_decl : "extern" "mod" ident [ '(' link_attrs ')' ] ? [ '=' string_lit ] ? ; link_attrs : link_attr [ ',' link_attrs ] + ; link_attr : ident '=' literal ; ~~~~~~~~ @@ -755,13 +755,25 @@ as the `ident` provided in the `extern_mod_decl`. The external crate is resolved to a specific `soname` at compile time, and a runtime linkage requirement to that `soname` is passed to the linker for -loading at runtime. The `soname` is resolved at compile time by scanning the -compiler's library path and matching the `link_attrs` provided in the -`use_decl` against any `#link` attributes that were declared on the external -crate when it was compiled. If no `link_attrs` are provided, a default `name` -attribute is assumed, equal to the `ident` given in the `use_decl`. - -Three examples of `extern mod` declarations: +loading at runtime. +The `soname` is resolved at compile time by scanning the compiler's library path +and matching the `link_attrs` provided in the `use_decl` against any `#link` attributes that +were declared on the external crate when it was compiled. +If no `link_attrs` are provided, +a default `name` attribute is assumed, +equal to the `ident` given in the `use_decl`. + +Optionally, an identifier in an `extern mod` declaration may be followed by an equals sign, +then a string literal denoting a relative path on the filesystem. +This path should exist in one of the directories in the Rust path, +which by default contains the `.rust` subdirectory of the current directory and each of its parents, +as well as any directories in the colon-separated (or semicolon-separated on Windows) +list of paths that is the `RUST_PATH` environment variable. +The meaning of `extern mod a = "b/c/d";`, supposing that `/a` is in the RUST_PATH, +is that the name `a` should be taken as a reference to the crate whose absolute location is +`/a/b/c/d`. + +Four examples of `extern mod` declarations: ~~~~~~~~{.xfail-test} extern mod pcre (uuid = "54aba0f8-a7b1-4beb-92f1-4cf625264841"); @@ -769,6 +781,8 @@ extern mod pcre (uuid = "54aba0f8-a7b1-4beb-92f1-4cf625264841"); extern mod extra; // equivalent to: extern mod extra ( name = "extra" ); extern mod rustextra (name = "extra"); // linking to 'extra' under another name + +extern mod complicated_mod = "some-file/in/the-rust/path"; ~~~~~~~~ ##### Use declarations diff --git a/mk/tests.mk b/mk/tests.mk index 45a6e1447fc07..536a153b22281 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -348,7 +348,7 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \ $$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \ $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \ - $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) + $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \ $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 637ea159d79d0..bd95f1b735b00 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -16,7 +16,7 @@ use lib::llvm::llvm; use lib::llvm::ModuleRef; use lib; use metadata::common::LinkMeta; -use metadata::{encoder, csearch, cstore}; +use metadata::{encoder, csearch, cstore, filesearch}; use middle::trans::context::CrateContext; use middle::trans::common::gensym_name; use middle::ty; @@ -497,6 +497,7 @@ pub fn build_link_meta(sess: Session, struct ProvidedMetas { name: Option<@str>, vers: Option<@str>, + pkg_id: Option<@str>, cmh_items: ~[@ast::MetaItem] } @@ -504,6 +505,7 @@ pub fn build_link_meta(sess: Session, ProvidedMetas { let mut name = None; let mut vers = None; + let mut pkg_id = None; let mut cmh_items = ~[]; let linkage_metas = attr::find_linkage_metas(c.attrs); attr::require_unique_names(sess.diagnostic(), linkage_metas); @@ -511,6 +513,7 @@ pub fn build_link_meta(sess: Session, match meta.name_str_pair() { Some((n, value)) if "name" == n => name = Some(value), Some((n, value)) if "vers" == n => vers = Some(value), + Some((n, value)) if "package_id" == n => pkg_id = Some(value), _ => cmh_items.push(*meta) } } @@ -518,6 +521,7 @@ pub fn build_link_meta(sess: Session, ProvidedMetas { name: name, vers: vers, + pkg_id: pkg_id, cmh_items: cmh_items } } @@ -525,7 +529,8 @@ pub fn build_link_meta(sess: Session, // This calculates CMH as defined above fn crate_meta_extras_hash(symbol_hasher: &mut hash::State, cmh_items: ~[@ast::MetaItem], - dep_hashes: ~[@str]) -> @str { + dep_hashes: ~[@str], + pkg_id: Option<@str>) -> @str { fn len_and_str(s: &str) -> ~str { fmt!("%u_%s", s.len(), s) } @@ -563,7 +568,10 @@ pub fn build_link_meta(sess: Session, write_string(symbol_hasher, len_and_str(*dh)); } - // tjc: allocation is unfortunate; need to change std::hash + for p in pkg_id.iter() { + write_string(symbol_hasher, len_and_str(*p)); + } + return truncated_hash_result(symbol_hasher).to_managed(); } @@ -605,6 +613,7 @@ pub fn build_link_meta(sess: Session, let ProvidedMetas { name: opt_name, vers: opt_vers, + pkg_id: opt_pkg_id, cmh_items: cmh_items } = provided_link_metas(sess, c); let name = crate_meta_name(sess, output, opt_name); @@ -612,11 +621,12 @@ pub fn build_link_meta(sess: Session, let dep_hashes = cstore::get_dep_hashes(sess.cstore); let extras_hash = crate_meta_extras_hash(symbol_hasher, cmh_items, - dep_hashes); + dep_hashes, opt_pkg_id); LinkMeta { name: name, vers: vers, + package_id: opt_pkg_id, extras_hash: extras_hash } } @@ -939,6 +949,11 @@ pub fn link_args(sess: Session, args.push(~"-L" + path.to_str()); } + let rustpath = filesearch::rust_path(); + for path in rustpath.iter() { + args.push(~"-L" + path.to_str()); + } + // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); for l in used_libs.iter() { args.push(~"-l" + *l); } diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 571721ed40cee..231295475621e 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -14,10 +14,7 @@ use metadata::cstore; use metadata::filesearch; use std::hashmap::HashSet; -use std::num; -use std::os; -use std::util; -use std::vec; +use std::{num, os, path, uint, util, vec}; fn not_win32(os: session::os) -> bool { os != session::os_win32 @@ -122,42 +119,7 @@ pub fn get_rpath_relative_to_output(os: session::os, session::os_win32 => util::unreachable() }; - Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output), - &os::make_absolute(lib))) -} - -// Find the relative path from one file to another -pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path { - assert!(abs1.is_absolute); - assert!(abs2.is_absolute); - let abs1 = abs1.normalize(); - let abs2 = abs2.normalize(); - debug!("finding relative path from %s to %s", - abs1.to_str(), abs2.to_str()); - let split1: &[~str] = abs1.components; - let split2: &[~str] = abs2.components; - let len1 = split1.len(); - let len2 = split2.len(); - assert!(len1 > 0); - assert!(len2 > 0); - - let max_common_path = num::min(len1, len2) - 1; - let mut start_idx = 0; - while start_idx < max_common_path - && split1[start_idx] == split2[start_idx] { - start_idx += 1; - } - - let mut path = ~[]; - for _ in range(start_idx, len1 - 1) { path.push(~".."); }; - - path.push_all(split2.slice(start_idx, len2 - 1)); - - return if !path.is_empty() { - Path("").push_many(path) - } else { - Path(".") - } + Path(prefix).push_rel(&os::make_absolute(output).get_relative_to(&os::make_absolute(lib))) } fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] { @@ -199,8 +161,7 @@ mod test { #[cfg(test)] #[cfg(test)] use back::rpath::{get_absolute_rpath, get_install_prefix_rpath}; - use back::rpath::{get_relative_to, get_rpath_relative_to_output}; - use back::rpath::{minimize_rpaths, rpaths_to_flags}; + use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; use driver::session; #[test] @@ -244,78 +205,9 @@ mod test { assert_eq!(res, ~[Path("1a"), Path("2"), Path("4a"), Path("3")]); } - #[test] - fn test_relative_to1() { - let p1 = Path("/usr/bin/rustc"); - let p2 = Path("/usr/lib/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to2() { - let p1 = Path("/usr/bin/rustc"); - let p2 = Path("/usr/bin/../lib/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to3() { - let p1 = Path("/usr/bin/whatever/rustc"); - let p2 = Path("/usr/lib/whatever/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../../lib/whatever")); - } - - #[test] - fn test_relative_to4() { - let p1 = Path("/usr/bin/whatever/../rustc"); - let p2 = Path("/usr/lib/whatever/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib/whatever")); - } - - #[test] - fn test_relative_to5() { - let p1 = Path("/usr/bin/whatever/../rustc"); - let p2 = Path("/usr/lib/whatever/../mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to6() { - let p1 = Path("/1"); - let p2 = Path("/2/3"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("2")); - } - - #[test] - fn test_relative_to7() { - let p1 = Path("/1/2"); - let p2 = Path("/3"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("..")); - } - - #[test] - fn test_relative_to8() { - let p1 = Path("/home/brian/Dev/rust/build/").push_rel( - &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); - let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( - &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); - let res = get_relative_to(&p1, &p2); - debug!("test_relative_tu8: %s vs. %s", - res.to_str(), - Path(".").to_str()); - assert_eq!(res, Path(".")); - } - #[test] #[cfg(target_os = "linux")] - #[cfg(target_os = "andorid")] + #[cfg(target_os = "android")] fn test_rpath_relative() { let o = session::os_linux; let res = get_rpath_relative_to_output(o, @@ -335,7 +227,6 @@ mod test { #[test] #[cfg(target_os = "macos")] fn test_rpath_relative() { - // this is why refinements would be nice let o = session::os_macos; let res = get_rpath_relative_to_output(o, &Path("bin/rustc"), diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 3a1129b1dd94e..2a61ea28e0c6b 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -47,7 +47,7 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate { let n1 = sess.next_node_id(); let vi1 = ast::view_item { node: ast::view_item_extern_mod( - sess.ident_of("std"), ~[], n1), + sess.ident_of("std"), None, ~[], n1), attrs: ~[ attr::mk_attr( attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed())) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index d2d2a8b4be99d..c6b1bdbe51ba1 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -282,7 +282,7 @@ fn mk_std(cx: &TestCtxt) -> ast::view_item { cx.sess.next_node_id()))]) } else { let mi = attr::mk_name_value_item_str(@"vers", @"0.8-pre"); - ast::view_item_extern_mod(id_extra, ~[mi], cx.sess.next_node_id()) + ast::view_item_extern_mod(id_extra, None, ~[mi], cx.sess.next_node_id()) }; ast::view_item { node: vi, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 1c5d202d4d953..f2d8b68faa6f3 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -185,5 +185,7 @@ pub static tag_item_impl_vtables: uint = 0x82; pub struct LinkMeta { name: @str, vers: @str, + // Optional package ID + package_id: Option<@str>, // non-None if this was a URL-like package ID extras_hash: @str } diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index d8f1422882435..0a9e8490f22dc 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -18,6 +18,7 @@ use metadata::loader; use std::hashmap::HashMap; use syntax::ast; +use std::vec; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::codemap::{span, dummy_sp}; @@ -137,18 +138,33 @@ fn visit_crate(e: &Env, c: &ast::Crate) { fn visit_view_item(e: @mut Env, i: &ast::view_item) { match i.node { - ast::view_item_extern_mod(ident, ref meta_items, id) => { - debug!("resolving extern mod stmt. ident: %?, meta: %?", - ident, *meta_items); - let cnum = resolve_crate(e, - ident, - (*meta_items).clone(), - @"", - i.span); - cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); + ast::view_item_extern_mod(ident, path_opt, ref meta_items, id) => { + let ident = token::ident_to_str(&ident); + let meta_items = match path_opt { + None => meta_items.clone(), + Some(p) => { + let p_path = Path(p); + match p_path.filestem() { + Some(s) => + vec::append( + ~[attr::mk_name_value_item_str(@"package_id", p), + attr::mk_name_value_item_str(@"name", s.to_managed())], + *meta_items), + None => e.diag.span_bug(i.span, "Bad package path in `extern mod` item") + } + } + }; + debug!("resolving extern mod stmt. ident: %?, meta: %?", + ident, meta_items); + let cnum = resolve_crate(e, + ident, + meta_items, + @"", + i.span); + cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); } _ => () - } + } } fn visit_item(e: &Env, i: @ast::item) { @@ -233,12 +249,12 @@ fn existing_match(e: &Env, metas: &[@ast::MetaItem], hash: &str) } fn resolve_crate(e: @mut Env, - ident: ast::ident, + ident: @str, metas: ~[@ast::MetaItem], hash: @str, span: span) -> ast::CrateNum { - let metas = metas_with_ident(token::ident_to_str(&ident), metas); + let metas = metas_with_ident(ident, metas); match existing_match(e, metas, hash) { None => { @@ -279,7 +295,7 @@ fn resolve_crate(e: @mut Env, match attr::last_meta_item_value_str_by_name(load_ctxt.metas, "name") { Some(v) => v, - None => token::ident_to_str(&ident), + None => ident }; let cmeta = @cstore::crate_metadata { name: cname, @@ -308,7 +324,6 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { let r = decoder::get_crate_deps(cdata); for dep in r.iter() { let extrn_cnum = dep.cnum; - let cname = dep.name; let cname_str = token::ident_to_str(&dep.name); let cmetas = metas_with(dep.vers, @"vers", ~[]); debug!("resolving dep crate %s ver: %s hash: %s", @@ -327,7 +342,7 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { // FIXME (#2404): Need better error reporting than just a bogus // span. let fake_span = dummy_sp(); - let local_cnum = resolve_crate(e, cname, cmetas, dep.hash, + let local_cnum = resolve_crate(e, cname_str, cmetas, dep.hash, fake_span); cnum_map.insert(extrn_cnum, local_cnum); } diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 2422be3960b44..2311ef0696199 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -11,12 +11,15 @@ use std::option; use std::os; -use std::result; +use std::{result, str}; +use std::hashmap::HashSet; // A module for searching for libraries // FIXME (#2658): I'm not happy how this module turned out. Should // probably just be folded into cstore. +/// Functions with type `pick` take a parent directory as well as +/// a file found in that directory. pub type pick<'self, T> = &'self fn(path: &Path) -> Option; pub fn pick_file(file: Path, path: &Path) -> Option { @@ -46,28 +49,33 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, impl FileSearch for FileSearchImpl { fn sysroot(&self) -> @Path { self.sysroot } fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool { + let mut visited_dirs = HashSet::new(); + debug!("filesearch: searching additional lib search paths [%?]", self.addl_lib_search_paths.len()); - // a little weird - self.addl_lib_search_paths.iter().advance(|path| f(path)); + for path in self.addl_lib_search_paths.iter() { + f(path); + visited_dirs.insert(path.to_str()); + } debug!("filesearch: searching target lib path"); - if !f(&make_target_lib_path(self.sysroot, - self.target_triple)) { - return false; - } - debug!("filesearch: searching rustpkg lib path nearest"); - if match get_rustpkg_lib_path_nearest() { - result::Ok(ref p) => f(p), - result::Err(_) => true - } { - return true; + let tlib_path = make_target_lib_path(self.sysroot, + self.target_triple); + if !visited_dirs.contains(&tlib_path.to_str()) { + if !f(&tlib_path) { + return false; } - debug!("filesearch: searching rustpkg lib path"); - match get_rustpkg_lib_path() { - result::Ok(ref p) => f(p), - result::Err(_) => true - } + } + visited_dirs.insert(tlib_path.to_str()); + // Try RUST_PATH + let rustpath = rust_path(); + for path in rustpath.iter() { + if !visited_dirs.contains(&path.push("lib").to_str()) { + f(&path.push("lib")); + visited_dirs.insert(path.push("lib").to_str()); + } + } + true } fn get_target_lib_path(&self) -> Path { make_target_lib_path(self.sysroot, self.target_triple) @@ -94,12 +102,15 @@ pub fn search(filesearch: @FileSearch, pick: pick) -> Option { for path in r.iter() { debug!("testing %s", path.to_str()); let maybe_picked = pick(path); - if maybe_picked.is_some() { - debug!("picked %s", path.to_str()); - rslt = maybe_picked; - break; - } else { - debug!("rejected %s", path.to_str()); + match maybe_picked { + Some(_) => { + debug!("picked %s", path.to_str()); + rslt = maybe_picked; + break; + } + None => { + debug!("rejected %s", path.to_str()); + } } } rslt.is_none() @@ -132,55 +143,59 @@ fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path { } } -pub fn get_rustpkg_sysroot() -> Result { - result::Ok(get_or_default_sysroot().push_many([libdir(), ~"rustpkg"])) +#[cfg(windows)] +static PATH_ENTRY_SEPARATOR: &'static str = ";"; +#[cfg(not(windows))] +static PATH_ENTRY_SEPARATOR: &'static str = ":"; + +/// Returns RUST_PATH as a string, without default paths added +pub fn get_rust_path() -> Option<~str> { + os::getenv("RUST_PATH") } -pub fn get_rustpkg_root() -> Result { - match os::getenv("RUSTPKG_ROOT") { - Some(ref _p) => result::Ok(Path((*_p))), - None => match os::homedir() { - Some(ref _q) => result::Ok((*_q).push(".rustpkg")), - None => result::Err(~"no RUSTPKG_ROOT or home directory") +/// Returns the value of RUST_PATH, as a list +/// of Paths. Includes default entries for, if they exist: +/// $HOME/.rust +/// DIR/.rust for any DIR that's the current working directory +/// or an ancestor of it +pub fn rust_path() -> ~[Path] { + let mut env_rust_path: ~[Path] = match get_rust_path() { + Some(env_path) => { + let env_path_components: ~[&str] = + env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect(); + env_path_components.map(|&s| Path(s)) } + None => ~[] + }; + let cwd = os::getcwd(); + // now add in default entries + let cwd_dot_rust = cwd.push(".rust"); + if !env_rust_path.contains(&cwd_dot_rust) { + env_rust_path.push(cwd_dot_rust); } -} - -pub fn get_rustpkg_root_nearest() -> Result { - do get_rustpkg_root().chain |p| { - let cwd = os::getcwd(); - let cwd_rustpkg = cwd.push(".rustpkg"); - let rustpkg_is_non_root_file = - !os::path_is_dir(&cwd_rustpkg) && cwd_rustpkg != p; - let mut par_rustpkg = cwd.pop().push(".rustpkg"); - let mut rslt = result::Ok(cwd_rustpkg); - - if rustpkg_is_non_root_file { - while par_rustpkg != p { - if os::path_is_dir(&par_rustpkg) { - rslt = result::Ok(par_rustpkg); - break; - } - if par_rustpkg.components.len() == 1 { - // We just checked /.rustpkg, stop now. - break; - } - par_rustpkg = par_rustpkg.pop().pop().push(".rustpkg"); - } + if !env_rust_path.contains(&cwd) { + env_rust_path.push(cwd.clone()); + } + do cwd.each_parent() |p| { + if !env_rust_path.contains(&p.push(".rust")) { + push_if_exists(&mut env_rust_path, p); } - rslt } -} - -fn get_rustpkg_lib_path() -> Result { - do get_rustpkg_root().chain |p| { - result::Ok(p.push(libdir())) + let h = os::homedir(); + for h in h.iter() { + if !env_rust_path.contains(&h.push(".rust")) { + push_if_exists(&mut env_rust_path, h); + } } + env_rust_path } -fn get_rustpkg_lib_path_nearest() -> Result { - do get_rustpkg_root_nearest().chain |p| { - result::Ok(p.push(libdir())) + +/// Adds p/.rust into vec, only if it exists +fn push_if_exists(vec: &mut ~[Path], p: &Path) { + let maybe_dir = p.push(".rust"); + if os::path_exists(&maybe_dir) { + vec.push(maybe_dir); } } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 9330cfc5c88b4..5f145d87ca8d5 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -18,7 +18,6 @@ use metadata::filesearch::FileSearch; use metadata::filesearch; use syntax::codemap::span; use syntax::diagnostic::span_handler; -use syntax::parse::token; use syntax::parse::token::ident_interner; use syntax::print::pprust; use syntax::{ast, attr}; @@ -46,7 +45,7 @@ pub struct Context { diag: @span_handler, filesearch: @FileSearch, span: span, - ident: ast::ident, + ident: @str, metas: ~[@ast::MetaItem], hash: @str, os: os, @@ -60,7 +59,7 @@ pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) { None => { cx.diag.span_fatal(cx.span, fmt!("can't find crate for `%s`", - token::ident_to_str(&cx.ident))); + cx.ident)); } } } @@ -89,37 +88,38 @@ fn find_library_crate_aux( filesearch: @filesearch::FileSearch ) -> Option<(~str, @~[u8])> { let crate_name = crate_name_from_metas(cx.metas); - let prefix = prefix + crate_name + "-"; - + // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" + let prefix = fmt!("%s%s-", prefix, crate_name); let mut matches = ~[]; filesearch::search(filesearch, |path| -> Option<()> { - debug!("inspecting file %s", path.to_str()); - match path.filename() { - Some(ref f) if f.starts_with(prefix) && f.ends_with(suffix) => { - debug!("%s is a candidate", path.to_str()); - match get_metadata_section(cx.os, path) { - Some(cvec) => - if !crate_matches(cvec, cx.metas, cx.hash) { - debug!("skipping %s, metadata doesn't match", - path.to_str()); - None - } else { - debug!("found %s with matching metadata", path.to_str()); - matches.push((path.to_str(), cvec)); - None - }, - _ => { - debug!("could not load metadata for %s", path.to_str()); - None - } - } - } - _ => { - debug!("skipping %s, doesn't look like %s*%s", path.to_str(), - prefix, suffix); - None - } - }}); + let path_str = path.filename(); + match path_str { + None => None, + Some(path_str) => + if path_str.starts_with(prefix) && path_str.ends_with(suffix) { + debug!("%s is a candidate", path.to_str()); + match get_metadata_section(cx.os, path) { + Some(cvec) => + if !crate_matches(cvec, cx.metas, cx.hash) { + debug!("skipping %s, metadata doesn't match", + path.to_str()); + None + } else { + debug!("found %s with matching metadata", path.to_str()); + matches.push((path.to_str(), cvec)); + None + }, + _ => { + debug!("could not load metadata for %s", path.to_str()); + None + } + } + } + else { + None + } + } + }); match matches.len() { 0 => None, @@ -137,8 +137,8 @@ fn find_library_crate_aux( } cx.diag.handler().abort_if_errors(); None - } } + } } pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str { @@ -151,6 +151,16 @@ pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str { fail!("expected to find the crate name") } +pub fn package_id_from_metas(metas: &[@ast::MetaItem]) -> Option<@str> { + for m in metas.iter() { + match m.name_str_pair() { + Some((name, s)) if "package_id" == name => { return Some(s); } + _ => {} + } + } + None +} + pub fn note_linkage_attrs(intr: @ident_interner, diag: @span_handler, attrs: ~[ast::Attribute]) { @@ -175,6 +185,8 @@ fn crate_matches(crate_data: @~[u8], pub fn metadata_matches(extern_metas: &[@ast::MetaItem], local_metas: &[@ast::MetaItem]) -> bool { +// extern_metas: metas we read from the crate +// local_metas: metas we're looking for debug!("matching %u metadata requirements against %u items", local_metas.len(), extern_metas.len()); diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index da0ba1558c9bd..6ffe7c17ff612 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1487,9 +1487,10 @@ impl Resolver { } } - view_item_extern_mod(name, _, node_id) => { + view_item_extern_mod(name, _, _, node_id) => { + // n.b. we don't need to look at the path option here, because cstore already did match find_extern_mod_stmt_cnum(self.session.cstore, - node_id) { + node_id) { Some(crate_id) => { let def_id = def_id { crate: crate_id, node: 0 }; let parent_link = ModuleParentLink diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index bcda135cbb666..2da66baa412b5 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -23,33 +23,30 @@ fn default_ctxt(p: @Path) -> Ctx { Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() } } -pub fn build_lib(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, +pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version, lib: Path) { let pkg_src = PkgSrc { root: root, - dst_dir: dest.clone(), - id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())}, + id: PkgId{ version: version, ..PkgId::new(name)}, libs: ~[mk_crate(lib)], mains: ~[], tests: ~[], benchs: ~[] }; - pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + pkg_src.build(&default_ctxt(sysroot), ~[]); } -pub fn build_exe(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, - main: Path) { +pub fn build_exe(sysroot: @Path, root: Path, name: ~str, version: Version, main: Path) { let pkg_src = PkgSrc { root: root, - dst_dir: dest.clone(), - id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())}, + id: PkgId{ version: version, ..PkgId::new(name)}, libs: ~[], mains: ~[mk_crate(main)], tests: ~[], benchs: ~[] }; - pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + pkg_src.build(&default_ctxt(sysroot), ~[]); } @@ -62,12 +59,9 @@ pub fn install_lib(sysroot: @Path, debug!("sysroot = %s", sysroot.to_str()); debug!("workspace = %s", workspace.to_str()); // make a PkgSrc - let pkg_id = PkgId{ version: version, ..PkgId::new(name, &workspace)}; - let build_dir = workspace.push("build"); - let dst_dir = build_dir.push_rel(&*pkg_id.local_path); + let pkg_id = PkgId{ version: version, ..PkgId::new(name)}; let pkg_src = PkgSrc { root: workspace.clone(), - dst_dir: dst_dir.clone(), id: pkg_id.clone(), libs: ~[mk_crate(lib_path)], mains: ~[], @@ -75,13 +69,13 @@ pub fn install_lib(sysroot: @Path, benchs: ~[] }; let cx = default_ctxt(sysroot); - pkg_src.build(&cx, dst_dir, ~[]); + pkg_src.build(&cx, ~[]); cx.install_no_build(&workspace, &pkg_id); } pub fn install_exe(sysroot: @Path, workspace: Path, name: ~str, version: Version) { default_ctxt(sysroot).install(&workspace, &PkgId{ version: version, - ..PkgId::new(name, &workspace)}); + ..PkgId::new(name)}); } diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 230a0f915ac31..f051be25f266d 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -12,6 +12,7 @@ use std::hashmap::HashMap; +use std::os; pub struct Ctx { // Sysroot -- if this is None, uses rustc filesearch's @@ -23,3 +24,26 @@ pub struct Ctx { // though I'm not sure why the value is a bool dep_cache: @mut HashMap<~str, bool>, } + +impl Ctx { + /// Debugging + pub fn sysroot_opt_str(&self) -> ~str { + match self.sysroot_opt { + None => ~"[none]", + Some(p) => p.to_str() + } + } +} + +/// We assume that if ../../rustc exists, then we're running +/// rustpkg from a Rust target directory. This is part of a +/// kludgy hack used to adjust the sysroot. +pub fn in_target(sysroot_opt: Option<@Path>) -> bool { + match sysroot_opt { + None => false, + Some(p) => { + debug!("Checking whether %s is in target", p.to_str()); + os::path_is_dir(&p.pop().pop().push("rustc")) + } + } +} diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index cec64f36947e0..7c3cde655173b 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -10,6 +10,7 @@ // Listing installed packages +use rustc::metadata::filesearch::rust_path; use path_util::*; use std::os; @@ -20,21 +21,46 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { for exec in binfiles.iter() { let exec_path = Path(*exec).filestem(); do exec_path.iter().advance |s| { - f(&PkgId::new(*s, p)) + f(&PkgId::new(*s)) }; } let libfiles = os::list_dir(&p.push("lib")); for lib in libfiles.iter() { - debug!("Full name: %s", *lib); - let lib_path = Path(*lib).filestem(); - do lib_path.iter().advance |s| { - f(&PkgId::new(*s, p)) - }; - } + let lib = Path(*lib); + debug!("Full name: %s", lib.to_str()); + match has_library(&lib) { + Some(basename) => { + debug!("parent = %s, child = %s", + p.push("lib").to_str(), lib.to_str()); + let rel_p = p.push("lib/").get_relative_to(&lib); + debug!("Rel: %s", rel_p.to_str()); + let rel_path = rel_p.push(basename).to_str(); + debug!("Rel name: %s", rel_path); + f(&PkgId::new(rel_path)); + } + None => () + } + }; } true } +pub fn has_library(p: &Path) -> Option<~str> { + let files = os::list_dir(p); + for q in files.iter() { + let as_path = Path(*q); + if as_path.filetype() == Some(os::consts::DLL_SUFFIX.to_owned()) { + let stuff : ~str = as_path.filestem().expect("has_library: weird path"); + let mut stuff2 = stuff.split_str_iter(&"-"); + let stuff3: ~[&str] = stuff2.collect(); + // argh + let chars_to_drop = os::consts::DLL_PREFIX.len(); + return Some(stuff3[0].slice(chars_to_drop, stuff3[0].len()).to_owned()); + } + } + None +} + pub fn package_is_installed(p: &PkgId) -> bool { let mut is_installed = false; do list_installed_packages() |installed| { @@ -44,4 +70,4 @@ pub fn package_is_installed(p: &PkgId) -> bool { false }; is_installed -} \ No newline at end of file +} diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index e1cf5b1fd35c5..233e975cbb7e4 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -45,7 +45,7 @@ impl PkgId { // The PkgId constructor takes a Path argument so as // to be able to infer the version if the path refers // to a local git repository - pub fn new(s: &str, work_dir: &Path) -> PkgId { + pub fn new(s: &str) -> PkgId { use conditions::bad_pkg_id::cond; let mut given_version = None; @@ -76,7 +76,7 @@ impl PkgId { let version = match given_version { Some(v) => v, - None => match try_getting_local_version(&work_dir.push_rel(&*local_path)) { + None => match try_getting_local_version(&*local_path) { Some(v) => v, None => match try_getting_version(&remote_path) { Some(v) => v, @@ -103,6 +103,11 @@ impl PkgId { pub fn short_name_with_version(&self) -> ~str { fmt!("%s%s", self.short_name, self.version.to_str()) } + + /// True if the ID has multiple components + pub fn is_complex(&self) -> bool { + self.short_name != self.local_path.to_str() + } } impl ToStr for PkgId { diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index bbe35ee5004f6..b14f95cfae583 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -23,7 +23,6 @@ use util::compile_crate; // This contains a list of files found in the source workspace. pub struct PkgSrc { root: Path, // root of where the package source code lives - dst_dir: Path, // directory where we will put the compiled output id: PkgId, libs: ~[Crate], mains: ~[Crate], @@ -37,11 +36,9 @@ condition! { impl PkgSrc { - pub fn new(src_dir: &Path, dst_dir: &Path, - id: &PkgId) -> PkgSrc { + pub fn new(src_dir: &Path, id: &PkgId) -> PkgSrc { PkgSrc { root: (*src_dir).clone(), - dst_dir: (*dst_dir).clone(), id: (*id).clone(), libs: ~[], mains: ~[], @@ -202,7 +199,6 @@ impl PkgSrc { fn build_crates(&self, ctx: &Ctx, - dst_dir: &Path, src_dir: &Path, crates: &[Crate], cfgs: &[~str], @@ -210,12 +206,13 @@ impl PkgSrc { for crate in crates.iter() { let path = &src_dir.push_rel(&crate.file).normalize(); note(fmt!("build_crates: compiling %s", path.to_str())); - note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); + note(fmt!("build_crates: using as workspace %s", self.root.to_str())); let result = compile_crate(ctx, &self.id, path, - dst_dir, + // compile_crate wants the workspace + &self.root, crate.flags, crate.cfgs + cfgs, false, @@ -229,15 +226,15 @@ impl PkgSrc { } } - pub fn build(&self, ctx: &Ctx, dst_dir: Path, cfgs: ~[~str]) { + pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) { let dir = self.check_dir(); debug!("Building libs in %s", dir.to_str()); - self.build_crates(ctx, &dst_dir, &dir, self.libs, cfgs, Lib); + self.build_crates(ctx, &dir, self.libs, cfgs, Lib); debug!("Building mains"); - self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main); + self.build_crates(ctx, &dir, self.mains, cfgs, Main); debug!("Building tests"); - self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test); + self.build_crates(ctx, &dir, self.tests, cfgs, Test); debug!("Building benches"); - self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench); + self.build_crates(ctx, &dir, self.benchs, cfgs, Bench); } } diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 1c54b6304215f..3eff260e79a9d 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -14,61 +14,14 @@ pub use package_path::{RemotePath, LocalPath, normalize}; pub use package_id::PkgId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; pub use version::{Version, NoVersion, split_version_general}; +pub use rustc::metadata::filesearch::rust_path; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os::mkdir_recursive; use std::os; -use std::iterator::IteratorUtil; use messages::*; use package_id::*; -fn push_if_exists(vec: &mut ~[Path], p: &Path) { - let maybe_dir = p.push(".rust"); - if os::path_exists(&maybe_dir) { - vec.push(maybe_dir); - } -} - -#[cfg(windows)] -static PATH_ENTRY_SEPARATOR: &'static str = ";"; -#[cfg(not(windows))] -static PATH_ENTRY_SEPARATOR: &'static str = ":"; - -/// Returns RUST_PATH as a string, without default paths added -pub fn get_rust_path() -> Option<~str> { - os::getenv("RUST_PATH") -} - -/// Returns the value of RUST_PATH, as a list -/// of Paths. Includes default entries for, if they exist: -/// $HOME/.rust -/// DIR/.rust for any DIR that's the current working directory -/// or an ancestor of it -pub fn rust_path() -> ~[Path] { - let mut env_rust_path: ~[Path] = match get_rust_path() { - Some(env_path) => { - let env_path_components: ~[&str] = - env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect(); - env_path_components.map(|&s| Path(s)) - } - None => ~[] - }; - debug!("RUST_PATH entries from environment: %?", env_rust_path); - let cwd = os::getcwd(); - // now add in default entries - env_rust_path.push(cwd.clone()); - do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) }; - let h = os::homedir(); - // Avoid adding duplicates - // could still add dups if someone puts one of these in the RUST_PATH - // manually, though... - for hdir in h.iter() { - if !(cwd.is_ancestor_of(hdir) || hdir.is_ancestor_of(&cwd)) { - push_if_exists(&mut env_rust_path, hdir); - } - } - env_rust_path -} - pub fn default_workspace() -> Path { let p = rust_path(); if p.is_empty() { @@ -99,39 +52,39 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) } /// pkgid's short name pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { let src_dir = workspace.push("src"); - let dirs = os::list_dir(&src_dir); - for p in dirs.iter() { - let p = Path((*p).clone()); + let mut found = false; + do os::walk_dir(&src_dir) |p| { debug!("=> p = %s", p.to_str()); - if !os::path_is_dir(&src_dir.push_rel(&p)) { - loop; - } - debug!("p = %s, remote_path = %s", p.to_str(), pkgid.remote_path.to_str()); + if os::path_is_dir(p) { + debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(), + src_dir.push_rel(&pkgid.path).to_str()); - if p == *pkgid.remote_path { - return true; - } - else { - let pf = p.filename(); - for pf in pf.iter() { - let f_ = (*pf).clone(); - let g = f_.to_str(); - match split_version_general(g, '-') { - Some((ref might_match, ref vers)) => { - debug!("might_match = %s, vers = %s", *might_match, + if *p == src_dir.push_rel(&pkgid.path) { + found = true; + } + else { + let pf = p.filename(); + for pf in pf.iter() { + let f_ = (*pf).clone(); + let g = f_.to_str(); + match split_version_general(g, '-') { + Some((ref might_match, ref vers)) => { + debug!("might_match = %s, vers = %s", *might_match, vers.to_str()); - if *might_match == pkgid.short_name - && (*vers == pkgid.version || pkgid.version == NoVersion) - { - return true; + if *might_match == pkgid.short_name + && (*vers == pkgid.version || pkgid.version == NoVersion) + { + found = true; + } } - } - None => () + None => () + } } } } - } - false + true + }; + found } /// Returns a list of possible directories diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index fa03a5bbfc2fb..bac31478bdee8 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -33,12 +33,13 @@ use std::hashmap::HashMap; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; +use rustc::metadata::filesearch::rust_path; use extra::{getopts}; use syntax::{ast, diagnostic}; use util::*; use messages::*; use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace}; -use path_util::{U_RWX, rust_path, in_rust_path}; +use path_util::{U_RWX, in_rust_path}; use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace}; use path_util::{target_executable_in_workspace, target_library_in_workspace}; use source_control::is_git_dir; @@ -138,35 +139,28 @@ impl<'self> PkgScript<'self> { let crate = util::ready_crate(sess, self.crate); debug!("Building output filenames with script name %s", driver::source_name(&self.input)); - match filesearch::get_rustpkg_sysroot() { - Ok(r) => { - let root = r.pop().pop().pop().pop(); // :-\ - debug!("Root is %s, calling compile_rest", root.to_str()); - let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); - util::compile_crate_from_input(&self.input, - &self.build_dir, - sess, - crate); - debug!("Running program: %s %s %s %s", exe.to_str(), - sysroot.to_str(), root.to_str(), "install"); - // FIXME #7401 should support commands besides `install` - let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); - if status != 0 { - return (~[], status); - } - else { - debug!("Running program (configs): %s %s %s", - exe.to_str(), root.to_str(), "configs"); - let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]); - // Run the configs() function to get the configs - let cfgs = str::from_bytes_slice(output.output).word_iter() - .transform(|w| w.to_owned()).collect(); - (cfgs, output.status) - } - } - Err(e) => { - fail!("Running package script, couldn't find rustpkg sysroot (%s)", e) - } + let root = filesearch::get_or_default_sysroot().pop().pop(); // :-\ + debug!("Root is %s, calling compile_rest", root.to_str()); + let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); + util::compile_crate_from_input(&self.input, + &self.build_dir, + sess, + crate); + debug!("Running program: %s %s %s %s", exe.to_str(), + sysroot.to_str(), root.to_str(), "install"); + // FIXME #7401 should support commands besides `install` + let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); + if status != 0 { + return (~[], status); + } + else { + debug!("Running program (configs): %s %s %s", + exe.to_str(), root.to_str(), "configs"); + let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]); + // Run the configs() function to get the configs + let cfgs = str::from_bytes_slice(output.output).word_iter() + .transform(|w| w.to_owned()).collect(); + (cfgs, output.status) } } @@ -205,7 +199,7 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let pkgid = PkgId::new(args[0].clone()); do each_pkg_parent_workspace(&pkgid) |workspace| { debug!("found pkg %s in workspace %s, trying to build", pkgid.to_str(), workspace.to_str()); @@ -228,7 +222,7 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let pkgid = PkgId::new(args[0].clone()); let cwd = os::getcwd(); self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd } @@ -254,13 +248,12 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0], &os::getcwd()); + let pkgid = PkgId::new(args[0]); let workspaces = pkg_parent_workspaces(&pkgid); if workspaces.is_empty() { let rp = rust_path(); assert!(!rp.is_empty()); - let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]), - &pkgid); + let src = PkgSrc::new(&rp[0], &pkgid); src.fetch_git(); self.install(&rp[0], &pkgid); } @@ -294,7 +287,7 @@ impl CtxMethods for Ctx { return usage::uninstall(); } - let pkgid = PkgId::new(args[0], &os::getcwd()); // ?? + let pkgid = PkgId::new(args[0]); if !installed_packages::package_is_installed(&pkgid) { warn(fmt!("Package %s doesn't seem to be installed! Doing nothing.", args[0])); return; @@ -332,8 +325,6 @@ impl CtxMethods for Ctx { in_rust_path(workspace), is_git_dir(&workspace.push_rel(&*pkgid.local_path)), pkgid.to_str()); let src_dir = first_pkgid_src_in_workspace(pkgid, workspace); - let build_dir = build_pkg_id_in_workspace(pkgid, workspace); - debug!("Destination dir = %s", build_dir.to_str()); // If workspace isn't in the RUST_PATH, and it's a git repo, // then clone it into the first entry in RUST_PATH, and repeat @@ -351,7 +342,7 @@ impl CtxMethods for Ctx { } // Create the package source - let mut src = PkgSrc::new(workspace, &build_dir, pkgid); + let mut src = PkgSrc::new(workspace, pkgid); debug!("Package src = %?", src); // Is there custom build logic? If so, use it @@ -385,7 +376,7 @@ impl CtxMethods for Ctx { // Find crates inside the workspace src.find_crates(); // Build it! - src.build(self, build_dir, cfgs); + src.build(self, cfgs); } } @@ -444,6 +435,7 @@ impl CtxMethods for Ctx { for lib in maybe_library.iter() { let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \ didn't install it!", lib.to_str())); + let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib")); debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) && os::copy_file(lib, &target_lib)) { @@ -518,9 +510,7 @@ pub fn main() { }; } - let sroot = match filesearch::get_rustpkg_sysroot() { - Ok(r) => Some(@r.pop().pop()), Err(_) => None - }; + let sroot = Some(@filesearch::get_or_default_sysroot()); debug!("Using sysroot: %?", sroot); Ctx { sysroot_opt: sroot, // Currently, only tests override this diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index e3b796a03bb25..caa004a53b228 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -10,7 +10,7 @@ // Utils for working with version control repositories. Just git right now. -use std::{os, run, str}; +use std::{io, os, run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; use version::*; @@ -19,14 +19,37 @@ pub fn git_clone(source: &Path, target: &Path, v: &Version) { assert!(os::path_is_dir(source)); assert!(is_git_dir(source)); if !os::path_exists(target) { - debug!("Running: git clone %s %s", source.to_str(), - target.to_str()); - assert!(git_clone_general(source.to_str(), target, v)); + debug!("Running: git clone %s %s", source.to_str(), target.to_str()); + let outp = run::process_output("git", [~"clone", source.to_str(), target.to_str()]); + if outp.status != 0 { + io::println(str::from_bytes_owned(outp.output.clone())); + io::println(str::from_bytes_owned(outp.error)); + fail!("Couldn't `git clone` %s", source.to_str()); + } + else { + match v { + &ExactRevision(ref s) => { + debug!("`Running: git --work-tree=%s --git-dir=%s checkout %s", + *s, target.to_str(), target.push(".git").to_str()); + let outp = run::process_output("git", + [fmt!("--work-tree=%s", target.to_str()), + fmt!("--git-dir=%s", target.push(".git").to_str()), + ~"checkout", fmt!("%s", *s)]); + if outp.status != 0 { + io::println(str::from_bytes_owned(outp.output.clone())); + io::println(str::from_bytes_owned(outp.error)); + fail!("Couldn't `git checkout %s` in %s", + *s, target.to_str()); + } + } + _ => () + } + } } else { - // Pull changes - // Note that this ignores tags, which is probably wrong. There are no tests for - // it, though. + // Check that no version was specified. There's no reason to not handle the + // case where a version was requested, but I haven't implemented it. + assert!(*v == NoVersion); debug!("Running: git --work-tree=%s --git-dir=%s pull --no-edit %s", target.to_str(), target.push(".git").to_str(), source.to_str()); let outp = run::process_output("git", [fmt!("--work-tree=%s", target.to_str()), diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 9fea866212975..98fd843925dc0 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -24,7 +24,9 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, make_dir_rwx, U_RWX, library_in_workspace, built_bench_in_workspace, built_test_in_workspace, built_library_in_workspace, built_executable_in_workspace, - installed_library_in_workspace, rust_path}; + installed_library_in_workspace}; +use rustc::metadata::filesearch::rust_path; +use rustc::driver::driver::host_triple; use target::*; /// Returns the last-modified date as an Option @@ -116,6 +118,22 @@ fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { package_dir } +fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) { + let cwd = (*cwd).clone(); + let mut prog = run::Process::new("git", args, run::ProcessOptions { + env: env.map(|v| v.slice(0, v.len())), + dir: Some(&cwd), + in_fd: None, + out_fd: None, + err_fd: None + }); + let rslt = prog.finish_with_output(); + if rslt.status != 0 { + fail!("%s [git returned %?, output = %s, error = %s]", err_msg, + rslt.status, str::from_bytes(rslt.output), str::from_bytes(rslt.error)); + } +} + /// Should create an empty git repo in p, relative to the tmp dir, and return the new /// absolute path fn init_git_repo(p: &Path) -> Path { @@ -125,37 +143,14 @@ fn init_git_repo(p: &Path) -> Path { let work_dir_for_opts = work_dir.clone(); assert!(os::mkdir_recursive(&work_dir, U_RWX)); debug!("Running: git init in %s", work_dir.to_str()); - let opts = run::ProcessOptions { - env: None, - dir: Some(&work_dir_for_opts), - in_fd: None, - out_fd: None, - err_fd: None - }; - let mut prog = run::Process::new("git", [~"init"], opts); - let mut output = prog.finish_with_output(); - if output.status == 0 { - // Add stuff to the dir so that git tag succeeds - writeFile(&work_dir.push("README"), ""); - prog = run::Process::new("git", [~"add", ~"README"], opts); - output = prog.finish_with_output(); - if output.status == 0 { - prog = run::Process::new("git", [~"commit", ~"-m", ~"whatever"], opts); - output = prog.finish_with_output(); - if output.status == 0 { - tmp - } - else { - fail!("Couldn't commit in %s", work_dir.to_str()); - } - } - else { - fail!("Couldn't add in %s", work_dir.to_str()); - } - } - else { - fail!("Couldn't initialize git repository in %s", work_dir.to_str()) - } + let ws = work_dir.to_str(); + run_git([~"init"], None, &work_dir_for_opts, + fmt!("Couldn't initialize git repository in %s", ws)); + // Add stuff to the dir so that git tag succeeds + writeFile(&work_dir.push("README"), ""); + run_git([~"add", ~"README"], None, &work_dir_for_opts, fmt!("Couldn't add in %s", ws)); + git_commit(&work_dir_for_opts, ~"whatever"); + tmp } fn add_all_and_commit(repo: &Path) { @@ -164,51 +159,20 @@ fn add_all_and_commit(repo: &Path) { } fn git_commit(repo: &Path, msg: ~str) { - let mut prog = run::Process::new("git", [~"commit", ~"-m", msg], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't commit in %s: output was %s", repo.to_str(), - str::from_bytes(output.output + output.error)) - } - + run_git([~"commit", ~"--author=tester ", ~"-m", msg], + None, repo, fmt!("Couldn't commit in %s", repo.to_str())); } fn git_add_all(repo: &Path) { - let mut prog = run::Process::new("git", [~"add", ~"-A"], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't add all files in %s: output was %s", - repo.to_str(), str::from_bytes(output.output + output.error)) - } + run_git([~"add", ~"-A"], None, repo, fmt!("Couldn't add all files in %s", repo.to_str())); } fn add_git_tag(repo: &Path, tag: ~str) { assert!(repo.is_absolute()); git_add_all(repo); git_commit(repo, ~"whatever"); - let mut prog = run::Process::new("git", [~"tag", tag.clone()], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't add git tag %s in %s", tag, repo.to_str()) - } + run_git([~"tag", tag.clone()], None, repo, + fmt!("Couldn't add git tag %s in %s", tag, repo.to_str())); } fn is_rwx(p: &Path) -> bool { @@ -231,6 +195,25 @@ fn test_sysroot() -> Path { self_path.pop() } +// Returns the path to rustpkg +fn rustpkg_exec() -> Path { + // Ugh + let first_try = test_sysroot().push("lib").push("rustc") + .push(host_triple()).push("bin").push("rustpkg"); + if is_executable(&first_try) { + first_try + } + else { + let second_try = test_sysroot().push("bin").push("rustpkg"); + if is_executable(&second_try) { + second_try + } + else { + fail!("in rustpkg test, can't find an installed rustpkg"); + } + } +} + fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { command_line_test_with_env(args, cwd, None) } @@ -240,8 +223,9 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { /// Returns the process's output. fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>) -> ProcessOutput { - let cmd = test_sysroot().push("bin").push("rustpkg").to_str(); - debug!("About to run command: %? %? in %s", cmd, args, cwd.to_str()); + let cmd = rustpkg_exec().to_str(); + debug!("cd %s; %s %s", + cwd.to_str(), cmd, args.connect(" ")); assert!(os::path_is_dir(&*cwd)); let cwd = (*cwd).clone(); let mut prog = run::Process::new(cmd, args, run::ProcessOptions { @@ -263,8 +247,9 @@ So tests that use this need to check the existence of a file to make sure the command succeeded */ if output.status != 0 { - fail!("Command %s %? failed with exit code %?", - cmd, args, output.status); + fail!("Command %s %? failed with exit code %?; its output was {{{ %s }}}", + cmd, args, output.status, + str::from_bytes(output.output) + str::from_bytes(output.error)); } output } @@ -329,24 +314,24 @@ fn create_local_package_with_custom_build_hook(pkgid: &PkgId, fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) { debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let lib = target_library_in_workspace(&(PkgId { - version: v, ..PkgId::new(short_name, repo)} - ), repo); - debug!("assert_lib_exists: checking whether %s exists", lib.to_str()); - assert!(os::path_exists(&lib)); - assert!(is_rwx(&lib)); + let lib = installed_library_in_workspace(short_name, repo); + debug!("assert_lib_exists: checking whether %? exists", lib); + assert!(lib.is_some()); + let libname = lib.get_ref(); + assert!(os::path_exists(libname)); + assert!(is_rwx(libname)); } fn assert_executable_exists(repo: &Path, short_name: &str) { debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let exec = target_executable_in_workspace(&PkgId::new(short_name, repo), repo); + let exec = target_executable_in_workspace(&PkgId::new(short_name), repo); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); } fn assert_built_executable_exists(repo: &Path, short_name: &str) { debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let exec = built_executable_in_workspace(&PkgId::new(short_name, repo), + let exec = built_executable_in_workspace(&PkgId::new(short_name), repo).expect("assert_built_executable_exists failed"); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); @@ -563,18 +548,18 @@ fn test_package_ids_must_be_relative_path_like() { */ - let whatever = PkgId::new("foo", &os::getcwd()); + let whatever = PkgId::new("foo"); assert_eq!(~"foo-0.1", whatever.to_str()); assert!("github.com/catamorphism/test_pkg-0.1" == - PkgId::new("github.com/catamorphism/test-pkg", &os::getcwd()).to_str()); + PkgId::new("github.com/catamorphism/test-pkg").to_str()); do cond.trap(|(p, e)| { assert!("" == p.to_str()); assert!("0-length pkgid" == e); whatever.clone() }).inside { - let x = PkgId::new("", &os::getcwd()); + let x = PkgId::new(""); assert_eq!(~"foo-0.1", x.to_str()); } @@ -583,8 +568,7 @@ fn test_package_ids_must_be_relative_path_like() { assert!("absolute pkgid" == e); whatever.clone() }).inside { - let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str(), - &os::getcwd()); + let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str()); assert_eq!(~"foo-0.1", z.to_str()); } @@ -607,7 +591,7 @@ fn test_package_version() { "#[bench] pub fn f() { (); }"); add_git_tag(&repo_subdir, ~"0.4"); - let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version", &repo); + let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version"); match temp_pkg_id.version { ExactRevision(~"0.4") => (), _ => fail!(fmt!("test_package_version: package version was %?, expected Some(0.4)", @@ -656,7 +640,7 @@ fn test_package_request_version() { } None => false }); - let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3", &repo); + let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3"); assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust")) == repo.push(".rust").push("bin").push("test_pkg_version")); @@ -696,12 +680,12 @@ fn rustpkg_library_target() { add_git_tag(&package_dir, ~"1.0"); command_line_test([~"install", ~"foo"], &foo_repo); - assert_lib_exists(&foo_repo, "foo", ExactRevision(~"1.0")); + assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0")); } #[test] fn rustpkg_local_pkg() { - let dir = create_local_package(&PkgId::new("foo", &os::getcwd())); + let dir = create_local_package(&PkgId::new("foo")); command_line_test([~"install", ~"foo"], &dir); assert_executable_exists(&dir, "foo"); } @@ -711,7 +695,7 @@ fn rustpkg_local_pkg() { #[test] #[ignore] fn package_script_with_default_build() { - let dir = create_local_package(&PkgId::new("fancy-lib", &os::getcwd())); + let dir = create_local_package(&PkgId::new("fancy-lib")); debug!("dir = %s", dir.to_str()); let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg"). push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs"); @@ -763,7 +747,7 @@ fn rustpkg_clean_no_arg() { command_line_test([~"build"], &package_dir); assert_built_executable_exists(&tmp, "foo"); command_line_test([~"clean"], &package_dir); - assert!(!built_executable_in_workspace(&PkgId::new("foo", &package_dir), + assert!(!built_executable_in_workspace(&PkgId::new("foo"), &tmp).map_default(false, |m| { os::path_exists(m) })); } @@ -777,8 +761,7 @@ fn rust_path_test() { let cwd = os::getcwd(); debug!("cwd = %s", cwd.to_str()); - debug!("Running command: cd %s; RUST_LOG=rustpkg RUST_PATH=%s rustpkg install foo", - cwd.to_str(), dir_for_path.to_str()); + // use command_line_test_with_env let mut prog = run::Process::new("rustpkg", [~"install", ~"foo"], run::ProcessOptions { env: Some(&[(~"RUST_LOG", @@ -830,39 +813,38 @@ fn rust_path_parse() { #[test] fn test_list() { let dir = mkdtemp(&os::tmpdir(), "test_list").expect("test_list failed"); - let foo = PkgId::new("foo", &dir); + let foo = PkgId::new("foo"); create_local_package_in(&foo, &dir); - let bar = PkgId::new("bar", &dir); + let bar = PkgId::new("bar"); create_local_package_in(&bar, &dir); - let quux = PkgId::new("quux", &dir); + let quux = PkgId::new("quux"); create_local_package_in(&quux, &dir); -// NOTE Not really great output, though... -// NOTE do any tests need to be unignored? +// list doesn't output very much right now... command_line_test([~"install", ~"foo"], &dir); let env_arg = ~[(~"RUST_PATH", dir.to_str())]; debug!("RUST_PATH = %s", dir.to_str()); let list_output = command_line_test_output_with_env([~"list"], env_arg.clone()); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); command_line_test([~"install", ~"bar"], &dir); let list_output = command_line_test_output_with_env([~"list"], env_arg.clone()); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); - assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); + assert!(list_output.iter().any(|x| x.starts_with("bar"))); command_line_test([~"install", ~"quux"], &dir); let list_output = command_line_test_output_with_env([~"list"], env_arg); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); - assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); - assert!(list_output.iter().any(|x| x.starts_with("libquux_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); + assert!(list_output.iter().any(|x| x.starts_with("bar"))); + assert!(list_output.iter().any(|x| x.starts_with("quux"))); } #[test] fn install_remove() { let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove"); - let foo = PkgId::new("foo", &dir); - let bar = PkgId::new("bar", &dir); - let quux = PkgId::new("quux", &dir); + let foo = PkgId::new("foo"); + let bar = PkgId::new("bar"); + let quux = PkgId::new("quux"); create_local_package_in(&foo, &dir); create_local_package_in(&bar, &dir); create_local_package_in(&quux, &dir); @@ -887,7 +869,7 @@ fn install_check_duplicates() { // ("Is already installed -- doing nothing") // check invariant that there are no dups in the pkg database let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove"); - let foo = PkgId::new("foo", &dir); + let foo = PkgId::new("foo"); create_local_package_in(&foo, &dir); command_line_test([~"install", ~"foo"], &dir); @@ -908,7 +890,7 @@ fn install_check_duplicates() { #[test] #[ignore(reason = "Workcache not yet implemented -- see #7075")] fn no_rebuilding() { - let p_id = PkgId::new("foo", &os::getcwd()); + let p_id = PkgId::new("foo"); let workspace = create_local_package(&p_id); command_line_test([~"build", ~"foo"], &workspace); let date = datestamp(&built_library_in_workspace(&p_id, @@ -922,8 +904,8 @@ fn no_rebuilding() { #[test] #[ignore(reason = "Workcache not yet implemented -- see #7075")] fn no_rebuilding_dep() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, @@ -935,8 +917,8 @@ fn no_rebuilding_dep() { #[test] fn do_rebuild_dep_dates_change() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); @@ -948,8 +930,8 @@ fn do_rebuild_dep_dates_change() { #[test] fn do_rebuild_dep_only_contents_change() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); @@ -962,8 +944,8 @@ fn do_rebuild_dep_only_contents_change() { #[test] fn test_versions() { - let workspace = create_local_package(&PkgId::new("foo#0.1", &os::getcwd())); - create_local_package(&PkgId::new("foo#0.2", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo#0.1")); + create_local_package(&PkgId::new("foo#0.2")); command_line_test([~"install", ~"foo#0.1"], &workspace); let output = command_line_test_output([~"list"]); // make sure output includes versions @@ -973,7 +955,7 @@ fn test_versions() { #[test] #[ignore(reason = "do not yet implemented")] fn test_build_hooks() { - let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo", &os::getcwd()), + let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo"), "frob"); command_line_test([~"do", ~"foo", ~"frob"], &workspace); } @@ -983,7 +965,7 @@ fn test_build_hooks() { #[ignore(reason = "info not yet implemented")] fn test_info() { let expected_info = ~"package foo"; // fill in - let workspace = create_local_package(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo")); let output = command_line_test([~"info", ~"foo"], &workspace); assert_eq!(str::from_bytes(output.output), expected_info); } @@ -992,7 +974,7 @@ fn test_info() { #[ignore(reason = "test not yet implemented")] fn test_rustpkg_test() { let expected_results = ~"1 out of 1 tests passed"; // fill in - let workspace = create_local_package_with_test(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package_with_test(&PkgId::new("foo")); let output = command_line_test([~"test", ~"foo"], &workspace); assert_eq!(str::from_bytes(output.output), expected_results); } @@ -1000,7 +982,7 @@ fn test_rustpkg_test() { #[test] #[ignore(reason = "test not yet implemented")] fn test_uninstall() { - let workspace = create_local_package(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo")); let _output = command_line_test([~"info", ~"foo"], &workspace); command_line_test([~"uninstall", ~"foo"], &workspace); let output = command_line_test([~"list"], &workspace); @@ -1031,3 +1013,62 @@ fn test_non_numeric_tag() { assert!(os::path_exists(&file1)); assert!(!os::path_exists(&file2)); } + +#[test] +fn test_extern_mod() { + let dir = mkdtemp(&os::tmpdir(), "test_extern_mod").expect("test_extern_mod"); + let main_file = dir.push("main.rs"); + let lib_depend_dir = mkdtemp(&os::tmpdir(), "foo").expect("test_extern_mod"); + let aux_dir = lib_depend_dir.push_many(["src", "mockgithub.com", "catamorphism", "test_pkg"]); + assert!(os::mkdir_recursive(&aux_dir, U_RWX)); + let aux_pkg_file = aux_dir.push("lib.rs"); + + writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); + assert!(os::path_exists(&aux_pkg_file)); + + writeFile(&main_file, + "extern mod test = \"mockgithub.com/catamorphism/test_pkg\";\nuse test::bar;\ + fn main() { bar::assert_true(); }\n"); + + command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg"], &lib_depend_dir); + + let exec_file = dir.push("out"); + // Be sure to extend the existing environment + let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env()); + let rustpkg_exec = rustpkg_exec(); + let rustc = rustpkg_exec.with_filename("rustc"); + debug!("RUST_PATH=%s %s %s \n --sysroot %s -o %s", + lib_depend_dir.to_str(), + rustc.to_str(), + main_file.to_str(), + test_sysroot().to_str(), + exec_file.to_str()); + + let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(), + ~"--sysroot", test_sysroot().to_str(), + ~"-o", exec_file.to_str()], + run::ProcessOptions { + env: env.map(|v| v.slice(0, v.len())), + dir: Some(&dir), + in_fd: None, + out_fd: None, + err_fd: None + }); + let outp = prog.finish_with_output(); + if outp.status != 0 { + fail!("output was %s, error was %s", + str::from_bytes(outp.output), + str::from_bytes(outp.error)); + } + assert!(os::path_exists(&exec_file) && is_executable(&exec_file)); +} + +/// Returns true if p exists and is executable +fn is_executable(p: &Path) -> bool { + use std::libc::consts::os::posix88::{S_IXUSR}; + + match p.get_mode() { + None => false, + Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint + } +} diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 81b47d6a16c0a..a1b318fcc9571 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{os, result}; +use std::os; use rustc::driver::{driver, session}; -use rustc::metadata::filesearch; use extra::getopts::groups::getopts; use syntax::ast_util::*; use syntax::codemap::{dummy_sp, spanned}; @@ -19,10 +18,10 @@ use syntax::{ast, attr, codemap, diagnostic, fold}; use syntax::attr::AttrMetaMethods; use rustc::back::link::output_type_exe; use rustc::driver::session::{lib_crate, bin_crate}; -use context::Ctx; +use context::{Ctx, in_target}; use package_id::PkgId; use search::find_library_in_search_path; -use path_util::target_library_in_workspace; +use path_util::{target_library_in_workspace, U_RWX}; pub use target::{OutputType, Main, Lib, Bench, Test}; // It would be nice to have the list of commands in just one place -- for example, @@ -47,13 +46,6 @@ impl ToStr for Pkg { } } -pub fn root() -> Path { - match filesearch::get_rustpkg_root() { - result::Ok(path) => path, - result::Err(err) => fail!(err) - } -} - pub fn is_cmd(cmd: &str) -> bool { COMMANDS.iter().any(|&c| c == cmd) } @@ -162,25 +154,25 @@ pub fn ready_crate(sess: session::Session, pub fn compile_input(ctxt: &Ctx, pkg_id: &PkgId, in_file: &Path, - out_dir: &Path, + workspace: &Path, flags: &[~str], cfgs: &[~str], opt: bool, what: OutputType) -> bool { - let workspace = out_dir.pop().pop(); - assert!(in_file.components.len() > 1); let input = driver::file_input((*in_file).clone()); debug!("compile_input: %s / %?", in_file.to_str(), what); // tjc: by default, use the package ID name as the link name // not sure if we should support anything else + let out_dir = workspace.push("build").push_rel(&*pkg_id.local_path); + let binary = os::args()[0].to_managed(); debug!("flags: %s", flags.connect(" ")); debug!("cfgs: %s", cfgs.connect(" ")); - debug!("compile_input's sysroot = %?", ctxt.sysroot_opt); + debug!("out_dir = %s", out_dir.to_str()); let crate_type = match what { Lib => lib_crate, @@ -196,12 +188,22 @@ pub fn compile_input(ctxt: &Ctx, + flags + cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }), driver::optgroups()).unwrap(); + // Hack so that rustpkg can run either out of a rustc target dir, + // or the host dir + let sysroot_to_use = if !in_target(ctxt.sysroot_opt) { + ctxt.sysroot_opt + } + else { + ctxt.sysroot_opt.map(|p| { @p.pop().pop().pop() }) + }; + debug!("compile_input's sysroot = %?", ctxt.sysroot_opt_str()); + debug!("sysroot_to_use = %?", sysroot_to_use); let options = @session::options { crate_type: crate_type, optimize: if opt { session::Aggressive } else { session::No }, test: what == Test || what == Bench, - maybe_sysroot: ctxt.sysroot_opt, - addl_lib_search_paths: @mut (~[(*out_dir).clone()]), + maybe_sysroot: sysroot_to_use, + addl_lib_search_paths: @mut (~[out_dir.clone()]), // output_type should be conditional output_type: output_type_exe, // Use this to get a library? That's weird .. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone() @@ -211,7 +213,12 @@ pub fn compile_input(ctxt: &Ctx, // Make sure all the library directories actually exist, since the linker will complain // otherwise for p in addl_lib_search_paths.iter() { - assert!(os::path_is_dir(p)); + if os::path_exists(p) { + assert!(os::path_is_dir(p)); + } + else { + assert!(os::mkdir_recursive(p, U_RWX)); + } } let sess = driver::build_session(options, diagnostic::emit); @@ -224,35 +231,44 @@ pub fn compile_input(ctxt: &Ctx, // Not really right. Should search other workspaces too, and the installed // database (which doesn't exist yet) - find_and_install_dependencies(ctxt, sess, &workspace, crate, + find_and_install_dependencies(ctxt, sess, workspace, crate, |p| { debug!("a dependency: %s", p.to_str()); // Pass the directory containing a dependency // as an additional lib search path - addl_lib_search_paths.push(p); + if !addl_lib_search_paths.contains(&p) { + // Might be inefficient, but this set probably + // won't get too large -- tjc + addl_lib_search_paths.push(p); + } }); // Inject the link attributes so we get the right package name and version if attr::find_linkage_metas(crate.attrs).is_empty() { - let short_name_to_use = match what { - Test => fmt!("%stest", pkg_id.short_name), - Bench => fmt!("%sbench", pkg_id.short_name), - _ => pkg_id.short_name.clone() + let name_to_use = match what { + Test => fmt!("%stest", pkg_id.local_path.to_str()).to_managed(), + Bench => fmt!("%sbench", pkg_id.local_path.to_str()).to_managed(), + _ => pkg_id.short_name.to_managed() }; - debug!("Injecting link name: %s", short_name_to_use); + debug!("Injecting link name: %s", name_to_use); let link_options = - ~[attr::mk_name_value_item_str(@"name", short_name_to_use.to_managed()), - attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())]; - + ~[attr::mk_name_value_item_str(@"name", name_to_use), + attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())] + + if pkg_id.is_complex() { + ~[attr::mk_name_value_item_str(@"package_id", + pkg_id.local_path.to_str().to_managed())] + } else { ~[] }; + + debug!("link options: %?", link_options); crate = @ast::Crate { attrs: ~[attr::mk_attr(attr::mk_list_item(@"link", link_options))], .. (*crate).clone() - }; + } } - debug!("calling compile_crate_from_input, out_dir = %s, + debug!("calling compile_crate_from_input, workspace = %s, building_library = %?", out_dir.to_str(), sess.building_library); - compile_crate_from_input(&input, out_dir, sess, crate); + compile_crate_from_input(&input, &out_dir, sess, crate); true } @@ -262,17 +278,22 @@ pub fn compile_input(ctxt: &Ctx, // call compile_upto and return the crate // also, too many arguments pub fn compile_crate_from_input(input: &driver::input, - build_dir: &Path, + // should be of the form /build/ + out_dir: &Path, sess: session::Session, crate: @ast::Crate) { debug!("Calling build_output_filenames with %s, building library? %?", - build_dir.to_str(), sess.building_library); + out_dir.to_str(), sess.building_library); // bad copy - let outputs = driver::build_output_filenames(input, &Some((*build_dir).clone()), &None, + debug!("out_dir = %s", out_dir.to_str()); + let outputs = driver::build_output_filenames(input, &Some(out_dir.clone()), &None, crate.attrs, sess); - debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type); + debug!("Outputs are out_filename: %s and obj_filename: %s and output type = %?", + outputs.out_filename.to_str(), + outputs.obj_filename.to_str(), + sess.opts.output_type); debug!("additional libraries:"); for lib in sess.opts.addl_lib_search_paths.iter() { debug!("an additional library: %s", lib.to_str()); @@ -298,15 +319,15 @@ pub fn exe_suffix() -> ~str { ~"" } // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId, - crate: &Path, dir: &Path, + crate: &Path, workspace: &Path, flags: &[~str], cfgs: &[~str], opt: bool, what: OutputType) -> bool { - debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); + debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); for fl in flags.iter() { debug!("+++ %s", *fl); } - compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what) + compile_input(ctxt, pkg_id, crate, workspace, flags, cfgs, opt, what) } @@ -327,19 +348,20 @@ pub fn find_and_install_dependencies(ctxt: &Ctx, debug!("A view item!"); match vi.node { // ignore metadata, I guess - ast::view_item_extern_mod(lib_ident, _, _) => { + ast::view_item_extern_mod(lib_ident, path_opt, _, _) => { match my_ctxt.sysroot_opt { - Some(ref x) => debug!("sysroot: %s", x.to_str()), + Some(ref x) => debug!("*** sysroot: %s", x.to_str()), None => debug!("No sysroot given") }; - let lib_name = sess.str_of(lib_ident); + let lib_name = match path_opt { // ??? + Some(p) => p, None => sess.str_of(lib_ident) }; match find_library_in_search_path(my_ctxt.sysroot_opt, lib_name) { Some(installed_path) => { debug!("It exists: %s", installed_path.to_str()); } None => { // Try to install it - let pkg_id = PkgId::new(lib_name, &os::getcwd()); + let pkg_id = PkgId::new(lib_name); my_ctxt.install(&my_workspace, &pkg_id); // Also, add an additional search path debug!("let installed_path...") diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index 8839185089116..b5203ef0756ea 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -17,6 +17,7 @@ use extra::semver; use std::{char, os, result, run, str}; use package_path::RemotePath; use extra::tempfile::mkdtemp; +use path_util::rust_path; #[deriving(Clone)] pub enum Version { @@ -92,19 +93,22 @@ pub fn parse_vers(vers: ~str) -> result::Result { } } -/// If `local_path` is a git repo, and the most recent tag in that repo denotes a version, -/// return it; otherwise, `None` +/// If `local_path` is a git repo in the RUST_PATH, and the most recent tag +/// in that repo denotes a version, return it; otherwise, `None` pub fn try_getting_local_version(local_path: &Path) -> Option { - debug!("in try_getting_local_version"); - let outp = run::process_output("git", + let rustpath = rust_path(); + for rp in rustpath.iter() { + let local_path = rp.push_rel(local_path); + debug!("in try_getting_local_version"); + let outp = run::process_output("git", [fmt!("--git-dir=%s", local_path.push(".git").to_str()), ~"tag", ~"-l"]); - debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status); + debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status); - if outp.status != 0 { - return None; - } + if outp.status != 0 { + loop; + } let mut output = None; let output_text = str::from_bytes(outp.output); @@ -112,8 +116,13 @@ pub fn try_getting_local_version(local_path: &Path) -> Option { if !l.is_whitespace() { output = Some(l); } + match output.chain(try_parsing_version) { + Some(v) => return Some(v), + None => () + } } - output.chain(try_parsing_version) + } + None } /// If `remote_path` refers to a git repo that can be downloaded, diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index d877b4ff489cf..2efe274a4a2fa 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -12,9 +12,11 @@ use std::os; use std::path::Path; -use path_util::{rust_path, workspace_contains_package_id}; +use path_util::workspace_contains_package_id; use package_id::PkgId; +use rustc::metadata::filesearch::rust_path; + pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool { // Using the RUST_PATH, find workspaces that contain // this package ID @@ -58,5 +60,5 @@ pub fn cwd_to_workspace() -> (Path, PkgId) { let ws = cwd.pop().pop(); let cwd_ = cwd.clone(); let pkgid = cwd_.components.last().to_str(); - (ws, PkgId::new(pkgid, &cwd)) + (ws, PkgId::new(pkgid)) } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 76001ae41887a..3e1cb50ce4e61 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -19,13 +19,14 @@ Cross-platform file path handling use clone::Clone; use container::Container; use cmp::Eq; -use iterator::{Iterator, IteratorUtil}; +use iterator::{Iterator, IteratorUtil, range}; use libc; +use num; use option::{None, Option, Some}; use str::{OwnedStr, Str, StrSlice, StrVector}; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; -use vec::{OwnedVector, ImmutableVector}; +use vec::{OwnedVector, ImmutableVector, OwnedCopyableVector}; #[cfg(windows)] pub use Path = self::WindowsPath; @@ -124,6 +125,43 @@ pub trait GenericPath { /// True if `self` is an ancestor of `other`. See `test_is_ancestor_of` for examples fn is_ancestor_of(&self, (&Self)) -> bool; + + /// Find the relative path from one file to another + fn get_relative_to(&self, abs2: (&Self)) -> Self { + assert!(self.is_absolute()); + assert!(abs2.is_absolute()); + let abs1 = self.normalize(); + let abs2 = abs2.normalize(); + + let split1: &[~str] = abs1.components(); + let split2: &[~str] = abs2.components(); + let len1 = split1.len(); + let len2 = split2.len(); + assert!(len1 > 0); + assert!(len2 > 0); + + let max_common_path = num::min(len1, len2) - 1; + let mut start_idx = 0; + while start_idx < max_common_path + && split1[start_idx] == split2[start_idx] { + start_idx += 1; + } + + let mut path: ~[~str] = ~[]; + for _ in range(start_idx, len1 - 1) { path.push(~".."); }; + + path.push_all(split2.slice(start_idx, len2 - 1)); + + let mut result: Self = GenericPath::from_str("."); + if !path.is_empty() { + // Without this type hint, the typechecker doesn't seem to like it + let p: Self = GenericPath::from_str(""); + result = p.push_many(path); + }; + result + } + + fn components(self) -> ~[~str]; } #[cfg(target_os = "linux")] @@ -703,6 +741,7 @@ impl GenericPath for PosixPath { self.is_ancestor_of(&other.pop())) } + fn components(self) -> ~[~str] { self.components } } @@ -985,6 +1024,8 @@ impl GenericPath for WindowsPath { (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) && self.is_ancestor_of(&other.pop())) } + + fn components(self) -> ~[~str] { self.components } } pub fn normalize(components: &[~str]) -> ~[~str] { @@ -1341,4 +1382,124 @@ mod tests { } + #[test] + fn test_relative_to1() { + let p1 = PosixPath("/usr/bin/rustc"); + let p2 = PosixPath("/usr/lib/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + + } + + #[test] + fn test_relative_to2() { + let p1 = PosixPath("/usr/bin/rustc"); + let p2 = PosixPath("/usr/bin/../lib/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin\\rustc"); + let p2 = WindowsPath("C:\\usr\\bin\\..\\lib\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + } + + #[test] + fn test_relative_to3() { + let p1 = PosixPath("/usr/bin/whatever/rustc"); + let p2 = PosixPath("/usr/lib/whatever/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../../lib/whatever")); + + let p1 = WindowsPath("C:\\usr\\bin\\whatever\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\..\\lib\\whatever")); + + } + + #[test] + fn test_relative_to4() { + let p1 = PosixPath("/usr/bin/whatever/../rustc"); + let p2 = PosixPath("/usr/lib/whatever/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib/whatever")); + + let p1 = WindowsPath("C:\\usr\\bin\\whatever\\..\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib\\whatever")); + + } + + #[test] + fn test_relative_to5() { + let p1 = PosixPath("/usr/bin/whatever/../rustc"); + let p2 = PosixPath("/usr/lib/whatever/../mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin/whatever\\..\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\..\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + } + + #[test] + fn test_relative_to6() { + let p1 = PosixPath("/1"); + let p2 = PosixPath("/2/3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("2")); + + let p1 = WindowsPath("C:\\1"); + let p2 = WindowsPath("C:\\2\\3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("2")); + + } + + #[test] + fn test_relative_to7() { + let p1 = PosixPath("/1/2"); + let p2 = PosixPath("/3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("..")); + + let p1 = WindowsPath("C:\\1\\2"); + let p2 = WindowsPath("C:\\3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..")); + + } + + #[test] + fn test_relative_to8() { + let p1 = PosixPath("/home/brian/Dev/rust/build/").push_rel( + &PosixPath("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); + let p2 = PosixPath("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( + &PosixPath("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); + let res = p1.get_relative_to(&p2); + debug!("test_relative_to8: %s vs. %s", + res.to_str(), + PosixPath(".").to_str()); + assert_eq!(res, PosixPath(".")); + + let p1 = WindowsPath("C:\\home\\brian\\Dev\\rust\\build\\").push_rel( + &WindowsPath("stage2\\lib\\rustc\\i686-unknown-linux-gnu\\lib\\librustc.so")); + let p2 = WindowsPath("\\home\\brian\\Dev\\rust\\build\\stage2\\bin\\..").push_rel( + &WindowsPath("lib\\rustc\\i686-unknown-linux-gnu\\lib\\libstd.so")); + let res = p1.get_relative_to(&p2); + debug!("test_relative_to8: %s vs. %s", + res.to_str(), + WindowsPath(".").to_str()); + assert_eq!(res, WindowsPath(".")); + + } + } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 435be3c71af6f..17247222c3ff9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -951,7 +951,11 @@ pub struct view_item { #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum view_item_ { - view_item_extern_mod(ident, ~[@MetaItem], NodeId), + // ident: name used to refer to this crate in the code + // optional @str: if present, this is a location (containing + // arbitrary characters) from which to fetch the crate sources + // For example, extern mod whatever = "github.com/mozilla/rust" + view_item_extern_mod(ident, Option<@str>, ~[@MetaItem], NodeId), view_item_use(~[@view_path]), } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index ba167fe67148e..9a8a3bc25d8a3 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -419,7 +419,7 @@ impl Visitor<()> for IdVisitor { fn visit_view_item(@mut self, view_item: &view_item, env: ()) { match view_item.node { - view_item_extern_mod(_, _, node_id) => { + view_item_extern_mod(_, _, _, node_id) => { (self.visit_callback)(node_id) } view_item_use(ref view_paths) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4902c4587ac39..5240edf00f14f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4169,8 +4169,16 @@ impl Parser { self.this_token_to_str())); } - let (sort, ident) = match *self.token { - token::IDENT(*) => (ast::named, self.parse_ident()), + let (sort, maybe_path, ident) = match *self.token { + token::IDENT(*) => { + let the_ident = self.parse_ident(); + let path = if *self.token == token::EQ { + self.bump(); + Some(self.parse_str()) + } + else { None }; + (ast::named, path, the_ident) + } _ => { if must_be_named_mod { self.span_fatal(*self.span, @@ -4179,7 +4187,7 @@ impl Parser { self.this_token_to_str())); } - (ast::anonymous, + (ast::anonymous, None, special_idents::clownshoes_foreign_mod) } }; @@ -4218,7 +4226,7 @@ impl Parser { let metadata = self.parse_optional_meta(); self.expect(&token::SEMI); iovi_view_item(ast::view_item { - node: view_item_extern_mod(ident, metadata, self.get_id()), + node: view_item_extern_mod(ident, maybe_path, metadata, self.get_id()), attrs: attrs, vis: visibility, span: mk_sp(lo, self.last_span.hi) @@ -4800,8 +4808,13 @@ impl Parser { } else if self.eat_keyword(keywords::Extern) { self.expect_keyword(keywords::Mod); let ident = self.parse_ident(); + let path = if *self.token == token::EQ { + self.bump(); + Some(self.parse_str()) + } + else { None }; let metadata = self.parse_optional_meta(); - view_item_extern_mod(ident, metadata, self.get_id()) + view_item_extern_mod(ident, path, metadata, self.get_id()) } else { self.bug("expected view item"); }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f517179f60366..ffe9575a8644e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1856,9 +1856,13 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) { print_outer_attributes(s, item.attrs); print_visibility(s, item.vis); match item.node { - ast::view_item_extern_mod(id, ref mta, _) => { + ast::view_item_extern_mod(id, ref optional_path, ref mta, _) => { head(s, "extern mod"); print_ident(s, id); + for p in optional_path.iter() { + word(s.s, "="); + print_string(s, *p); + } if !mta.is_empty() { popen(s); commasep(s, consistent, *mta, |p, &i| print_meta_item(p, i)); diff --git a/src/test/run-pass/extern-mod-url.rs b/src/test/run-pass/extern-mod-url.rs deleted file mode 100644 index 363c54f68129a..0000000000000 --- a/src/test/run-pass/extern-mod-url.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Just a test that new-style extern mods parse - -// xfail-test FIXME #6407 -extern mod test = "github.com/catamorphism/test-pkg"; - -fn main() {} From 37fd8f03fdbc622457396877168d2a8d82cf3d2b Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 2 Aug 2013 16:59:58 -0700 Subject: [PATCH 18/18] rustpkg: Simplify the PkgId struct Get rid of special cases for names beginning with "rust-" or containing hyphens, and just store a Path in a package ID. The Rust-identifier for the crate is none of rustpkg's business. --- mk/tests.mk | 3 +- src/librustpkg/package_id.rs | 71 ++++++++++++++++++-------------- src/librustpkg/package_path.rs | 68 ------------------------------ src/librustpkg/package_source.rs | 38 +++++------------ src/librustpkg/path_util.rs | 21 ++++------ src/librustpkg/rustpkg.rs | 13 +++--- src/librustpkg/tests.rs | 59 +++++++++++--------------- src/librustpkg/util.rs | 8 ++-- src/librustpkg/version.rs | 5 +-- src/librustpkg/workspace.rs | 2 +- 10 files changed, 99 insertions(+), 189 deletions(-) delete mode 100644 src/librustpkg/package_path.rs diff --git a/mk/tests.mk b/mk/tests.mk index 536a153b22281..6165fbc855759 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -349,7 +349,8 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \ $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \ - $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) + $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \ + $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index 233e975cbb7e4..e3b3252587a08 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -8,33 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use package_path::{RemotePath, LocalPath, normalize, hash}; use version::{try_getting_version, try_getting_local_version, Version, NoVersion, split_version}; +use std::rt::io::Writer; +use std::hash::Streaming; +use std::hash; /// Path-fragment identifier of a package such as /// 'github.com/graydon/test'; path must be a relative /// path with >=1 component. #[deriving(Clone)] pub struct PkgId { - /// Remote path: for example, github.com/mozilla/quux-whatever - remote_path: RemotePath, - /// Local path: for example, /home/quux/github.com/mozilla/quux_whatever - /// Note that '-' normalizes to '_' when mapping a remote path - /// onto a local path - /// Also, this will change when we implement #6407, though we'll still - /// need to keep track of separate local and remote paths - local_path: LocalPath, - /// Short name. This is the local path's filestem, but we store it + /// This is a path, on the local filesystem, referring to where the + /// files for this package live. For example: + /// github.com/mozilla/quux-whatever (it's assumed that if we're + /// working with a package ID of this form, rustpkg has already cloned + /// the sources into a local directory in the RUST_PATH). + path: Path, + /// Short name. This is the path's filestem, but we store it /// redundantly so as to not call get() everywhere (filestem() returns an /// option) + /// The short name does not need to be a valid Rust identifier. + /// Users can write: `extern mod foo = "...";` to get around the issue + /// of package IDs whose short names aren't valid Rust identifiers. short_name: ~str, + /// The requested package version. version: Version } impl Eq for PkgId { fn eq(&self, p: &PkgId) -> bool { - *p.local_path == *self.local_path && p.version == self.version + p.path == self.path && p.version == self.version } fn ne(&self, p: &PkgId) -> bool { !(self.eq(p)) @@ -42,9 +46,6 @@ impl Eq for PkgId { } impl PkgId { - // The PkgId constructor takes a Path argument so as - // to be able to infer the version if the path refers - // to a local git repository pub fn new(s: &str) -> PkgId { use conditions::bad_pkg_id::cond; @@ -63,40 +64,37 @@ impl PkgId { } }; - let p = Path(s); - if p.is_absolute { - return cond.raise((p, ~"absolute pkgid")); + let path = Path(s); + if path.is_absolute { + return cond.raise((path, ~"absolute pkgid")); } - if p.components.len() < 1 { - return cond.raise((p, ~"0-length pkgid")); + if path.components.len() < 1 { + return cond.raise((path, ~"0-length pkgid")); } - let remote_path = RemotePath(p); - let local_path = normalize(remote_path.clone()); - let short_name = local_path.clone().filestem().expect(fmt!("Strange path! %s", s)); + let short_name = path.clone().filestem().expect(fmt!("Strange path! %s", s)); let version = match given_version { Some(v) => v, - None => match try_getting_local_version(&*local_path) { + None => match try_getting_local_version(&path) { Some(v) => v, - None => match try_getting_version(&remote_path) { + None => match try_getting_version(&path) { Some(v) => v, None => NoVersion } } }; - debug!("local_path = %s, remote_path = %s", local_path.to_str(), remote_path.to_str()); + debug!("path = %s", path.to_str()); PkgId { - local_path: local_path, - remote_path: remote_path, + path: path, short_name: short_name, version: version } } pub fn hash(&self) -> ~str { - fmt!("%s-%s-%s", self.remote_path.to_str(), - hash(self.remote_path.to_str() + self.version.to_str()), + fmt!("%s-%s-%s", self.path.to_str(), + hash(self.path.to_str() + self.version.to_str()), self.version.to_str()) } @@ -106,13 +104,24 @@ impl PkgId { /// True if the ID has multiple components pub fn is_complex(&self) -> bool { - self.short_name != self.local_path.to_str() + self.short_name != self.path.to_str() } } impl ToStr for PkgId { fn to_str(&self) -> ~str { // should probably use the filestem and not the whole path - fmt!("%s-%s", self.local_path.to_str(), self.version.to_str()) + fmt!("%s-%s", self.path.to_str(), self.version.to_str()) } } + + +pub fn write(writer: &mut W, string: &str) { + writer.write(string.as_bytes()); +} + +pub fn hash(data: ~str) -> ~str { + let hasher = &mut hash::default_state(); + write(hasher, data); + hasher.result_str() +} diff --git a/src/librustpkg/package_path.rs b/src/librustpkg/package_path.rs deleted file mode 100644 index 4ba9c8066e4f3..0000000000000 --- a/src/librustpkg/package_path.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// rustpkg utilities having to do with local and remote paths - -use std::clone::Clone; -use std::hash::Streaming; -use std::hash; -use std::option::Some; -use std::path::Path; -use std::rt::io::Writer; - -/// Wrappers to prevent local and remote paths from getting confused -/// (These will go away after #6407) -pub struct RemotePath (Path); - -impl Clone for RemotePath { - fn clone(&self) -> RemotePath { - RemotePath((**self).clone()) - } -} - -pub struct LocalPath (Path); - -impl Clone for LocalPath { - fn clone(&self) -> LocalPath { - LocalPath((**self).clone()) - } -} - - -// normalize should be the only way to construct a LocalPath -// (though this isn't enforced) -/// Replace all occurrences of '-' in the stem part of path with '_' -/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux -/// as the same name -pub fn normalize(p_: RemotePath) -> LocalPath { - let RemotePath(p) = p_; - match p.filestem() { - None => LocalPath(p), - Some(st) => { - let replaced = st.replace("-", "_"); - if replaced != st { - LocalPath(p.with_filestem(replaced)) - } - else { - LocalPath(p) - } - } - } -} - -pub fn write(writer: &mut W, string: &str) { - writer.write(string.as_bytes()); -} - -pub fn hash(data: ~str) -> ~str { - let hasher = &mut hash::default_state(); - write(hasher, data); - hasher.result_str() -} diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index b14f95cfae583..9833e18e016b6 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -11,7 +11,7 @@ use target::*; use package_id::PkgId; use std::path::Path; -use std::{os, str}; +use std::os; use context::*; use crate::Crate; use messages::*; @@ -51,8 +51,7 @@ impl PkgSrc { fn check_dir(&self) -> Path { use conditions::nonexistent_package::cond; - debug!("Pushing onto root: %s | %s", self.id.remote_path.to_str(), - self.root.to_str()); + debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str()); let dir; let dirs = pkgid_src_in_workspace(&self.id, &self.root); debug!("Checking dirs: %?", dirs); @@ -86,18 +85,18 @@ impl PkgSrc { os::remove_dir_recursive(&local); debug!("Checking whether %s exists locally. Cwd = %s, does it? %?", - self.id.local_path.to_str(), + self.id.path.to_str(), os::getcwd().to_str(), - os::path_exists(&*self.id.local_path)); + os::path_exists(&self.id.path)); - if os::path_exists(&*self.id.local_path) { + if os::path_exists(&self.id.path) { debug!("%s exists locally! Cloning it into %s", - self.id.local_path.to_str(), local.to_str()); - git_clone(&*self.id.local_path, &local, &self.id.version); + self.id.path.to_str(), local.to_str()); + git_clone(&self.id.path, &local, &self.id.version); return Some(local); } - let url = fmt!("https://%s", self.id.remote_path.to_str()); + let url = fmt!("https://%s", self.id.path.to_str()); note(fmt!("Fetching package: git clone %s %s [version=%s]", url, local.to_str(), self.id.version.to_str())); if git_clone_general(url, &local, &self.id.version) { @@ -122,25 +121,8 @@ impl PkgSrc { } /// True if the given path's stem is self's pkg ID's stem - /// or if the pkg ID's stem is and the given path's - /// stem is foo - /// Requires that dashes in p have already been normalized to - /// underscores fn stem_matches(&self, p: &Path) -> bool { - let self_id = self.id.local_path.filestem(); - if self_id == p.filestem() { - return true; - } - else { - for pth in self_id.iter() { - if pth.starts_with("rust_") // because p is already normalized - && match p.filestem() { - Some(s) => str::eq_slice(s, pth.slice(5, pth.len())), - None => false - } { return true; } - } - } - false + p.filestem().map_default(false, |p| { p == &self.id.short_name }) } fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) { @@ -161,7 +143,7 @@ impl PkgSrc { let dir = self.check_dir(); debug!("Called check_dir, I'm in %s", dir.to_str()); let prefix = dir.components.len(); - debug!("Matching against %?", self.id.local_path.filestem()); + debug!("Matching against %?", self.id.short_name); do os::walk_dir(&dir) |pth| { match pth.filename() { Some(~"lib.rs") => PkgSrc::push_crate(&mut self.libs, diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 3eff260e79a9d..bbe84b2ecac4f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -10,7 +10,6 @@ // rustpkg utilities having to do with paths and directories -pub use package_path::{RemotePath, LocalPath, normalize}; pub use package_id::PkgId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; pub use version::{Version, NoVersion, split_version_general}; @@ -94,9 +93,9 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> ~[Path] { let mut results = ~[]; let result = workspace.push("src").push(fmt!("%s-%s", - pkgid.local_path.to_str(), pkgid.version.to_str())); + pkgid.path.to_str(), pkgid.version.to_str())); results.push(result); - results.push(workspace.push("src").push_rel(&*pkgid.remote_path)); + results.push(workspace.push("src").push_rel(&pkgid.path)); results } @@ -159,14 +158,12 @@ fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Opt /// Figure out what the library name for in 's build /// directory is, and if the file exists, return it. pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { - library_in_workspace(&pkgid.local_path, pkgid.short_name, - Build, workspace, "build") + library_in_workspace(&pkgid.path, pkgid.short_name, Build, workspace, "build") } /// Does the actual searching stuff pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option { - library_in_workspace(&normalize(RemotePath(Path(short_name))), - short_name, Install, workspace, "lib") + library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib") } @@ -174,7 +171,7 @@ pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Opt /// don't know the entire package ID. /// `workspace` is used to figure out the directory to search. /// `short_name` is taken as the link name of the library. -pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, +pub fn library_in_workspace(path: &Path, short_name: &str, where: Target, workspace: &Path, prefix: &str) -> Option { debug!("library_in_workspace: checking whether a library named %s exists", short_name); @@ -186,7 +183,7 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, prefix = %s", short_name, where, workspace.to_str(), prefix); let dir_to_search = match where { - Build => workspace.push(prefix).push_rel(&**path), + Build => workspace.push(prefix).push_rel(path), Install => workspace.push(prefix) }; debug!("Listing directory %s", dir_to_search.to_str()); @@ -302,7 +299,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, // Artifacts in the build directory live in a package-ID-specific subdirectory, // but installed ones don't. let result = match where { - Build => workspace.push(subdir).push_rel(&*pkgid.local_path), + Build => workspace.push(subdir).push_rel(&pkgid.path), _ => workspace.push(subdir) }; if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) { @@ -321,7 +318,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { let mut result = workspace.push("build"); // n.b. Should actually use a target-specific // subdirectory of build/ - result = result.push_rel(&*pkgid.local_path); + result = result.push_rel(&pkgid.path); if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) { result } @@ -342,7 +339,7 @@ pub fn mk_output_path(what: OutputType, where: Target, // If we're installing, it just goes under ... Install => workspace, // and if we're just building, it goes in a package-specific subdir - Build => workspace.push_rel(&*pkg_id.local_path) + Build => workspace.push_rel(&pkg_id.path) }; debug!("[%?:%?] mk_output_path: short_name = %s, path = %s", what, where, if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() }, diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index bac31478bdee8..26dab4120fda4 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -55,7 +55,6 @@ mod crate; mod installed_packages; mod messages; mod package_id; -mod package_path; mod package_source; mod path_util; mod search; @@ -268,7 +267,7 @@ impl CtxMethods for Ctx { "list" => { io::println("Installed packages:"); do installed_packages::list_installed_packages |pkg_id| { - println(pkg_id.local_path.to_str()); + println(pkg_id.path.to_str()); true }; } @@ -322,18 +321,18 @@ impl CtxMethods for Ctx { fn build(&self, workspace: &Path, pkgid: &PkgId) { debug!("build: workspace = %s (in Rust path? %? is git dir? %? \ pkgid = %s", workspace.to_str(), - in_rust_path(workspace), is_git_dir(&workspace.push_rel(&*pkgid.local_path)), + in_rust_path(workspace), is_git_dir(&workspace.push_rel(&pkgid.path)), pkgid.to_str()); let src_dir = first_pkgid_src_in_workspace(pkgid, workspace); // If workspace isn't in the RUST_PATH, and it's a git repo, // then clone it into the first entry in RUST_PATH, and repeat debug!("%? %? %s", in_rust_path(workspace), - is_git_dir(&workspace.push_rel(&*pkgid.local_path)), + is_git_dir(&workspace.push_rel(&pkgid.path)), workspace.to_str()); - if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&*pkgid.local_path)) { - let out_dir = default_workspace().push("src").push_rel(&*pkgid.local_path); - source_control::git_clone(&workspace.push_rel(&*pkgid.local_path), + if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&pkgid.path)) { + let out_dir = default_workspace().push("src").push_rel(&pkgid.path); + source_control::git_clone(&workspace.push_rel(&pkgid.path), &out_dir, &pkgid.version); let default_ws = default_workspace(); debug!("Calling build recursively with %? and %?", default_ws.to_str(), diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 98fd843925dc0..121dcf4015021 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -12,11 +12,10 @@ use context::Ctx; use std::hashmap::HashMap; -use std::{io, libc, os, result, run, str}; +use std::{io, libc, os, run, str}; use extra::tempfile::mkdtemp; use std::run::ProcessOutput; use installed_packages::list_installed_packages; -use package_path::*; use package_id::{PkgId}; use version::{ExactRevision, NoVersion, Version, Tagged}; use path_util::{target_executable_in_workspace, target_library_in_workspace, @@ -44,31 +43,25 @@ fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { fn fake_pkg() -> PkgId { let sn = ~"bogus"; - let remote = RemotePath(Path(sn)); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, + path: Path(sn), short_name: sn, version: NoVersion } } fn git_repo_pkg() -> PkgId { - let remote = RemotePath(Path("mockgithub.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, - short_name: ~"test_pkg", + path: Path("mockgithub.com/catamorphism/test-pkg"), + short_name: ~"test-pkg", version: NoVersion } } fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { - let remote = RemotePath(Path("mockgithub.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, - short_name: ~"test_pkg", + path: Path("mockgithub.com/catamorphism/test-pkg"), + short_name: ~"test-pkg", version: Tagged(a_tag) } } @@ -78,13 +71,13 @@ fn writeFile(file_path: &Path, contents: &str) { out.write_line(contents); } -fn mk_empty_workspace(short_name: &LocalPath, version: &Version) -> Path { +fn mk_empty_workspace(short_name: &Path, version: &Version) -> Path { let workspace_dir = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); mk_workspace(&workspace_dir, short_name, version); workspace_dir } -fn mk_workspace(workspace: &Path, short_name: &LocalPath, version: &Version) -> Path { +fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path { // include version number in directory name let package_dir = workspace.push("src").push(fmt!("%s-%s", short_name.to_str(), version.to_str())); @@ -92,7 +85,7 @@ fn mk_workspace(workspace: &Path, short_name: &LocalPath, version: &Version) -> package_dir } -fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { +fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path { let package_dir = mk_empty_workspace(short_name, version).push("src").push(fmt!("%s-%s", short_name.to_str(), @@ -255,7 +248,7 @@ to make sure the command succeeded } fn create_local_package(pkgid: &PkgId) -> Path { - let parent_dir = mk_temp_workspace(&pkgid.local_path, &pkgid.version); + let parent_dir = mk_temp_workspace(&pkgid.path, &pkgid.version); debug!("Created empty package dir for %s, returning %s", pkgid.to_str(), parent_dir.to_str()); parent_dir.pop().pop() } @@ -312,7 +305,7 @@ fn create_local_package_with_custom_build_hook(pkgid: &PkgId, } -fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) { +fn assert_lib_exists(repo: &Path, short_name: &str, _v: Version) { // ??? version? debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name); let lib = installed_library_in_workspace(short_name, repo); debug!("assert_lib_exists: checking whether %? exists", lib); @@ -357,11 +350,11 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~ result } -// assumes short_name and local_path are one and the same -- I should fix +// assumes short_name and path are one and the same -- I should fix fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path { debug!("lib_output_file_name: given %s and parent %s and short name %s", workspace.to_str(), parent, short_name); - library_in_workspace(&normalize(RemotePath(Path(short_name))), + library_in_workspace(&Path(short_name), short_name, Build, workspace, @@ -436,7 +429,7 @@ fn test_install_valid() { debug!("sysroot = %s", sysroot.to_str()); let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = fake_pkg(); - let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path, &NoVersion).pop().pop(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path, &NoVersion).pop().pop(); debug!("temp_workspace = %s", temp_workspace.to_str()); // should have test, bench, lib, and main ctxt.install(&temp_workspace, &temp_pkg_id); @@ -489,7 +482,7 @@ fn test_install_git() { let sysroot = test_sysroot(); debug!("sysroot = %s", sysroot.to_str()); let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&Path(temp_pkg_id.local_path.to_str())); + let repo = init_git_repo(&temp_pkg_id.path); let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg"); writeFile(&repo_subdir.push("main.rs"), "fn main() { let _x = (); }"); @@ -502,9 +495,9 @@ fn test_install_git() { add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files debug!("test_install_git: calling rustpkg install %s in %s", - temp_pkg_id.local_path.to_str(), repo.to_str()); + temp_pkg_id.path.to_str(), repo.to_str()); // should have test, bench, lib, and main - command_line_test([~"install", temp_pkg_id.local_path.to_str()], &repo); + command_line_test([~"install", temp_pkg_id.path.to_str()], &repo); // Check that all files exist debug!("Checking for files in %s", repo.to_str()); let exec = target_executable_in_workspace(&temp_pkg_id, &repo); @@ -551,7 +544,7 @@ fn test_package_ids_must_be_relative_path_like() { let whatever = PkgId::new("foo"); assert_eq!(~"foo-0.1", whatever.to_str()); - assert!("github.com/catamorphism/test_pkg-0.1" == + assert!("github.com/catamorphism/test-pkg-0.1" == PkgId::new("github.com/catamorphism/test-pkg").to_str()); do cond.trap(|(p, e)| { @@ -755,7 +748,7 @@ fn rustpkg_clean_no_arg() { #[ignore (reason = "Specifying env doesn't work -- see #8028")] fn rust_path_test() { let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed"); - let dir = mk_workspace(&dir_for_path, &normalize(RemotePath(Path("foo"))), &NoVersion); + let dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion); debug!("dir = %s", dir.to_str()); writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }"); @@ -877,7 +870,7 @@ fn install_check_duplicates() { let mut contents = ~[]; let check_dups = |p: &PkgId| { if contents.contains(p) { - fail!("package %s appears in `list` output more than once", p.local_path.to_str()); + fail!("package %s appears in `list` output more than once", p.path.to_str()); } else { contents.push((*p).clone()); @@ -992,8 +985,8 @@ fn test_uninstall() { #[test] fn test_non_numeric_tag() { let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&Path(temp_pkg_id.local_path.to_str())); - let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg"); + let repo = init_git_repo(&temp_pkg_id.path); + let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg"); writeFile(&repo_subdir.push("foo"), "foo"); writeFile(&repo_subdir.push("lib.rs"), "pub fn f() { let _x = (); }"); @@ -1003,12 +996,10 @@ fn test_non_numeric_tag() { writeFile(&repo_subdir.push("not_on_testbranch_only"), "bye bye"); add_all_and_commit(&repo_subdir); - - command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.remote_path.to_str())], - &repo); + command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.path.to_str())], &repo); let file1 = repo.push_many(["mockgithub.com", "catamorphism", - "test_pkg", "testbranch_only"]); - let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test_pkg", + "test-pkg", "testbranch_only"]); + let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]); assert!(os::path_exists(&file1)); assert!(!os::path_exists(&file2)); diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index a1b318fcc9571..ed21f8e0872fb 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -166,7 +166,7 @@ pub fn compile_input(ctxt: &Ctx, // tjc: by default, use the package ID name as the link name // not sure if we should support anything else - let out_dir = workspace.push("build").push_rel(&*pkg_id.local_path); + let out_dir = workspace.push("build").push_rel(&pkg_id.path); let binary = os::args()[0].to_managed(); @@ -246,8 +246,8 @@ pub fn compile_input(ctxt: &Ctx, // Inject the link attributes so we get the right package name and version if attr::find_linkage_metas(crate.attrs).is_empty() { let name_to_use = match what { - Test => fmt!("%stest", pkg_id.local_path.to_str()).to_managed(), - Bench => fmt!("%sbench", pkg_id.local_path.to_str()).to_managed(), + Test => fmt!("%stest", pkg_id.short_name).to_managed(), + Bench => fmt!("%sbench", pkg_id.short_name).to_managed(), _ => pkg_id.short_name.to_managed() }; debug!("Injecting link name: %s", name_to_use); @@ -256,7 +256,7 @@ pub fn compile_input(ctxt: &Ctx, attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())] + if pkg_id.is_complex() { ~[attr::mk_name_value_item_str(@"package_id", - pkg_id.local_path.to_str().to_managed())] + pkg_id.path.to_str().to_managed())] } else { ~[] }; debug!("link options: %?", link_options); diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index b5203ef0756ea..ab4f47ba69abc 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -15,7 +15,6 @@ extern mod std; use extra::semver; use std::{char, os, result, run, str}; -use package_path::RemotePath; use extra::tempfile::mkdtemp; use path_util::rust_path; @@ -128,7 +127,7 @@ pub fn try_getting_local_version(local_path: &Path) -> Option { /// If `remote_path` refers to a git repo that can be downloaded, /// and the most recent tag in that repo denotes a version, return it; /// otherwise, `None` -pub fn try_getting_version(remote_path: &RemotePath) -> Option { +pub fn try_getting_version(remote_path: &Path) -> Option { debug!("try_getting_version: %s", remote_path.to_str()); if is_url_like(remote_path) { debug!("Trying to fetch its sources.."); @@ -199,7 +198,7 @@ fn try_parsing_version(s: &str) -> Option { } /// Just an approximation -fn is_url_like(p: &RemotePath) -> bool { +fn is_url_like(p: &Path) -> bool { let str = p.to_str(); str.split_iter('/').len_() > 2 } diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index 2efe274a4a2fa..3e0e08dfe2d7c 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -25,7 +25,7 @@ pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> b // tjc: make this a condition fail!("Package %s not found in any of \ the following workspaces: %s", - pkgid.remote_path.to_str(), + pkgid.path.to_str(), rust_path().to_str()); } for ws in workspaces.iter() {