sdr-client 0.15.0 → 0.17.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: 76c749fe07c1e54f2326bb0ff00b448d0dff1211c7bada06865c1259fa1ccdb7
4
- data.tar.gz: 4ae3c617f450a7d6d388522830232a42567dd376e6a6192d942a242f1351e39b
3
+ metadata.gz: 065c4f605e60c45bb76c98eac741d67f5b7e848a5b59402396b4c7273ba80334
4
+ data.tar.gz: f826dad9e9e758242672f92baffde17f65c347f05013d7420a5ff69459344935
5
5
  SHA512:
6
- metadata.gz: 57a774eb99df08439e040198a6b45ce6b37ecad275fb3db8030ca90793ae407183bb514ab907e9d8f54aee4febcaa0a15d62b8cfbb99aa29efd4db071c63265c
7
- data.tar.gz: d7dd88626f1ea6c20f3be68cb1b31787aeaf353450952ca7b2e5862e2acaf0f308ec66ce4a7e385c237f5d08ba66d8647fe77fa95dad9e08602382b87f4f0746
6
+ metadata.gz: '06295472bb1577491a3ea0f40a89cd904c14bb19c2064c226e129487d74828c0335109b2818bd280eed1d80af266d2352a72bc4b4838fa1fea7ff9830f81f1d8'
7
+ data.tar.gz: 6830c8249d6ae651fdbf1c6a62e582db254f663fe6d4316de84c7a1d6a2ba17fd516a129991ca8634a98ccd5857fe59ba56b12341412d0f7732232e93e78fa2d
@@ -13,6 +13,7 @@ Layout/LineLength:
13
13
  Metrics/BlockLength:
14
14
  Exclude:
15
15
  - 'spec/**/*'
16
+ - 'sdr-client.gemspec'
16
17
  ExcludedMethods:
17
18
  - 'OptionParser.new'
18
19
 
data/README.md CHANGED
@@ -8,6 +8,8 @@
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
+ This provides a way for consumers to easily and correctly deposit files to the SDR without requiring access to the `/dor` NFS mount or to use Hydrus. A primary design goal was for this to have as few dependencies as possible so that it can be easily distributed by `gem install sdr-client` and then it can be used as a CLI.
12
+
11
13
  ## Install
12
14
 
13
15
  `gem install sdr-client`
@@ -5,6 +5,7 @@ require 'faraday'
5
5
 
6
6
  require 'sdr_client/version'
7
7
  require 'sdr_client/deposit'
8
+ require 'sdr_client/model_deposit'
8
9
  require 'sdr_client/credentials'
9
10
  require 'sdr_client/login'
10
11
  require 'sdr_client/login_prompt'
@@ -5,10 +5,11 @@ require 'logger'
5
5
  module SdrClient
6
6
  # The namespace for the "deposit" command
7
7
  module Deposit
8
+ BOOK_TYPE = 'http://cocina.sul.stanford.edu/models/book.jsonld'
8
9
  # rubocop:disable Metrics/ParameterLists
9
10
  # rubocop:disable Metrics/MethodLength
10
11
  def self.run(label: nil,
11
- type: 'http://cocina.sul.stanford.edu/models/book.jsonld',
12
+ type: BOOK_TYPE,
12
13
  viewing_direction: nil,
13
14
  access: 'dark',
14
15
  use_statement: nil,
@@ -26,6 +27,7 @@ module SdrClient
26
27
  logger: Logger.new(STDOUT))
27
28
  token = Credentials.read
28
29
 
30
+ augmented_metadata = FileMetadataBuilder.build(files: files, files_metadata: files_metadata)
29
31
  metadata = Request.new(label: label,
30
32
  type: type,
31
33
  access: access,
@@ -38,7 +40,7 @@ module SdrClient
38
40
  embargo_release_date: embargo_release_date,
39
41
  embargo_access: embargo_access,
40
42
  viewing_direction: viewing_direction,
41
- files_metadata: files_metadata)
43
+ files_metadata: augmented_metadata)
42
44
  Process.new(metadata: metadata, url: url, token: token, files: files,
43
45
  grouping_strategy: grouping_strategy, logger: logger).run
44
46
  end
@@ -52,6 +54,7 @@ require 'sdr_client/deposit/matching_file_grouping_strategy'
52
54
  require 'sdr_client/deposit/files/direct_upload_request'
53
55
  require 'sdr_client/deposit/files/direct_upload_response'
54
56
  require 'sdr_client/deposit/file'
57
+ require 'sdr_client/deposit/file_metadata_builder'
55
58
  require 'sdr_client/deposit/file_set'
