sdr-client 0.3.1 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c634551367640a9eb3647e55fcac169a61b40af1a111582d3e857bc2cc1f020
4
- data.tar.gz: 75f3a024adf97dad2cf85a8e8b117a232c71b2f644655b98752c1320af005e17
3
+ metadata.gz: 85bf3bb61e2edeca3fd59c4bcb72e65c0ca8a6fa2555095059c774d6adbb5cd9
4
+ data.tar.gz: 29ef71e2e7778c28b8db875e7c910ee4f477857422d61d59774ab09b0fdb5852
5
5
  SHA512:
6
- metadata.gz: 04a14d2edbb8334fbcc13b7ae131d7bf1697869c580395c2ea8c2971c18b911d55b7b0128e0cdff25b7a5844333f11eb2af23bc435ab7c6e692e4951092e22ed
7
- data.tar.gz: 6c3369f015d8e3201ba1f58664c4d9b15208064eb5fdd24deca2de26ae7d4575889d22f7aa25eacb2e1232cfd2068d288771c6ba0c04737b7e5fc6c7508d2ba8
6
+ metadata.gz: 61cc5ce0d28aeddbcd20273a7086d9b4dc0482b76f91b19002496b80e4db7d32471f9b8e827ffc800c58172fb3cf7d1f2ccdf920ca11bd88f5ac141002406703
7
+ data.tar.gz: c2149a463c52831fee474f8c43e00982fce4ea9f56da629f8b87f1889bb59630419ed6c8c5296b56b6985324195ff1bb700277cbdfa91e9de89388319689b461
@@ -13,3 +13,9 @@ Layout/LineLength:
13
13
  Metrics/BlockLength:
14
14
  Exclude:
15
15
  - 'spec/**/*'
16
+ ExcludedMethods:
17
+ - 'OptionParser.new'
18
+
19
+ Naming/FileName:
20
+ Exclude:
21
+ - 'lib/sdr-client.rb'
@@ -14,8 +14,3 @@ Metrics/AbcSize:
14
14
  # Configuration parameters: CountComments, ExcludedMethods.
15
15
  Metrics/MethodLength:
16
16
  Max: 13
17
-
18
- # Offense count: 2
19
- # Configuration parameters: CountKeywordArgs.
20
- Metrics/ParameterLists:
21
- Max: 8
data/README.md CHANGED
@@ -8,6 +8,10 @@
8
8
  This is a CLI for interacting with the Stanford Digital Repository API.
9
9
  The code for the SDR API server is at https://github.com/sul-dlss/sdr-api
10
10
 
11
+ ## Install
12
+
13
+ `gem install sdr-client`
14
+
11
15
  ## Usage
12
16
 
13
17
  Log in:
data/exe/sdr CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  $LOAD_PATH.unshift 'lib'
5
5
  require 'optparse'
6
+ require 'sdr_client'
6
7
 
7
8
  options = {}
8
9
  global = OptionParser.new do |opts|
@@ -60,6 +61,20 @@ subcommands = {
60
61
  options[:source_id] = source_id
61
62
  end
62
63
 
64
+ opts.on('--strategy STRATEGY',
65
+ 'The strategy to use for distributing files into filesets. Either "default" or "filename"') do |strategy|
66
+ strategy_class = case strategy
67
+ when 'filename'
68
+ SdrClient::Deposit::MatchingFileGroupingStrategy
69
+ when 'default'
70
+ SdrClient::Deposit::SingleFileGroupingStrategy
71
+ else
72
+ warn "Unknown strategy #{strategy}"
73
+ exit(1)
74
+ end
75
+ options[:grouping_strategy] = strategy_class
76
+ end
77
+
63
78
  opts.on('-h', '--help', 'Display this screen') do
64
79
  puts opts
65
80
  exit
@@ -75,6 +90,5 @@ end
75
90
 
76
91
  subcommands[command].order!
77
92
 
78
- require 'sdr_client'
79
93
  options[:files] = ARGV unless ARGV.empty?
80
94
  SdrClient::CLI.start(command, options)
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sdr_client'
@@ -1,15 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'logger'
4
+
3
5
  module SdrClient
4
6
  # The namespace for the "deposit" command
5
7
  module Deposit
8
+ # rubocop:disable Metrics/ParameterLists
6
9
  def self.run(label: nil,
7
10
  type: 'http://cocina.sul.stanford.edu/models/book.jsonld',
8
11
  apo:,
9
12
  collection:,
10
13
  catkey: nil,
11
14
  source_id:,
12
- url:, files: [])
15
+ url:,
16
+ files: [],
17
+ files_metadata: {},
18
+ grouping_strategy: SingleFileGroupingStrategy,
19
+ logger: Logger.new(STDOUT))
13
20
  token = Credentials.read
