auto merge of #6904 : catamorphism/rust/rustpkg_version_vcs, r=catamorphism
r? @brson
This commit is contained in:
commit
94f72dd736
58
src/librustpkg/crate.rs
Normal file
58
src/librustpkg/crate.rs
Normal file
@ -0,0 +1,58 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::path::Path;
|
||||
use core::vec;
|
||||
|
||||
/// A crate is a unit of Rust code to be compiled into a binary or library
|
||||
pub struct Crate {
|
||||
file: Path,
|
||||
flags: ~[~str],
|
||||
cfgs: ~[~str]
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
|
||||
pub fn new(p: &Path) -> Crate {
|
||||
Crate {
|
||||
file: copy *p,
|
||||
flags: ~[],
|
||||
cfgs: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
fn flag(&self, flag: ~str) -> Crate {
|
||||
Crate {
|
||||
flags: vec::append(copy self.flags, [flag]),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
|
||||
fn flags(&self, flags: ~[~str]) -> Crate {
|
||||
Crate {
|
||||
flags: vec::append(copy self.flags, flags),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
|
||||
fn cfg(&self, cfg: ~str) -> Crate {
|
||||
Crate {
|
||||
cfgs: vec::append(copy self.cfgs, [cfg]),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
|
||||
fn cfgs(&self, cfgs: ~[~str]) -> Crate {
|
||||
Crate {
|
||||
cfgs: vec::append(copy self.cfgs, cfgs),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
}
|
@ -9,12 +9,8 @@
|
||||
// except according to those terms.
|
||||
|
||||
pub use package_path::{RemotePath, LocalPath, normalize, hash};
|
||||
use extra::semver;
|
||||
use core::prelude::*;
|
||||
use core::result;
|
||||
|
||||
/// Placeholder
|
||||
pub fn default_version() -> Version { ExactRevision(0.1) }
|
||||
use version::{try_getting_version, Version, NoVersion, split_version};
|
||||
|
||||
/// Path-fragment identifier of a package such as
|
||||
/// 'github.com/graydon/test'; path must be a relative
|
||||
@ -39,6 +35,21 @@ impl PkgId {
|
||||
pub fn new(s: &str) -> PkgId {
|
||||
use conditions::bad_pkg_id::cond;
|
||||
|
||||
let mut given_version = None;
|
||||
|
||||
// Did the user request a specific version?
|
||||
let s = match split_version(s) {
|
||||
Some((path, v)) => {
|
||||
debug!("s = %s, path = %s, v = %s", s, path, v.to_str());
|
||||
given_version = Some(v);
|
||||
path
|
||||
}
|
||||
None => {
|
||||
debug!("%s has no explicit version", s);
|
||||
s
|
||||
}
|
||||
};
|
||||
|
||||
let p = Path(s);
|
||||
if p.is_absolute {
|
||||
return cond.raise((p, ~"absolute pkgid"));
|
||||
@ -49,11 +60,20 @@ impl PkgId {
|
||||
let remote_path = RemotePath(p);
|
||||
let local_path = normalize(copy remote_path);
|
||||
let short_name = (copy local_path).filestem().expect(fmt!("Strange path! %s", s));
|
||||
|
||||
let version = match given_version {
|
||||
Some(v) => v,
|
||||
None => match try_getting_version(&remote_path) {
|
||||
Some(v) => v,
|
||||
None => NoVersion
|
||||
}
|
||||
};
|
||||
|
||||
PkgId {
|
||||
local_path: local_path,
|
||||
remote_path: remote_path,
|
||||
short_name: short_name,
|
||||
version: default_version()
|
||||
version: version
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,69 +84,17 @@ impl PkgId {
|
||||
}
|
||||
|
||||
pub fn short_name_with_version(&self) -> ~str {
|
||||
fmt!("%s-%s", self.short_name, self.version.to_str())
|
||||
fmt!("%s%s", self.short_name, self.version.to_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStr for PkgId {
|
||||
fn to_str(&self) -> ~str {
|
||||
let maybe_dash = match self.version {
|
||||
NoVersion => "",
|
||||
_ => "-"
|
||||
};
|
||||
// should probably use the filestem and not the whole path
|
||||
fmt!("%s-%s", self.local_path.to_str(), self.version.to_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// A version is either an exact revision,
|
||||
/// or a semantic version
|
||||
pub enum Version {
|
||||
ExactRevision(float),
|
||||
SemVersion(semver::Version)
|
||||
}
|
||||
|
||||
|
||||
impl Ord for Version {
|
||||
fn lt(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(f1), &ExactRevision(f2)) => f1 < f2,
|
||||
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 < v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
fn le(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(f1), &ExactRevision(f2)) => f1 <= f2,
|
||||
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 <= v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
fn ge(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(f1), &ExactRevision(f2)) => f1 > f2,
|
||||
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 > v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
fn gt(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(f1), &ExactRevision(f2)) => f1 >= f2,
|
||||
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 >= v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl ToStr for Version {
|
||||
fn to_str(&self) -> ~str {
|
||||
match *self {
|
||||
ExactRevision(ref n) => n.to_str(),
|
||||
SemVersion(ref v) => v.to_str()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
|
||||
match semver::parse(vers) {
|
||||
Some(vers) => result::Ok(vers),
|
||||
None => result::Err(~"could not parse version: invalid")
|
||||
fmt!("%s%s%s", self.local_path.to_str(), maybe_dash, self.version.to_str())
|
||||
}
|
||||
}
|
||||
|
239
src/librustpkg/package_source.rs
Normal file
239
src/librustpkg/package_source.rs
Normal file
@ -0,0 +1,239 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use target::*;
|
||||
use package_id::PkgId;
|
||||
use core::path::Path;
|
||||
use core::option::*;
|
||||
use core::{os, run, str, vec};
|
||||
use context::*;
|
||||
use crate::Crate;
|
||||
use path_util::pkgid_src_in_workspace;
|
||||
use util::{compile_crate, note};
|
||||
use version::{ExactRevision, SemanticVersion, NoVersion};
|
||||
|
||||
// An enumeration of the unpacked source of a package workspace.
|
||||
// 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],
|
||||
tests: ~[Crate],
|
||||
benchs: ~[Crate],
|
||||
}
|
||||
|
||||
condition! {
|
||||
build_err: (~str) -> ();
|
||||
}
|
||||
|
||||
impl PkgSrc {
|
||||
|
||||
pub fn new(src_dir: &Path, dst_dir: &Path,
|
||||
id: &PkgId) -> PkgSrc {
|
||||
PkgSrc {
|
||||
root: copy *src_dir,
|
||||
dst_dir: copy *dst_dir,
|
||||
id: copy *id,
|
||||
libs: ~[],
|
||||
mains: ~[],
|
||||
tests: ~[],
|
||||
benchs: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
let dir;
|
||||
let dirs = pkgid_src_in_workspace(&self.id, &self.root);
|
||||
debug!("Checking dirs: %?", dirs);
|
||||
let path = dirs.find(|d| os::path_exists(d));
|
||||
match path {
|
||||
Some(d) => dir = d,
|
||||
None => dir = match self.fetch_git() {
|
||||
None => cond.raise((copy self.id, ~"supplied path for package dir does not \
|
||||
exist, and couldn't interpret it as a URL fragment")),
|
||||
Some(d) => d
|
||||
}
|
||||
}
|
||||
if !os::path_is_dir(&dir) {
|
||||
cond.raise((copy self.id, ~"supplied path for package dir is a \
|
||||
non-directory"));
|
||||
}
|
||||
|
||||
dir
|
||||
}
|
||||
|
||||
/// Try interpreting self's package id as a remote package, and try
|
||||
/// fetching it and caching it in a local directory. Return the cached directory
|
||||
/// if this was successful, None otherwise
|
||||
/// (right now we only support git)
|
||||
pub fn fetch_git(&self) -> Option<Path> {
|
||||
|
||||
let mut local = self.root.push("src");
|
||||
local = local.push(self.id.to_str());
|
||||
// Git can't clone into a non-empty directory
|
||||
os::remove_dir_recursive(&local);
|
||||
|
||||
let url = fmt!("https://%s", self.id.remote_path.to_str());
|
||||
let branch_args = match self.id.version {
|
||||
NoVersion => ~[],
|
||||
ExactRevision(ref s) => ~[~"--branch", copy *s],
|
||||
SemanticVersion(ref s) => ~[~"--branch", s.to_str()]
|
||||
};
|
||||
|
||||
|
||||
note(fmt!("git clone %s %s %?", url, local.to_str(), branch_args));
|
||||
|
||||
if run::process_output("git",
|
||||
~[~"clone", copy url, local.to_str()] + branch_args).status != 0 {
|
||||
note(fmt!("fetching %s failed: can't clone repository", url));
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some(local)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If a file named "pkg.rs" in the current directory exists,
|
||||
// return the path for it. Otherwise, None
|
||||
pub fn package_script_option(&self, cwd: &Path) -> Option<Path> {
|
||||
let maybe_path = cwd.push("pkg.rs");
|
||||
if os::path_exists(&maybe_path) {
|
||||
Some(maybe_path)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// True if the given path's stem is self's pkg ID's stem
|
||||
/// or if the pkg ID's stem is <rust-foo> 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 self_id.each |pth| {
|
||||
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
|
||||
}
|
||||
|
||||
fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
|
||||
assert!(p.components.len() > prefix);
|
||||
let mut sub = Path("");
|
||||
for vec::slice(p.components, prefix,
|
||||
p.components.len()).each |c| {
|
||||
sub = sub.push(*c);
|
||||
}
|
||||
debug!("found crate %s", sub.to_str());
|
||||
cs.push(Crate::new(&sub));
|
||||
}
|
||||
|
||||
/// Infers crates to build. Called only in the case where there
|
||||
/// is no custom build logic
|
||||
pub fn find_crates(&mut self) {
|
||||
use conditions::missing_pkg_files::cond;
|
||||
|
||||
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());
|
||||
for os::walk_dir(&dir) |pth| {
|
||||
match pth.filename() {
|
||||
Some(~"lib.rs") => PkgSrc::push_crate(&mut self.libs,
|
||||
prefix,
|
||||
pth),
|
||||
Some(~"main.rs") => PkgSrc::push_crate(&mut self.mains,
|
||||
prefix,
|
||||
pth),
|
||||
Some(~"test.rs") => PkgSrc::push_crate(&mut self.tests,
|
||||
prefix,
|
||||
pth),
|
||||
Some(~"bench.rs") => PkgSrc::push_crate(&mut self.benchs,
|
||||
prefix,
|
||||
pth),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
if self.libs.is_empty() && self.mains.is_empty()
|
||||
&& self.tests.is_empty() && self.benchs.is_empty() {
|
||||
|
||||
note(~"Couldn't infer any crates to build.\n\
|
||||
Try naming a crate `main.rs`, `lib.rs`, \
|
||||
`test.rs`, or `bench.rs`.");
|
||||
cond.raise(copy self.id);
|
||||
}
|
||||
|
||||
debug!("found %u libs, %u mains, %u tests, %u benchs",
|
||||
self.libs.len(),
|
||||
self.mains.len(),
|
||||
self.tests.len(),
|
||||
self.benchs.len())
|
||||
}
|
||||
|
||||
fn build_crates(&self,
|
||||
ctx: &Ctx,
|
||||
dst_dir: &Path,
|
||||
src_dir: &Path,
|
||||
crates: &[Crate],
|
||||
cfgs: &[~str],
|
||||
what: OutputType) {
|
||||
for crates.each |&crate| {
|
||||
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()));
|
||||
|
||||
let result = compile_crate(ctx,
|
||||
&self.id,
|
||||
path,
|
||||
dst_dir,
|
||||
crate.flags,
|
||||
crate.cfgs + cfgs,
|
||||
false,
|
||||
what);
|
||||
if !result {
|
||||
build_err::cond.raise(fmt!("build failure on %s",
|
||||
path.to_str()));
|
||||
}
|
||||
debug!("Result of compiling %s was %?",
|
||||
path.to_str(), result);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self, ctx: &Ctx, dst_dir: Path, 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);
|
||||
debug!("Building mains");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main);
|
||||
debug!("Building tests");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test);
|
||||
debug!("Building benches");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench);
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
|
||||
use core::prelude::*;
|
||||
pub use package_path::{RemotePath, LocalPath};
|
||||
pub use package_id::{PkgId, Version};
|
||||
pub use package_id::PkgId;
|
||||
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
|
||||
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||
use core::os::mkdir_recursive;
|
||||
@ -210,11 +210,17 @@ pub fn target_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
|
||||
}
|
||||
|
||||
|
||||
/// Returns the executable that would be installed for <pkgid>
|
||||
/// in <workspace>
|
||||
/// Returns the installed path for <built_library> in <workspace>
|
||||
/// As a side effect, creates the lib-dir if it doesn't exist
|
||||
pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
|
||||
target_file_in_workspace(pkgid, workspace, Lib, Install)
|
||||
pub fn target_library_in_workspace(workspace: &Path,
|
||||
built_library: &Path) -> Path {
|
||||
use conditions::bad_path::cond;
|
||||
let result = workspace.push("lib");
|
||||
if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) {
|
||||
cond.raise((copy result, ~"I couldn't create the library directory"));
|
||||
}
|
||||
result.push(built_library.filename().expect(fmt!("I don't know how to treat %s as a library",
|
||||
built_library.to_str())))
|
||||
}
|
||||
|
||||
/// Returns the test executable that would be installed for <pkgid>
|
||||
|
@ -18,6 +18,7 @@
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[no_core];
|
||||
#[no_std];
|
||||
|
||||
extern mod core(name = "std");
|
||||
@ -35,24 +36,28 @@ use rustc::metadata::filesearch;
|
||||
use extra::{getopts};
|
||||
use syntax::{ast, diagnostic};
|
||||
use util::*;
|
||||
use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, first_pkgid_src_in_workspace};
|
||||
use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace};
|
||||
use path_util::u_rwx;
|
||||
use path_util::{built_executable_in_workspace, built_library_in_workspace};
|
||||
use path_util::{target_executable_in_workspace, target_library_in_workspace};
|
||||
use workspace::pkg_parent_workspaces;
|
||||
use context::Ctx;
|
||||
use package_id::PkgId;
|
||||
use package_source::PkgSrc;
|
||||
|
||||
mod conditions;
|
||||
mod context;
|
||||
mod crate;
|
||||
mod package_id;
|
||||
mod package_path;
|
||||
mod package_source;
|
||||
mod path_util;
|
||||
mod search;
|
||||
mod target;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod util;
|
||||
mod version;
|
||||
mod workspace;
|
||||
|
||||
pub mod usage;
|
||||
@ -335,11 +340,11 @@ impl Ctx {
|
||||
let maybe_executable = built_executable_in_workspace(id, workspace);
|
||||
let maybe_library = built_library_in_workspace(id, workspace);
|
||||
let target_exec = target_executable_in_workspace(id, workspace);
|
||||
let target_lib = target_library_in_workspace(id, workspace);
|
||||
let target_lib = maybe_library.map(|p| target_library_in_workspace(workspace, p));
|
||||
|
||||
debug!("target_exec = %s target_lib = %s \
|
||||
debug!("target_exec = %s target_lib = %? \
|
||||
maybe_executable = %? maybe_library = %?",
|
||||
target_exec.to_str(), target_lib.to_str(),
|
||||
target_exec.to_str(), target_lib,
|
||||
maybe_executable, maybe_library);
|
||||
|
||||
for maybe_executable.each |exec| {
|
||||
@ -350,6 +355,8 @@ impl Ctx {
|
||||
}
|
||||
}
|
||||
for maybe_library.each |lib| {
|
||||
let target_lib = (copy target_lib).expect(fmt!("I built %s but apparently \
|
||||
didn't install it!", lib.to_str()));
|
||||
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)) {
|
||||
@ -430,51 +437,6 @@ pub fn main() {
|
||||
}.run(cmd, args);
|
||||
}
|
||||
|
||||
/// A crate is a unit of Rust code to be compiled into a binary or library
|
||||
pub struct Crate {
|
||||
file: Path,
|
||||
flags: ~[~str],
|
||||
cfgs: ~[~str]
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
pub fn new(p: &Path) -> Crate {
|
||||
Crate {
|
||||
file: copy *p,
|
||||
flags: ~[],
|
||||
cfgs: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flag(&self, flag: ~str) -> Crate {
|
||||
Crate {
|
||||
flags: vec::append(copy self.flags, [flag]),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flags(&self, flags: ~[~str]) -> Crate {
|
||||
Crate {
|
||||
flags: vec::append(copy self.flags, flags),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cfg(&self, cfg: ~str) -> Crate {
|
||||
Crate {
|
||||
cfgs: vec::append(copy self.cfgs, [cfg]),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cfgs(&self, cfgs: ~[~str]) -> Crate {
|
||||
Crate {
|
||||
cfgs: vec::append(copy self.cfgs, cfgs),
|
||||
.. copy *self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the working directory of the package script.
|
||||
* Assumes that the package script has been compiled
|
||||
@ -493,213 +455,3 @@ pub fn work_dir() -> Path {
|
||||
pub fn src_dir() -> Path {
|
||||
os::getcwd()
|
||||
}
|
||||
|
||||
// An enumeration of the unpacked source of a package workspace.
|
||||
// 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],
|
||||
tests: ~[Crate],
|
||||
benchs: ~[Crate],
|
||||
}
|
||||
|
||||
condition! {
|
||||
build_err: (~str) -> ();
|
||||
}
|
||||
|
||||
impl PkgSrc {
|
||||
|
||||
fn new(src_dir: &Path, dst_dir: &Path,
|
||||
id: &PkgId) -> PkgSrc {
|
||||
PkgSrc {
|
||||
root: copy *src_dir,
|
||||
dst_dir: copy *dst_dir,
|
||||
id: copy *id,
|
||||
libs: ~[],
|
||||
mains: ~[],
|
||||
tests: ~[],
|
||||
benchs: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
let dir;
|
||||
let dirs = pkgid_src_in_workspace(&self.id, &self.root);
|
||||
debug!("Checking dirs: %?", dirs);
|
||||
let path = dirs.find(|d| os::path_exists(d));
|
||||
match path {
|
||||
Some(d) => dir = d,
|
||||
None => dir = match self.fetch_git() {
|
||||
None => cond.raise((copy self.id, ~"supplied path for package dir does not \
|
||||
exist, and couldn't interpret it as a URL fragment")),
|
||||
Some(d) => d
|
||||
}
|
||||
}
|
||||
if !os::path_is_dir(&dir) {
|
||||
cond.raise((copy self.id, ~"supplied path for package dir is a \
|
||||
non-directory"));
|
||||
}
|
||||
|
||||
dir
|
||||
}
|
||||
|
||||
/// Try interpreting self's package id as a remote package, and try
|
||||
/// fetching it and caching it in a local directory. Return the cached directory
|
||||
/// if this was successful, None otherwise
|
||||
/// (right now we only support git)
|
||||
fn fetch_git(&self) -> Option<Path> {
|
||||
|
||||
let mut local = self.root.push("src");
|
||||
local = local.push(self.id.to_str());
|
||||
// Git can't clone into a non-empty directory
|
||||
os::remove_dir_recursive(&local);
|
||||
|
||||
let url = fmt!("https://%s", self.id.remote_path.to_str());
|
||||
util::note(fmt!("git clone %s %s", url, local.to_str()));
|
||||
|
||||
if run::process_output("git", [~"clone", copy url, local.to_str()]).status != 0 {
|
||||
util::note(fmt!("fetching %s failed: can't clone repository", url));
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some(local)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If a file named "pkg.rs" in the current directory exists,
|
||||
// return the path for it. Otherwise, None
|
||||
fn package_script_option(&self, cwd: &Path) -> Option<Path> {
|
||||
let maybe_path = cwd.push("pkg.rs");
|
||||
if os::path_exists(&maybe_path) {
|
||||
Some(maybe_path)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// True if the given path's stem is self's pkg ID's stem
|
||||
/// or if the pkg ID's stem is <rust-foo> 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 self_id.each |pth| {
|
||||
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
|
||||
}
|
||||
|
||||
fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
|
||||
assert!(p.components.len() > prefix);
|
||||
let mut sub = Path("");
|
||||
for vec::slice(p.components, prefix,
|
||||
p.components.len()).each |c| {
|
||||
sub = sub.push(*c);
|
||||
}
|
||||
debug!("found crate %s", sub.to_str());
|
||||
cs.push(Crate::new(&sub));
|
||||
}
|
||||
|
||||
/// Infers crates to build. Called only in the case where there
|
||||
/// is no custom build logic
|
||||
fn find_crates(&mut self) {
|
||||
use conditions::missing_pkg_files::cond;
|
||||
|
||||
let dir = self.check_dir();
|
||||
let prefix = dir.components.len();
|
||||
debug!("Matching against %?", self.id.local_path.filestem());
|
||||
for os::walk_dir(&dir) |pth| {
|
||||
match pth.filename() {
|
||||
Some(~"lib.rs") => PkgSrc::push_crate(&mut self.libs,
|
||||
prefix,
|
||||
pth),
|
||||
Some(~"main.rs") => PkgSrc::push_crate(&mut self.mains,
|
||||
prefix,
|
||||
pth),
|
||||
Some(~"test.rs") => PkgSrc::push_crate(&mut self.tests,
|
||||
prefix,
|
||||
pth),
|
||||
Some(~"bench.rs") => PkgSrc::push_crate(&mut self.benchs,
|
||||
prefix,
|
||||
pth),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
if self.libs.is_empty() && self.mains.is_empty()
|
||||
&& self.tests.is_empty() && self.benchs.is_empty() {
|
||||
|
||||
util::note("Couldn't infer any crates to build.\n\
|
||||
Try naming a crate `main.rs`, `lib.rs`, \
|
||||
`test.rs`, or `bench.rs`.");
|
||||
cond.raise(copy self.id);
|
||||
}
|
||||
|
||||
debug!("found %u libs, %u mains, %u tests, %u benchs",
|
||||
self.libs.len(),
|
||||
self.mains.len(),
|
||||
self.tests.len(),
|
||||
self.benchs.len())
|
||||
}
|
||||
|
||||
fn build_crates(&self,
|
||||
ctx: &Ctx,
|
||||
dst_dir: &Path,
|
||||
src_dir: &Path,
|
||||
crates: &[Crate],
|
||||
cfgs: &[~str],
|
||||
what: OutputType) {
|
||||
for crates.each |&crate| {
|
||||
let path = &src_dir.push_rel(&crate.file).normalize();
|
||||
util::note(fmt!("build_crates: compiling %s", path.to_str()));
|
||||
util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str()));
|
||||
|
||||
let result = util::compile_crate(ctx,
|
||||
&self.id,
|
||||
path,
|
||||
dst_dir,
|
||||
crate.flags,
|
||||
crate.cfgs + cfgs,
|
||||
false,
|
||||
what);
|
||||
if !result {
|
||||
build_err::cond.raise(fmt!("build failure on %s",
|
||||
path.to_str()));
|
||||
}
|
||||
debug!("Result of compiling %s was %?",
|
||||
path.to_str(), result);
|
||||
}
|
||||
}
|
||||
|
||||
fn build(&self, ctx: &Ctx, dst_dir: Path, cfgs: ~[~str]) {
|
||||
let dir = self.check_dir();
|
||||
debug!("Building libs");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.libs, cfgs, Lib);
|
||||
debug!("Building mains");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main);
|
||||
debug!("Building tests");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test);
|
||||
debug!("Building benches");
|
||||
self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench);
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,15 @@ use core::prelude::*;
|
||||
use core::result;
|
||||
use extra::tempfile::mkdtemp;
|
||||
use package_path::*;
|
||||
use package_id::{PkgId, default_version};
|
||||
use package_id::PkgId;
|
||||
use package_source::*;
|
||||
use version::{ExactRevision, NoVersion, Version};
|
||||
use path_util::{target_executable_in_workspace, target_library_in_workspace,
|
||||
target_test_in_workspace, target_bench_in_workspace,
|
||||
make_dir_rwx, u_rwx,
|
||||
built_bench_in_workspace, built_test_in_workspace};
|
||||
built_bench_in_workspace, built_test_in_workspace,
|
||||
built_library_in_workspace, built_executable_in_workspace,
|
||||
installed_library_in_workspace};
|
||||
|
||||
fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
|
||||
Ctx {
|
||||
@ -39,7 +43,7 @@ fn fake_pkg() -> PkgId {
|
||||
local_path: normalize(copy remote),
|
||||
remote_path: remote,
|
||||
short_name: sn,
|
||||
version: default_version()
|
||||
version: NoVersion
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +53,7 @@ fn remote_pkg() -> PkgId {
|
||||
local_path: normalize(copy remote),
|
||||
remote_path: remote,
|
||||
short_name: ~"test_pkg",
|
||||
version: default_version()
|
||||
version: NoVersion
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,11 +64,21 @@ fn writeFile(file_path: &Path, contents: &str) {
|
||||
out.write_line(contents);
|
||||
}
|
||||
|
||||
fn mk_temp_workspace(short_name: &LocalPath) -> Path {
|
||||
fn mk_empty_workspace(short_name: &LocalPath, version: &Version) -> Path {
|
||||
let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
|
||||
// include version number in directory name
|
||||
let package_dir = workspace.push("src").push(fmt!("%s-0.1", short_name.to_str()));
|
||||
let package_dir = workspace.push("src").push(fmt!("%s%s",
|
||||
short_name.to_str(), version.to_str()));
|
||||
assert!(os::mkdir_recursive(&package_dir, u_rwx));
|
||||
package_dir.pop().pop()
|
||||
}
|
||||
|
||||
fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path {
|
||||
let package_dir = mk_empty_workspace(short_name,
|
||||
version).push("src").push(fmt!("%s%s",
|
||||
short_name.to_str(),
|
||||
version.to_str()));
|
||||
|
||||
debug!("Created %s and does it exist? %?", package_dir.to_str(),
|
||||
os::path_is_dir(&package_dir));
|
||||
// Create main, lib, test, and bench files
|
||||
@ -76,7 +90,7 @@ fn mk_temp_workspace(short_name: &LocalPath) -> Path {
|
||||
"#[test] pub fn f() { (); }");
|
||||
writeFile(&package_dir.push("bench.rs"),
|
||||
"#[bench] pub fn f() { (); }");
|
||||
workspace
|
||||
package_dir.pop().pop()
|
||||
}
|
||||
|
||||
fn is_rwx(p: &Path) -> bool {
|
||||
@ -120,7 +134,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);
|
||||
let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path, &NoVersion);
|
||||
// should have test, bench, lib, and main
|
||||
ctxt.install(&temp_workspace, &temp_pkg_id);
|
||||
// Check that all files exist
|
||||
@ -178,7 +192,10 @@ fn test_install_url() {
|
||||
debug!("exec = %s", exec.to_str());
|
||||
assert!(os::path_exists(&exec));
|
||||
assert!(is_rwx(&exec));
|
||||
let lib = target_library_in_workspace(&temp_pkg_id, &workspace);
|
||||
let built_lib =
|
||||
built_library_in_workspace(&temp_pkg_id,
|
||||
&workspace).expect("test_install_url: built lib should exist");
|
||||
let lib = target_library_in_workspace(&workspace, &built_lib);
|
||||
debug!("lib = %s", lib.to_str());
|
||||
assert!(os::path_exists(&lib));
|
||||
assert!(is_rwx(&lib));
|
||||
@ -212,16 +229,11 @@ fn test_package_ids_must_be_relative_path_like() {
|
||||
|
||||
*/
|
||||
|
||||
let default_version_str = "0.1";
|
||||
let addversion = |s| {
|
||||
fmt!("%s-%s", s, default_version_str)
|
||||
};
|
||||
|
||||
let whatever = PkgId::new("foo");
|
||||
|
||||
assert_eq!(addversion("foo"), whatever.to_str());
|
||||
assert!(addversion("github.com/mozilla/rust") ==
|
||||
PkgId::new("github.com/mozilla/rust").to_str());
|
||||
assert_eq!(~"foo", whatever.to_str());
|
||||
assert!("github.com/catamorphism/test_pkg" ==
|
||||
PkgId::new("github.com/catamorphism/test-pkg").to_str());
|
||||
|
||||
do cond.trap(|(p, e)| {
|
||||
assert!("" == p.to_str());
|
||||
@ -229,7 +241,7 @@ fn test_package_ids_must_be_relative_path_like() {
|
||||
copy whatever
|
||||
}).in {
|
||||
let x = PkgId::new("");
|
||||
assert_eq!(addversion("foo"), x.to_str());
|
||||
assert_eq!(~"foo", x.to_str());
|
||||
}
|
||||
|
||||
do cond.trap(|(p, e)| {
|
||||
@ -238,7 +250,70 @@ fn test_package_ids_must_be_relative_path_like() {
|
||||
copy whatever
|
||||
}).in {
|
||||
let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str());
|
||||
assert_eq!(addversion("foo"), z.to_str());
|
||||
assert_eq!(~"foo", z.to_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_package_version() {
|
||||
let temp_pkg_id = PkgId::new("github.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)",
|
||||
temp_pkg_id.version))
|
||||
}
|
||||
let temp = mk_empty_workspace(&LocalPath(Path("test_pkg_version")), &temp_pkg_id.version);
|
||||
let ctx = fake_ctxt(Some(@test_sysroot()));
|
||||
ctx.build(&temp, &temp_pkg_id);
|
||||
assert!(match built_library_in_workspace(&temp_pkg_id, &temp) {
|
||||
Some(p) => p.to_str().ends_with(fmt!("0.4%s", os::consts::DLL_SUFFIX)),
|
||||
None => false
|
||||
});
|
||||
assert!(built_executable_in_workspace(&temp_pkg_id, &temp)
|
||||
== Some(temp.push("build").
|
||||
push("github.com").
|
||||
push("catamorphism").
|
||||
push("test_pkg_version").
|
||||
push("test_pkg_version")));
|
||||
}
|
||||
|
||||
// FIXME #7006: Fails on linux for some reason
|
||||
#[test]
|
||||
#[ignore(cfg(target_os = "linux"))]
|
||||
fn test_package_request_version() {
|
||||
let temp_pkg_id = PkgId::new("github.com/catamorphism/test_pkg_version#0.3");
|
||||
let temp = mk_empty_workspace(&LocalPath(Path("test_pkg_version")), &ExactRevision(~"0.3"));
|
||||
let pkg_src = PkgSrc::new(&temp, &temp, &temp_pkg_id);
|
||||
match temp_pkg_id.version {
|
||||
ExactRevision(~"0.3") => {
|
||||
match pkg_src.fetch_git() {
|
||||
Some(p) => {
|
||||
assert!(os::path_exists(&p.push("version-0.3-file.txt")));
|
||||
assert!(!os::path_exists(&p.push("version-0.4-file.txt")));
|
||||
|
||||
}
|
||||
None => fail!("test_package_request_version: fetch_git failed")
|
||||
}
|
||||
}
|
||||
ExactRevision(n) => {
|
||||
fail!("n is %? and %? %s %?", n, n, if n == ~"0.3" { "==" } else { "!=" }, "0.3");
|
||||
}
|
||||
_ => fail!(fmt!("test_package_version: package version was %?, expected ExactRevision(0.3)",
|
||||
temp_pkg_id.version))
|
||||
}
|
||||
let c = fake_ctxt(Some(@test_sysroot()));
|
||||
c.install(&temp, &temp_pkg_id);
|
||||
debug!("installed_library_in_workspace(%s, %s) = %?", temp_pkg_id.short_name, temp.to_str(),
|
||||
installed_library_in_workspace(temp_pkg_id.short_name, &temp));
|
||||
assert!(match installed_library_in_workspace(temp_pkg_id.short_name, &temp) {
|
||||
Some(p) => {
|
||||
debug!("installed: %s", p.to_str());
|
||||
p.to_str().ends_with(fmt!("0.3%s", os::consts::DLL_SUFFIX))
|
||||
}
|
||||
None => false
|
||||
});
|
||||
assert!(target_executable_in_workspace(&temp_pkg_id, &temp)
|
||||
== temp.push("bin").push("test_pkg_version"));
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ use rustc::driver::driver::compile_upto;
|
||||
use rustc::driver::session::{lib_crate, bin_crate};
|
||||
use context::Ctx;
|
||||
use package_id::PkgId;
|
||||
use path_util::target_library_in_workspace;
|
||||
use path_util::{target_library_in_workspace, built_library_in_workspace};
|
||||
use search::find_library_in_search_path;
|
||||
pub use target::{OutputType, Main, Lib, Bench, Test};
|
||||
|
||||
@ -274,7 +274,7 @@ pub fn compile_input(ctxt: &Ctx,
|
||||
~[@dummy_spanned(meta_name_value(@~"name",
|
||||
mk_string_lit(@short_name_to_use))),
|
||||
@dummy_spanned(meta_name_value(@~"vers",
|
||||
mk_string_lit(@(copy pkg_id.version.to_str()))))])))],
|
||||
mk_string_lit(@pkg_id.version.to_str_nonempty())))])))],
|
||||
..copy crate.node});
|
||||
}
|
||||
|
||||
@ -371,9 +371,14 @@ fn find_and_install_dependencies(ctxt: &Ctx,
|
||||
// Try to install it
|
||||
let pkg_id = PkgId::new(*lib_name);
|
||||
my_ctxt.install(&my_workspace, &pkg_id);
|
||||
let built_lib =
|
||||
built_library_in_workspace(&pkg_id,
|
||||
&my_workspace).expect(fmt!("find_and_install_dependencies: \
|
||||
I thought I already built %s, but the library doesn't seem \
|
||||
to exist", *lib_name));
|
||||
// Also, add an additional search path
|
||||
let installed_path = target_library_in_workspace(&pkg_id,
|
||||
&my_workspace).pop();
|
||||
let installed_path = target_library_in_workspace(&my_workspace,
|
||||
&built_lib).pop();
|
||||
debug!("Great, I installed %s, and it's in %s",
|
||||
*lib_name, installed_path.to_str());
|
||||
save(installed_path);
|
||||
|
215
src/librustpkg/version.rs
Normal file
215
src/librustpkg/version.rs
Normal file
@ -0,0 +1,215 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// A version is either an exact revision,
|
||||
/// or a semantic version
|
||||
|
||||
extern mod std;
|
||||
|
||||
use extra::semver;
|
||||
use core::prelude::*;
|
||||
use core::{char, os, result, run, str};
|
||||
use package_path::RemotePath;
|
||||
use extra::tempfile::mkdtemp;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum Version {
|
||||
ExactRevision(~str), // Should look like a m.n.(...).x
|
||||
SemanticVersion(semver::Version),
|
||||
NoVersion // user didn't specify a version
|
||||
}
|
||||
|
||||
|
||||
impl Ord for Version {
|
||||
fn lt(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 < f2,
|
||||
(&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 < v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
fn le(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 <= f2,
|
||||
(&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 <= v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
fn ge(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 > f2,
|
||||
(&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 > v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
fn gt(&self, other: &Version) -> bool {
|
||||
match (self, other) {
|
||||
(&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 >= f2,
|
||||
(&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 >= v2,
|
||||
_ => false // incomparable, really
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl ToStr for Version {
|
||||
fn to_str(&self) -> ~str {
|
||||
match *self {
|
||||
ExactRevision(ref n) => fmt!("%s", n.to_str()),
|
||||
SemanticVersion(ref v) => fmt!("%s", v.to_str()),
|
||||
NoVersion => ~""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Version {
|
||||
/// Fills in a bogus default version for NoVersion -- for use when
|
||||
/// injecting link_meta attributes
|
||||
fn to_str_nonempty(&self) -> ~str {
|
||||
match *self {
|
||||
NoVersion => ~"0.1",
|
||||
_ => self.to_str()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
|
||||
match semver::parse(vers) {
|
||||
Some(vers) => result::Ok(vers),
|
||||
None => result::Err(~"could not parse version: invalid")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 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<Version> {
|
||||
debug!("try_getting_version: %s", remote_path.to_str());
|
||||
if is_url_like(remote_path) {
|
||||
debug!("Trying to fetch its sources..");
|
||||
let tmp_dir = mkdtemp(&os::tmpdir(),
|
||||
"test").expect("try_getting_version: couldn't create temp dir");
|
||||
debug!("executing {git clone https://%s %s}", remote_path.to_str(), tmp_dir.to_str());
|
||||
let outp = run::process_output("git", [~"clone", fmt!("https://%s", remote_path.to_str()),
|
||||
tmp_dir.to_str()]);
|
||||
if outp.status == 0 {
|
||||
debug!("Cloned it... ( %s, %s )",
|
||||
str::from_bytes(outp.output),
|
||||
str::from_bytes(outp.error));
|
||||
let mut output = None;
|
||||
debug!("executing {git --git-dir=%s tag -l}", tmp_dir.push(".git").to_str());
|
||||
let outp = run::process_output("git",
|
||||
[fmt!("--git-dir=%s", tmp_dir.push(".git").to_str()),
|
||||
~"tag", ~"-l"]);
|
||||
let output_text = str::from_bytes(outp.output);
|
||||
debug!("Full output: ( %s ) [%?]", output_text, outp.status);
|
||||
for output_text.each_split_char('\n') |l| {
|
||||
debug!("A line of output: %s", l);
|
||||
if !l.is_whitespace() {
|
||||
output = Some(l);
|
||||
}
|
||||
}
|
||||
|
||||
output.chain(try_parsing_version)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Being lazy since we don't have a regexp library now
|
||||
#[deriving(Eq)]
|
||||
enum ParseState {
|
||||
Start,
|
||||
SawDigit,
|
||||
SawDot
|
||||
}
|
||||
|
||||
fn try_parsing_version(s: &str) -> Option<Version> {
|
||||
let s = s.trim();
|
||||
debug!("Attempting to parse: %s", s);
|
||||
let mut parse_state = Start;
|
||||
// I gave up on using external iterators (tjc)
|
||||
for str::to_chars(s).each() |&c| {
|
||||
if char::is_digit(c) {
|
||||
parse_state = SawDigit;
|
||||
}
|
||||
else if c == '.' && parse_state == SawDigit {
|
||||
parse_state = SawDot;
|
||||
}
|
||||
else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
match parse_state {
|
||||
SawDigit => Some(ExactRevision(s.to_owned())),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Just an approximation
|
||||
fn is_url_like(p: &RemotePath) -> bool {
|
||||
let mut n = 0;
|
||||
for p.to_str().each_split_char('/') |_| {
|
||||
n += 1;
|
||||
}
|
||||
n > 2
|
||||
}
|
||||
|
||||
/// If s is of the form foo#bar, where bar is a valid version
|
||||
/// number, return the prefix before the # and the version.
|
||||
/// Otherwise, return None.
|
||||
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
|
||||
// reject strings with multiple '#'s
|
||||
if { let mut i: uint = 0; for str::to_chars(s).each |&c| { if c == '#' { i += 1; } }; i > 1 } {
|
||||
return None;
|
||||
}
|
||||
match str::rfind_char(s, '#') {
|
||||
Some(i) => {
|
||||
debug!("in %s, i = %?", s, i);
|
||||
let path = s.slice(0, i);
|
||||
debug!("path = %s", path);
|
||||
// n.b. for now, assuming an exact revision is intended, not a SemVer
|
||||
Some((path, ExactRevision(s.slice(i + 1, s.len()).to_owned())))
|
||||
}
|
||||
None => {
|
||||
debug!("%s doesn't look like an explicit-version thing", s);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_version() {
|
||||
assert!(try_parsing_version("1.2") == Some(ExactRevision(~"1.2")));
|
||||
assert!(try_parsing_version("1.0.17") == Some(ExactRevision(~"1.0.17")));
|
||||
assert!(try_parsing_version("you're_a_kitty") == None);
|
||||
assert!(try_parsing_version("42..1") == None);
|
||||
assert!(try_parsing_version("17") == Some(ExactRevision(~"17")));
|
||||
assert!(try_parsing_version(".1.2.3") == None);
|
||||
assert!(try_parsing_version("2.3.") == None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_version() {
|
||||
let s = "a/b/c#0.1";
|
||||
debug!("== %? ==", split_version(s));
|
||||
assert!(split_version(s) == Some((s.slice(0, 5), ExactRevision(~"0.1"))));
|
||||
assert!(split_version("a/b/c") == None);
|
||||
let s = "a#1.2";
|
||||
assert!(split_version(s) == Some((s.slice(0, 1), ExactRevision(~"1.2"))));
|
||||
assert!(split_version("a#a#3.4") == None);
|
||||
}
|
@ -47,7 +47,7 @@ pub static neg_infinity: float = -1.0/0.0;
|
||||
/* Module: consts */
|
||||
pub mod consts {
|
||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
||||
// staticants from cmath.
|
||||
// constants from cmath.
|
||||
/// Archimedes' constant
|
||||
pub static pi: float = 3.14159265358979323846264338327950288;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user