56
59
  require 'sdr_client/deposit/request'
57
60
  require 'sdr_client/deposit/upload_files'
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sdr_client/deposit/file_metadata_builder_operations/mime_type'
4
+ require 'sdr_client/deposit/file_metadata_builder_operations/md5'
5
+ require 'sdr_client/deposit/file_metadata_builder_operations/sha1'
6
+
7
+ module SdrClient
8
+ module Deposit
9
+ # Build basic metadata for files, iterating over a series of operations
10
+ # The available options are here: https://github.com/sul-dlss/sdr-client/blob/v0.8.1/lib/sdr_client/deposit/file.rb#L8-L10
11
+ class FileMetadataBuilder
12
+ OPERATIONS = [
13
+ FileMetadataBuilderOperations::MimeType,
14
+ FileMetadataBuilderOperations::MD5,
15
+ FileMetadataBuilderOperations::SHA1
16
+ ].freeze
17
+ private_constant :OPERATIONS
18
+
19
+ # @param (see #initialize)
20
+ # @return (see #build)
21
+ def self.build(files:, files_metadata:)
22
+ new(files: files, files_metadata: files_metadata.dup).build
23
+ end
24
+
25
+ # @param [Array<String>] files the list of files for which to generate metadata
26
+ def initialize(files:, files_metadata:)
27
+ @files = files
28
+ @files_metadata = files_metadata
29
+ end
30
+
31
+ # @return [Hash<String, Hash<String, String>>]
32
+ def build
33
+ files.each do |file_path|
34
+ file_key = ::File.basename(file_path)
35
+ OPERATIONS.each do |operation|
36
+ result = operation.for(file_path: file_path)
37
+ next if result.nil?
38
+
39
+ files_metadata[file_key] ||= {}
40
+ files_metadata[file_key][operation::NAME] = result
41
+ end
42
+ end
43
+ files_metadata
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :files, :files_metadata
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module SdrClient
6
+ module Deposit
7
+ module FileMetadataBuilderOperations
8
+ # MD5 for this file.
9
+ class MD5
10
+ NAME = 'md5'
11
+ def self.for(file_path:, **)
12
+ Digest::MD5.file(file_path).hexdigest
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module SdrClient
6
+ module Deposit
7
+ module FileMetadataBuilderOperations
8
+ # Mime-type for this file.
9
+ class MimeType
10
+ NAME = 'mime_type'
11
+ def self.for(file_path:, **)
12
+ `file --mime-type -b #{file_path}`.chomp
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module SdrClient
6
+ module Deposit
7
+ module FileMetadataBuilderOperations
8
+ # SHA1 for this file.
9
+ class SHA1
10
+ NAME = 'sha1'
11
+ def self.for(file_path:, **)
12
+ Digest::SHA1.file(file_path).hexdigest
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -16,6 +16,8 @@ module SdrClient
16
16
  @grouping_strategy = grouping_strategy
17
17
  end
18
18
 
19
+ # @param [UploadFiles] upload_responses the uploaded file information
20
+ # @return [Request] the metadata with fileset information added in.
19
21
  def with_uploads(upload_responses)
20
22
  file_sets = build_filesets(uploads: upload_responses)
21
23
  metadata.with_file_sets(file_sets)
@@ -30,9 +32,25 @@ module SdrClient
30
32
  def build_filesets(uploads:)
31
33
  grouped_uploads = grouping_strategy.run(uploads: uploads)
32
34
  grouped_uploads.map.with_index(1) do |upload_group, i|
33
- metadata_group = {}
34
- upload_group.each { |upload| metadata_group[upload.filename] = metadata.for(upload.filename) }
35
- FileSet.new(uploads: upload_group, uploads_metadata: metadata_group, label: "Object #{i}")
35
+ FileSet.new(uploads: upload_group,
36
+ uploads_metadata: metadata_group(upload_group),
37
+ label: label(i))
38
+ end
39
+ end
40
+
41
+ def label(index)
42
+ case metadata.type
43
+ when BOOK_TYPE
44
+ "Page #{index}"
45
+ else
46
+ "Object #{index}"
47
+ end
48
+ end
49
+
50
+ # Get the metadata for the files belonging to a fileset
51
+ def metadata_group(upload_group)
52
+ upload_group.each_with_object({}) do |upload, obj|
53
+ obj[upload.filename] = metadata.for(upload.filename)
36
54
  end
37
55
  end