14
21
 
15
22
  metadata = Request.new(label: label,
@@ -18,11 +25,15 @@ module SdrClient
18
25
  collection: collection,
19
26
  source_id: source_id,
20
27
  catkey: catkey)
21
- Process.new(metadata: metadata, url: url, token: token, files: files).run
28
+ Process.new(metadata: metadata, url: url, token: token, files: files,
29
+ files_metadata: files_metadata, grouping_strategy: grouping_strategy, logger: logger).run
22
30
  end
31
+ # rubocop:enable Metrics/ParameterLists
23
32
  end
24
33
  end
25
34
  require 'json'
35
+ require 'sdr_client/deposit/single_file_grouping_strategy'
36
+ require 'sdr_client/deposit/matching_file_grouping_strategy'
26
37
  require 'sdr_client/deposit/files/direct_upload_request'
27
38
  require 'sdr_client/deposit/files/direct_upload_response'
28
39
  require 'sdr_client/deposit/file'
@@ -4,15 +4,23 @@ module SdrClient
4
4
  module Deposit
5
5
  # This represents the File metadata that we send to the server for doing a deposit
6
6
  class File
7
- def initialize(external_identifier:, label:, filename:, access: 'dark', preserve: false, shelve: false)
7
+ # rubocop:disable Metrics/ParameterLists
8
+ def initialize(external_identifier:, label:, filename:,
9
+ access: 'dark', preserve: false, shelve: false,
10
+ mime_type: nil, md5: nil, sha1: nil)
8
11
  @external_identifier = external_identifier
9
12
  @label = label
10
13
  @filename = filename
11
14
  @access = access
12
15
  @preserve = preserve
13
16
  @shelve = shelve
17
+ @mime_type = mime_type
18
+ @md5 = md5
19
+ @sha1 = sha1
14
20
  end
21
+ # rubocop:enable Metrics/ParameterLists
15
22
 
23
+ # rubocop:disable Metrics/MethodLength
16
24
  def as_json
17
25
  {
18
26
  "type": 'http://cocina.sul.stanford.edu/models/file.jsonld',
@@ -26,6 +34,26 @@ module SdrClient
26
34
  sdrPreserve: @preserve,
27
35
  shelve: @shelve
28
36
  }
37
+ }.tap do |json|
38
+ json['hasMessageDigests'] = message_digests unless message_digests.empty?
39
+ json['hasMimeType'] = @mime_type if @mime_type
40
+ end
41
+ end
42
+ # rubocop:enable Metrics/MethodLength
43
+
44
+ private
45
+
46
+ def message_digests
47
+ @message_digests ||= [].tap do |message_digests|
48
+ message_digests << create_message_digest('md5', @md5) unless @md5.nil?
49
+ message_digests << create_message_digest('sha1', @sha1) unless @sha1.nil?
50
+ end
51
+ end
52
+
53
+ def create_message_digest(algorithm, digest)
54
+ {
55
+ "type": algorithm,
56
+ digest: digest
29
57
  }
30
58
  end
31
59
  end
@@ -4,11 +4,11 @@ module SdrClient
4
4
  module Deposit
5
5
  # This represents the FileSet metadata that we send to the server for doing a deposit
6
6
  class FileSet
7
- def initialize(uploads: [], files: [], label:)
7
+ def initialize(uploads: [], uploads_metadata: {}, files: [], label:)
8
8
  @label = label
9
9
  @files = if !uploads.empty?
10
10
  uploads.map do |upload|
11
- File.new(external_identifier: upload.signed_id, label: upload.filename, filename: upload.filename)
11
+ File.new(file_args(upload, uploads_metadata.fetch(upload.filename, {})))
12
12
  end
13
13
  else
14
14
  files
@@ -20,7 +20,7 @@ module SdrClient
20
20
  "type": 'http://cocina.sul.stanford.edu/models/fileset.jsonld',
21
21
  "label": label,
22
22
  structural: {
23
- hasMember: files.map(&:as_json)
23
+ contains: files.map(&:as_json)
24
24
  }
25
25
  }
26
26
  end
@@ -28,6 +28,15 @@ module SdrClient
28
28
  private
29
29
 
30
30
  attr_reader :files, :label
31
+
32
+ def file_args(upload, upload_metadata)
33
+ args = {
34
+ external_identifier: upload.signed_id,
35
+ label: upload.filename,
36
+ filename: upload.filename
37
+ }
38
+ args.merge(upload_metadata)
39
+ end
31
40
  end
32
41
  end
33
42
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ module Deposit
5
+ # This strategy is for building one file set per set of similarly prefixed uploaded files
6
+ class MatchingFileGroupingStrategy
7
+ # @param [Array<SdrClient::Deposit::Files::DirectUploadResponse>] uploads the uploaded files to attach.
8
+ # @return [Array<Array<SdrClient::Deposit::Files::DirectUploadResponse>>] uploads the grouped uploaded files.
9
+ def self.run(uploads: [])
10
+ # Call `#values` on the result of the grouping operation because 1)
11
+ # `Process#build_filesets` expects an array of arrays, not an array of
12
+ # hashes, and 2) the keys aren't used anywhere
13
+ uploads.group_by { |ul| ::File.basename(ul.filename, '.*') }.values
14
+ end
15
+ end
16
+ end
17
+ end
@@ -9,30 +9,39 @@ module SdrClient
9
9
  BLOB_PATH = '/v1/direct_uploads'
10
10
  DRO_PATH = '/v1/resources'
11
11
  # @param [Request] metadata information about the object
12
+ # @param [Class] grouping_strategy class whose run method groups an array of uploads
12
13
  # @param [String] url the server to send to
13
14
  # @param [String] token the bearer auth token for the server
14
15
  # @param [Array<String>] files a list of file names to upload
16
+ # @param [Hash<String, Hash<String, String>>] files_metadata file name, hash of additional file metadata
17
+ # Additional metadata includes access, preserve, shelve, md5, sha1
15
18
  # @param [Logger] logger the logger to use
16
- def initialize(metadata:, url:, token:, files: [], logger: Logger.new(STDOUT))
19
+ # rubocop:disable Metrics/ParameterLists
20
+ def initialize(metadata:, grouping_strategy: SingleFileGroupingStrategy, url:,
21
+ token:, files: [], files_metadata: {}, logger: Logger.new(STDOUT))
17
22
  @files = files
18
23
  @url = url
19
24
  @token = token
20
25
  @metadata = metadata
21
26
  @logger = logger
27
+ @grouping_strategy = grouping_strategy
28
+ @files_metadata = files_metadata
22
29
  end
30
+ # rubocop:enable Metrics/ParameterLists
23
31
 
24
32
  def run
25
33
  check_files_exist
26
34
  file_metadata = collect_file_metadata
27
35
  upload_responses = upload_file_metadata(file_metadata)
28
36
  upload_files(upload_responses)
29
- request = metadata.with_uploads(upload_responses.values)
37
+ file_sets = build_filesets(uploads: upload_responses.values, files_metadata: files_metadata)
38
+ request = metadata.with_file_sets(file_sets)
30
39
  upload_metadata(request.as_json)
31
40
  end
32
41
 
33
42
  private
34
43
 
35
- attr_reader :metadata, :files, :url, :token, :logger
44
+ attr_reader :metadata, :files, :url, :token, :logger, :grouping_strategy, :files_metadata
36
45
 
37
46
  def check_files_exist
38
47
  logger.info('checking to see if files exist')
@@ -111,6 +120,18 @@ module SdrClient
111
120
  conn.adapter :net_http
112
121
  end
113
122
  end
123
+
124
+ # @param [Array<SdrClient::Deposit::Files::DirectUploadResponse>] uploads the uploaded files to attach.
125
+ # @param [Hash<String,Hash<String, String>>] files_metadata filename, hash of additional file metadata.
126
+ # @return [Array<SdrClient::Deposit::FileSet>] the uploads transformed to filesets
127
+ def build_filesets(uploads:, files_metadata:)
128
+ grouped_uploads = grouping_strategy.run(uploads: uploads)
129
+ grouped_uploads.map.with_index(1) do |upload_group, i|
130
+ metadata_group = {}
131
+ upload_group.each { |upload| metadata_group[upload.filename] = files_metadata.fetch(upload.filename, {}) }
132
+ FileSet.new(uploads: upload_group, uploads_metadata: metadata_group, label: "Object #{i}")
133
+ end
134
+ end
114
135
  end
