mogilefs-client 2.2.0 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.document +11 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +4 -0
  4. data/.wrongdoc.yml +5 -0
  5. data/GIT-VERSION-GEN +28 -0
  6. data/GNUmakefile +44 -0
  7. data/HACKING +33 -0
  8. data/{History.txt → History} +0 -1
  9. data/{LICENSE.txt → LICENSE} +0 -1
  10. data/Manifest.txt +34 -7
  11. data/README +51 -0
  12. data/Rakefile +11 -11
  13. data/TODO +10 -0
  14. data/bin/mog +109 -68
  15. data/examples/mogstored_rack.rb +189 -0
  16. data/lib/mogilefs.rb +56 -17
  17. data/lib/mogilefs/admin.rb +128 -62
  18. data/lib/mogilefs/backend.rb +205 -95
  19. data/lib/mogilefs/bigfile.rb +54 -70
  20. data/lib/mogilefs/bigfile/filter.rb +58 -0
  21. data/lib/mogilefs/chunker.rb +30 -0
  22. data/lib/mogilefs/client.rb +0 -2
  23. data/lib/mogilefs/copy_stream.rb +30 -0
  24. data/lib/mogilefs/http_file.rb +175 -0
  25. data/lib/mogilefs/http_reader.rb +79 -0
  26. data/lib/mogilefs/mogilefs.rb +242 -148
  27. data/lib/mogilefs/mysql.rb +3 -4
  28. data/lib/mogilefs/paths_size.rb +24 -0
  29. data/lib/mogilefs/pool.rb +0 -1
  30. data/lib/mogilefs/socket.rb +9 -0
  31. data/lib/mogilefs/socket/kgio.rb +55 -0
  32. data/lib/mogilefs/socket/pure_ruby.rb +70 -0
  33. data/lib/mogilefs/socket_common.rb +58 -0
  34. data/lib/mogilefs/util.rb +6 -169
  35. data/test/aggregate.rb +11 -11
  36. data/test/exec.rb +72 -0
  37. data/test/fresh.rb +222 -0
  38. data/test/integration.rb +43 -0
  39. data/test/setup.rb +1 -0
  40. data/test/socket_test.rb +98 -0
  41. data/test/test_admin.rb +14 -37
  42. data/test/test_backend.rb +50 -107
  43. data/test/test_bigfile.rb +2 -2
  44. data/test/test_db_backend.rb +1 -2
  45. data/test/test_fresh.rb +8 -0
  46. data/test/test_http_reader.rb +34 -0
  47. data/test/test_mogilefs.rb +278 -98
  48. data/test/test_mogilefs_integration.rb +174 -0
  49. data/test/test_mogilefs_integration_large_pipe.rb +62 -0
  50. data/test/test_mogilefs_integration_list_keys.rb +40 -0
  51. data/test/test_mogilefs_socket_kgio.rb +11 -0
  52. data/test/test_mogilefs_socket_pure.rb +7 -0
  53. data/test/test_mogstored_rack.rb +89 -0
  54. data/test/test_mogtool_bigfile.rb +116 -0
  55. data/test/test_mysql.rb +1 -2
  56. data/test/test_pool.rb +1 -1
  57. data/test/test_unit_mogstored_rack.rb +72 -0
  58. metadata +76 -54
  59. data/README.txt +0 -80
  60. data/lib/mogilefs/httpfile.rb +0 -157
  61. data/lib/mogilefs/network.rb +0 -107
  62. data/test/test_network.rb +0 -56
  63. data/test/test_util.rb +0 -121
data/.document ADDED
@@ -0,0 +1,11 @@
1
+ History
2
+ ChangeLog
3
+ LICENSE
4
+ README
5
+ HACKING
6
+ TODO
7
+ lib/mogilefs.rb
8
+ lib/mogilefs/admin.rb
9
+ lib/mogilefs/backend.rb
10
+ lib/mogilefs/client.rb
11
+ lib/mogilefs/mogilefs.rb
data/.gemtest ADDED
File without changes
data/.gitignore CHANGED
@@ -2,3 +2,7 @@
2
2
  /doc
3
3
  /.config
4
4
  /InstalledFiles
