Implement cargo-package

This command will assemble the current package into a tarball ready for
uploading to the cargo registry. Currently no further verification is done
beyond packaging the local repository into a tarball, but in the future this
could execute other operations such as api stability tools.
This commit is contained in:
Alex Crichton 2014-07-18 08:40:45 -07:00
parent 6f765b358f
commit 69c16fc6c8
11 changed files with 146 additions and 5 deletions

12
Cargo.lock generated
View File

@ -4,8 +4,10 @@ version = "0.0.1-pre"
dependencies = [
"docopt 0.6.0 (git+https://github.com/burntsushi/docopt.rs#fc7ba2f1a5a351f7874257d880223d2ff5c75d36)",
"docopt_macros 0.6.0 (git+https://github.com/burntsushi/docopt.rs#fc7ba2f1a5a351f7874257d880223d2ff5c75d36)",
"flate2 0.0.1 (git+https://github.com/alexcrichton/flate2-rs#12593d1b9ccf09c2eabac176a6e233b171eed843)",
"hamcrest 0.1.0 (git+https://github.com/carllerche/hamcrest-rust.git#f0fd1546b0a7a278a12658ab8602b5c827cc3a42)",
"semver 0.0.1 (git+https://github.com/rust-lang/semver#c78b40d7fdf8acd99b503e6ce394fbcf9eb8982f)",
"tar 0.0.1 (git+https://github.com/alexcrichton/tar-rs#689bbc003ae47feae5bc99c53b56736e4ad994ba)",
"toml 0.1.0 (git+https://github.com/alexcrichton/toml-rs#8c128cb550ba66d4962cd81acca93857c605eaa0)",
"url 0.1.0 (git+https://github.com/servo/rust-url#23fb9ec22cca9d643ad2cce9894a947c005b7fe2)",
]
@ -28,6 +30,11 @@ name = "encoding"
version = "0.1.0"
source = "git+https://github.com/lifthrasiir/rust-encoding#7e7950ddbd46428a439db3e2594fa78f0972ef2e"
[[package]]
name = "flate2"
version = "0.0.1"
source = "git+https://github.com/alexcrichton/flate2-rs#12593d1b9ccf09c2eabac176a6e233b171eed843"
[[package]]
name = "hamcrest"
version = "0.1.0"
@ -38,6 +45,11 @@ name = "semver"
version = "0.0.1"
source = "git+https://github.com/rust-lang/semver#c78b40d7fdf8acd99b503e6ce394fbcf9eb8982f"
[[package]]
name = "tar"
version = "0.0.1"
source = "git+https://github.com/alexcrichton/tar-rs#689bbc003ae47feae5bc99c53b56736e4ad994ba"
[[package]]
name = "toml"
version = "0.1.0"

View File

@ -26,6 +26,12 @@ git = "https://github.com/servo/rust-url"
[dependencies.semver]
git = "https://github.com/rust-lang/semver"
[dependencies.tar]
git = "https://github.com/alexcrichton/tar-rs"
[dependencies.flate2]
git = "https://github.com/alexcrichton/flate2-rs"
[[bin]]
name = "cargo"
test = false

View File

