duracloud-client 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -1
  3. data/lib/duracloud.rb +5 -1
  4. data/lib/duracloud/cli.rb +29 -107
  5. data/lib/duracloud/command_options.rb +120 -0
  6. data/lib/duracloud/commands.rb +40 -0
  7. data/lib/duracloud/commands/command.rb +6 -2
  8. data/lib/duracloud/commands/count.rb +15 -0
  9. data/lib/duracloud/commands/download_manifest.rb +0 -2
  10. data/lib/duracloud/commands/find.rb +16 -0
  11. data/lib/duracloud/commands/find_item.rb +16 -0
  12. data/lib/duracloud/commands/find_items.rb +22 -0
  13. data/lib/duracloud/commands/find_missing_items.rb +15 -0
  14. data/lib/duracloud/commands/find_space.rb +12 -0
  15. data/lib/duracloud/commands/get_storage_report.rb +16 -0
  16. data/lib/duracloud/commands/get_storage_report_for_all_spaces.rb +12 -0
  17. data/lib/duracloud/commands/get_storage_report_for_space.rb +10 -0
  18. data/lib/duracloud/commands/get_storage_report_for_store.rb +10 -0
  19. data/lib/duracloud/commands/list_content_ids.rb +11 -0
  20. data/lib/duracloud/commands/list_items.rb +17 -0
  21. data/lib/duracloud/commands/sync.rb +0 -2
  22. data/lib/duracloud/commands/validate.rb +2 -3
  23. data/lib/duracloud/content.rb +12 -3
  24. data/lib/duracloud/fast_sync_validation.rb +42 -0
  25. data/lib/duracloud/rest_methods.rb +15 -0
  26. data/lib/duracloud/storage_report.rb +33 -0
  27. data/lib/duracloud/storage_reports.rb +52 -0
  28. data/lib/duracloud/sync_validation.rb +122 -39
  29. data/lib/duracloud/version.rb +1 -1
  30. data/spec/unit/cli_spec.rb +59 -15
  31. data/spec/unit/client_spec.rb +24 -0
  32. data/spec/unit/content_spec.rb +17 -7
  33. data/spec/unit/storage_report_spec.rb +15 -0
  34. data/spec/unit/storage_reports_spec.rb +45 -0
  35. metadata +23 -3
  36. data/lib/duracloud/commands/get_properties.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 935b71b6483353f2dee2f6919df2844e31f51ba7
4
- data.tar.gz: 369ec0668fbc416e23978241668a983e2bd92caa
3
+ metadata.gz: a80c928604f4871e81e40df21497f669d57dce14
4
+ data.tar.gz: bb0f71e139c0fff9e5634a56c205106daed5a0d5
5
5
  SHA512:
6
- metadata.gz: 6f8717da6c2ef7515e7bf791456d923c6156a445c541a3a5c21bd7b8d73730881ba4bd681ffc7539ca5717c9b2b25a887cd6de50107ad5c4149c4806aed553d4
7
- data.tar.gz: 351a64019bdea2b4426d9288df4ac5c7f7fa166dfe89ee25d3cecd14930a8c20ae71f01a29a34a1d9118431eb8df1d173e72d055b583b5359639e5d30ec6dbca
6
+ metadata.gz: 39311c8c6a74b5100779f0f32e3aa0b08c8c27d406492d3b4a3cf477736b75b8b8a9028a5935b9b6724f3922284bd4972ee4247a5f394cc7e8a58295e9b1cfb3
7
+ data.tar.gz: 266f141ab9f3d0d87759411ba76d63816498ea4980354eb6e9824cc89ac9c93fa802a7edb132bcf5b6535c90fff96d0a1f0ba76e528233f210eda0d6bb9fab43
data/README.md CHANGED
@@ -140,12 +140,25 @@ Assumptions:
140
140
  Process:
141
141
  - The space manifest is downloaded from DuraCloud and converted to the expected input format for `md5deep` (two columns: md5 hash and file path, separated by two spaces).
142
142
  - `md5deep` is run against the content directory in "non-matching" mode (-X) with the converted manifest as the list of "known hashes".
143
- - Non-matching files from the `md5deep` run are re-checked individually by calling `Duracloud::Content.exist?`. This pass will account for content sync after `md5deep` started as well as files that have been chunked in DuraCloud.
143
+ - Non-matching files from the `md5deep` run are re-checked individually by calling `Duracloud::Content.exist?`.
144
+ This pass will account for content sync after `md5deep` started as well as files that have been chunked in DuraCloud.
145
+ Results of this re-check are printed to STDOUT (or, if using the `:work_dir` option, below, to a file).
144
146
 