5
+ /ChangeLog
6
+ /NEWS
7
+ /LATEST
8
+ /lib/mogilefs/version.rb
data/.wrongdoc.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ cgit_url: http://bogomips.org/mogilefs-client.git
3
+ git_url: git://bogomips.org/mogilefs-client.git
4
+ rdoc_url: http://bogomips.org/mogilefs-client
5
+ changelog_start: v1.2.1
data/GIT-VERSION-GEN ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ CONSTANT = "MogileFS::VERSION"
3
+ RVF = "lib/mogilefs/version.rb"
4
+ DEF_VER = "v3.0.0-rc1"
5
+ vn = DEF_VER
6
+
7
+ # First see if there is a version file (included in release tarballs),
8
+ # then try git-describe, then default.
9
+ if File.exist?(".git")
10
+ describe = `git describe --abbrev=4 HEAD 2>/dev/null`.strip
11
+ case describe
12
+ when /\Av[0-9]*/
13
+ vn = describe
14
+ system(*%w(git update-index -q --refresh))
15
+ unless `git diff-index --name-only HEAD --`.chomp.empty?
16
+ vn << "-dirty"
17
+ end
18
+ vn.tr!('-', '.')
19
+ end
20
+ end
21
+
22
+ vn = vn.sub!(/\Av/, "")
23
+ new_ruby_version = "#{CONSTANT} = '#{vn}'\n"
24
+ cur_ruby_version = File.read(RVF) rescue nil
25
+ if new_ruby_version != cur_ruby_version
26
+ File.open(RVF, "w") { |fp| fp.write(new_ruby_version) }
27
+ end
28
+ puts vn if $0 == __FILE__
data/GNUmakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  # use GNU Make to run tests in parallel, and without depending on Rubygems
2
2
  all:: test
3
+ RSYNC_DEST := bogomips.org:/srv/bogomips/mogilefs-client
4
+ git_version_gen := $(shell ./GIT-VERSION-GEN)
3
5
 
4
6
  T := $(wildcard test/test*.rb)
5
7
  TO := $(subst .rb,.log,$(T))
@@ -31,10 +33,12 @@ $(T): export RUBYLIB := $(CURDIR)/lib:$(RUBYLIB)
31
33
  $(T):
32
34
  $(run_test)
33
35
 
36
+ RUBY_VERSION_FILE = lib/mogilefs/version.rb
34
37
  # using make instead of rake since Rakefile takes too long to load
35
38
  manifest: Manifest.txt
36
39
  Manifest.txt:
37
40
  git ls-files > $@+
41
+ echo $(RUBY_VERSION_FILE) >> $@+
38
42
  cmp $@+ $@ || mv $@+ $@
39
43
  $(RM) -f $@+
40
44
 
@@ -52,3 +56,43 @@ flay: $(libs)
52
56
  flog: $(libs)
53
57
  flog $(flog_flags) $^
54
58
  .PHONY: $(T) Manifest.txt
59
+
60
+ check-warnings:
61
+ @(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
62
+ do ruby -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
63
+ RSYNC = rsync
64
+ WRONGDOC = wrongdoc
65
+
66
+ doc:: .document .wrongdoc.yml $(pkg_extra)
67
+ -find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
68
+ $(RM) -r doc
69
+ $(WRONGDOC) all
70
+ install -m644 $(shell LC_ALL=C grep '^[A-Z]' .document) doc/
71
+ cd doc && \
72
+ ln -s README README.txt && \
73
+ ln -s README.html README_txt.html && \
74
+ ln -s LICENSE LICENSE.txt && \
75
+ ln -s LICENSE.html LICENSE_txt.html && \
76
+ ln -s History History.txt && \
77
+ ln -s History.html History_txt.html
78
+
79
+ # Create gzip variants of the same timestamp as the original so nginx
80
+ # "gzip_static on" can serve the gzipped versions directly.
81
+ doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
82
+ doc_gz:
83
+ for i in $(docs); do \
84
+ gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
85
+
86
+ # this requires GNU coreutils variants
87
+ ifneq ($(RSYNC_DEST),)
88
+ publish_doc:
89
+ -git set-file-times
90
+ $(MAKE) doc
91
+ find doc/images -type f | \
92
+ TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
93
+ $(MAKE) doc_gz
94
+ $(RSYNC) -av doc/ $(RSYNC_DEST)/
95
+ git ls-files | xargs touch
96
+ endif
97
+
98
+ .PHONY: doc .FORCE-GIT-VERSION-FILE
data/HACKING ADDED
@@ -0,0 +1,33 @@
1
+ = Hacking mogilefs-client for Ruby
2
+
3
+ * The latest code is available via git:
4
+ - git://bogomips.org/mogilefs-client.git
5
+ - git://repo.or.cz/ruby-mogilefs-client
6
+
7
+ * Follow conventions set in existing code, don't add hard runtime
8
+ dependencies outside of the standard Ruby library.
9
+
10
+ * Do not hesitate to send plain-text(-only) email to Eric Wong at
11
+ mailto:normalperson@yhbt.net about anything not covered in
12
+ the documentation or mailing list archives. General MogileFS
13
+ topics can go to the public mailing list at mailto:mogile@googlegroups.com
14
+ You may still email Wong directly if you do not trust the corporation
15
+ that hosts the public mailing list.
16
+
17
+ * Use "git format-patch" and "git send-email" for sending patches.
18
+
19
+ * Use "git request-pull" as a guideline for formatting pull-requests.
20
+
21
+ * Test with the latest upstream MogileFS and Ruby versions.
22
+
23
+ * Integration tests exist for setting up a fresh MogileFS instance
24
+ with a single host and device using a SQLite backend if you
25
+ have "mogdbsetup", "mogilefsd", and "mogstored" in your PATH.
26
+
27
+ * Setting MOG_TEST_TRACKERS= to a comma-delimited list of trackers
28
+ can enable additional integration tests against a live tracker
29
+ (with multiple devices/hosts).
30
+
31
+ * Tests may be run in parallel using GNU make:
32
+
33
+ make -j6 test
@@ -78,4 +78,3 @@
78
78
  = 1.2.0
79
79
 
80
80
  * Changes lost to time.
81
-
@@ -25,4 +25,3 @@ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
25
  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
26
  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
27
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
-
data/Manifest.txt CHANGED
@@ -1,33 +1,60 @@
1
+ .document
1
2
  .gitignore
3
+ .wrongdoc.yml
4
+ GIT-VERSION-GEN
2
5
  GNUmakefile
3
- History.txt
4
- LICENSE.txt
6
+ HACKING
7
+ History
8
+ LICENSE
5
9
  Manifest.txt
6
- README.txt
10
+ README
7
11
  Rakefile
12
+ TODO
8
13
  bin/mog
14
+ examples/mogstored_rack.rb
9
15
  lib/mogilefs.rb
10
16
  lib/mogilefs/admin.rb
11
17
  lib/mogilefs/backend.rb
12
18
  lib/mogilefs/bigfile.rb
19
+ lib/mogilefs/bigfile/filter.rb
20
+ lib/mogilefs/chunker.rb
13
21
  lib/mogilefs/client.rb
14
- lib/mogilefs/httpfile.rb
22
+ lib/mogilefs/copy_stream.rb
23
+ lib/mogilefs/http_file.rb
24
+ lib/mogilefs/http_reader.rb
15
25
  lib/mogilefs/mogilefs.rb
16
26
  lib/mogilefs/mysql.rb
17
- lib/mogilefs/network.rb
27
+ lib/mogilefs/paths_size.rb
18
28
  lib/mogilefs/pool.rb
29
+ lib/mogilefs/socket.rb
30
+ lib/mogilefs/socket/kgio.rb
31
+ lib/mogilefs/socket/pure_ruby.rb
32
+ lib/mogilefs/socket_common.rb
19
33
  lib/mogilefs/util.rb
20
34
  setup.rb
21
35
  test/.gitignore
22
36
  test/aggregate.rb
37
+ test/exec.rb
38
+ test/fresh.rb
39
+ test/integration.rb
23
40
  test/setup.rb
41
+ test/socket_test.rb
24
42
  test/test_admin.rb
25
43
  test/test_backend.rb
26
44
  test/test_bigfile.rb
27
45
  test/test_client.rb
28
46
  test/test_db_backend.rb
47
+ test/test_fresh.rb
48
+ test/test_http_reader.rb
29
49
  test/test_mogilefs.rb
50
+ test/test_mogilefs_integration.rb
51
+ test/test_mogilefs_integration_large_pipe.rb
52
+ test/test_mogilefs_integration_list_keys.rb
53
+ test/test_mogilefs_socket_kgio.rb
54
+ test/test_mogilefs_socket_pure.rb
55
+ test/test_mogstored_rack.rb
56
+ test/test_mogtool_bigfile.rb
30
57
  test/test_mysql.rb
31
- test/test_network.rb
32
58
  test/test_pool.rb
33
- test/test_util.rb
59
+ test/test_unit_mogstored_rack.rb
60
+ lib/mogilefs/version.rb
data/README ADDED
@@ -0,0 +1,51 @@
1
+ = mogilefs-client - MogileFS client library for Ruby
2
+
3
+ A MogileFS client library for Ruby. MogileFS is an open source
4
+ distributed filesystem, see: http://mogilefs.org for more details. This
5
+ library allows any Ruby application to read, write and delete files in a
6
+ MogileFS instance.
7
+
8
+ == Links
9
+
10
+ rdoc :: http://bogomips.org/mogilefs-client
11
+ mogilefs :: http://mogilefs.org/
12
+ list :: mailto:mogile@googlegroups.com
13
+ email :: mailto:normalperson@yhbt.net
14
+ repo :: git://bogomips.org/mogilefs-client.git
15
+ cgit :: http://bogomips.org/mogilefs-client.git
16
+ gitweb :: http://repo.or.cz/w/ruby-mogilefs-client.git
17
+
18
+ == Install
19
+
20
+ First you need a MogileFS 2.x installation. You can find information on
21
+ how to do that at http://mogilefs.org
22
+
23
+ Then install the RubyGem:
24
+
25
+ $ gem install mogilefs-client
26
+
27
+ This library supports Ruby 1.8.7 and later, but Ruby 1.9.3 is
28
+ recommended. No other libraries are required on the client.
29
+
30
+ == Usage
31
+
32
+ See MogileFS::MogileFS
33
+
34
+ == Contact
35
+
36
+ Feedback (bug reports, user/development dicussion, patches, pull
37
+ requests) are greatly appreciated and handled via email. We currently
38
+ piggy-back onto the public MogileFS
39
+ {mailing list}[mailto:mogile@googlegroups.com] for feedback.
40
+
41
+ If you do not want to deal with the corporate host of the MogileFS
42
+ mailing list, or if you wish to keep your issue secret, feel free to
43
+ email {Eric Wong at}[mailto:normalperson@yhbt.net].
44
+
45
+ Do not expect Eric Wong to read HTML mail under any circumstances.
46
+
47
+ == WARNING!
48
+
49
+ This client is only supported in HTTP mode. NFS mode was previously
50
+ supported in 1.3.x, but since MogileFS 2.x has dropped support for
51
+ NFS, this client has removed support for it.
data/Rakefile CHANGED
@@ -1,20 +1,20 @@
1
1
  require 'rubygems'
2
2
  require 'hoe'
3
+ load "./GIT-VERSION-GEN"
3
4
 
4
5
  $:.unshift 'lib'
5
6
  require 'mogilefs'
7
+ Hoe.plugin :seattlerb
6
8
 
7
- Hoe.new 'mogilefs-client', MogileFS::VERSION do |p|
8
- p.rubyforge_name = 'seattlerb'
9
- p.author = [ 'Eric Wong', 'Eric Hodel' ]
10
- p.email = 'normalperson@yhbt.net' # (Eric Wong)
11
- # p.email = 'drbrain@segment7.net' # (Eric Hodel)
12
- p.summary = p.paragraphs_of('README.txt', 1).first
13
- p.description = p.paragraphs_of('README.txt', 9).first
14
- p.url = p.paragraphs_of('README.txt', 5).first
15
- p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
16
-
17
- p.extra_dev_deps << ['ZenTest', '>= 3.6.1']
9
+ Hoe.spec 'mogilefs-client' do
10
+ self.rubyforge_name = 'seattlerb'
11
+ developer 'Eric Wong', 'normalperson@yhbt.net'
12
+ # developer 'drbrain@segment7.net', 'Eric Hodel'
13
+ self.readme_file = "README"
14
+ self.history_file = "History"
15
+ self.url = "http://bogomips.org/mogilefs-client"
16
+ self.description = self.paragraphs_of("README", 1)
17
+ self.summary = "MogileFS client library for Ruby"
18
18
  end
19
19
 
20
20
  task :fix_perms do
data/TODO ADDED
@@ -0,0 +1,10 @@
1
+ Patches and pull-requests (by [public]{mailto:mogile@googlegroups.com} or
2
+ [private email]{mailto:normalperson@yhbt.net}) greatly appreciated!
3
+
4
+ * MogileFS::Admin needs to be fleshed out
5
+
6
+ * optional Cool.io support
7
+
8
+ * optional EventMachine support
9
+
10
+ * manpage for "mog"
data/bin/mog CHANGED
@@ -1,24 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'mogilefs'
3
3
  require 'optparse'
4
- [ STDIN, STDOUT, STDERR].each { |io| io.binmode }
4
+ $stdin.binmode
5
+ $stdout.binmode
6
+ $stderr.sync = $stdout.sync = true
5
7
 
6
8
  trap('INT') { exit 130 }
7
9
  trap('PIPE') { exit 0 }
10
+ if md5_trailer_nodes = ENV["MD5_TRAILER_NODES"]
11
+ md5_trailer_nodes.split(/\s*,\s*/).each do |host|
12
+ MogileFS::HTTPFile::MD5_TRAILER_NODES[host] = true
13
+ end
14
+ end
8
15
 
9
16
  # this is to be compatible with config files used by the Perl tools
10
17
  def parse_config_file!(path, overwrite = false)
11
18
  dest = {}
12
19
  File.open(path).each_line do |line|
13
- line.strip!
14
- if /^(domain|class)\s*=\s*(\S+)/.match(line)
20
+ case line
21
+ when /^(domain|class)\s*=\s*(\S+)/
15
22
  dest[$1.to_sym] = $2
16
- elsif m = /^(?:trackers|hosts)\s*=\s*(.*)/.match(line)
23
+ when /^(?:trackers|hosts)\s*=\s*(.*)/
17
24
  dest[:hosts] = $1.split(/\s*,\s*/)
18
- elsif m = /^timeout\s*=\s*(.*)/.match(line)
19
- dest[:timeout] = m[1].to_f
25
+ when /^timeout\s*=\s*(.*)/
26
+ dest[:timeout] = $1.to_f
27
+ when /^noclobber\s*=\s*true\s*/
28
+ dest[:noclobber] = true
20
29
  else
21
- STDERR.puts "Ignored configuration line: #{line}" unless /^#/.match(line)
30
+ warn "Ignored configuration line: #{line}" unless /^#/.match(line)
22
31
  end
23
32
  end
24
33
  dest
@@ -33,6 +42,7 @@ cli_cfg = {}
33
42
  config_file = nil
34
43
  ls_l = false
35
44
  ls_h = false
45
+ chunk = false
36
46
  test = {}
37
47
  cat = { :raw => false }
38
48
 
@@ -50,15 +60,19 @@ ARGV.options do |x|
50
60
 
51
61
  x.on('-e', 'True if key exists') { test[:e] = true }
52
62
  x.on('-r', '--raw', 'show raw big_info file information') { cat[:raw] = true }
63
+ x.on('-n', '--no-clobber', 'do not clobber existing key') do
64
+ cli_cfg[:noclobber] = true
65
+ end
53
66
 
54
67
  x.on('-C', '--class=s', 'class') { |klass| cli_cfg[:class] = klass }
55
68
  x.on('-d', '--domain=s', 'domain') { |domain| cli_cfg[:domain] = domain }
56
69
  x.on('-l', "long listing format (`ls' command)") { ls_l = true }
57
70
  x.on('-h', '--human-readable',
58
71
  "print sizes in human-readable format (`ls' command)") { ls_h = true }
59
-
72
+ x.on('--chunk', "chunk uploads (`tee' command)") { chunk = true }
60
73
  x.separator ''
61
74
  x.on('--help', 'Show this help message.') { puts x; exit }
75
+ x.on('--version', 'Show --version') { puts "#$0 #{MogileFS::VERSION}"; exit }
62
76
  x.parse!
63
77
  end
64
78
 
@@ -86,18 +100,17 @@ err = []
86
100
  err << "trackers must be specified" if cfg[:hosts].nil? || cfg[:hosts].empty?
87
101
  err << "domain must be specified" unless cfg[:domain]
88
102
  if err.any?
89
- STDERR.puts "Errors:\n #{err.join("\n ")}"
90
- STDERR.puts ARGV.options
103
+ warn "Errors:\n #{err.join("\n ")}"
104
+ warn ARGV.options
91
105
  exit 1
92
106
  end
93
107
 
94
108
  unless cmd = ARGV.shift
95
- STDERR.puts ARGV.options
109
+ warn ARGV.options
96
110
  exit 1
97
111
  end
98
112
 
99
113
  cfg[:timeout] ||= 30 # longer timeout for interactive use
100
- include MogileFS::Util
101
114
  mg = MogileFS::MogileFS.new(cfg)
102
115
 
103
116
  def store_file_retry(mg, key, storage_class, filepath)
@@ -107,56 +120,57 @@ def store_file_retry(mg, key, storage_class, filepath)
107
120
  rescue MogileFS::UnreadableSocketError,
108
121
  MogileFS::Backend::NoDevicesError => err
109
122
  if ((tries += 1) < 10)
110
- STDERR.puts "Retrying on error: #{err}: #{err.message} tries: #{tries}"
123
+ warn "Retrying on error: #{err}: #{err.message} tries: #{tries}"
111
124
  retry
112
125
  else
113
- STDERR.puts "FATAL: #{err}: #{err.message} tries: #{tries}"
126
+ warn "FATAL: #{err}: #{err.message} tries: #{tries}"
114
127
  end
115
128
  exit 1
116
129
  end
117
130
  end
118
131
 
132
+ def human_size(size)
133
+ suff = ''
134
+ %w(K M G).each do |s|
135
+ size /= 1024.0
136
+ if size <= 1024
137
+ suff = s
138
+ break
139
+ end
140
+ end
141
+ sprintf("%.1f%s", size, suff)
142
+ end
143
+
119
144
  begin
120
145
  case cmd
121
146
  when 'cp'
122
147
  filename = ARGV.shift or raise ArgumentError, '<filename> <key>'
123
- key = ARGV.shift or raise ArgumentError, '<filename> <key>'
148
+ dkey = ARGV.shift or raise ArgumentError, '<filename> <key>'
124
149
  ARGV.shift and raise ArgumentError, '<filename> <key>'
125
- store_file_retry(mg, key, cfg[:class], filename)
150
+ cfg[:noclobber] && mg.exist?(dkey) and
151
+ abort "`#{dkey}' already exists and -n/--no-clobber was specified"
152
+ store_file_retry(mg, dkey, cfg[:class], filename)
126
153
  when 'cat'
127
154
  ARGV.empty? and raise ArgumentError, '<key1> [<key2> ...]'
128
155
  ARGV.each do |key|
129
156
  if (!cat[:raw] && key =~ /^_big_info:/)
130
- mg.bigfile_write(key, STDOUT, {:verify => true})
157
+ mg.bigfile_write(key, $stdout, {:verify => true})
131
158
  else
132
- mg.get_file_data(key) { |fp| sysrwloop(fp, STDOUT) }
159
+ mg.get_file_data(key, $stdout)
133
160
  end
134
161
  end
135
162
  when 'ls'
136
163
  prefixes = ARGV.empty? ? [ nil ] : ARGV
137
- prefixes.each do |prefix|
138
- mg.each_key(prefix) do |key|
139
- if ls_l
140
- path_nr = "% 2d" % mg.get_paths(key).size
141
- size = mg.size(key)
142
- if ls_h && size > 1024
143
- suff = ''
144
- %w(K M G).each do |s|
145
- size /= 1024.0
146
- suff = s
147
- break if size <= 1024
148
- end
149
- size = sprintf("%.1f%s", size, suff)
150
- else
151
- size = size.to_s
152
- end
153
- size = (' ' * (12 - size.length)) << size # right justify
154
- puts [ path_nr, size, key ].pack("A4 A16 A32")
155
- else
156
- puts key
157
- end
164
+ if ls_l
165
+ each_key = lambda do |key, size, devcount|
166
+ size = ls_h && size > 1024 ? human_size(size) : size.to_s
167
+ size = (' ' * (12 - size.length)) << size # right justify
168
+ puts [ sprintf("% 2d", devcount), size, key ].pack("A4 A16 A*")
158
169
  end
170
+ else
171
+ each_key = lambda { |key| puts key }
159
172
  end
173
+ prefixes.each { |prefix| mg.each_key(prefix, &each_key) }
160
174
  when 'rm'
161
175
  ARGV.empty? and raise ArgumentError, '<key1> [<key2>]'
162
176
  ARGV.each { |key| mg.delete(key) }
@@ -167,35 +181,67 @@ begin
167
181
  mg.rename(from, to)
168
182
  when 'stat' # this outputs a RFC822-like format
169
183
  ARGV.empty? and raise ArgumentError, '<key1> [<key2>]'
170
- ARGV.each_with_index do |key, i|
171
- if size = mg.size(key)
184
+ ok = true
185
+ ARGV.each_with_index do |key,j|
186
+ begin
187
+ info = mg.file_info(key)
172
188
  puts "Key: #{key}"
173
- puts "Size: #{size}"
174
- mg.get_paths(key).each_with_index do |path,i|
189
+ puts "Size: #{info['length']}"
190
+ puts "Class: #{info['class']}"
191
+ o = { :pathcount => info["devcount"] }
192
+ mg.get_paths(key, o).each_with_index do |path,i|
175
193
  puts "URL-#{i}: #{path}"
176
194
  end
177
- puts ""
178
- else
179
- STDERR.puts "No such key: #{key}"
195
+ puts "" if ARGV.size != (j + 1)
196
+ rescue MogileFS::Backend::UnknownKeyError
197
+ warn "No such key: #{key}"
198
+ ok = false
180
199
  end
181
200
  end
201
+ exit(ok)
182
202
  when 'tee'
183
203
  require 'tempfile'
184
- key = ARGV.shift or raise ArgumentError, '<key>'
204
+ dkey = ARGV.shift or raise ArgumentError, '<key>'
185
205
  ARGV.shift and raise ArgumentError, '<key>'
186
- cfg[:class] or raise ArgumentError, 'E: --class must be specified'
187
- buf = ''
188
- tmp = Tempfile.new('mog-tee') # TODO: explore Transfer-Encoding:chunked :)
189
-
190
- # if stdout is pointing to /dev/null, don't bother installing the filter.
191
- STDOUT.sync = true
192
- tee_filter = File.stat('/dev/null') == STDOUT.stat ?
193
- nil : Proc.new { |buf| STDOUT.write(buf); buf }
194
- begin
195
- sysrwloop(STDIN, tmp, tee_filter)
196
- store_file_retry(mg, key, cfg[:class], tmp.path)
197
- ensure
198
- tmp.close!
206
+ cfg[:noclobber] && mg.exist?(dkey) and
207
+ abort "`#{dkey}' already exists and -n/--no-clobber was specified"
208
+ skip_tee = File.stat('/dev/null') == $stdout.stat
209
+
210
+ if chunk
211
+ if skip_tee
212
+ tee_obj = $stdin
213
+ else
214
+ tee_obj = lambda do |*args|
215
+ buf = $stdin.readpartial(*args)
216
+ $stdout.write(buf)
217
+ buf
218
+ end
219
+ class << tee_obj
220
+ alias readpartial call
221
+ end
222
+ end
223
+ mg.store_file(dkey, cfg[:class], tee_obj)
224
+ else # buffer input, first
225
+ tmp = Tempfile.new('mog-tee')
226
+ tmp.sync = true
227
+
228
+ # if stdout is pointing to /dev/null, don't bother installing the filter.
229
+ tee_obj = tmp
230
+ unless skip_tee
231
+ tee_obj = lambda do |buf|
232
+ $stdout.write(buf)
233
+ tmp.write(buf)
234
+ end
235
+ class << tee_obj
236
+ alias write call
237
+ end
238
+ end
239
+ begin
240
+ MogileFS.io.copy_stream($stdin, tee_obj)
241
+ store_file_retry(mg, dkey, cfg[:class], tmp.path)
242
+ ensure
243
+ tmp.close!
244
+ end
199
245
  end
200
246
  when 'test'
201
247
  truth, ok = true, nil
@@ -213,20 +259,15 @@ begin
213
259
  raise ArgumentError, "Too many arguments"
214
260
  end
215
261
 
216
- paths = mg.get_paths(key)
217
- if test[:e]
218
- ok = !!(paths && paths.size > 0)
219
- else
220
- raise ArgumentError, "Unknown flag: -#{test.keys.first}"
221
- end
222
-
262
+ test[:e] or raise ArgumentError, "Unknown flag: -#{test.keys.first}"
263
+ ok = mg.exist?(key)
223
264
  truth or ok = ! ok
224
265
  exit ok ? 0 : 1
225
266
  else
226
267
  raise ArgumentError, "Unknown command: #{cmd}"
227
268
  end
228
269
  rescue ArgumentError => err
229
- STDERR.puts "Usage: #{$0} #{cmd} #{err.message}"
270
+ warn "Usage: #{$0} #{cmd} #{err.message}"
230
271
  exit 1
231
272
  end
232
273
  exit 0