@ -59,6 +59,7 @@ macro_rules! each_subcommand( ($macro:ident) => ({
$macro!(git_checkout)
$macro!(locate_project)
$macro!(new)
$macro!(package)
$macro!(read_manifest)
$macro!(run)
$macro!(test)

31
src/bin/package.rs Normal file
View File

@ -0,0 +1,31 @@
use docopt;
use cargo::ops;
use cargo::core::{MultiShell};
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::find_root_manifest_for_cwd;
docopt!(Options, "
Assemble a the local package into a distributable tarball
Usage:
cargo package [options]
Options:
-h, --help Print this message
--manifest-path PATH Path to the manifest to compile
-v, --verbose Use verbose output
", flag_manifest_path: Option<String>)
pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
shell.set_verbose(options.flag_verbose);
let Options {
flag_manifest_path,
..
} = options;
let root = try!(find_root_manifest_for_cwd(flag_manifest_path.clone()));
ops::package(&root, shell).map(|_| None).map_err(|err| {
CliError::from_boxed(err, 101)
})
}

View File

@ -1,7 +1,7 @@
use semver;
use std::hash::Hash;
use std::fmt::{mod, Show, Formatter};
use collections::hash;
use std::hash;
use serialize::{
Encodable,
Encoder,

View File

@ -5,19 +5,19 @@
#![feature(default_type_params)]
#![deny(warnings)]
extern crate collections;
extern crate debug;
extern crate glob;
extern crate regex;
extern crate semver;
extern crate serialize;
extern crate term;
extern crate time;
extern crate url;
#[phase(plugin)] extern crate regex_macros;
#[phase(plugin, link)] extern crate log;
extern crate semver;
extern crate docopt;
extern crate flate2;
extern crate tar;
extern crate url;
extern crate toml;
#[cfg(test)] extern crate hamcrest;

View File

@ -0,0 +1,60 @@
use std::io::File;
use tar::Archive;
use flate2::{GzBuilder, BestCompression};
use core::source::Source;
use core::{Package, MultiShell};
use sources::PathSource;
use util::{CargoResult, human, internal, ChainError, Require};
pub fn package(manifest_path: &Path,
shell: &mut MultiShell) -> CargoResult<Path> {
let mut src = try!(PathSource::for_path(&manifest_path.dir_path()));
try!(src.update());
let pkg = try!(src.get_root_package());
let filename = format!("{}-{}.tar.gz", pkg.get_name(), pkg.get_version());
let dst = pkg.get_manifest_path().dir_path().join(filename);
try!(shell.status("Packaging", pkg.get_package_id().to_string()));
try!(tar(&pkg, &src, shell, &dst).chain_error(|| {
human("failed to prepare local package for uploading")
}));
Ok(dst)
}
fn tar(pkg: &Package, src: &PathSource, shell: &mut MultiShell,
dst: &Path) -> CargoResult<()> {
if dst.exists() {
return Err(human(format!("destination already exists: {}",
dst.display())))
}
let tmpfile = try!(File::create(dst));
// Prepare the encoder and its header
let encoder = GzBuilder::new().filename(dst.filename().unwrap())
.writer(tmpfile, BestCompression);
// Put all package files into a compressed archive
let ar = Archive::new(encoder);
for file in try!(src.list_files(pkg)).iter() {
let relative = file.path_relative_from(&dst.dir_path()).unwrap();
let relative = try!(relative.as_str().require(|| {
human(format!("non-utf8 path in source directory: {}",
relative.display()))
}));
let mut file = try!(File::open(file));
try!(shell.verbose(|shell| {
shell.status("Archiving", relative.as_slice())
}));
let path = format!("{}-{}/{}", pkg.get_name(),
pkg.get_version(), relative);
try!(ar.append(path.as_slice(), &mut file).chain_error(|| {
internal(format!("could not archive source file `{}`", relative))
}));
}
Ok(())
}

View File

@ -8,6 +8,7 @@ pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::{generate_lockfile, write_resolve};
pub use self::cargo_generate_lockfile::{update_lockfile, load_lockfile};
pub use self::cargo_test::{run_tests, run_benches, TestOptions};
pub use self::cargo_package::package;
mod cargo_clean;
mod cargo_compile;
@ -18,3 +19,4 @@ mod cargo_new;
mod cargo_doc;
mod cargo_generate_lockfile;
mod cargo_test;
mod cargo_package;

View File

@ -507,3 +507,4 @@ pub static COMPILING: &'static str = " Compiling";
pub static FRESH: &'static str = " Fresh";
pub static UPDATING: &'static str = " Updating";
pub static DOCTEST: &'static str = " Doc-tests";
pub static PACKAGING: &'static str = " Packaging";

View File

@ -0,0 +1,27 @@
use support::{project, execs};
use support::{PACKAGING};
use hamcrest::{assert_that, existing_file};
fn setup() {
}
test!(simple {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#);
assert_that(p.cargo_process("package"),
execs().with_status(0).with_stdout(format!("\
{packaging} foo v0.0.1 ({dir})
",
packaging = PACKAGING,
dir = p.url()).as_slice()));
assert_that(&p.root().join("foo-0.0.1.tar.gz"), existing_file());
})

View File

@ -37,3 +37,4 @@ mod test_cargo_compile_plugins;
mod test_cargo_doc;
mod test_cargo_freshness;
mod test_cargo_generate_lockfile;
mod test_cargo_package;