Skip to content

Commit a8620c4

Browse files
authored
Merge pull request #1 from hathitrust/DEV-667-stage-item
DEV-667: get it working so we can stage an item
2 parents 1ad323b + f00c790 commit a8620c4

File tree

9 files changed

+116
-95
lines changed

9 files changed

+116
-95
lines changed

.github/workflows/tests.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Run Tests
2+
3+
on: push
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
name: Ruby ${{ matrix.ruby }}
9+
strategy:
10+
matrix:
11+
ruby: [2.7, 3.0, 3.1, 3.2]
12+
steps:
13+
- uses: actions/checkout@v3
14+
- name: Set up Ruby
15+
uses: ruby/setup-ruby@v1
16+
with:
17+
ruby-version: ${{ matrix.ruby }}
18+
bundler-cache: true
19+
- name: Run linter for Ruby
20+
run: bundle exec standardrb
21+
- name: Run tests
22+
run: bundle exec rspec

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@
99

1010
# rspec failure tracking
1111
.rspec_status
12+
Gemfile.lock
13+
vendor

Gemfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
source "https://rubygems.org"
22

3-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
44

55
# Specify your gem's dependencies in ht-pairtree.gemspec
66
gemspec
7+
8+
group :development do
9+
gem "pry"
10+
end

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# HathiTrust::Pairtree
22

