Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/uu/shuf/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,22 @@ shuf-about = Shuffle the input by outputting a random permutation of input lines
shuf-usage = shuf [OPTION]... [FILE]
shuf -e [OPTION]... [ARG]...
shuf -i LO-HI [OPTION]...

# Help messages
shuf-help-echo = treat each ARG as an input line
shuf-help-input-range = treat each number LO through HI as an input line
shuf-help-head-count = output at most COUNT lines
shuf-help-output = write result to FILE instead of standard output
shuf-help-random-source = get random bytes from FILE
shuf-help-repeat = output lines can be repeated
shuf-help-zero-terminated = line delimiter is NUL, not newline

# Error messages
shuf-error-unexpected-argument = unexpected argument { $arg } found
shuf-error-failed-to-open-for-writing = failed to open { $file } for writing
shuf-error-failed-to-open-random-source = failed to open random source { $file }
shuf-error-read-error = read error
shuf-error-no-lines-to-repeat = no lines to repeat
shuf-error-start-exceeds-end = start exceeds end
shuf-error-missing-dash = missing '-'
shuf-error-write-failed = write failed
25 changes: 25 additions & 0 deletions src/uu/shuf/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
shuf-about = Mélanger l'entrée en affichant une permutation aléatoire des lignes d'entrée.
Chaque permutation de sortie est également probable.
Sans FICHIER, ou quand FICHIER est -, lire l'entrée standard.
shuf-usage = shuf [OPTION]... [FICHIER]
shuf -e [OPTION]... [ARG]...
shuf -i MIN-MAX [OPTION]...

# Messages d'aide
shuf-help-echo = traiter chaque ARG comme une ligne d'entrée
shuf-help-input-range = traiter chaque nombre de MIN à MAX comme une ligne d'entrée
shuf-help-head-count = afficher au maximum NOMBRE lignes
shuf-help-output = écrire le résultat dans FICHIER au lieu de la sortie standard
shuf-help-random-source = obtenir des octets aléatoires depuis FICHIER
shuf-help-repeat = les lignes de sortie peuvent être répétées
shuf-help-zero-terminated = le délimiteur de ligne est NUL, pas nouvelle ligne

# Messages d'erreur
shuf-error-unexpected-argument = argument inattendu { $arg } trouvé
shuf-error-failed-to-open-for-writing = échec de l'ouverture de { $file } en écriture
shuf-error-failed-to-open-random-source = échec de l'ouverture de la source aléatoire { $file }
shuf-error-read-error = erreur de lecture
shuf-error-no-lines-to-repeat = aucune ligne à répéter
shuf-error-start-exceeds-end = le début dépasse la fin
shuf-error-missing-dash = '-' manquant
shuf-error-write-failed = échec de l'écriture
62 changes: 43 additions & 19 deletions src/uu/shuf/src/shuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use rand::prelude::SliceRandom;
use rand::seq::IndexedRandom;
use rand::{Rng, RngCore};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io::{BufWriter, Error, Read, Write, stdin, stdout};
Expand All @@ -20,7 +20,7 @@
use uucore::display::{OsWrite, Quotable};
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
use uucore::format_usage;
use uucore::locale::get_message;
use uucore::locale::{get_message, get_message_with_args};

mod rand_read_adapter;

Expand Down Expand Up @@ -71,7 +71,10 @@
if let Some(second_file) = operands.next() {
return Err(UUsageError::new(
1,
format!("unexpected argument {} found", second_file.quote()),
get_message_with_args(
"shuf-error-unexpected-argument",
HashMap::from([("arg".to_string(), second_file.quote().to_string())]),
),
));
};
Mode::Default(file.into())
Expand Down Expand Up @@ -101,8 +104,12 @@
let mut output = BufWriter::new(match options.output {
None => Box::new(stdout()) as Box<dyn OsWrite>,
Some(ref s) => {
let file = File::create(s)
.map_err_context(|| format!("failed to open {} for writing", s.quote()))?;
let file = File::create(s).map_err_context(|| {
get_message_with_args(
"shuf-error-failed-to-open-for-writing",
HashMap::from([("file".to_string(), s.quote().to_string())]),
)
})?;
Box::new(file) as Box<dyn OsWrite>
}
});
Expand All @@ -114,8 +121,12 @@