38
56
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module SdrClient
6
+ module Deposit
7
+ # The process for doing a deposit from a Cocina Model
8
+ class ModelProcess
9
+ DRO_PATH = '/v1/resources'
10
+ # @param [Cocina::Model::RequestDRO] request_dro for depositing
11
+ # @param [String] url the server to send to
12
+ # @param [String] token the bearer auth token for the server
13
+ # @param [Array<String>] files a list of file names to upload
14
+ # @param [Logger] logger the logger to use
15
+ def initialize(request_dro:, url:,
16
+ token:, files: [], logger: Logger.new(STDOUT))
17
+ @files = files
18
+ @url = url
19
+ @token = token
20
+ @request_dro = request_dro
21
+ @logger = logger
22
+ end
23
+
24
+ def run
25
+ check_files_exist
26
+ UploadFiles.new(files: files,
27
+ logger: logger,
28
+ connection: connection,
29
+ mime_types: mime_types).run
30
+ upload_request_dro
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :request_dro, :files, :url, :token, :logger
36
+
37
+ def check_files_exist
38
+ logger.info('checking to see if files exist')
39
+ files.each do |file_name|
40
+ raise Errno::ENOENT, file_name unless ::File.exist?(file_name)
41
+ end
42
+ end
43
+
44
+ # @return [Hash<Symbol,String>] the result of the metadata call
45
+ # rubocop:disable Metrics/AbcSize
46
+ def upload_request_dro
47
+ request_json = request_dro.to_json
48
+ logger.info("Starting upload metadata: #{request_json}")
49
+ response = connection.post(DRO_PATH, request_json, 'Content-Type' => 'application/json')
50
+ unexpected_response(response) unless response.status == 201
51
+
52
+ logger.info("Response from server: #{response.body}")
53
+
54
+ { druid: JSON.parse(response.body)['druid'], background_job: response.headers['Location'] }
55
+ end
56
+ # rubocop:enable Metrics/AbcSize
57
+
58
+ def unexpected_response(response)
59
+ raise "There was an error with your request: #{response.body}" if response.status == 400
60
+ raise 'There was an error with your credentials. Perhaps they have expired?' if response.status == 401
61
+
62
+ raise "unexpected response: #{response.status} #{response.body}"
63
+ end
64
+
65
+ def connection
66
+ @connection ||= Faraday.new(url: url) do |conn|
67
+ conn.authorization :Bearer, token
68
+ conn.adapter :net_http
69
+ end
70
+ end
71
+
72
+ def mime_types
73
+ @mime_types ||=
74
+ Hash[
75
+ request_dro.structural.contains.map do |file_set|
76
+ file_set.structural.contains.map do |file|
77
+ [file.filename, file.hasMimeType || 'application/octet-stream']
78
+ end
79
+ end.flatten(1)
80
+ ]
81
+ end
82
+ end
83
+ end
84
+ end
@@ -30,7 +30,7 @@ module SdrClient
30
30
  upload_responses = UploadFiles.new(files: files,
31
31
  logger: logger,
32
32
  connection: connection,
33
- metadata: metadata).run
33
+ mime_types: mime_types).run
34
34
  metadata_builder = MetadataBuilder.new(metadata: metadata,
35
35
  grouping_strategy: grouping_strategy,
36
36
  logger: logger)
@@ -74,6 +74,16 @@ module SdrClient
74
74
  conn.adapter :net_http
75
75
  end
76
76
  end
77
+
78
+ def mime_types
79
+ @mime_types ||=
80
+ Hash[
81
+ files.map do |filepath|
82
+ filename = ::File.basename(filepath)
83
+ [filename, metadata.for(filename)['mime_type']]
84
+ end
85
+ ]
86
+ end
77
87
  end
78
88
  end
79
89
  end
@@ -61,11 +61,13 @@ module SdrClient
61
61
  access: access,
62
62
  apo: apo,
63
63
  collection: collection,
64
+ copyright: copyright,
64
65
  source_id: source_id,
65
66
  catkey: catkey,
66
67
  embargo_release_date: embargo_release_date,
67
68
  embargo_access: embargo_access,
68
69
  type: type,
70
+ use_statement: use_statement,
69
71
  viewing_direction: viewing_direction,
70
72
  file_sets: file_sets,
71
73
  files_metadata: files_metadata)
@@ -77,10 +79,12 @@ module SdrClient
77
79
  files_metadata.fetch(filename, {})
78
80
  end
79
81
 
82
+ attr_reader :type
83
+
80
84
  private
81
85
 
82
86
  attr_reader :access, :label, :file_sets, :source_id, :catkey, :apo, :collection,
