Merge lp:~letterj/swift/st_stream into lp:~hudson-openstack/swift/trunk

Proposed by Jay Payne
Status: Merged
Approved by: Chuck Thier
Approved revision: 119
Merged at revision: 129
Proposed branch: lp:~letterj/swift/st_stream
Merge into: lp:~hudson-openstack/swift/trunk
Diff against target: 91 lines (+29/-7)
1 file modified
bin/st (+29/-7)
To merge this branch: bzr merge lp:~letterj/swift/st_stream
Reviewer Review Type Date Requested Status
Chuck Thier (community) Approve
clayg Pending
Review via email: mp+40679@code.launchpad.net

Description of the change

Added "-o" option to the st tool

The option "-o <filename>" will send the object data to a file named <filename>
The option "-o -" will send the object data to standard out

Special Note: This option only works with a single file download.

To post a comment you must log in.
Revision history for this message
clayg (clay-gerrard) wrote :

This is a great enhancement, nice work letterj. Also, you had mentioned some problems when you were setting up the branch, but I didn't have any issues merging these changes against trunk, very clean.

I found the help string for the -o option confusing at first:
"For a single file download stream the output other location"

I read it as "file download stream" - might be easier to read with a comma:
"For a single file download, stream the output to other location"

But I'm not sure about limiting all stream downloads to only a single file at a time? I think there's a use case for multi-file download to stdout (like if you want to pipe a stream of multiple log files to grep).

Whatever you want to do, I definitely think that we should return an error if the user supplies incompatible input (i.e. multiple file download single out_file filename) instead of guessing (i.e. silently ignore the -o option). Maybe you could add a test for it right at the top of st_download next to the "if (not args ..." bit?

Last thing, an implementation detail... I had to re-read the section at the top of _download_container where you're "inferring the behavior based on the length of the item coming off the queue" a couple of times before I got what was going on. That may not mean much tho, I'm kinda dense and tend to struggle with trixy python code, plus I'm not that familiar with st - so take this with a grain of salt - but I think it would be more readable to *me* if you just added an optional keyword argument to _download_container (i.e. http://paste.openstack.org/show/140/)

Let me know if you have any questions.

Revision history for this message
Chuck Thier (cthier) wrote :

works for me

review: Approve
Revision history for this message
Chuck Thier (cthier) wrote :

> This is a great enhancement, nice work letterj. Also, you had mentioned some
> problems when you were setting up the branch, but I didn't have any issues
> merging these changes against trunk, very clean.
>
> I found the help string for the -o option confusing at first:
> "For a single file download stream the output other location"
>
> I read it as "file download stream" - might be easier to read with a comma:
> "For a single file download, stream the output to other location"
>
> But I'm not sure about limiting all stream downloads to only a single file at
> a time? I think there's a use case for multi-file download to stdout (like if
> you want to pipe a stream of multiple log files to grep).
>
> Whatever you want to do, I definitely think that we should return an error if
> the user supplies incompatible input (i.e. multiple file download single
> out_file filename) instead of guessing (i.e. silently ignore the -o option).
> Maybe you could add a test for it right at the top of st_download next to the
> "if (not args ..." bit?
>
> Last thing, an implementation detail... I had to re-read the section at the
> top of _download_container where you're "inferring the behavior based on the
> length of the item coming off the queue" a couple of times before I got what
> was going on. That may not mean much tho, I'm kinda dense and tend to
> struggle with trixy python code, plus I'm not that familiar with st - so take
> this with a grain of salt - but I think it would be more readable to *me* if
> you just added an optional keyword argument to _download_container (i.e.
> http://paste.openstack.org/show/140/)
>
> Let me know if you have any questions.

Streaming several files we can add as a future feature request.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/st'
2--- bin/st 2010-10-07 16:28:59 +0000
3+++ bin/st 2010-11-11 23:43:56 +0000
4@@ -821,7 +821,7 @@
5 from os import environ, listdir, makedirs, utime
6 from os.path import basename, dirname, getmtime, getsize, isdir, join
7 from Queue import Empty, Queue
8-from sys import argv, exit, stderr
9+from sys import argv, exit, stderr, stdout
10 from threading import enumerate as threading_enumerate, Thread
11 from time import sleep
12
13@@ -969,14 +969,23 @@
14 st_download_help = '''
15 download --all OR download container [object] [object] ...
16 Downloads everything in the account (with --all), or everything in a
17- container, or a list of objects depending on the args given.'''.strip('\n')
18+ container, or a list of objects depending on the args given. Use
19+ the -o [--output] <filename> option to redirect the output to a file
20+ or if "-" then the just redirect to stdout. '''.strip('\n')
21 def st_download(options, args):
22 if (not args and not options.yes_all) or (args and options.yes_all):
23 options.error_queue.put('Usage: %s [options] %s' %
24 (basename(argv[0]), st_download_help))
25 return
26 object_queue = Queue(10000)
27- def _download_object((container, obj), conn):
28+ def _download_object(queue_arg, conn):
29+ if len(queue_arg) == 2:
30+ container, obj = queue_arg
31+ out_file = None
32+ elif len(queue_arg) == 3:
33+ container, obj, out_file = queue_arg
34+ else:
35+ raise Exception("Invalid queue_arg length of %s" % len(queue_arg))
36 try:
37 headers, body = \
38 conn.get_object(container, obj, resp_chunk_size=65536)
39@@ -998,7 +1007,12 @@
40 dirpath = dirname(path)
41 if dirpath and not isdir(dirpath):
42 mkdirs(dirpath)
43- fp = open(path, 'wb')
44+ if out_file == "-":
45+ fp = stdout
46+ elif out_file:
47+ fp = open(out_file, 'wb')
48+ else:
49+ fp = open(path, 'wb')
50 read_length = 0
51 md5sum = md5()
52 for chunk in body :
53@@ -1013,7 +1027,7 @@
54 options.error_queue.put(
55 '%s: read_length != content_length, %d != %d' %
56 (path, read_length, content_length))
57- if 'x-object-meta-mtime' in headers:
58+ if 'x-object-meta-mtime' in headers and not options.out_file:
59 mtime = float(headers['x-object-meta-mtime'])
60 utime(path, (mtime, mtime))
61 if options.verbose:
62@@ -1070,8 +1084,12 @@
63 elif len(args) == 1:
64 _download_container(args[0], create_connection())
65 else:
66- for obj in args[1:]:
67- object_queue.put((args[0], obj))
68+ if len(args) == 2:
69+ obj = args[1]
70+ object_queue.put((args[0], obj, options.out_file))
71+ else:
72+ for obj in args[1:]:
73+ object_queue.put((args[0], obj))
74 while not container_queue.empty():
75 sleep(0.01)
76 for thread in container_threads:
77@@ -1438,10 +1456,14 @@
78 help='User name for obtaining an auth token')
79 parser.add_option('-K', '--key', dest='key',
80 help='Key for obtaining an auth token')
81+ parser.add_option('-o', '--output', dest='out_file',
82+ help='For a single file download stream the output other location ')
83 args = argv[1:]
84 if not args:
85 args.append('-h')
86 (options, args) = parser.parse_args(args)
87+ if options.out_file == '-':
88+ options.verbose = 0
89
90 required_help = '''
91 Requires ST_AUTH, ST_USER, and ST_KEY environment variables be set or