sdr-client 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []