forked from EmbarkStudios/gsutil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cat.rs
54 lines (45 loc) · 1.62 KB
/
cat.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use crate::util;
use tame_gcs::{http, objects::Object};
#[derive(clap::Parser, Debug)]
pub struct Args {
#[clap(
short,
allow_hyphen_values = true,
long_help = "Causes gsutil to output just the specified byte range of the object.
Ranges are can be of these forms:
* start-end (e.g., -r 256-5939)
* start- (e.g., -r 256-)
* -numbytes (e.g., -r -5)
where offsets start at 0, start-end means to return bytes start
through end (inclusive), start- means to return bytes start
through the end of the object, and -numbytes means to return the
last numbytes of the object."
)]
range: Option<String>,
/// The gs:// url to the object
url: url::Url,
}
pub async fn cmd(ctx: &util::RequestContext, args: Args) -> Result<(), anyhow::Error> {
let oid = util::gs_url_to_object_id(&args.url)?;
let mut download_req = Object::download(
&(
oid.bucket(),
oid.object()
.ok_or_else(|| anyhow::anyhow!("invalid object name specified"))?,
),
None,
)?;
if let Some(range) = args.range {
// The format specified in the arguments exactly matches those HTTP range
// value, so we just pass it along (almost) verbatim and let GCS actually
// handle nefarious users for us
download_req.headers_mut().insert(
http::header::RANGE,
http::header::HeaderValue::from_str(&format!("bytes={}", range))?,
);
}
let mut response: tame_gcs::objects::DownloadObjectResponse =
util::execute(ctx, download_req).await?;
std::io::copy(&mut response, &mut std::io::stdout())?;
Ok(())
}