Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move mkdir and mkdir_with_final_link from DruidTools #329

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/workspaces_controller.rb
Expand Up @@ -2,7 +2,7 @@

# Handles API routes for managing the DOR workspace
class WorkspacesController < ApplicationController
rescue_from(DruidTools::SameContentExistsError, DruidTools::DifferentContentExistsError) do |e|
rescue_from(DruidPath::SameContentExistsError, DruidPath::DifferentContentExistsError) do |e|
render status: 409, plain: e.message
end

Expand Down
48 changes: 48 additions & 0 deletions app/services/druid_path.rb
@@ -0,0 +1,48 @@
# frozen_string_literal: true

# Creates and removes the druid path from the filesystem
class DruidPath
class SameContentExistsError < RuntimeError; end
class DifferentContentExistsError < RuntimeError; end

# @param [DruidTools::Druid] druid
def initialize(druid:)
@druid = druid
end

def mkdir(extra = nil)
new_path = druid.path(extra)
raise DifferentContentExistsError, "Unable to create directory, link already exists: #{new_path}" if File.symlink? new_path
raise SameContentExistsError, "The directory already exists: #{new_path}" if File.directory? new_path

FileUtils.mkdir_p(new_path)
end

def mkdir_with_final_link(source, extra = nil)
new_path = druid.path(extra)
raise DifferentContentExistsError, "Unable to create link, directory already exists: #{new_path}" if File.directory?(new_path) && !File.symlink?(new_path)

real_path = File.expand_path('..', new_path)
FileUtils.mkdir_p(real_path)
FileUtils.ln_s(source, new_path, force: true)
end

def rmdir(extra = nil)
parts = druid.tree
parts << extra unless extra.nil?
until parts.empty?
dir = File.join(druid.base, *parts)
begin
FileUtils.rm(File.join(dir, '.DS_Store'), force: true)
FileUtils.rmdir(dir)
rescue Errno::ENOTEMPTY
break
end
parts.pop
end
end

private

attr_reader :druid
end
7 changes: 3 additions & 4 deletions app/services/workspace_service.rb
Expand Up @@ -3,11 +3,10 @@
# Creates workspaces. This replaces https://github.com/sul-dlss/dor-services/blob/master/lib/dor/models/concerns/assembleable.rb
class WorkspaceService
# @param [Dor::Item] work the work to create the workspace for
# @param [String] source the path to create
# @param [String, nil] source the path to create
def self.create(work, source)
druid = DruidTools::Druid.new(work.pid, Settings.stacks.local_workspace_root)
return druid.mkdir if source.nil?

druid.mkdir_with_final_link(source)
druid_path = DruidPath.new(druid: druid)
source ? druid_path.mkdir_with_final_link(source) : druid_path.mkdir
end
end
4 changes: 2 additions & 2 deletions spec/controllers/workspaces_controller_spec.rb
Expand Up @@ -38,7 +38,7 @@
context 'when the link/directory already exists' do
before do
druid = DruidTools::Druid.new(item.pid, TEST_WORKSPACE)
druid.mkdir
DruidPath.new(druid: druid).mkdir
end

it 'returns a 409 Conflict http status code' do
Expand All @@ -51,7 +51,7 @@
context 'when the workspace already exists with different content' do
before do
druid = DruidTools::Druid.new(item.pid, TEST_WORKSPACE)
druid.mkdir
DruidPath.new(druid: druid).mkdir
end

it 'returns a 409 Conflict http status code' do
Expand Down
10 changes: 5 additions & 5 deletions spec/services/cleanup_service_spec.rb
Expand Up @@ -148,10 +148,10 @@ def create_tempfile(path)
dr1_assembly = DruidTools::Druid.new(druid_1, assembly_dir)
dr2_assembly = DruidTools::Druid.new(druid_2, assembly_dir)

dr1_wspace.mkdir
dr2_wspace.mkdir
dr1_assembly.mkdir
dr2_assembly.mkdir
DruidPath.new(druid: dr1_wspace).mkdir
DruidPath.new(druid: dr2_wspace).mkdir
DruidPath.new(druid: dr1_assembly).mkdir
DruidPath.new(druid: dr2_assembly).mkdir

