sdr-client 0.3.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 80a6d11a266d546eb1e0763b99b13b18d9f64c558ef21db50f3f509623a4f4bf
4
+ data.tar.gz: 5ec2344617583af3322f0426e39328aee355ee4c12d7338d8734f529110e8da6
5
+ SHA512:
6
+ metadata.gz: 3a145ef20a1c42abaed33ab79746778844e922b530a6c48d1b7f6d6f50a0e5a2c3f23e15a804fc5b75b3baeaac6baa4e67b35391965b5bb5da34892b345c9805
7
+ data.tar.gz: 2600c209c4f35f2ab7a8d7209189c690ec8f06de819666fd7bdd38f63290b997aa87355d54c7a5b5b2e4633ecfd02f75e908815923c2f44116373a999789bf68
@@ -0,0 +1,5 @@
1
+ ## Why was this change made?
2
+
3
+
4
+
5
+ ## Was the documentation (README, wiki) updated?
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.DS_Store
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+
14
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,15 @@
1
+
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.6
6
+ Exclude:
7
+ - 'bin/console'
8
+ - 'vendor/**/*'
9
+
10
+ Layout/LineLength:
11
+ Max: 120
12
+
13
+ Metrics/BlockLength:
14
+ Exclude:
15
+ - 'spec/**/*'
@@ -0,0 +1,21 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2020-01-10 17:16:01 -0600 using RuboCop version 0.79.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Metrics/AbcSize:
11
+ Max: 16
12
+
13
+ # Offense count: 1
14
+ # Configuration parameters: CountComments, ExcludedMethods.
15
+ Metrics/MethodLength:
16
+ Max: 13
17
+
18
+ # Offense count: 2
19
+ # Configuration parameters: CountKeywordArgs.
20
+ Metrics/ParameterLists:
21
+ Max: 8
@@ -0,0 +1,20 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.4
7
+ before_install: gem install bundler -v 2.1.2
8
+
9
+ before_script:
10
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
11
+ - chmod +x ./cc-test-reporter
12
+ - ./cc-test-reporter before-build
13
+ after_script:
14
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
15
+
16
+ env:
17
+ global:
18
+ - CC_TEST_REPORTER_ID=859fcfe88b00c026d15dce30e838e2299face8088b49fe62bc3a02d1507ce3d5
19
+ notifications:
20
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in sdr-client.gemspec
6
+ gemspec
7
+
8
+ gem 'byebug'
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (c) 2020 by The Board of Trustees of the Leland Stanford
2
+ Junior University. All rights reserved.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License"); you
5
+ may not use this file except in compliance with the License. You
6
+ may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
+ implied. See the License for the specific language governing
14
+ permissions and limitations under the License.
@@ -0,0 +1,25 @@
1
+ [![Build Status](https://travis-ci.org/sul-dlss/sdr-client.svg?branch=master)](https://travis-ci.org/sul-dlss/sdr-client)
2
+ [![Maintainability](https://api.codeclimate.com/v1/badges/1210855d46d4f424bf30/maintainability)](https://codeclimate.com/github/sul-dlss/sdr-client/maintainability)
3
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/1210855d46d4f424bf30/test_coverage)](https://codeclimate.com/github/sul-dlss/sdr-client/test_coverage)
4
+ [![Gem Version](https://badge.fury.io/rb/sdr-client.svg)](https://badge.fury.io/rb/sdr-client)
5
+
6
+ # Sdr::Client
7
+
8
+ This is a CLI for interacting with the Stanford Digital Repository API.
9
+ The code for the SDR API server is at https://github.com/sul-dlss/sdr-api
10
+
11
+ ## Usage
12
+
13
+ Log in:
14
+ ```
15
+ sdr --service-url http://sdr-api-server:3000 login
16
+ ```
17
+
18
+
19
+ Deposit a new object:
20
+ ```
21
+ sdr --service-url https://sdr-api-server:3000 deposit --label 'hey there' \
22
+ --admin-policy 'druid:bk123gh4567' \
23
+ --collection 'druid:gh456kw9876' \
24
+ --source-id 'googlebooks:stanford_12345' file1.png file2.png
25
+ ```
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RuboCop::RakeTask.new
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ desc 'Run linter and tests'
11
+ task default: %i[rubocop spec]
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'sdr/client'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/sdr ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift 'lib'
5
+ require 'optparse'
6
+
7
+ options = {}
8
+ global = OptionParser.new do |opts|
9
+ opts.on('--service-url URL', 'Connect to the host at this URL') do |url|
10
+ options[:url] = url
11
+ end
12
+ opts.on('-h', '--help', 'Display this screen') do
13
+ puts <<~HELP
14
+ DESCRIPTION:
15
+ The SDR Command Line Interface is a tool to interact with the Stanford Digital Repository.
16
+
17
+ SYNOPSIS:
18
+ sdr [options] <command>
19
+
20
+ OPTIONS:
21
+ --service-url (string)
22
+ Override the command's default URL with the given URL.
23
+
24
+ -h, --help
25
+ Displays this screen
26
+
27
+ COMMANDS
28
+ deposit
29
+ deposit files to the SDR
30
+
31
+ login
32
+ Will prompt for email & password and exchange it for an login token, which it saves in ~/.sdr/token
33
+
34
+ HELP
35
+ exit
36
+ end
37
+ end
38
+
39
+ global.order!
40
+ command = ARGV.shift
41
+
42
+ subcommands = {
43
+ 'deposit' => OptionParser.new do |opts|
44
+ opts.on('--label LABEL', 'The object label') do |label|
45
+ options[:label] = label
46
+ end
47
+
48
+ opts.on('--admin-policy ADMIN_POLICY', 'The druid identifier of the admin policy object') do |apo|
49
+ options[:apo] = apo
50
+ end
51
+ opts.on('--collection COLLECTION', 'The druid identifier of the collection object') do |collection|
52
+ options[:collection] = collection
53
+ end
54
+
55
+ opts.on('--catkey CATKEY', 'The catkey for this item') do |catkey|
56
+ options[:catkey] = catkey
57
+ end
58
+
59
+ opts.on('--source-id SOURCE_ID', 'The source id for this object') do |source_id|
60
+ options[:source_id] = source_id
61
+ end
62
+
63
+ opts.on('-h', '--help', 'Display this screen') do
64
+ puts opts
65
+ exit
66
+ end
67
+ end,
68
+ 'login' => OptionParser.new
69
+ }
70
+
71
+ unless subcommands.key?(command)
72
+ puts "unknown command '#{command}'"
73
+ exit
74
+ end
75
+
76
+ subcommands[command].order!
77
+
78
+ require 'sdr_client'
79
+ options[:files] = ARGV unless ARGV.empty?
80
+ SdrClient::CLI.start(command, options)
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/monads'
4
+ require 'faraday'
5
+
6
+ require 'sdr_client/version'
7
+ require 'sdr_client/deposit'
8
+ require 'sdr_client/credentials'
9
+ require 'sdr_client/login'
10
+ require 'sdr_client/login_prompt'
11
+ require 'sdr_client/cli'
12
+
13
+ module SdrClient
14
+ class Error < StandardError; end
15
+ # Your code goes here...
16
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ # The command line interface
5
+ module CLI
6
+ def self.start(command, options)
7
+ case command
8
+ when 'deposit'
9
+ SdrClient::Deposit.run(options)
10
+ when 'login'
11
+ status = SdrClient::Login.run(options)
12
+ puts status.value if status.failure?
13
+ else
14
+ raise "Unknown command #{command}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ # The stored credentials
5
+ class Credentials
6
+ # @param [String] a json string that contains a field 'token'
7
+ def self.write(body)
8
+ json = JSON.parse(body)
9
+ Dir.mkdir(credentials_path, 0o700) unless Dir.exist?(credentials_path)
10
+ File.open(credentials_file, 'w', 0o600) do |file|
11
+ file.write(json.fetch('token'))
12
+ end
13
+ puts 'Signed in.'
14
+ end
15
+
16
+ def self.read
17
+ return IO.readlines(credentials_file, chomp: true).first if ::File.exist?(credentials_file)
18
+
19
+ puts 'Log in first'
20
+ exit(1)
21
+ end
22
+
23
+ def self.credentials_path
24
+ @credentials_path ||= File.join(Dir.home, '.sdr')
25
+ end
26
+
27
+ def self.credentials_file
28
+ File.join(credentials_path, 'credentials')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ # The namespace for the "deposit" command
5
+ module Deposit
6
+ def self.run(label: nil,
7
+ type: 'http://cocina.sul.stanford.edu/models/book.jsonld',
8
+ apo:,
9
+ collection:,
10
+ catkey: nil,
11
+ source_id:,
12
+ url:, files: [])
13
+ token = Credentials.read
14
+
15
+ metadata = Request.new(label: label,
16
+ type: type,
17
+ apo: apo,
18
+ collection: collection,
19
+ source_id: source_id,
20
+ catkey: catkey)
21
+ Process.new(metadata: metadata, url: url, token: token, files: files).run
22
+ end
23
+ end
24
+ end
25
+ require 'json'
26
+ require 'sdr_client/deposit/files/direct_upload_request'
27
+ require 'sdr_client/deposit/files/direct_upload_response'
28
+ require 'sdr_client/deposit/file'
29
+ require 'sdr_client/deposit/file_set'
30
+ require 'sdr_client/deposit/request'
31
+ require 'sdr_client/deposit/process'
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ module Deposit
5
+ # This represents the File metadata that we send to the server for doing a deposit
6
+ class File
7
+ def initialize(external_identifier:, label:, filename:, access: 'dark', preserve: false, shelve: false)
8
+ @external_identifier = external_identifier
9
+ @label = label
10
+ @filename = filename
11
+ @access = access
12
+ @preserve = preserve
13
+ @shelve = shelve
14
+ end
15
+
16
+ def as_json
17
+ {
18
+ "type": 'http://cocina.sul.stanford.edu/models/file.jsonld',
19
+ label: @label,
20
+ filename: @filename,
21
+ externalIdentifier: @external_identifier,
22
+ access: {
23
+ access: @access
24
+ },
25
+ administrative: {
26
+ sdrPreserve: @preserve,
27
+ shelve: @shelve
28
+ }
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ module Deposit
5
+ # This represents the FileSet metadata that we send to the server for doing a deposit
6
+ class FileSet
7
+ def initialize(uploads: [], files: [])
8
+ @files = if !uploads.empty?
9
+ uploads.map do |upload|
10
+ File.new(external_identifier: upload.signed_id, label: upload.filename, filename: upload.filename)
11
+ end
12
+ else
13
+ files
14
+ end
15
+ end
16
+
17
+ def as_json
18
+ {
19
+ "type": 'http://cocina.sul.stanford.edu/models/fileset.jsonld',
20
+ structural: {
21
+ hasMember: files.map(&:as_json)
22
+ }
23
+ }
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :files
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module SdrClient
6
+ module Deposit
7
+ module Files
8
+ DirectUploadRequest = Struct.new(:checksum, :byte_size, :content_type, :filename, keyword_init: true) do
9
+ def self.from_file(filename)
10
+ checksum = Digest::MD5.file(filename).base64digest
11
+ new(checksum: checksum,
12
+ byte_size: ::File.size(filename),
13
+ content_type: 'text/html',
14
+ filename: ::File.basename(filename))
15
+ end
16
+
17
+ def as_json
18
+ {
19
+ blob: { filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type }
20
+ }
21
+ end
22
+
23
+ def to_json(*_args)
24
+ JSON.generate(as_json)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ module Deposit
5
+ module Files
6
+ DirectUploadResponse = Struct.new(:id, :key, :checksum, :byte_size, :content_type,
7
+ :filename, :metadata, :created_at, :direct_upload,
8
+ :signed_id, keyword_init: true)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module SdrClient
6
+ module Deposit
7
+ # The process for doing a deposit
8
+ class Process
9
+ BLOB_PATH = '/v1/direct_uploads'
10
+ DRO_PATH = '/v1/resources'
11
+ # @param [Request] metadata information about the object
12
+ # @param [String] url the server to send to
13
+ # @param [String] token the bearer auth token for the server
14
+ # @param [Array<String>] files a list of file names to upload
15
+ # @param [Logger] logger the logger to use
16
+ def initialize(metadata:, url:, token:, files: [], logger: Logger.new(STDOUT))
17
+ @files = files
18
+ @url = url
19
+ @token = token
20
+ @metadata = metadata
21
+ @logger = logger
22
+ end
23
+
24
+ def run
25
+ check_files_exist
26
+ file_metadata = collect_file_metadata
27
+ upload_responses = upload_file_metadata(file_metadata)
28
+ upload_files(upload_responses)
29
+ request = metadata.with_uploads(upload_responses.values)
30
+ upload_metadata(request.as_json)
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :metadata, :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
+ def collect_file_metadata
45
+ files.each_with_object({}) do |filename, obj|
46
+ obj[filename] = Files::DirectUploadRequest.from_file(filename)
47
+ end
48
+ end
49
+
50
+ # @param [Hash<String,Files::DirectUploadRequest>] file_metadata the filenames and their upload request
51
+ def upload_file_metadata(file_metadata)
52
+ Hash[file_metadata.map { |filename, metadata| [filename, direct_upload(metadata.to_json)] }]
53
+ end
54
+
55
+ def direct_upload(metadata_json)
56
+ logger.info("Starting an upload request: #{metadata_json}")
57
+ response = connection.post(BLOB_PATH, metadata_json, 'Content-Type' => 'application/json')
58
+ raise "unexpected response: #{response.inspect}" unless response.status == 200
59
+
60
+ logger.info("Response from server: #{response.body}")
61
+
62
+ Files::DirectUploadResponse.new(JSON.parse(response.body))
63
+ end
64
+
65
+ # @param [Hash<String,Files::DirectUploadResponse>] upload_responses the filenames and their upload response
66
+ def upload_files(upload_responses)
67
+ upload_responses.each do |filename, response|
68
+ upload_file(filename: filename,
69
+ url: response.direct_upload.fetch('url'),
70
+ content_type: response.content_type,
71
+ content_length: response.byte_size)
72
+
73
+ logger.info('Upload complete')
74
+ end
75
+ end
76
+
77
+ def upload_file(filename:, url:, content_type:, content_length:)
78
+ logger.info("Uploading `#{filename}' to #{url}")
79
+
80
+ upload_response = connection.put(url) do |req|
81
+ req.body = ::File.open(filename)
82
+ req.headers['Content-Type'] = content_type
83
+ req.headers['Content-Length'] = content_length.to_s
84
+ end
85
+
86
+ raise "unexpected response: #{upload_response.inspect}" unless upload_response.status == 204
87
+ end
88
+
89
+ # @return [Hash<Symbol,String>] the result of the metadata call
90
+ def upload_metadata(metadata)
91
+ logger.info("Starting upload metadata: #{metadata}")
92
+ request_json = JSON.generate(metadata)
93
+ response = connection.post(DRO_PATH, request_json, 'Content-Type' => 'application/json')
94
+ unexpected_response(response) unless response.status == 201
95
+
96
+ logger.info("Response from server: #{response.body}")
97
+
98
+ { druid: JSON.parse(response.body)['druid'], background_job: response.headers['Location'] }
99
+ end
100
+
101
+ def unexpected_response(response)
102
+ raise "unexpected response: #{response.inspect}" unless response.status == 400
103
+
104
+ puts "\nThere was an error with your request: #{response.body}"
105
+ exit(1)
106
+ end
107
+
108
+ def connection
109
+ @connection ||= Faraday.new(url: url) do |conn|
110
+ conn.authorization :Bearer, token
111
+ conn.adapter :net_http
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ module Deposit
5
+ # This represents the metadata that we send to the server for doing a deposit
6
+ class Request
7
+ # @param [String] label the required object label
8
+ # @param [String] type (http://cocina.sul.stanford.edu/models/object.jsonld) the required object type.
9
+ # @param [Array<FileSet>] file_sets the file sets to attach.
10
+ def initialize(label: nil,
11
+ apo:,
12
+ collection:,
13
+ source_id:,
14
+ catkey: nil,
15
+ type: 'http://cocina.sul.stanford.edu/models/object.jsonld',
16
+ file_sets: [])
17
+ @label = label
18
+ @type = type
19
+ @source_id = source_id
20
+ @collection = collection
21
+ @catkey = catkey
22
+ @apo = apo
23
+ @file_sets = file_sets
24
+ end
25
+
26
+ def as_json
27
+ {
28
+ access: {},
29
+ type: type,
30
+ administrative: administrative,
31
+ identification: identification,
32
+ structural: structural
33
+ }.tap do |json|
34
+ json[:label] = label if label
35
+ end
36
+ end
37
+
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
+
43
+ Request.new(label: label,
44
+ apo: apo,
45
+ collection: collection,
46
+ source_id: source_id,
47
+ catkey: catkey,
48
+ type: type,
49
+ file_sets: file_sets)
50
+ end
51
+
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
+ private
58
+
59
+ attr_reader :label, :file_sets, :source_id, :catkey, :apo, :collection, :type
60
+
61
+ def administrative
62
+ {
63
+ hasAdminPolicy: apo
64
+ }
65
+ end
66
+
67
+ def identification
68
+ { sourceId: source_id }.tap do |json|
69
+ json[:catkey] = catkey if catkey
70
+ end
71
+ end
72
+
73
+ def structural
74
+ {
75
+ isMemberOf: collection,
76
+ hasMember: file_sets.map(&:as_json)
77
+ }
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ # The namespace for the "login" command
5
+ module Login
6
+ LOGIN_PATH = '/v1/auth/login'
7
+ extend Dry::Monads[:result]
8
+
9
+ # @return [Result] the status of the call
10
+ def self.run(url:, login_service: LoginPrompt)
11
+ request_json = JSON.generate(login_service.run)
12
+ response = Faraday.post(url + LOGIN_PATH, request_json, 'Content-Type' => 'application/json')
13
+ case response.status
14
+ when 200
15
+ Credentials.write(response.body)
16
+ Success()
17
+ when 400
18
+ Failure('Email address is not a valid email')
19
+ when 401
20
+ Failure('Invalid username or password')
21
+ else
22
+ Failure("Status: #{response.status}\n#{response.body}")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'io/console'
4
+
5
+ module SdrClient
6
+ # The namespace for the "login" command
7
+ module LoginPrompt
8
+ def self.run
9
+ print 'Email: '
10
+ email = gets
11
+ email.strip!
12
+ print 'Password: '
13
+ password = $stdin.noecho(&:gets)
14
+ password.strip!
15
+ puts
16
+ { email: email, password: password }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SdrClient
4
+ VERSION = '0.3.0'
5
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'sdr_client/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'sdr-client'
9
+ spec.version = SdrClient::VERSION
10
+ spec.authors = ['Justin Coyne']
11
+ spec.email = ['jcoyne@justincoyne.com']
12
+
13
+ spec.summary = 'The CLI for https://github.com/sul-dlss/sdr-api'
14
+ spec.description = 'This provides a way to deposit repository objects into the Stanford Digital Repository'
15
+ spec.homepage = 'https://github.com/sul-dlss/sdr-client'
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/sul-dlss/sdr-client'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/sul-dlss/sdr-client/releases'
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = 'exe'
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_dependency 'dry-monads'
31
+ spec.add_dependency 'faraday', '>= 0.16'
32
+
33
+ spec.add_development_dependency 'bundler', '~> 2.0'
34
+ spec.add_development_dependency 'rake', '~> 13.0'
35
+ spec.add_development_dependency 'rspec', '~> 3.0'
36
+ spec.add_development_dependency 'rubocop', '~> 0.79.0'
37
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.37.1'
38
+ spec.add_development_dependency 'simplecov'
39
+ spec.add_development_dependency 'webmock', '~> 3.7'
40
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sdr-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin Coyne
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-monads
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.79.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.79.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.37.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.37.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.7'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.7'
139
+ description: This provides a way to deposit repository objects into the Stanford Digital
140
+ Repository
141
+ email:
142
+ - jcoyne@justincoyne.com
143
+ executables:
144
+ - sdr
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".github/pull_request_template.md"
149
+ - ".gitignore"
150
+ - ".rspec"
151
+ - ".rubocop.yml"
152
+ - ".rubocop_todo.yml"
153
+ - ".travis.yml"
154
+ - Gemfile
155
+ - LICENSE
156
+ - README.md
157
+ - Rakefile
158
+ - bin/console
159
+ - bin/setup
160
+ - exe/sdr
161
+ - lib/sdr_client.rb
162
+ - lib/sdr_client/cli.rb
163
+ - lib/sdr_client/credentials.rb
164
+ - lib/sdr_client/deposit.rb
165
+ - lib/sdr_client/deposit/file.rb
166
+ - lib/sdr_client/deposit/file_set.rb
167
+ - lib/sdr_client/deposit/files/direct_upload_request.rb
168
+ - lib/sdr_client/deposit/files/direct_upload_response.rb
169
+ - lib/sdr_client/deposit/process.rb
170
+ - lib/sdr_client/deposit/request.rb
171
+ - lib/sdr_client/login.rb
172
+ - lib/sdr_client/login_prompt.rb
173
+ - lib/sdr_client/version.rb
174
+ - sdr-client.gemspec
175
+ homepage: https://github.com/sul-dlss/sdr-client
176
+ licenses: []
177
+ metadata:
178
+ homepage_uri: https://github.com/sul-dlss/sdr-client
179
+ source_code_uri: https://github.com/sul-dlss/sdr-client
180
+ changelog_uri: https://github.com/sul-dlss/sdr-client/releases
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubygems_version: 3.0.3
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: The CLI for https://github.com/sul-dlss/sdr-api
200
+ test_files: []