145
147
  ```ruby
146
148
  Duracloud::SyncValidation.call(space_id: 'foo', content_dir: '/var/foo/bar')
147
149
  ```
148
150
 
151
+ *Added in version 0.9.0* - `:work_dir` option to specify existing directory in which to write validation files. The default behavior is to
152
+ create a temporary directory which is deleted on completion of the process. If `:work_dir` is specified, no cleanup is performed.
153
+
154
+ Files created in work directory:
155
+ - `{SPACE_ID}-manifest.tsv` (DuraCloud manifest as downloaded)
156
+ - `{SPACE_ID}-md5.txt` (Munged manifest for md5deep)
157
+ - `{SPACE_ID}-audit.txt` (Output of md5deep, empty if all files match)
158
+ - `{SPACE_ID}-recheck.txt` (Out of audit recheck, if necessary)
159
+
160
+ *Added in version 0.9.0* - `Duracloud::FastSyncValidation`. This variant of sync validation does not compute local hashes but instead compares the local file list (generated with `find`) to the list of content IDs in the space manifest. Local misses are rechecked as in `SyncValidation` (but without MD5 comparison).
161
+
149
162
  ### Content
150
163
 
151
164
  #### Create a new content item and store it in DuraCloud
data/lib/duracloud.rb CHANGED
@@ -8,13 +8,15 @@ module Duracloud
8
8
  autoload :ChunkedContent, "duracloud/chunked_content"
9
9
  autoload :Client, "duracloud/client"
10
10
  autoload :CLI, "duracloud/cli"
11
+ autoload :CommandOptions, "duracloud/command_options"
12
+ autoload :Commands, "duracloud/commands"
11
13
  autoload :Configuration, "duracloud/configuration"
12
14
  autoload :Connection, "duracloud/connection"
13
15
  autoload :Content, "duracloud/content"
14
16
  autoload :ContentManifest, "duracloud/content_manifest"
15
17
  autoload :DurastoreRequest, "duracloud/durastore_request"
16
18
  autoload :ErrorHandler, "duracloud/error_handler"
17
- autoload :HasProperties, "duracloud/has_properties"
19
+ autoload :FastSyncValidation, "duracloud/fast_sync_validation"
18
20
  autoload :Manifest, "duracloud/manifest"
19
21
  autoload :Persistence, "duracloud/persistence"
20
22
  autoload :Properties, "duracloud/properties"
@@ -24,6 +26,8 @@ module Duracloud
24
26
  autoload :Space, "duracloud/space"
25
27
  autoload :SpaceAcls, "duracloud/space_acls"
26
28
  autoload :Store, "duracloud/store"
29
+ autoload :StorageReport, "duracloud/storage_report"
30
+ autoload :StorageReports, "duracloud/storage_reports"
27
31
  autoload :SyncValidation, "duracloud/sync_validation"
28
32
  autoload :TSV, "duracloud/tsv"
29
33
  end
data/lib/duracloud/cli.rb CHANGED
@@ -4,8 +4,9 @@ require 'active_model'
4
4
  module Duracloud
5
5
  class CLI
6
6
  include ActiveModel::Model
7
+ include Commands
7
8
 
8
- COMMANDS = %w( sync validate manifest properties )
9
+ COMMANDS = Commands.public_instance_methods.map(&:to_s)
9
10
 
10
11
  USAGE = <<-EOS
11
12
  Usage: duracloud [COMMAND] [options]
@@ -17,13 +18,28 @@ Options:
17
18
  EOS
18
19
  HELP = "Type 'duracloud -h/--help' for usage."
19
20
 
20
- attr_accessor :command, :user, :password, :host, :port,
21
- :space_id, :store_id, :content_id,
22
- :content_type, :md5,
23
- :content_dir, :format, :infile,
24
- :logging
25
-
26
- validates_presence_of :space_id, message: "-s/--space-id option is required."
21
+ attr_accessor :all_spaces,
22
+ :command,
23
+ :content_dir,
24
+ :content_id,
25
+ :content_type,
26
+ :fast,
27
+ :format,
28
+ :host,
29
+ :infile,
30
+ :logging,
31
+ :md5,
32
+ :missing,
33
+ :password,
34
+ :port,
35
+ :prefix,
36
+ :space_id,
37
+ :store_id,
38
+ :user,
39
+ :work_dir
40
+
41
+ validates_presence_of :space_id, message: "-s/--space-id option is required.", unless: "command == 'get_storage_report'"
42
+ validates_inclusion_of :command, in: COMMANDS
27
43
 
28
44
  def self.error!(exception)
29
45
  $stderr.puts exception.message
@@ -34,112 +50,20 @@ EOS
34
50
  end
35
51
 
36
52
  def self.call(*args)
37
- options = {}
38
-
39
- parser = OptionParser.new do |opts|
40
- opts.banner = USAGE
41
-
42
- opts.on("-h", "--help",
43
- "Prints help") do
44
- puts opts
45
- exit
46
- end
47
-
48
- opts.on("-H", "--host HOST",
49
- "DuraCloud host") do |v|
50
- options[:host] = v
51
- end
52
-
53
- opts.on("-P", "--port PORT",
54
- "DuraCloud port") do |v|
55
- options[:port] = v
56
- end
57
-
58
- opts.on("-u", "--user USER",
59
- "DuraCloud user") do |v|
60
- options[:user] = v
61
- end
62
-
63
- opts.on("-p", "--password PASSWORD",
64
- "DuraCloud password") do |v|
65
- options[:password] = v
66
- end
67
-
68
- opts.on("-l", "--[no-]logging",
69
- "Enable/disable logging to STDERR") do |v|
70
- options[:logging] = v
71
- end
72
-
73
- opts.on("-s", "--space-id SPACE_ID",
74
- "DuraCloud space ID") do |v|
75
- options[:space_id] = v
76
- end
77
-
78
- opts.on("-i", "--store-id STORE_ID",
79
- "DuraCloud store ID") do |v|
80
- options[:store_id] = v
81
- end
82
-
83
- opts.on("-c", "--content-id CONTENT_ID",
84
- "DuraCloud content ID") do |v|
85
- options[:content_id] = v
86
- end
87
-
88
- opts.on("-m", "--md5 MD5",
89
- "MD5 digest of content to store or retrieve") do |v|
90
- options[:md5] = v
91
- end
92
-
93
- opts.on("-b", "--bagit",
94
- "Get manifest in BAGIT format (default is TSV)") do
95
- options[:format] = Manifest::BAGIT_FORMAT
96
- end
97
-
98
- opts.on("-d", "--content-dir CONTENT_DIR",
99
- "Local content directory") do |v|
100
- options[:content_dir] = v
101
- end
102
-
103
- opts.on("-f", "--infile FILE",
104
- "Input file") do |v|
105
- options[:infile] = v
106
- end
107
- end
108
-
109
- command = args.shift if COMMANDS.include?(args.first)
110
- parser.parse!(args)
111
-
112
- cli = new(options)
53
+ options = CommandOptions.new(*args)
54
+ cli = new(options) # .merge(command: command))
113
55
  if cli.invalid?
114
56
  message = cli.errors.map { |k, v| "ERROR: #{v}" }.join("\n")
115
57
  raise CommandError, message
116
58
  end
117
- cli.execute(command)
59
+ cli.execute
118
60
  rescue => e
119
61
  error!(e)
120
62
  end
121
63
 
122
- def execute(command)
64
+ def execute
123
65
  configure_client
124
- send(command).call(self)
125
- end
126
-
127
- protected
128
-
129
- def sync
130
- Commands::Sync
131
- end
132
-
133
- def validate
134
- Commands::Validate
135
- end
136
-
137
- def manifest
138
- Commands::DownloadManifest
139
- end
140
-
141
- def properties
142
- Commands::GetProperties
66
+ send(command, self)
143
67
  end
144
68
 
145
69
  private
@@ -157,5 +81,3 @@ EOS
157
81
 
158
82
  end
159
83
  end
