class Dbox::DB::DropboxDir

Attributes

contents[R]
contents_hash[R]

Public Class Methods

new(db, res) click to toggle source
Calls superclass method Dbox::DB::DropboxBlob::new
# File lib/dbox/db.rb, line 290
def initialize(db, res)
  @contents_hash = nil
  @contents = {}
  super(db, res)
end

Public Instance Methods

calculate_changes(res) click to toggle source
# File lib/dbox/db.rb, line 334
def calculate_changes(res)
  raise(ArgumentError, "Not a directory: #{res.inspect}") unless res["is_dir"]

  if @contents_hash && res["hash"] && @contents_hash == res["hash"]
    # dir hash hasn't changed -- no need to calculate changes
    []
  elsif res["contents"]
    # dir has changed -- calculate changes on contents
    out = []
    got_paths = []

    remove_dotfiles(res["contents"]).each do |c|
      p = @db.remote_to_relative_path(c["path"])
      c["rel_path"] = p
      got_paths << p

      if @contents.has_key?(p)
        # only update file if it's been modified
        if @contents[p].modified?(c)
          out << [:update, c]
        end
      else
        out << [:create, c]
      end
    end
    out += (@contents.keys.sort - got_paths.sort).map {|p| [:delete, { "rel_path" => p }] }
    out
  else
    raise(RuntimeError, "Trying to calculate dir changes without any contents")
  end
end
create_local() click to toggle source
# File lib/dbox/db.rb, line 430
def create_local
  log.info "Creating #{local_path}"
  saving_parent_timestamp do
    FileUtils.mkdir_p(local_path)
    update_file_timestamp
  end
end
create_remote() click to toggle source
# File lib/dbox/db.rb, line 449
def create_remote
  api.create_dir(remote_path)
  force_metadata_update_from_server
end
delete_local() click to toggle source
# File lib/dbox/db.rb, line 438
def delete_local
  log.info "Deleting #{local_path}"
  saving_parent_timestamp do
    FileUtils.rm_r(local_path)
  end
end
delete_remote() click to toggle source
# File lib/dbox/db.rb, line 454
def delete_remote
  api.delete_dir(remote_path)
end
dir?() click to toggle source
# File lib/dbox/db.rb, line 426
def dir?
  true
end
execute_changes(changes, direction) click to toggle source
# File lib/dbox/db.rb, line 366
def execute_changes(changes, direction)
  log.debug "executing changes: #{changes.inspect}"
  changelist = { :created => [], :deleted => [], :updated => [] }
  changes.each do |op, c|
    case op
    when :create
      e = smart_new(c)
      e.create(direction)
      @contents[e.path] = e
      changelist[:created] << e.path
    when :update
      e = @contents[c["rel_path"]]
      e.update_modification_info(c) if direction == :down
      e.update(direction)
      changelist[:updated] << e.path
    when :delete
      e = @contents[c["rel_path"]]
      e.delete(direction)
      @contents.delete(e.path)
      changelist[:deleted] << e.path
    else
      raise(RuntimeError, "Unknown operation type: #{op}")
    end
    @db.save
  end
  changelist.keys.each {|k| changelist[k].sort! }
  changelist
end
gather_local_info(rel, list_contents=true) click to toggle source
# File lib/dbox/db.rb, line 399
def gather_local_info(rel, list_contents=true)
  full = @db.relative_to_local_path(rel)
  remote = @db.relative_to_remote_path(rel)

  attrs = {
    "path" => remote,
    "is_dir" => File.directory?(full),
    "modified" => File.mtime(full),
    "revision" => @contents[rel] ? @contents[rel].revision : nil
  }

  if attrs["is_dir"] && list_contents
    contents = Dir.entries(full).reject {|s| s == "." || s == ".." }
    attrs["contents"] = contents.map do |s|
      p = File.join(full, s)
      r = @db.local_to_relative_path(p)
      gather_local_info(r, false)
    end
  end

  attrs
end
merge_changelists(old, new) click to toggle source
# File lib/dbox/db.rb, line 395
def merge_changelists(old, new)
  old.merge(new) {|k, v1, v2| (v1 + v2).sort }
end
print() click to toggle source
pull() click to toggle source
# File lib/dbox/db.rb, line 296
def pull
  # calculate changes on this dir
  res = api.metadata(remote_path)
  changes = calculate_changes(res)

  # execute changes on this dir
  changelist = execute_changes(changes, :down)

  # recur on subdirs, expanding changelist as we go
  changelist = subdirs.inject(changelist) {|c, d| merge_changelists(c, d.pull) }

  # only update the modification info on the directory once all descendants are updated
  update_modification_info(res)

  # return changes
  @db.save
  changelist
end
push() click to toggle source
# File lib/dbox/db.rb, line 315
def push
  # calculate changes on this dir
  res = gather_local_info(@path)
  changes = calculate_changes(res)

  # execute changes on this dir
  changelist = execute_changes(changes, :up)

  # recur on subdirs, expanding changelist as we go
  changelist = subdirs.inject(changelist) {|c, d| merge_changelists(c, d.push) }

  # only update the modification info on the directory once all descendants are updated
  update_modification_info(res)

  # return changes
  @db.save
  changelist
end
remove_dotfiles(contents) click to toggle source
# File lib/dbox/db.rb, line 422
def remove_dotfiles(contents)
  contents.reject {|c| File.basename(c["path"]).start_with?(".") }
end
subdirs() click to toggle source
# File lib/dbox/db.rb, line 462
def subdirs
  @contents.values.select {|c| c.dir? }
end
update_local() click to toggle source
# File lib/dbox/db.rb, line 445
def update_local
  update_file_timestamp
end
update_remote() click to toggle source
# File lib/dbox/db.rb, line 458
def update_remote
  # do nothing
end