diff --git a/src/sort/Cargo.toml b/src/sort/Cargo.toml index f9d265d49..545206f57 100644 --- a/src/sort/Cargo.toml +++ b/src/sort/Cargo.toml @@ -10,6 +10,7 @@ path = "sort.rs" [dependencies] getopts = "*" libc = "*" +semver = "*" uucore = { path="../uucore" } [[bin]] diff --git a/src/sort/sort.rs b/src/sort/sort.rs index 6fd61a7f3..1abb854b5 100644 --- a/src/sort/sort.rs +++ b/src/sort/sort.rs @@ -13,6 +13,7 @@ extern crate getopts; extern crate libc; +extern crate semver; #[macro_use] extern crate uucore; @@ -22,6 +23,7 @@ use std::fs::File; use std::io::{BufRead, BufReader, BufWriter, Read, stdin, stdout, Write}; use std::path::Path; use uucore::fs::is_stdin_interactive; +use semver::Version; static NAME: &'static str = "sort"; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -33,6 +35,7 @@ enum SortMode { Numeric, HumanNumeric, Month, + Version, Default, } @@ -66,6 +69,7 @@ pub fn uumain(args: Vec) -> i32 { opts.optflag("", "version", "output version information and exit"); opts.optopt("o", "output", "write output to FILENAME instead of stdout", "FILENAME"); opts.optflag("u", "unique", "output only the first of an equal run"); + opts.optflag("V", "version-sort", "Sort by SemVer version number, eg 1.12.2 > 1.1.2"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, @@ -97,6 +101,8 @@ With no FILE, or when FILE is -, read standard input.", NAME, VERSION); SortMode::HumanNumeric } else if matches.opt_present("month-sort") { SortMode::Month + } else if matches.opt_present("version-sort") { + SortMode::Version } else { SortMode::Default }; @@ -139,6 +145,7 @@ fn exec(files: Vec, settings: &Settings) { SortMode::Numeric => lines.sort_by(numeric_compare), SortMode::HumanNumeric => lines.sort_by(human_numeric_size_compare), SortMode::Month => lines.sort_by(month_compare), + SortMode::Version => lines.sort_by(version_compare), SortMode::Default => lines.sort() } @@ -263,6 +270,20 @@ fn month_compare(a: &String, b: &String) -> Ordering { month_parse(a).cmp(&month_parse(b)) } +fn version_compare(a: &String, b: &String) -> Ordering { + let ver_a = Version::parse(a); + let ver_b = Version::parse(b); + if ver_a > ver_b { + Ordering::Greater + } + else if ver_a < ver_b { + Ordering::Less + } + else { + Ordering::Equal + } +} + fn print_sorted>(iter: T, outfile: &Option) where S: std::fmt::Display { let mut file: Box = match *outfile { Some(ref filename) => { diff --git a/tests/fixtures/sort/version.expected b/tests/fixtures/sort/version.expected new file mode 100644 index 000000000..0d6ece21b --- /dev/null +++ b/tests/fixtures/sort/version.expected @@ -0,0 +1,4 @@ +1.2.3-alpha +1.2.3-alpha2 +1.12.4 +11.2.3 diff --git a/tests/fixtures/sort/version.txt b/tests/fixtures/sort/version.txt new file mode 100644 index 000000000..dbfdb2ed7 --- /dev/null +++ b/tests/fixtures/sort/version.txt @@ -0,0 +1,4 @@ +11.2.3 +1.2.3-alpha2 +1.2.3-alpha +1.12.4 diff --git a/tests/test_sort.rs b/tests/test_sort.rs index f4f85f0ad..50e22d80f 100644 --- a/tests/test_sort.rs +++ b/tests/test_sort.rs @@ -47,6 +47,11 @@ fn test_numeric_unique_ints() { test_helper("numeric_unsorted_ints_unique", "-nu"); } +#[test] +fn test_version() { + test_helper("version", "-V"); +} + fn test_helper(file_name: &str, args: &str) { let (at, mut ucmd) = testing(UTIL_NAME); ucmd.arg(args);