Module: Bitferry

Extended by:
Logging
Includes:
Logging
Defined in:
lib/bitferry.rb

Defined Under Namespace

Modules: Logging, Rclone, Restic Classes: Endpoint, Task, Volume

Constant Summary collapse

VERSION =
'0.0.7'
PATH_LIST_SEPARATOR =

Specify OS-specific path name list separator (such as in the $PATH environment variable)

windows? ? ';' : ':'
UNIX_SYSTEM_MOUNTS =

Match OS-specific system mount points (/dev /proc etc.) which normally should be omitted when scanning for Bitferry voulmes

%r!^/(dev|sys|proc|efi)!

Class Method Summary collapse

Methods included from Logging

log, log, log=

Class Method Details

.commitObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/bitferry.rb', line 61

def self.commit
  log.info('committing changes')
  result = true
  modified = false
  Volume.registered.each do |volume|
    begin
      modified = true if volume.modified?
      volume.commit
    rescue IOError => e
       log.error(e.message)
       result = false
    end
  end
  if result
    log.info(modified ? 'changes committed' : 'commits skipped (no changes)')
  else
    log.warn('commit failure(s) reported')
  end
  result
end

.endpoint(root) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/bitferry.rb', line 125

def self.endpoint(root)
  case root
    when /^:(\w+):(.*)/
      volumes = Volume.lookup($1)
      volume = case volumes.size
        when 0 then raise ArgumentError, "no intact volume matching (partial) tag #{$1}"
        when 1 then volumes.first
        else
          tags = volumes.collect { |v| v.tag }.join(', ')
          raise ArgumentError, "multiple intact volumes matching (partial) tag #{$1}: #{tags}"
      end
      Endpoint::Bitferry.new(volume, $2)
    when /^(?:local)?:(.*)/ then Endpoint::Local.new($1)
    when /^(\w{2,}):(.*)/ then Endpoint::Rclone.new($1, $2)
    else Volume.endpoint(root)
  end
end

.environment_mountsObject

Return list of live user-provided mounts (mount points on *NIX and disk drives on Windows) which may contain Bitferry volumes Look for the $BITFERRY_PATH environment variable



166
167
168
# File 'lib/bitferry.rb', line 166

def self.environment_mounts
  ENV['BITFERRY_PATH'].split(PATH_LIST_SEPARATOR).collect { |path| File.directory?(path) ? path : nil }.compact rescue []
end

.intact_tasksObject



90
# File 'lib/bitferry.rb', line 90

def self.intact_tasks = Volume.intact.collect { |volume| volume.intact_tasks }.flatten.uniq

.optional(option, route) ⇒ Object



493
494
495
496
497
498
499
500
# File 'lib/bitferry.rb', line 493

def self.optional(option, route)
  case option
  when Array then option # Array is passed verbatim
  when '-' then nil # Disable adding any options with -
  when /^-/ then option.split(',') # Split comma-separated string into array --foo,bar --> [--foo, bar]
  else route.fetch(option.nil? ? nil : option.to_sym) # Obtain options from the profile database
  end
end

.process(*tags, &block) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/bitferry.rb', line 92

def self.process(*tags, &block)
  log.info('processing tasks')
  tasks = intact_tasks
  if tags.empty?
    process = tasks
  else
    process = []
    tags.each do |tag|
      case (tasks = Task.match([tag], tasks)).size
        when 0 then log.warn("no tasks matching (partial) tag #{tag}")
        when 1 then process += tasks
        else
          tags = tasks.collect { |v| v.tag }.join(', ')
          raise ArgumentError, "multiple tasks matching (partial) tag #{tag}: #{tags}"
      end
    end
  end
  tasks = process.uniq
  total = tasks.size
  processed = 0
  failed = 0
  result = tasks.all? do |task|
    r = task.process
    processed += 1
    failed += 1 unless r
    yield(total, processed, failed) if block_given?
    r
  end
  result ? log.info('tasks processed') : log.warn('task process failure(s) reported')
  result
end

.resetObject



83
84
85
86
87
# File 'lib/bitferry.rb', line 83

def self.reset
  log.info('resetting state')
  Volume.reset
  Task.reset
end

.restoreObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/bitferry.rb', line 40

def self.restore
  reset
  log.info('restoring volumes')
  result = true
  roots = (environment_mounts + system_mounts + [Dir.home]).uniq
  log.info("distilled volume search path: #{roots.join(', ')}")
  roots.each do |root|
    if File.exist?(File.join(root, Volume::STORAGE))
      log.info("trying to restore volume from #{root}")
      Volume.restore(root) rescue result = false
    end
  end
  if result
    log.info('volumes restored')
  else
    log.warn('volume restore failure(s) reported')
  end
  result
end

.simulate=(mode) ⇒ Object



146
# File 'lib/bitferry.rb', line 146

def self.simulate=(mode) @simulate = mode end

.simulate?Boolean

Returns:

  • (Boolean)


145
# File 'lib/bitferry.rb', line 145

def self.simulate? = @simulate

.system_mountsObject



182
183
184
# File 'lib/bitferry.rb', line 182

def self.system_mounts
  java.nio.file.FileSystems.getDefault.getFileStores.collect {|x| /^(.*)\s+\(.*\)$/.match(x.to_s)[1]}
end

.tagObject



37
# File 'lib/bitferry.rb', line 37

def self.tag = format('%08x', 2**32*rand)

.uiObject



155
# File 'lib/bitferry.rb', line 155

def self.ui = @ui

.ui=(ui) ⇒ Object



156
# File 'lib/bitferry.rb', line 156

def self.ui=(ui) @ui = ui end

.verbosityObject



150
# File 'lib/bitferry.rb', line 150

def self.verbosity = @verbosity

.verbosity=(mode) ⇒ Object



151
# File 'lib/bitferry.rb', line 151

def self.verbosity=(mode) @verbosity = mode end

.windows?Boolean

Return true if run in the real Windows environment (e.g. not in real *NIX or various emulation layers such as MSYS, Cygwin etc.)

Returns:

  • (Boolean)


160
161
162
# File 'lib/bitferry.rb', line 160

def self.windows?
  @windows ||= /^(mingw)/.match?(RbConfig::CONFIG['target_os']) # RubyInstaller's MRI, other MinGW-build MRI
end