Class: DruidTools::Druid

Inherits:
Object
  • Object
show all
Defined in:
lib/druid_tools/druid.rb

Direct Known Subclasses

AccessDruid

Constant Summary collapse

STRICT_LET =

See consul.stanford.edu/pages/viewpage.action?title=SURI+2.0+Specification&spaceKey=chimera character class matching allowed letters in a druid suitable for use in regex (no aeioul)

'[b-df-hjkmnp-tv-z]'.freeze
@@deletes_directory_name =
'.deletes'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(druid, base = '.', strict = false) ⇒ Druid

Returns a new instance of Druid.

Parameters:

  • druid (String)

    A valid druid

  • true (boolean)

    if validation should be more restrictive about allowed letters (no aeioul)

  • base (String) (defaults to: '.')

    The directory used by #path



58
59
60
61
62
63
64
65
66
# File 'lib/druid_tools/druid.rb', line 58

def initialize(druid, base='.', strict=false)
  druid = druid.to_s unless druid.is_a? String
  unless self.class.valid?(druid, strict)
    raise ArgumentError, "Invalid DRUID: '#{druid}'"
  end
  druid = [self.class.prefix, druid].join(':') unless druid =~ /^#{self.class.prefix}:/
  @base = base
  @druid = druid
end

Class Attribute Details

.prefixObject

Returns the value of attribute prefix.



14
15
16
# File 'lib/druid_tools/druid.rb', line 14

def prefix
  @prefix
end

Instance Attribute Details

#baseObject

Returns the value of attribute base.



7
8
9
# File 'lib/druid_tools/druid.rb', line 7

def base
  @base
end

#druidObject

Returns the value of attribute druid.



7
8
9
# File 'lib/druid_tools/druid.rb', line 7

def druid
  @druid
end

Class Method Details

.globString

