Write torrent to stdout if -
is passed to --output
type: added
This commit is contained in:
parent
5a1de1acd2
commit
df3326510c
|
@ -17,6 +17,10 @@ impl Capture {
|
|||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn bytes(&self) -> Vec<u8> {
|
||||
self.cursor.borrow().get_ref().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Capture {
|
||||
|
|
|
@ -49,7 +49,7 @@ pub(crate) use crate::{
|
|||
bytes::Bytes, env::Env, error::Error, file_info::FileInfo, files::Files, hasher::Hasher,
|
||||
info::Info, lint::Lint, linter::Linter, metainfo::Metainfo, mode::Mode, opt::Opt,
|
||||
piece_length_picker::PieceLengthPicker, platform::Platform, style::Style, table::Table,
|
||||
torrent_summary::TorrentSummary, use_color::UseColor,
|
||||
target::Target, torrent_summary::TorrentSummary, use_color::UseColor,
|
||||
};
|
||||
|
||||
// test stdlib types
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
clippy::result_expect_used,
|
||||
clippy::result_unwrap_used,
|
||||
clippy::shadow_reuse,
|
||||
clippy::too_many_lines,
|
||||
clippy::unreachable,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::wildcard_enum_match_arm
|
||||
|
@ -76,6 +77,7 @@ mod platform_interface;
|
|||
mod reckoner;
|
||||
mod style;
|
||||
mod table;
|
||||
mod target;
|
||||
mod torrent_summary;
|
||||
mod use_color;
|
||||
|
||||
|
|
26
src/opt.rs
26
src/opt.rs
|
@ -2,19 +2,6 @@ use crate::common::*;
|
|||
|
||||
mod torrent;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
pub(crate) enum Subcommand {
|
||||
Torrent(torrent::Torrent),
|
||||
}
|
||||
|
||||
impl Subcommand {
|
||||
pub(crate) fn run(self, env: &mut Env, unstable: bool) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Torrent(torrent) => torrent.run(env, unstable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(
|
||||
about(consts::ABOUT),
|
||||
|
@ -51,3 +38,16 @@ impl Opt {
|
|||
self.subcommand.run(env, self.unstable)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
pub(crate) enum Subcommand {
|
||||
Torrent(torrent::Torrent),
|
||||
}
|
||||
|
||||
impl Subcommand {
|
||||
pub(crate) fn run(self, env: &mut Env, unstable: bool) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Torrent(torrent) => torrent.run(env, unstable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,8 @@ Note: Many BitTorrent clients do not implement the behavior described in BEP 12.
|
|||
name = "INPUT",
|
||||
long = "input",
|
||||
help = "Read torrent contents from `INPUT`.",
|
||||
long_help = "Read torrent contents from `INPUT`. If `INPUT` is a file, torrent will be a single-file torrent, otherwise if `INPUT` is a directory, torrent will be a multi-file torrent."
|
||||
long_help = "Read torrent contents from `INPUT`. If `INPUT` is a file, torrent will be a single-file torrent, otherwise if `INPUT` is a directory, torrent will be a multi-file torrent.",
|
||||
parse(from_os_str)
|
||||
)]
|
||||
input: PathBuf,
|
||||
#[structopt(
|
||||
|
@ -85,9 +86,10 @@ Note: Many BitTorrent clients do not implement the behavior described in BEP 12.
|
|||
#[structopt(
|
||||
name = "OUTPUT",
|
||||
long = "output",
|
||||
help = "Save `.torrent` file to `OUTPUT`. Defaults to `$INPUT.torrent`."
|
||||
help = "Save `.torrent` file to `OUTPUT`, or `-` for standard output. Defaults to `$INPUT.torrent`.",
|
||||
parse(from_os_str)
|
||||
)]
|
||||
output: Option<PathBuf>,
|
||||
output: Option<Target>,
|
||||
#[structopt(
|
||||
name = "PIECE-LENGTH",
|
||||
long = "piece-length",
|
||||
|
@ -175,12 +177,12 @@ impl Create {
|
|||
let output = self
|
||||
.output
|
||||
.as_ref()
|
||||
.map(|output| env.resolve(&output))
|
||||
.map(|output| output.resolve(env))
|
||||
.unwrap_or_else(|| {
|
||||
let mut torrent_name = name.to_owned();
|
||||
torrent_name.push_str(".torrent");
|
||||
|
||||
input.parent().unwrap().join(torrent_name)
|
||||
Target::File(input.parent().unwrap().join(torrent_name))
|
||||
});
|
||||
|
||||
let private = if self.private { Some(1) } else { None };
|
||||
|
@ -228,12 +230,15 @@ impl Create {
|
|||
|
||||
let bytes = metainfo.serialize()?;
|
||||
|
||||
fs::write(&output, &bytes).context(error::Filesystem { path: &output })?;
|
||||
|
||||
match &output {
|
||||
Target::File(path) => {
|
||||
fs::write(path, &bytes).context(error::Filesystem { path })?;
|
||||
TorrentSummary::from_metainfo(metainfo)?.write(env)?;
|
||||
|
||||
if self.open {
|
||||
Platform::open(&output)?;
|
||||
Platform::open(&path)?;
|
||||
}
|
||||
}
|
||||
Target::Stdio => env.out.write_all(&bytes).context(error::Stdout)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -890,4 +895,21 @@ Content Size 0 bytes
|
|||
";
|
||||
assert_eq!(have, want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_to_stdout() {
|
||||
let mut env = environment(&[
|
||||
"--input",
|
||||
"foo",
|
||||
"--announce",
|
||||
"http://bar",
|
||||
"--output",
|
||||
"-",
|
||||
]);
|
||||
fs::write(env.resolve("foo"), "").unwrap();
|
||||
env.run().unwrap();
|
||||
let bytes = env.out_bytes();
|
||||
let value = bencode::Value::decode(&bytes).unwrap();
|
||||
assert!(matches!(value, bencode::Value::Dict(_)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ pub(crate) struct Show {
|
|||
#[structopt(
|
||||
name = "TORRENT",
|
||||
long = "input",
|
||||
help = "Show information about `TORRENT`."
|
||||
help = "Show information about `TORRENT`.",
|
||||
parse(from_os_str)
|
||||
)]
|
||||
input: PathBuf,
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ Extract and display values under key paths that match `REGEX`. Subkeys of a benc
|
|||
long = "input",
|
||||
short = "i",
|
||||
help = "Search `INPUT` for torrents.",
|
||||
long_help = "Search `INPUT` for torrents. May be a directory to search or a single torrent file."
|
||||
long_help = "Search `INPUT` for torrents. May be a directory to search or a single torrent file.",
|
||||
parse(from_os_str)
|
||||
)]
|
||||
input: PathBuf,
|
||||
#[structopt(
|
||||
|
|
41
src/target.rs
Normal file
41
src/target.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use crate::common::*;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub(crate) enum Target {
|
||||
File(PathBuf),
|
||||
Stdio,
|
||||
}
|
||||
|
||||
impl Target {
|
||||
pub(crate) fn resolve(&self, env: &Env) -> Self {
|
||||
match self {
|
||||
Self::File(path) => Self::File(env.resolve(path)),
|
||||
Self::Stdio => Self::Stdio,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&OsStr> for Target {
|
||||
fn from(text: &OsStr) -> Self {
|
||||
if text == OsStr::new("-") {
|
||||
Self::Stdio
|
||||
} else {
|
||||
Self::File(text.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn file() {
|
||||
assert_eq!(Target::from(OsStr::new("foo")), Target::File("foo".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stdio() {
|
||||
assert_eq!(Target::from(OsStr::new("-")), Target::Stdio);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,10 @@ impl TestEnv {
|
|||
pub(crate) fn out(&self) -> String {
|
||||
self.out.string()
|
||||
}
|
||||
|
||||
pub(crate) fn out_bytes(&self) -> Vec<u8> {
|
||||
self.out.bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TestEnv {
|
||||
|
|
Loading…
Reference in New Issue
Block a user