115
136
  end
116
137
  end
@@ -7,6 +7,7 @@ module SdrClient
7
7
  # @param [String] label the required object label
8
8
  # @param [String] type (http://cocina.sul.stanford.edu/models/object.jsonld) the required object type.
9
9
  # @param [Array<FileSet>] file_sets the file sets to attach.
10
+ # rubocop:disable Metrics/ParameterLists
10
11
  def initialize(label: nil,
11
12
  apo:,
12
13
  collection:,
@@ -22,6 +23,7 @@ module SdrClient
22
23
  @apo = apo
23
24
  @file_sets = file_sets
24
25
  end
26
+ # rubocop:enable Metrics/ParameterLists
25
27
 
26
28
  def as_json
27
29
  {
@@ -35,13 +37,8 @@ module SdrClient
35
37
  end
36
38
  end
37
39
 
38
- # @param [Array<SdrClient::Deposit::Files::DirectUploadResponse>] uploads the uploaded files to attach.
39
- # @return [Request] a clone of this request with the uploads added
40
- def with_uploads(uploads)
41
- file_sets = uploads.each_with_index.map do |upload, i|
42
- FileSet.new(uploads: [upload], label: "Object #{i + 1}")
43
- end
44
-
40
+ # @return [Request] a clone of this request with the file_sets added
41
+ def with_file_sets(file_sets)
45
42
  Request.new(label: label,
46
43
  apo: apo,
47
44
  collection: collection,
@@ -51,11 +48,6 @@ module SdrClient
51
48
  file_sets: file_sets)
52
49
  end
53
50
 
54
- # In this case there is a 1-1 mapping between Files and FileSets,
55
- # but this doesn't always have to be the case. We could change this in the
56
- # future so that we have one FileSet that has an Image and its OCR file.
57
- def add_uploads_each_as_resource(uploads); end
58
-
59
51
  private
60
52
 
61
53
  attr_reader :label, :file_sets, :source_id, :catkey, :apo, :collection, :type
@@ -75,7 +67,7 @@ module SdrClient
75
67
  def structural
76
68
  {
77
69
  isMemberOf: collection,
78
- hasMember: file_sets.map(&:as_json)
70
+ contains: file_sets.map(&:as_json)
79
71
  }
80
72
  end
81
73
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ module Deposit
5
+ # This strategy is for building one file set per uploaded file
6
+ class SingleFileGroupingStrategy
7
+ # @param [Array<SdrClient::Deposit::Files::DirectUploadResponse>] uploads the uploaded files to attach.
8
+ # @return [Array<Array<SdrClient::Deposit::Files::DirectUploadResponse>>] uploads the grouped uploaded files.
9
+ def self.run(uploads: [])
10
+ uploads.map { |upload| [upload] }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SdrClient
4
- VERSION = '0.3.1'
4
+ VERSION = '0.7.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sdr-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Coyne
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-23 00:00:00.000000000 Z
11
+ date: 2020-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-monads
@@ -158,6 +158,7 @@ files:
158
158
  - bin/console
159
159
  - bin/setup
160
160
  - exe/sdr
161
+ - lib/sdr-client.rb
161
162
  - lib/sdr_client.rb
162
163
  - lib/sdr_client/cli.rb
163
164
  - lib/sdr_client/credentials.rb
@@ -166,8 +167,10 @@ files:
166
167
  - lib/sdr_client/deposit/file_set.rb
167
168
  - lib/sdr_client/deposit/files/direct_upload_request.rb
168
169
  - lib/sdr_client/deposit/files/direct_upload_response.rb
170
+ - lib/sdr_client/deposit/matching_file_grouping_strategy.rb
169
171
  - lib/sdr_client/deposit/process.rb
170
172
  - lib/sdr_client/deposit/request.rb
173
+ - lib/sdr_client/deposit/single_file_grouping_strategy.rb
171
174
  - lib/sdr_client/login.rb
172
175
  - lib/sdr_client/login_prompt.rb
173
176
  - lib/sdr_client/version.rb
@@ -193,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
196
  - !ruby/object:Gem::Version
194
197
  version: '0'
195
198
  requirements: []
196
- rubygems_version: 3.0.3
199
+ rubygems_version: 3.1.2
197
200
  signing_key:
198
201
  specification_version: 4
199
202
  summary: The CLI for https://github.com/sul-dlss/sdr-api