Implement skeleton install utility

Add install utility skeleton source, based on
mv, including the getopts setup mirroring
GNU's `man install` documentation.  Also
add a single test and build system code.
This commit is contained in:
Ben Eills 2016-07-12 20:56:21 +02:00
parent 61cf4e4fba
commit e72ec4a5bb
8 changed files with 174 additions and 0 deletions

31
Cargo.lock generated
View file

@ -8,6 +8,7 @@ dependencies = [
"basename 0.0.1",
"cat 0.0.1",
"chmod 0.0.1",
"chown 0.0.1",
"chroot 0.0.1",
"cksum 0.0.1",
"comm 0.0.1",
@ -31,6 +32,7 @@ dependencies = [
"hostid 0.0.1",
"hostname 0.0.1",
"id 0.0.1",
"install 0.0.1",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kill 0.0.1",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -177,6 +179,17 @@ dependencies = [
"walker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chown"
version = "0.0.1"
dependencies = [
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.1",
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chroot"
version = "0.0.1"
@ -408,6 +421,15 @@ dependencies = [
"uucore 0.0.1",
]
[[package]]
name = "install"
version = "0.0.1"
dependencies = [
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.1",
]
[[package]]
name = "itertools"
version = "0.4.15"
@ -1204,6 +1226,15 @@ name = "vec_map"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "walker"
version = "1.0.0"

View file

@ -15,6 +15,7 @@ unix = [
"hostid",
"hostname",
"id",
"install",
"kill",
"logname",
"mkfifo",
@ -126,6 +127,7 @@ head = { optional=true, path="src/head" }
hostid = { optional=true, path="src/hostid" }
hostname = { optional=true, path="src/hostname" }
id = { optional=true, path="src/id" }
install = { optional=true, path="src/install" }
kill = { optional=true, path="src/kill" }
link = { optional=true, path="src/link" }
ln = { optional=true, path="src/ln" }

View file

@ -107,6 +107,7 @@ UNIX_PROGS := \
hostid \
hostname \
id \
install \
kill \
logname \
mkfifo \
@ -152,6 +153,7 @@ TEST_PROGS := \
fold \
hashsum \
head \
install \
link \
ln \
ls \

20
src/install/Cargo.toml Normal file
View file

@ -0,0 +1,20 @@
[package]
name = "install"
version = "0.0.1"
authors = ["Ben Eills <ben@beneills.com>"]
[lib]
name = "uu_install"
path = "install.rs"
[dependencies]
getopts = "*"
libc = "*"
uucore = { path="../uucore" }
[dev-dependencies]
time = "*"
[[bin]]
name = "install"
path = "main.rs"

92
src/install/install.rs Normal file
View file

@ -0,0 +1,92 @@
#![crate_name = "uu_install"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Ben Eills <ben@beneills.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
#[macro_use]
extern crate uucore;
use std::io::{Write};
use std::path::{Path, PathBuf};
static NAME: &'static str = "install";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflagopt("", "backup", "make a backup of each existing destination file", "CONTROL");
opts.optflag("b", "", "like --backup but does not accept an argument");
opts.optflag("C", "compare", "compare each pair of source and destination files, and in\n \
some cases, do not modify the destination at all");
opts.optflag("d", "directory", "treat all arguments as directory names; create all\n \
components of the specified directories");
opts.optflag("D", "", "create all leading components of DEST except the last, then copy\n \
SOURCE to DEST");
opts.optflagopt("g", "group", "set group ownership, instead of process' current group",
"GROUP");
opts.optflagopt("m", "mode", "set permission mode (as in chmod), instead of rwxr-xr-x",
"MODE");
opts.optflagopt("o", "owner", "set ownership (super-user only)",
"OWNER");
opts.optflag("p", "preserve-timestamps", "apply access/modification times of SOURCE files\n \
to corresponding destination files");
opts.optflag("s", "strip", "strip symbol tables");
opts.optflagopt("", "strip-program", "program used to strip binaries", "PROGRAM");
opts.optopt("S", "suffix", "override the usual backup suffix", "SUFFIX");
opts.optopt("t", "target-directory", "move all SOURCE arguments into DIRECTORY", "DIRECTORY");
opts.optflag("T", "no-target-directory", "treat DEST as a normal file");
opts.optflag("v", "verbose", "explain what is being done");
opts.optflag("P", "preserve-context", "preserve security context");
opts.optflagopt("Z", "context", "set security context of files and directories", "CONTEXT");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
show_error!("Invalid options\n{}", f);
return 1;
}
};
let usage = opts.usage("Copy SOURCE to DEST or multiple SOURCE(s) to the existing\n \
DIRECTORY, while setting permission modes and owner/group");
let paths: Vec<PathBuf> = {
fn string_to_path<'a>(s: &'a String) -> &'a Path {
Path::new(s)
};
let to_owned = |p: &Path| p.to_owned();
let arguments = matches.free.iter().map(string_to_path);
arguments.map(to_owned).collect()
};
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
0
} else if matches.opt_present("help") {
help(&usage);
0
} else {
println!("Not implemented.");
1
}
}
fn help(usage: &str) {
println!("{0} {1}\n\n\
Usage: {0} SOURCE DEST\n \
or: {0} SOURCE... DIRECTORY\n\n\
{2}", NAME, VERSION, usage);
}

5
src/install/main.rs Normal file
View file

@ -0,0 +1,5 @@
extern crate uu_install;
fn main() {
std::process::exit(uu_install::uumain(std::env::args().collect()));
}

21
tests/test_install.rs Normal file
View file

@ -0,0 +1,21 @@
extern crate libc;
extern crate time;
extern crate kernel32;
extern crate winapi;
extern crate filetime;
use self::filetime::*;
use common::util::*;
static UTIL_NAME: &'static str = "install";
#[test]
fn test_install_help() {
let (at, mut ucmd) = testing(UTIL_NAME);
let result = ucmd.arg("--help").run();
assert_empty_stderr!(result);
assert!(result.success);
// assert!(result.stdout.contains("Usage:"));
}

View file

@ -27,6 +27,7 @@ macro_rules! unix_only {
unix_only! {
"chmod", test_chmod;
"chown", test_chown;
"install", test_install;
"mv", test_mv;
"pathchk", test_pathchk;
"stdbuf", test_stdbuf;