160
-
161
- Dir[File.expand_path("../commands/*.rb", __FILE__)].each { |m| require m }
@@ -0,0 +1,120 @@
1
+ require 'optparse'
2
+ require 'hashie'
3
+
4
+ module Duracloud
5
+ class CommandOptions < Hashie::Mash
6
+
7
+ def initialize(*args)
8
+ super()
9
+ self.command = args.shift if CLI::COMMANDS.include?(args.first)
10
+ parser.parse!(args)
11
+ end
12
+
13
+ def print_version
14
+ puts "duracloud-client #{Duracloud::VERSION}"
15
+ end
16
+
17
+ def parser
18
+ OptionParser.new do |opts|
19
+ opts.banner = CLI::USAGE
20
+
21
+ opts.on("-h", "--help",
22
+ "Prints help") do
23
+ print_version
24
+ puts opts
25
+ exit
26
+ end
27
+
28
+ opts.on("-H", "--host HOST",
29
+ "DuraCloud host") do |v|
30
+ self.host = v
31
+ end
32
+
33
+ opts.on("-P", "--port PORT",
34
+ "DuraCloud port") do |v|
35
+ self.port = v
36
+ end
37
+
38
+ opts.on("-u", "--user USER",
39
+ "DuraCloud user") do |v|
40
+ self.user = v
41
+ end
42
+
43
+ opts.on("-p", "--password PASSWORD",
44
+ "DuraCloud password") do |v|
45
+ self.password = v
46
+ end
47
+
48
+ opts.on("-l", "--[no-]logging",
49
+ "Enable/disable logging to STDERR") do |v|
50
+ self.logging = v
51
+ end
52
+
53
+ opts.on("-s", "--space-id SPACE_ID",
54
+ "DuraCloud space ID") do |v|
55
+ self.space_id = v
56
+ end
57
+
58
+ opts.on("-i", "--store-id STORE_ID",
59
+ "DuraCloud store ID") do |v|
60
+ self.store_id = v
61
+ end
62
+
63
+ opts.on("-c", "--content-id CONTENT_ID",
64
+ "DuraCloud content ID") do |v|
65
+ self.content_id = v
66
+ end
67
+
68
+ opts.on("-m", "--md5 MD5",
69
+ "MD5 digest of content to store or retrieve") do |v|
70
+ self.md5 = v
71
+ end
72
+
73
+ opts.on("-b", "--bagit",
74
+ "Get manifest in BAGIT format (default is TSV)") do
75
+ self.format = Manifest::BAGIT_FORMAT
76
+ end
77
+
78
+ opts.on("-d", "--content-dir DIR",
79
+ "Local content directory") do |v|
80
+ self.content_dir = v
81
+ end
82
+
83
+ opts.on("-f", "--infile FILE",
84
+ "Input file") do |v|
85
+ self.infile = v
86
+ end
87
+
88
+ opts.on("-v", "--version",
89
+ "Print version and exit") do |v|
90
+ print_version
91
+ exit
92
+ end
93
+
94
+ opts.on("-w", "--work-dir DIR",
95
+ "Working directory") do |v|
96
+ self.work_dir = v
97
+ end
98
+
99
+ opts.on("-F", "--[no-]fast-audit",
100
+ "Use fast audit for sync validation") do |v|
101
+ self.fast = v
102
+ end
103
+
104
+ opts.on("-a", "--prefix PREFIX",
105
+ "Content prefix") do |v|
106
+ self.prefix = v
107
+ end
108
+
109
+ opts.on("-M", "--[no-]missing", "Find missing items") do |v|
110
+ self.missing = v
111
+ end
112
+
113
+ opts.on("--[no-]all-spaces", "Get report for all spaces") do |v|
114
+ self.all_spaces = v
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,40 @@
1
+ module Duracloud
2
+ module Commands
3
+
4
+ def find(cli)
5
+ Find.call(cli)
6
+ end
7
+
8
+ def count(cli)
9
+ Count.call(cli)
10
+ end
11
+
12
+ def get_storage_report(cli)
13
+ GetStorageReport.call(cli)
14
+ end
15
+
16
+ def sync(cli)
17
+ Sync.call(cli)
18
+ end
19
+
20
+ def validate(cli)
21
+ Validate.call(cli)
22
+ end
23
+
24
+ def download_manifest(cli)
25
+ DownloadManifest.call(cli)
26
+ end
27
+
28
+ def list_content_ids(cli)
29
+ ListContentIds.call(cli)
30
+ end
31
+
32
+ def list_items(cli)
33
+ ListItems.call(cli)
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+ require 'duracloud/commands/command'
40
+ Dir[File.expand_path("../commands/*.rb", __FILE__)].each { |m| require m }
@@ -3,8 +3,12 @@ require 'delegate'
3
3
  module Duracloud::Commands
4
4
  class Command < SimpleDelegator
5
5
 
6
- def self.call(command)
7
- new(command).call
6
+ def self.call(cli)
7
+ new(cli).call
8
+ end
9
+
10
+ def cli
11
+ __getobj__
8
12
  end
9
13
 
10
14
  end
@@ -0,0 +1,15 @@
1
+ module Duracloud::Commands
2
+ class Count < Command
3
+
4
+ def call
5
+ space = Duracloud::Space.find(space_id, store_id)
6
+ count = if prefix || space.count == 1000
7
+ space.content_ids(prefix: prefix).to_a.length
8
+ else
9
+ space.count
10
+ end
11
+ puts count
12
+ end
13
+
14
+ end
15
+ end
@@ -1,5 +1,3 @@
1
- require_relative "command"
2
-
3
1
  module Duracloud::Commands
4
2
  class DownloadManifest < Command
5
3
 
@@ -0,0 +1,16 @@
1
+ module Duracloud::Commands
2
+ class Find < Command
3
+
4
+ def call
5
+ delegate_to = if content_id
6
+ FindItem
7
+ elsif infile
8
+ missing ? FindMissingItems : FindItems
9
+ else
10
+ FindSpace
11
+ end
12
+ delegate_to.call(cli)
13
+ end
14
+
15
+ end
16
+ end