let mut rng = match options.random_source {
Some(ref r) => {
let file = File::open(r)
.map_err_context(|| format!("failed to open random source {}", r.quote()))?;
let file = File::open(r).map_err_context(|| {
get_message_with_args(
"shuf-error-failed-to-open-random-source",
HashMap::from([("file".to_string(), r.quote().to_string())]),

Check warning on line 127 in src/uu/shuf/src/shuf.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/shuf/src/shuf.rs#L124-L127

Added lines #L124 - L127 were not covered by tests
)
})?;

Check warning on line 129 in src/uu/shuf/src/shuf.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/shuf/src/shuf.rs#L129

Added line #L129 was not covered by tests
WrappedRng::RngFile(rand_read_adapter::ReadRng::new(file))
}
None => WrappedRng::RngDefault(rand::rng()),
Expand Down Expand Up @@ -149,7 +160,7 @@
Arg::new(options::ECHO)
.short('e')
.long(options::ECHO)
.help("treat each ARG as an input line")
.help(get_message("shuf-help-echo"))
.action(ArgAction::SetTrue)
.overrides_with(options::ECHO)
.conflicts_with(options::INPUT_RANGE),
Expand All @@ -159,7 +170,7 @@
.short('i')
.long(options::INPUT_RANGE)
.value_name("LO-HI")
.help("treat each number LO through HI as an input line")
.help(get_message("shuf-help-input-range"))
.value_parser(parse_range)
.conflicts_with(options::FILE_OR_ARGS),
)
Expand All @@ -169,39 +180,39 @@
.long(options::HEAD_COUNT)
.value_name("COUNT")
.action(ArgAction::Append)
.help("output at most COUNT lines")
.help(get_message("shuf-help-head-count"))
.value_parser(usize::from_str),
)
.arg(
Arg::new(options::OUTPUT)
.short('o')
.long(options::OUTPUT)
.value_name("FILE")
.help("write result to FILE instead of standard output")
.help(get_message("shuf-help-output"))
.value_parser(ValueParser::path_buf())
.value_hint(clap::ValueHint::FilePath),
)
.arg(
Arg::new(options::RANDOM_SOURCE)
.long(options::RANDOM_SOURCE)
.value_name("FILE")
.help("get random bytes from FILE")
.help(get_message("shuf-help-random-source"))
.value_parser(ValueParser::path_buf())
.value_hint(clap::ValueHint::FilePath),
)
.arg(
Arg::new(options::REPEAT)
.short('r')
.long(options::REPEAT)
.help("output lines can be repeated")
.help(get_message("shuf-help-repeat"))
.action(ArgAction::SetTrue)
.overrides_with(options::REPEAT),
)
.arg(
Arg::new(options::ZERO_TERMINATED)
.short('z')
.long(options::ZERO_TERMINATED)
.help("line delimiter is NUL, not newline")
.help(get_message("shuf-help-zero-terminated"))
.action(ArgAction::SetTrue)
.overrides_with(options::ZERO_TERMINATED),
)
Expand All @@ -218,7 +229,7 @@
let mut data = Vec::new();
stdin()
.read_to_end(&mut data)
.map_err_context(|| "read error".into())?;
.map_err_context(|| get_message("shuf-error-read-error"))?;
Ok(data)
} else {
std::fs::read(filename).map_err_context(|| filename.maybe_quote().to_string())
Expand Down Expand Up @@ -250,15 +261,18 @@

impl<'a> Shufable for Vec<&'a [u8]> {
type Item = &'a [u8];

fn is_empty(&self) -> bool {
(**self).is_empty()
}

fn choose(&self, rng: &mut WrappedRng) -> Self::Item {
// Note: "copied()" only copies the reference, not the entire [u8].
// Returns None if the slice is empty. We checked this before, so
// this is safe.
(**self).choose(rng).unwrap()
}

fn partial_shuffle<'b>(
&'b mut self,
rng: &'b mut WrappedRng,
Expand All @@ -271,12 +285,15 @@

impl<'a> Shufable for Vec<&'a OsStr> {
type Item = &'a OsStr;

fn is_empty(&self) -> bool {
(**self).is_empty()
}

fn choose(&self, rng: &mut WrappedRng) -> Self::Item {
(**self).choose(rng).unwrap()
}

fn partial_shuffle<'b>(
&'b mut self,
rng: &'b mut WrappedRng,
Expand All @@ -288,12 +305,15 @@

impl Shufable for RangeInclusive<usize> {
type Item = usize;

fn is_empty(&self) -> bool {
self.is_empty()
}

fn choose(&self, rng: &mut WrappedRng) -> usize {
rng.random_range(self.clone())
}

fn partial_shuffle<'b>(
&'b mut self,
rng: &'b mut WrappedRng,
Expand Down Expand Up @@ -420,10 +440,14 @@
rng: &mut WrappedRng,
output: &mut BufWriter<Box<dyn OsWrite>>,
) -> UResult<()> {
let ctx = || "write failed".to_string();
let ctx = || get_message("shuf-error-write-failed");

if opts.repeat {
if input.is_empty() {
return Err(USimpleError::new(1, "no lines to repeat"));
return Err(USimpleError::new(
1,
get_message("shuf-error-no-lines-to-repeat"),
));
}
for _ in 0..opts.head_count {
let r = input.choose(rng);
Expand All @@ -449,10 +473,10 @@
if begin <= end || begin == end + 1 {
Ok(begin..=end)
} else {
Err("start exceeds end".into())
Err(get_message("shuf-error-start-exceeds-end"))
}
} else {
Err("missing '-'".into())
Err(get_message("shuf-error-missing-dash"))
}
}

Expand Down
Loading