83
- :type, :files_metadata, :embargo_release_date, :embargo_access,
87
+ :files_metadata, :embargo_release_date, :embargo_access,
84
88
  :viewing_direction, :use_statement, :copyright
85
89
 
86
90
  def administrative
@@ -7,13 +7,13 @@ module SdrClient
7
7
  # The file uploading part of a deposit
8
8
  class UploadFiles
9
9
  BLOB_PATH = '/v1/direct_uploads'
10
- # @param [Array<String>] files a list of file names to upload
10
+ # @param [Array<String>] files a list of filepaths to upload
11
11
  # @param [Logger] logger the logger to use
12
12
  # @param [Faraday::Connection] connection
13
- # @param [Request] metadata information about the object
14
- def initialize(files:, metadata:, logger:, connection:)
13
+ # @param [Hash<String,String] mime_types a map of filenames to mime types
14
+ def initialize(files:, mime_types:, logger:, connection:)
15
15
  @files = files
16
- @metadata = metadata
16
+ @mime_types = mime_types
17
17
  @logger = logger
18
18
  @connection = connection
19
19
  end
@@ -28,14 +28,14 @@ module SdrClient
28
28
 
29
29
  private
30
30
 
31
- attr_reader :files, :metadata, :logger, :connection
31
+ attr_reader :files, :mime_types, :logger, :connection
32
32
 
33
33
  def collect_file_metadata
34
34
  files.each_with_object({}) do |path, obj|
35
35
  file_name = ::File.basename(path)
36
36
  obj[path] = Files::DirectUploadRequest.from_file(path,
37
37
  file_name: file_name,
38
- content_type: metadata.for(file_name)[:mime_type])
38
+ content_type: mime_types[file_name])
39
39
  end
40
40
  end
41
41
 
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module SdrClient
6
+ # The namespace for the "deposit" command
7
+ module Deposit
8
+ def self.model_run(request_dro:,
9
+ files: [],
10
+ url:,
11
+ logger: Logger.new(STDOUT))
12
+ token = Credentials.read
13
+
14
+ ModelProcess.new(request_dro: request_dro, url: url, token: token, files: files, logger: logger).run
15
+ end
16
+ end
17
+ end
18
+ require 'sdr_client/deposit/model_process'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SdrClient
4
- VERSION = '0.15.0'
4
+ VERSION = '0.17.0'
5
5
  end
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency 'faraday', '>= 0.16'
32
32
 
33
33
  spec.add_development_dependency 'bundler', '~> 2.0'
34
+ spec.add_development_dependency 'cocina-models'
34
35
  spec.add_development_dependency 'rake', '~> 13.0'
35
36
  spec.add_development_dependency 'rspec', '~> 3.0'
36
37
  spec.add_development_dependency 'rubocop', '~> 0.79.0'
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.15.0
4
+ version: 0.17.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-03-02 00:00:00.000000000 Z
11
+ date: 2020-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-monads
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cocina-models
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -164,17 +178,23 @@ files:
164
178
  - lib/sdr_client/credentials.rb
165
179
  - lib/sdr_client/deposit.rb
166
180
  - lib/sdr_client/deposit/file.rb
181
+ - lib/sdr_client/deposit/file_metadata_builder.rb
182
+ - lib/sdr_client/deposit/file_metadata_builder_operations/md5.rb
183
+ - lib/sdr_client/deposit/file_metadata_builder_operations/mime_type.rb
184
+ - lib/sdr_client/deposit/file_metadata_builder_operations/sha1.rb
167
185
  - lib/sdr_client/deposit/file_set.rb
168
186
  - lib/sdr_client/deposit/files/direct_upload_request.rb
169
187
  - lib/sdr_client/deposit/files/direct_upload_response.rb
170
188
  - lib/sdr_client/deposit/matching_file_grouping_strategy.rb
171
189
  - lib/sdr_client/deposit/metadata_builder.rb
190
+ - lib/sdr_client/deposit/model_process.rb
172
191
  - lib/sdr_client/deposit/process.rb
173
192
  - lib/sdr_client/deposit/request.rb
174
193
  - lib/sdr_client/deposit/single_file_grouping_strategy.rb
175
194
  - lib/sdr_client/deposit/upload_files.rb
176
195
  - lib/sdr_client/login.rb
177
196
  - lib/sdr_client/login_prompt.rb
197
+ - lib/sdr_client/model_deposit.rb
178
198
  - lib/sdr_client/version.rb
179
199
  - sdr-client.gemspec
180
200
  homepage: https://github.com/sul-dlss/sdr-client