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 +4 -4
- data/.rubocop.yml +1 -0
- data/README.md +2 -0
- data/lib/sdr_client.rb +1 -0
- data/lib/sdr_client/deposit.rb +5 -2
- data/lib/sdr_client/deposit/file_metadata_builder.rb +51 -0
- data/lib/sdr_client/deposit/file_metadata_builder_operations/md5.rb +17 -0
- data/lib/sdr_client/deposit/file_metadata_builder_operations/mime_type.rb +17 -0
- data/lib/sdr_client/deposit/file_metadata_builder_operations/sha1.rb +17 -0
- data/lib/sdr_client/deposit/metadata_builder.rb +21 -3
- data/lib/sdr_client/deposit/model_process.rb +84 -0
- data/lib/sdr_client/deposit/process.rb +11 -1
- data/lib/sdr_client/deposit/request.rb +5 -1
- data/lib/sdr_client/deposit/upload_files.rb +6 -6
- data/lib/sdr_client/model_deposit.rb +18 -0
- data/lib/sdr_client/version.rb +1 -1
- data/sdr-client.gemspec +1 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 065c4f605e60c45bb76c98eac741d67f5b7e848a5b59402396b4c7273ba80334
|
4
|
+
data.tar.gz: f826dad9e9e758242672f92baffde17f65c347f05013d7420a5ff69459344935
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '06295472bb1577491a3ea0f40a89cd904c14bb19c2064c226e129487d74828c0335109b2818bd280eed1d80af266d2352a72bc4b4838fa1fea7ff9830f81f1d8'
|
7
|
+
data.tar.gz: 6830c8249d6ae651fdbf1c6a62e582db254f663fe6d4316de84c7a1d6a2ba17fd516a129991ca8634a98ccd5857fe59ba56b12341412d0f7732232e93e78fa2d
|
data/.rubocop.yml
CHANGED
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`
|
data/lib/sdr_client.rb
CHANGED
data/lib/sdr_client/deposit.rb
CHANGED
@@ -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:
|
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:
|
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
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
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
|
-
:
|
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
|
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 [
|
14
|
-
def initialize(files:,
|
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
|
-
@
|
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, :
|
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:
|
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'
|
data/lib/sdr_client/version.rb
CHANGED
data/sdr-client.gemspec
CHANGED
@@ -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.
|
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-
|
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
|