sdr-client 0.3.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80a6d11a266d546eb1e0763b99b13b18d9f64c558ef21db50f3f509623a4f4bf
4
- data.tar.gz: 5ec2344617583af3322f0426e39328aee355ee4c12d7338d8734f529110e8da6
3
+ metadata.gz: bb3f20e21233ef1ef0f4d72f4d7dcd0e4bb52968b955152e62259e023b730b7b
4
+ data.tar.gz: ecbb08752fcd3c71b4868404bc48871eaba138c852304678a466cd85de3fe4bd
5
5
  SHA512:
6
- metadata.gz: 3a145ef20a1c42abaed33ab79746778844e922b530a6c48d1b7f6d6f50a0e5a2c3f23e15a804fc5b75b3baeaac6baa4e67b35391965b5bb5da34892b345c9805
7
- data.tar.gz: 2600c209c4f35f2ab7a8d7209189c690ec8f06de819666fd7bdd38f63290b997aa87355d54c7a5b5b2e4633ecfd02f75e908815923c2f44116373a999789bf68
6
+ metadata.gz: '08307c141dd01737019f40e1a999b8fd9aa41abca57379f655a9ac5773eba55f974c4d3c34c804e44cd7c8a8792c292e84f5d8c7bf62dd2021b32dd87832420b'
7
+ data.tar.gz: 928ba2d1377cf11bc1e1cfaff2891748ac916d3a3d9e83fca0ac07e0efdbd450ceb895a066bcc3c3a7a4355f186717efb4f5c4d6540867336a21095064f02cb2
@@ -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'
@@ -3,13 +3,17 @@
3
3
  module SdrClient
4
4
  # The namespace for the "deposit" command
5
5
  module Deposit
6
+ # rubocop:disable Metrics/ParameterLists
6
7
  def self.run(label: nil,
7
8
  type: 'http://cocina.sul.stanford.edu/models/book.jsonld',
8
9
  apo:,
9
10
  collection:,
10
11
  catkey: nil,
11
12
  source_id:,
12
- url:, files: [])
13
+ url:,
14
+ files: [],
15
+ files_metadata: {},
16
+ grouping_strategy: SingleFileGroupingStrategy)
13
17
  token = Credentials.read
14
18
 
15
19
  metadata = Request.new(label: label,
@@ -18,11 +22,15 @@ module SdrClient
18
22
  collection: collection,
19
23
  source_id: source_id,
20
24
  catkey: catkey)
21
- Process.new(metadata: metadata, url: url, token: token, files: files).run
25
+ Process.new(metadata: metadata, url: url, token: token,
26
+ files: files, files_metadata: files_metadata, grouping_strategy: grouping_strategy).run
22
27
  end
28
+ # rubocop:enable Metrics/ParameterLists
23
29
  end
24
30
  end
25
31
  require 'json'
32
+ require 'sdr_client/deposit/single_file_grouping_strategy'
33
+ require 'sdr_client/deposit/matching_file_grouping_strategy'
26
34
  require 'sdr_client/deposit/files/direct_upload_request'
27
35
  require 'sdr_client/deposit/files/direct_upload_response'
28
36
  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,10 +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: [])
7
+ def initialize(uploads: [], uploads_metadata: {}, files: [], label:)
8
+ @label = label
8
9
  @files = if !uploads.empty?
9
10
  uploads.map do |upload|
10
- File.new(external_identifier: upload.signed_id, label: upload.filename, filename: upload.filename)
11
+ File.new(file_args(upload, uploads_metadata.fetch(upload.filename, {})))
11
12
  end
12
13
  else
13
14
  files
@@ -17,15 +18,25 @@ module SdrClient
17
18
  def as_json
18
19
  {
19
20
  "type": 'http://cocina.sul.stanford.edu/models/fileset.jsonld',
21
+ "label": label,
20
22
  structural: {
21
- hasMember: files.map(&:as_json)
23
+ contains: files.map(&:as_json)
22
24
  }
23
25
  }
24
26
  end
25
27
 
26
28
  private
27
29
 
28
- attr_reader :files
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
29
40
  end
30
41
  end
31
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,11 +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.map { |upload| FileSet.new(uploads: [upload]) }
42
-
40
+ # @return [Request] a clone of this request with the file_sets added
41
+ def with_file_sets(file_sets)
43
42
  Request.new(label: label,
44
43
  apo: apo,
45
44
  collection: collection,
@@ -49,11 +48,6 @@ module SdrClient
49
48
  file_sets: file_sets)
50
49
  end
51
50
 
52
- # In this case there is a 1-1 mapping between Files and FileSets,
53
- # but this doesn't always have to be the case. We could change this in the
54
- # future so that we have one FileSet that has an Image and its OCR file.
55
- def add_uploads_each_as_resource(uploads); end
56
-
57
51
  private
58
52
 
59
53
  attr_reader :label, :file_sets, :source_id, :catkey, :apo, :collection, :type
@@ -73,7 +67,7 @@ module SdrClient
73
67
  def structural
74
68
  {
75
69
  isMemberOf: collection,
76
- hasMember: file_sets.map(&:as_json)
70
+ contains: file_sets.map(&:as_json)
77
71
  }
78
72
  end
79
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.0'
4
+ VERSION = '0.7.0'
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.0
4
+ version: 0.7.0
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