3+
[![Tests](https://github.com/hathitrust/ht-pairtree/actions/workflows/tests.yml/badge.svg)](https://github.com/hathitrust/ht-pairtree/actions/workflows/tests.yml)
4+
35
Deal with a [Pairtree](https://github.com/mlibrary/pairtree) given an HTID.
46

57
Allows both reading and creation of the underlying pairtree directories
@@ -39,9 +41,9 @@ pairtree = pt[id]
3941
### Create a new pairtree object (directory)
4042

4143
newthing = pt.create('one.two3four')
42-
#=> Pairtree::PathError (because there's no pairtree at .../obj/one)
44+
#=> HathiTrust::Pairtree::NamespaceDoesNotExist (because there's no pairtree at .../obj/one)
4345

44-
newthing = pt.create('one.two3four', create_new_namespace: true)
46+
newthing = pt.create('one.two3four', new_namespace_allowed: true)
4547
#=> Pairtree::Obj<blah blah blah>
4648

4749
```
@@ -69,7 +71,7 @@ function htcd() {
6971
Add this line to your application's Gemfile:
7072

7173
```ruby
72-
gem 'ht-rpairtree'
74+
gem 'ht-pairtree'
7375
```
7476

7577
And then execute:

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
33

44
RSpec::Core::RakeTask.new(:spec)
55

6-
task :default => :spec
6+
task default: :spec

ht-pairtree.gemspec

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,41 @@
1-
21
lib = File.expand_path("../lib", __FILE__)
32
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
43
require "ht/pairtree/version"
54

65
Gem::Specification.new do |spec|
7-
spec.name = "ht-pairtree"
8-
spec.version = HathiTrust::Pairtree::VERSION
9-
spec.authors = ["Bill Dueber"]
10-
spec.email = ["[email protected]"]
11-
#
12-
spec.summary = %q{Pairtree with extra sugar for the HathiTrust environment}
6+
spec.name = "ht-pairtree"
7+
spec.version = HathiTrust::Pairtree::VERSION
8+
spec.authors = ["Bill Dueber"]
9+
spec.email = ["[email protected]"]
10+
spec.summary = "Pairtree with extra sugar for the HathiTrust environment"
1311
# spec.description = %q{TODO: Write a longer description or delete this line.}
14-
spec.homepage = "https://github.com/hathitrust/ht-pairtree"
15-
spec.license = "MIT"
12+
spec.homepage = "https://github.com/hathitrust/ht-pairtree"
13+
spec.license = "MIT"
1614
#
1715
# # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
1816
# # to allow pushing to a single host or delete this section to allow pushing to any host.
1917
if spec.respond_to?(:metadata)
2018
spec.metadata["allowed_push_host"] = "https://gems.www.lib.umich.edu"
2119
spec.metadata["homepage_uri"] = spec.homepage
2220
spec.metadata["source_code_uri"] = spec.homepage
23-
spec.metadata["changelog_uri"] = spec.homepage + '/CHANGELOG.md'
21+
spec.metadata["changelog_uri"] = spec.homepage + "/CHANGELOG.md"
2422
else
2523
raise "RubyGems 2.0 or newer is required to protect against " \
2624
"public gem pushes."
2725
end
2826

2927
# Specify which files should be added to the gem when it is released.
3028
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
29+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
3230
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
3331
end
34-
spec.bindir = "exe"
35-
spec.executables = %w[htdir]
32+
spec.bindir = "exe"
33+
spec.executables = %w[htdir]
3634
spec.require_paths = ["lib"]
3735

38-
# The 'pairtree' gem seems to be abandoned. Use the mlibrary
39-
# clone
40-
spec.add_dependency 'rpairtree'
41-
42-
36+
spec.add_dependency "pairtree", "~> 0.3"
4337
spec.add_development_dependency "bundler", "~> 2.0"
4438
spec.add_development_dependency "rake", "~> 12.0"
4539
spec.add_development_dependency "rspec", "~> 3.0"
40+
spec.add_development_dependency "standardrb"
4641
end

lib/ht/pairtree.rb

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,31 @@
1-
# coding: utf-8
21
require "ht/pairtree/version"
32

43
# Pairtree is ancient and throws warnings so we suppress them on require
54
oldverbose = $VERBOSE
65
$VERBOSE = nil
7-
require 'pairtree'
6+
require "pairtree"
87
$VERBOSE = oldverbose
98

10-
require 'fileutils'
9+
require "fileutils"
1110

1211
module HathiTrust
1312
# A simple Pairtree implementation to make it easier to work with
1413
# the HathiTrust pairtree structure.
1514
class Pairtree
16-
17-
class PairtreeError < StandardError;
15+
class PairtreeError < StandardError
1816
end
1917

2018
class NamespaceDoesNotExist < PairtreeError
2119
end
2220

23-
SDR_DATA_ROOT_DEFAULT = (ENV["SDRDATAROOT"] || '/sdr1') + '/obj'
21+
SDR_DATA_ROOT_DEFAULT = (ENV["SDRDATAROOT"] || "/sdr1") + "/obj"
2422

2523
# Create a new pairtree object rooted at the given directory
2624
# @param [String] root The root of the über-pairtree (takes `ENV['SDRDATAROOT'] + 'obj'` by default)
2725
def initialize(root: SDR_DATA_ROOT_DEFAULT)
2826
@root = Pathname.new(root)
2927
end
3028

31-
32-
3329
# Get a Pathname object corresponding to the directory holding data for the given HTID
3430
# @param [String] htid The HathiTrust ID for an object
3531
# @return [Pathname] Path to the given object's directory
@@ -40,58 +36,47 @@ def path_for(htid)
4036
alias_method :dir, :path_for
4137
alias_method :path_to, :path_for
4238

43-
4439
# Get the underlying pairtree for the given obj.
4540
# @param [String] htid The HathiTrust ID for an object
41+
# @param [Boolean] create Whether to create the pairtree if it doesn't exist
4642
# @return [Pairtree] the pairtree for that object
47-
def pairtree_for(htid)
48-
pairtree_root(htid)
43+
def pairtree_for(htid, create: false)
44+
pairtree_root(htid, create: create)
4945
end
5046

51-
# Create a pairtree for the given htid. Allow namespace creation
52-
# only if told to.
47+
# Create the pairtree directory for the given htid. Allow namespace
48+
# creation only if told to.
5349
# @param htid [String] The HTID
5450
# @param new_namespace_allowed [Boolean] Whether or not to error if the namespace DNE
5551
# @raise [NamespaceDoesNotExist] if namespace DNE and new namespace not allowed
5652
# @return [Pairtree::Obj] the underlying pairtree object
5753
def create(htid, new_namespace_allowed: false)
58-
if !namespace_exists?(htid)
59-
if new_namespace_allowed
60-
create_namespace_dir(htid)
61-
else
62-
raise NamespaceDoesNotExist.new("Namespace #{namespace(htid)} does not exist")
63-
end
54+
unless namespace_exists?(htid) || new_namespace_allowed
55+
raise NamespaceDoesNotExist.new("Namespace #{namespace(htid)} does not exist")
6456
end
65-
pairtree_for(htid).mk(htid)
66-
end
67-
68-
def namespace_exists?(htid)
69-
namespace_dir(htid).exists?
57+
pairtree_for(htid, create: new_namespace_allowed).mk(htid)
7058
end
7159

60+
private
7261

73-
def create_namespace_dir(htid)
74-
ndir = namespace_dir(htid)
75-
return self if Dir.exists?(ndir)
76-
Dir.mkdir(ndir)
77-
File.open(ndir + "pairtree_prefix", 'w:utf-8') {|f| f.print namespace(htid)}
78-
File.open(ndir + "pairtree_version0_1", 'w:utf-8') {|f| }
79-
Dir.mkdir(ndir + "pairtree_root")
80-
return self
62+
def namespace_exists?(htid)
63+
namespace_dir(htid).exist?
8164
end
8265

83-
8466
def namespace_dir(htid)
8567
@root + namespace(htid)
8668
end
8769

8870
def namespace(htid)
89-
htid.split('.', 2).first
71+
htid.split(".", 2).first
9072
end
9173

92-
def pairtree_root(htid)
93-
::Pairtree.at(namespace_dir(htid))
74+
def pairtree_root(htid, create: false)
75+
::Pairtree.at(namespace_dir(htid), prefix: pairtree_prefix(htid), create: create)
9476
end
9577

78+
def pairtree_prefix(htid)
79+
namespace(htid) + "."
80+
end
9681
end
9782
end

lib/ht/pairtree/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module HathiTrust
2-
class Pairtree
2+
class Pairtree
33
VERSION = "0.1.0"
44
end
55
end

spec/ht/pairtree_spec.rb

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,69 @@
1-
require 'pairtree'
2-
require 'fileutils'
3-
require 'tmpdir'
4-
1+
require "pairtree"
2+
require "fileutils"
3+
require "tmpdir"
54

65
RSpec.describe HathiTrust::Pairtree do
7-
TMPDIR = Pathname.new(Dir.mktmpdir)
8-
puts TMPDIR
9-
10-
idmap = {
11-
'uc1.c3292592' => 'sdr1/obj/uc1/pairtree_root/c3/29/25/92/c3292592',
12-
'loc.ark:/13960/t9w09k00s' => 'sdr1/obj/loc/pairtree_root/ar/k+/=1/39/60/=t/9w/09/k0/0s/ark+=13960=t9w09k00s',
13-
'ia.ark:/13960/t9w10cs7x' => 'sdr1/obj/ia/pairtree_root/ar/k+/=1/39/60/=t/9w/10/cs/7x/ark+=13960=t9w10cs7x'
14-
}
15-
6+
let(:idmap) do
7+
{
8+
"uc1.c3292592" => "sdr1/obj/uc1/pairtree_root/c3/29/25/92/c3292592",
9+
"loc.ark:/13960/t9w09k00s" => "sdr1/obj/loc/pairtree_root/ar/k+/=1/39/60/=t/9w/09/k0/0s/ark+=13960=t9w09k00s",
10+
"ia.ark:/13960/t9w10cs7x" => "sdr1/obj/ia/pairtree_root/ar/k+/=1/39/60/=t/9w/10/cs/7x/ark+=13960=t9w10cs7x"
11+
}
12+
end
1613

17-
before(:context) do
14+
def make_paths(idmap)
1815
idmap.values.each do |subdir|
19-
dir = TMPDIR + subdir
20-
puts "Trying to make #{dir}"
16+
dir = @tmpdir + subdir
2117
FileUtils.mkdir_p(dir)
22-
root = TMPDIR + Pathname.new(subdir.split('/')[0..2].join('/'))
23-
prefix = subdir.split('/')[2]
24-
File.open(root + 'pairtree_prefix', 'w:utf-8') do |pp|
25-
pp.print(prefix + '.')
18+
root = @tmpdir + Pathname.new(subdir.split("/")[0..2].join("/"))
19+
prefix = subdir.split("/")[2]
20+
File.open(root + "pairtree_prefix", "w:utf-8") do |pp|
21+
pp.print(prefix + ".")
2622
end
27-
File.open(root + 'pairtree_version0_1', 'w:utf-8') {}
23+
File.open(root + "pairtree_version0_1", "w:utf-8") {}
2824
end
2925
end
3026

31-
after(:context) do
32-
FileUtils.rm_f(TMPDIR)
27+
around(:each) do |example|
28+
Dir.mktmpdir do |d|
29+
@tmpdir = Pathname.new(d)
30+
FileUtils.mkdir_p(@tmpdir + "sdr1/obj")
31+
example.run
32+
end
3333
end
3434

35-
3635
it "has a version number" do
3736
expect(HathiTrust::Pairtree::VERSION).not_to be nil
3837
end
3938

40-
41-
describe "translates names into directories" do
42-
pt = HathiTrust::Pairtree.new(root: TMPDIR + 'sdr1/obj')
39+
it "translates names into directories" do
40+
make_paths(idmap)
41+
pt = HathiTrust::Pairtree.new(root: @tmpdir + "sdr1/obj")
4342

4443
idmap.each_pair do |id, dir|
45-
it id do
46-
expect(pt.path_for(id).to_s).to eq((TMPDIR + dir).to_s)
47-
end
44+
expect(pt.path_for(id).to_s).to eq((@tmpdir + dir).to_s)
4845
end
4946
end
5047

51-
it "Can create new object directories" do
52-
pt = HathiTrust::Pairtree.new(root: TMPDIR + 'sdr1/obj')
53-
expect {pt.create('bill.dueber', create_new_namespace: false)}.to raise_error(Pairtree::PathError)
54-
expect(pt.create('bill.dueber', create_new_namespace: true).exists?('.')).to be true
55-
end
48+
describe "#create" do
49+
let(:pt) { HathiTrust::Pairtree.new(root: @tmpdir + "sdr1/obj") }
50+
51+
it "can create new object directories in the expected location" do
52+
expect { pt.create("test.something", new_namespace_allowed: false) }.to raise_error(HathiTrust::Pairtree::NamespaceDoesNotExist)
5653

54+
pt_obj = pt.create("test.something", new_namespace_allowed: true)
55+
expect(pt_obj.exist?(".")).to be true
56+
expect(pt_obj.to_path).to eq((@tmpdir + "sdr1/obj/test/pairtree_root/so/me/th/in/g/something").to_s)
57+
end
5758

59+
it "create is idempotent" do
60+
pt.create("test.something", new_namespace_allowed: true)
61+
expect(pt.create("test.something").exist?(".")).to be true
62+
end
63+
64+
it "new_namespace_allowed is idempotent" do
65+
pt.create("test.something", new_namespace_allowed: true)
66+
expect(pt.create("test.somethingelse", new_namespace_allowed: true).exist?(".")).to be true
67+
end
68+
end
5869
end

0 commit comments

Comments
 (0)