Returns suitable for use in [Dir#glob].

Returns:

  • (String)

    suitable for use in [Dir#glob]



24
25
26
# File 'lib/druid_tools/druid.rb', line 24

def glob
  "{#{self.prefix}:,}[a-z][a-z][0-9][0-9][0-9][a-z][a-z][0-9][0-9][0-9][0-9]"
end

.pattern(strict = false) ⇒ Regexp

Returns matches druid:aa111aa1111 or aa111aa1111.

Parameters:

  • true (boolean)

    if validation should be more restrictive about allowed letters (no aeioul)

Returns:

  • (Regexp)

    matches druid:aa111aa1111 or aa111aa1111



18
19
20
21
# File 'lib/druid_tools/druid.rb', line 18

def pattern(strict=false)
  return /\A(?:#{self.prefix}:)?(#{STRICT_LET}{2})(\d{3})(#{STRICT_LET}{2})(\d{4})\z/ if strict
  /\A(?:#{self.prefix}:)?([a-z]{2})(\d{3})([a-z]{2})(\d{4})\z/
end

.strict_globString

Returns suitable for use in [Dir#glob].

Returns:

  • (String)

    suitable for use in [Dir#glob]



29
30
31
# File 'lib/druid_tools/druid.rb', line 29

def strict_glob
  "{#{self.prefix}:,}#{STRICT_LET}#{STRICT_LET}[0-9][0-9][0-9]#{STRICT_LET}#{STRICT_LET}[0-9][0-9][0-9][0-9]"
end

.valid?(druid, strict = false) ⇒ Boolean

Returns true if druid matches pattern; otherwise false.

Parameters:

  • druid (String)

    id

  • true (boolean)

    if validation should be more restrictive about allowed letters (no aeioul)

Returns:

  • (Boolean)

    true if druid matches pattern; otherwise false



36
37
38
# File 'lib/druid_tools/druid.rb', line 36

def valid?(druid, strict=false)
  druid =~ pattern(strict) ? true : false
end

Instance Method Details

#base_pathnameObject



145
146
147
# File 'lib/druid_tools/druid.rb', line 145

def base_pathname
  Pathname self.base
end

#create_deletes_dirvoid

This method returns an undefined value.

Creates the deletes dir using the path supplied by deletes_dir_pathname



200
201
202
# File 'lib/druid_tools/druid.rb', line 200

def create_deletes_dir
  FileUtils::mkdir_p deletes_dir_pathname
end

#creates_delete_recordvoid

This method returns an undefined value.

Creates an empty (pointer) file using the object’s id in the .deletes dir



218
219
220
221
# File 'lib/druid_tools/druid.rb', line 218

def creates_delete_record
  prep_deletes_dir
  FileUtils.touch(deletes_record_pathname)
end

#deletes_delete_recordObject

Deletes the delete record if it currently exists. This is done to change the filed created, not just last modified time, on the system

return [void]



209
210
211
# File 'lib/druid_tools/druid.rb', line 209

def deletes_delete_record
  FileUtils.rm(deletes_record_pathname) if deletes_record_exists? #thrown in to prevent an  Errno::ENOENT if you call this on something without a delete record
end

#deletes_dir_exists?Boolean

Using the deletes directory path supplied by deletes_dir_pathname, this function determines if this directory exists

Returns:

  • (Boolean)

    true if if exists, false if it does not



187
188
189
# File 'lib/druid_tools/druid.rb', line 187

def deletes_dir_exists?
  return File.directory?(deletes_dir_pathname)
end

#deletes_dir_pathnamePathname

Provide the location for the .deletes directory in the tree

Returns:

  • (Pathname)

    the path to the directory, ex: “stacks/.deletes”



176
177
178
# File 'lib/druid_tools/druid.rb', line 176

def deletes_dir_pathname
  return Pathname(self.base.to_s + (File::SEPARATOR+@@deletes_directory_name))
end

#deletes_record_exists?Boolean

Returns:

  • (Boolean)


191
192
193
# File 'lib/druid_tools/druid.rb', line 191

def deletes_record_exists?
  return File.exists?(deletes_dir_pathname.to_s + File::SEPARATOR + self.id)
end

#deletes_record_pathnameObject



180
181
182
# File 'lib/druid_tools/druid.rb', line 180

def deletes_record_pathname
  return Pathname(deletes_dir_pathname.to_s + File::SEPARATOR + self.id)
end

#find(type, path) ⇒ Object



93
94
95
96
97
# File 'lib/druid_tools/druid.rb', line 93

def find(type, path)
  possibles = [self.path(type.to_s),self.path,File.expand_path('..',self.path)]
  loc = possibles.find { |p| File.exists?(File.join(p,path)) }
  loc.nil? ? nil : File.join(loc,path)
end

#find_filelist_parent(type, filelist) ⇒ Pathname

Returns Search for and return the pathname of the directory that contains the list of files. Raises an exception unless a directory is found that contains all the files in the list.

Parameters:

  • type (String)

    The type of directory being sought (‘content’, ‘metadata’, or ‘temp’)

  • filelist (Array<String>, String)

    The files that are expected to be present in the directory

Returns:

  • (Pathname)

    Search for and return the pathname of the directory that contains the list of files. Raises an exception unless a directory is found that contains all the files in the list.



103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/druid_tools/druid.rb', line 103

def find_filelist_parent(type, filelist)
  raise "File list not specified" if filelist.nil? or filelist.empty?
  filelist = [filelist] unless filelist.is_a?(Array)
  search_dir = Pathname(self.path(type))
  directories = [search_dir, search_dir.parent, search_dir.parent.parent]
  found_dir = directories.find { |pathname| pathname.join(filelist[0]).exist? }
  raise "#{type} dir not found for '#{filelist[0]}' when searching '#{search_dir}'" if found_dir.nil?
  filelist.each do |filename|
    raise "File '#{filename}' not found in #{type} dir s'#{found_dir}'" unless found_dir.join(filename).exist?
  end
  found_dir
end

#idObject



68
69
70
# File 'lib/druid_tools/druid.rb', line 68

def id
  @druid.scan(self.class.pattern).flatten.join('')
end

#mkdir(extra = nil) ⇒ Object



82
83
84
85
86
87
88
89
90
91
# File 'lib/druid_tools/druid.rb', line 82

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


116
117
118
119
120
121
122
123
124
# File 'lib/druid_tools/druid.rb', line 116

def mkdir_with_final_link(source, extra=nil)
  new_path = path(extra)
  if(File.directory?(new_path) && !File.symlink?(new_path))
    raise DruidTools::DifferentContentExistsError, "Unable to create link, directory already exists: #{new_path}"
  end
  real_path = File.expand_path('..',new_path)
  FileUtils.mkdir_p(real_path)
  FileUtils.ln_s(source, new_path, :force=>true)
end

#path(extra = nil, create = false) ⇒ Object



76
77
78
79
80
# File 'lib/druid_tools/druid.rb', line 76

def path(extra=nil, create=false)
  result = File.join(*([base,tree,extra].compact))
  mkdir(extra) if create and not File.exists?(result)
  result
end

#pathnameObject



141
142
143
# File 'lib/druid_tools/druid.rb', line 141

def pathname
  Pathname self.path
end

#prep_deletes_dirvoid

This method returns an undefined value.

This function checks for existance of a .deletes dir one level into the path (ex: stacks/.deletes or purl/.deletes). If the directory does not exist, it is created. If the directory exists, check to see if the current druid has an entry there, if it does delete it. This is done because a file might be deleted, then republishing, then deleted we again, and we want to log the most recent delete.



164
165
166
167
168
169
170
171
# File 'lib/druid_tools/druid.rb', line 164

def prep_deletes_dir
  #Check for existences of deletes dir
  create_deletes_dir if !deletes_dir_exists?
  #In theory we could return true after this step (if it fires), since if there was no deletes dir then the file can't be present in the dir

  #Check to see if this druid has been deleted before, meaning file currently exists
  deletes_delete_record if deletes_record_exists?
end

#prune!Object



149
150
151
152
153
154
155
# File 'lib/druid_tools/druid.rb', line 149

def prune!
  this_path = pathname
  parent = this_path.parent
  parent.rmtree if parent.exist? && parent != base_pathname
  prune_ancestors parent.parent
  creates_delete_record
end

#prune_ancestors(outermost_branch) ⇒ void

This method returns an undefined value.

Returns Ascend the druid tree and prune empty branches.

Parameters:

  • outermost_branch (Pathname)

    The branch at which pruning begins



225
226
227
228
229
230
231
# File 'lib/druid_tools/druid.rb', line 225

def prune_ancestors(outermost_branch)
  while outermost_branch.exist? && outermost_branch.children.size == 0
    outermost_branch.rmdir
    outermost_branch = outermost_branch.parent
    break if  outermost_branch == base_pathname
  end
end

#rmdir(extra = nil) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/druid_tools/druid.rb', line 126

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

#treeObject



72
73
74
# File 'lib/druid_tools/druid.rb', line 72

def tree
  @druid.scan(self.class.pattern).flatten + [id]
end