From 53b83525521960b4ae6f9dc90b82429013346708 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 30 May 2013 12:03:21 -0700 Subject: [PATCH] rustpkg: Extract version number from git, as per #5684 For now, the test I added just checks that PkgId::new parses the version number out of a git repo's tags list, where relevant. --- src/librustpkg/package_id.rs | 69 +++-------------- src/librustpkg/rustpkg.rc | 2 + src/librustpkg/tests.rs | 28 ++++++- src/librustpkg/version.rs | 140 +++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 61 deletions(-) create mode 100644 src/librustpkg/version.rs diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index 85c82787f266e..9b05c848b6e32 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -12,9 +12,8 @@ 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 core::prelude::*; +use version::{default_version, try_getting_version, Version}; /// Path-fragment identifier of a package such as /// 'github.com/graydon/test'; path must be a relative @@ -49,11 +48,17 @@ 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 try_getting_version(remote_path) { + Some(v) => v, + None => default_version() + }; + PkgId { local_path: local_path, remote_path: remote_path, short_name: short_name, - version: default_version() + version: version } } @@ -74,59 +79,3 @@ impl ToStr for PkgId { 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 { - match semver::parse(vers) { - Some(vers) => result::Ok(vers), - None => result::Err(~"could not parse version: invalid") - } -} diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 5bc52b1eb35ab..8591251d4cd5f 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -18,6 +18,7 @@ #[license = "MIT/ASL2"]; #[crate_type = "lib"]; +#[no_core]; #[no_std]; extern mod core(name = "std"); @@ -53,6 +54,7 @@ mod target; #[cfg(test)] mod tests; mod util; +mod version; mod workspace; pub mod usage; diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index a96a7a0a5fc9a..e897f757ec229 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -18,7 +18,8 @@ use core::prelude::*; use core::result; use extra::tempfile::mkdtemp; use package_path::*; -use package_id::{PkgId, default_version}; +use package_id::PkgId; +use version::{default_version, ExactRevision}; use path_util::{target_executable_in_workspace, target_library_in_workspace, target_test_in_workspace, target_bench_in_workspace, make_dir_rwx, u_rwx, @@ -53,6 +54,16 @@ fn remote_pkg() -> PkgId { } } +fn remote_versioned_pkg() -> PkgId { + let remote = RemotePath(Path("github.com/catamorphism/test_pkg_version")); + PkgId { + local_path: normalize(copy remote), + remote_path: remote, + short_name: ~"test_pkg_version", + version: default_version() + } +} + fn writeFile(file_path: &Path, contents: &str) { let out: @io::Writer = result::get(&io::file_writer(file_path, @@ -242,3 +253,18 @@ fn test_package_ids_must_be_relative_path_like() { } } + +#[test] +fn test_package_version() { + let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); + let sysroot = test_sysroot(); + debug!("sysroot = %s", sysroot.to_str()); + let ctxt = fake_ctxt(Some(@sysroot)); + let temp_pkg_id = PkgId::new("github.com/catamorphism/test_pkg_version"); + match temp_pkg_id.version { + ExactRevision(0.2) => (), + _ => fail!(fmt!("test_package_version: package version was %?, expected Some(0.2)", + temp_pkg_id.version)) + } + // also check that file paths are right +} diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs new file mode 100644 index 0000000000000..2de020970210d --- /dev/null +++ b/src/librustpkg/version.rs @@ -0,0 +1,140 @@ +// 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. + +/// A version is either an exact revision, +/// or a semantic version + +extern mod std; + +use std::semver; +use core::prelude::*; +use core::run; +use package_path::RemotePath; +use std::tempfile::mkdtemp; + +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 { + 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 { + 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 + } +} + +fn try_parsing_version(s: &str) -> Option { + let s = s.trim(); + debug!("Attempting to parse: %s", s); + match float::from_str(s) { + Some(f) => { + debug!("%s -> %f", s, f); + Some(ExactRevision(f)) // semver not handled yet + } + None => { + debug!("None!!"); + None + } + } +} + +/// Placeholder +pub fn default_version() -> Version { ExactRevision(0.1) } + +/// 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 +} \ No newline at end of file