# Add some 'content'
create_tempfile dr1_wspace.path
Expand Down Expand Up @@ -192,7 +192,7 @@ def create_tempfile(path)

it 'cleans up without assembly content' do
dr1_wspace = DruidTools::Druid.new(druid_1, workspace_dir)
dr1_wspace.mkdir
DruidPath.new(druid: dr1_wspace).mkdir

described_class.cleanup_by_druid druid_1
expect(File).not_to exist(dr1_wspace.path)
Expand Down
83 changes: 83 additions & 0 deletions spec/services/druid_path_spec.rb
@@ -0,0 +1,83 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe DruidPath do
let(:strictly_valid_druid_str) { 'druid:cd456gh1234' }
let(:tree2) { File.join(fixture_dir, 'cd/456/gh/1234/cd456gh1234') }

after do
FileUtils.rm_rf(File.join(fixture_dir, 'cd'))
end

describe '#mkdir error handling' do
it 'raises SameContentExistsError if the directory already exists' do
druid_obj = DruidTools::Druid.new(strictly_valid_druid_str, fixture_dir)
service = described_class.new(druid: druid_obj)
service.mkdir
expect { service.mkdir }.to raise_error(described_class::SameContentExistsError)
end

it 'raises DifferentContentExistsError if a link already exists in the workspace for this druid' do
source_dir = '/tmp/content_dir'
FileUtils.mkdir_p(source_dir)
dr = DruidTools::Druid.new(strictly_valid_druid_str, fixture_dir)
service = described_class.new(druid: dr)
service.mkdir_with_final_link(source_dir)

expect { service.mkdir }.to raise_error(described_class::DifferentContentExistsError)
end
end

describe '#mkdir_with_final_link' do
let(:source_dir) { '/tmp/content_dir' }
let(:druid_obj) { DruidTools::Druid.new(strictly_valid_druid_str, fixture_dir) }
let(:service) { described_class.new(druid: druid_obj) }

before do
FileUtils.mkdir_p(source_dir)
end

it 'creates a druid tree in the workspace with the final directory being a link to the passed in source' do
service.mkdir_with_final_link(source_dir)
expect(File).to be_symlink(druid_obj.path)
expect(File.readlink(tree2)).to eq(source_dir)
end

it 'raises DifferentContentExistsError if a directory already exists in the workspace for this druid' do
service.mkdir(fixture_dir)
expect { service.mkdir_with_final_link(source_dir) }.to raise_error(described_class::DifferentContentExistsError)
end
end

describe '#rmdir' do
let(:druid_str) { 'druid:cd456ef7890' }
let(:tree1) { File.join(fixture_dir, 'cd/456/ef/7890/cd456ef7890') }
let(:druid1) { DruidTools::Druid.new(druid_str, fixture_dir) }
let(:druid2) { DruidTools::Druid.new(strictly_valid_druid_str, fixture_dir) }
let(:service1) { described_class.new(druid: druid1) }
let(:service2) { described_class.new(druid: druid2) }

it 'destroys druid directories' do
expect(File.exist?(tree1)).to eq false
expect(File.exist?(tree2)).to eq false

service1.mkdir
expect(File.exist?(tree1)).to eq true
expect(File.exist?(tree2)).to eq false

service2.mkdir
expect(File.exist?(tree1)).to eq true
expect(File.exist?(tree2)).to eq true

service2.rmdir
expect(File.exist?(tree1)).to eq true
expect(File.exist?(tree2)).to eq false

service1.rmdir
expect(File.exist?(tree1)).to eq false
expect(File.exist?(tree2)).to eq false
expect(File.exist?(File.join(fixture_dir, 'cd'))).to eq false
end
end
end
2 changes: 1 addition & 1 deletion spec/services/prune_service_spec.rb
Expand Up @@ -53,7 +53,7 @@
# Nil the create records for this test
source_dir = File.join workspace, 'src_dir'
FileUtils.mkdir_p(source_dir)
dr2.mkdir_with_final_link(source_dir)
DruidPath.new(druid: dr2).mkdir_with_final_link(source_dir)
described_class.new(druid: dr2).prune!

expect(File).not_to exist(dr2.path)
Expand Down