rubyyabt 0.0.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,6 +36,7 @@ OptionParser.new do |opts|
36
36
  opts.on("-g", "--gpg-key KEY", "Use KEY as GPG key for encryption and signing") { |v| options[:gpg_key] = v }
37
37
  opts.on("-h", "--gpg-pass PASS", "Password for GPG key") { |v| options[:gpg_pass] = v }
38
38
  opts.on("-H", "--gpg-passfile FILE", "Read password for GPG key from FILE") { |v| options[:gpg_pass] = File.read(v) }
39
+ opts.on("-l", "--log-file FILE", "Write log to FILE") { |v| options[:logfile] = v.to_s }
39
40
  opts.on("-c", "--cache-max-age DAYS", "Allow maximum of DAYS time for a positive cache hit. False hits are never cached.") { |v| options[:cache_max_age] = v.to_i *(24*60*60) }
40
41
  opts.on("", "--http-timeout SECS", "Require all http requests to complete within SECS seconds.") { |v| options[:http_timeout] = v.to_i }
41
42
  opts.on("-C", "--empty-cache", "Start with an empty cache instead of restoring the cache from saved data") { options[:empty_cache] = true }
@@ -32,20 +32,20 @@ class Backup
32
32
  @time = Time.now
33
33
  @time.utc
34
34
  @name = @time.strftime("%Y%m%dT%H%M%S") unless @name
35
- @cui.message("Initialized backup #{@name}")
35
+ @cui.message("Initialized backup #{@name}", true, true)
36
36
  end
37
37
 
38
38
  def backup!()
39
39
  $errors = 0 if not $errors
40
- @cui.message("Scanning for files...")
40
+ @cui.message("Scanning for files...", true, true)
41
41
  @cui.start
42
- @cui.message("Found #{@source.files.count.to_s} files and directories")
42
+ @cui.message("Found #{@source.files.count.to_s} files and directories", true, true)
43
43
  backup_meta = Array.new
44
44
  backup_meta << '[Backup]'
45
45
  cache_timer = Time.now
46
46
  @source.files.each { | f |
47
47
  if (Time.now - cache_timer) > 900 then
48
- @cui.message("Uploading cache data...")
48
+ @cui.message("Uploading cache data...", true, true)
49
49
  @target.upload_cache
50
50
  cache_timer = Time.now
51
51
  end
@@ -65,19 +65,19 @@ class Backup
65
65
  $errors += 1
66
66
  end
67
67
  }
68
- @cui.message("Waiting for last chunk to finish uploading...")
68
+ @cui.message("Waiting for last chunk to finish uploading...", true, true)
69
69
  @cui.error("DEBUG[#{Thread.current.inspect}]: Joining chunk threads") if $myDEBUG
70
70
  chunk = Chunk.new
71
71
  chunk.join
72
72
  @cui.stop
73
73
  @cui.update
74
- @cui.message("Finished backing up data. Now uploading metadata for backup #{@name}.")
74
+ @cui.message("Finished backing up data. Now uploading metadata for backup #{@name}.", true, true)
75
75
  backup_meta = backup_meta.join("\n")
76
76
  @cui.error("DEBUG[#{Thread.current.inspect}]: Writing backup info") if $myDEBUG
77
77
  @target.write(:backup, @name, backup_meta)
78
- @cui.message("Uploading cache data...")
78
+ @cui.message("Uploading cache data...", true, true)
79
79
  @target.upload_cache
80
- @cui.error("Errors: A total of #{$errors} errors have been encountered.") if $errors > 0
80
+ @cui.error("Errors: A total of #{$errors} errors have been encountered.", true, true) if $errors > 0
81
81
  return $errors
82
82
  end
83
83
 
@@ -10,8 +10,6 @@ require 'classes/Target'
10
10
  #noinspection RubyResolve
11
11
  require 'classes/cui'
12
12
 
13
- $myDEBUG = false unless $myDEBUG
14
-
15
13
  class Chunk
16
14
  attr_reader :data, :length
17
15
  @@upload_mutex = Mutex.new
@@ -27,16 +25,12 @@ class Chunk
27
25
  end
28
26
 
29
27
  def join()
30
- @cui.error("DEBUG[#{Thread.current.inspect}]: Joining chunk thread") if $myDEBUG
31
28
  @@upload_thread.join if @@upload_thread
32
29
  end
33
30
 
34
31
  def set_data(data)
35
- @cui.error("DEBUG[#{Thread.current.inspect}: Entered chunk set_data") if $myDEBUG
36
32
  @data = data
37
- @cui.error("DEBUG[#{Thread.current.inspect}: Set data") if $myDEBUG
38
33
  @length = @data.length
39
- @cui.error("DEBUG[#{Thread.current.inspect}: Calculated length") if $myDEBUG
40
34
  @md5 = nil
41
35
  @md5 = Digest::MD5.hexdigest(@data)
42
36
  @sha256 = nil
@@ -64,26 +58,20 @@ class Chunk
64
58
  end
65
59
 
66
60
  def backup!()
67
- @cui.error("DEBUG[#{Thread.current.inspect}]: Locking chunk upload mutex in thread #{Thread.current.inspect}") if $myDEBUG
68
61
  @@upload_mutex.synchronize {
69
- @cui.error("DEBUG[#{Thread.current.inspect}]: Got lock of chunk upload mutex in thread #{Thread.current.inspect}") if $myDEBUG
70
- @cui.error("DEBUG[#{Thread.current.inspect}]: Trying to join earlier upload threads if any (@@uploadThread: #{@@upload_thread.inspect})") if $myDEBUG
71
62
  @@upload_thread.join if @@upload_thread
72
63
  @@upload_thread = Thread.new {
73
64
  target = Target.instance # Get a target object, then ...
74
- @cui.error("DEBUG[#{Thread.current.inspect}]: Checking if target chunk exists (#{sha256}, #{md5})") if $myDEBUG
75
65
  if not target.exists?(:chunk, "#{sha256}.#{md5}") then
76
- @cui.error("Uploading chunk #{sha256}.#{md5}...") if $myDEBUG
77
66
  target.write(:chunk, "#{sha256}.#{md5}", @data)
67
+ @cui.message("Chunk #{sha256}.#{md5} (#{@data.length} bytes) uploaded.", true, false)
78
68
  end
79
- @cui.error("DEBUG[#{Thread.current.inspect}]: Upload chunk thread finished (thread id: #{Thread.current.inspect})") if $myDEBUG
80
69
  }
81
- @cui.error("DEBUG[#{Thread.current.inspect}]: New upload thread: @@upload_thread = #{@@upload_thread.inspect}") if $myDEBUG
82
70
  }
83
71
  end
84
72
 
85
73
  def restore!()
86
- @cui.message("Downloading chunk #{sha256}.#{md5}...")
74
+ @cui.message("Downloading chunk #{sha256}.#{md5}...", true, true)
87
75
  target = Target.instance
88
76
  @data = target.read(:chunk, "#{sha256}.#{md5}")
89
77
  @length = @data.length
@@ -92,9 +80,9 @@ class Chunk
92
80
  @md5 = nil
93
81
  @sha256 = nil
94
82
  if (expected_md5 == md5) and (expected_sha256 == sha256) then
95
- @cui.message("chunk verified")
83
+ @cui.message("Chunk verified", true, true)
96
84
  else
97
- @cui.message("checksum error in chunk #{sha256}.#{md5}")
85
+ @cui.error("checksum error in chunk #{sha256}.#{md5}", true, true)
98
86
  raise 'checksum error'
99
87
  end
100
88
  end
@@ -8,8 +8,6 @@ require 'thread'
8
8
  #noinspection RubyResolve
9
9
  require 'classes/proxy_http_cache_hash'
10
10
 
11
- $myDEBUG = false if not $myDEBUG
12
- $myVERBOSE = false if not $myVERBOSE
13
11
  $options = nil unless $options
14
12
 
15
13
  class ProxyHTTP
@@ -60,48 +58,43 @@ class ProxyHTTP
60
58
  @cui.error("Cache is not compatible. Starting with an empty cache.")
61
59
  @cache = ProxyHTTPCache_Hash.new
62
60
  end
61
+ @cui.message("Successfully restored cache with a size of #{cache_data.length} bytes.", true, true)
63
62
  rescue Exception # Just start out with an empty cache
64
63
  @cache = ProxyHTTPCache_Hash.new
64
+ @cui.message("Unable to restore cache. Starting with an empty cache.", true, true)
65
65
  end
66
66
 
67
67
  end
68
68
 
69
69
  #noinspection RubyScope
70
70
  def request(http_request, timeout = 300, tries = 20)
71
- @cui.error("DEBUG[#{Thread.current.inspect}]: Trying to lock ProxyHTTP request mutex in thread #{Thread.current.inspect}") if $myDEBUG
72
71
  @mutex.synchronize {
73
- @cui.error("DEBUG[#{Thread.current.inspect}]: Got ProxyHTTP request mutex in thread #{Thread.current.inspect}") if $myDEBUG
74
72
  response = ''
75
73
  while tries > 0 do
76
- @cui.error("DEBUG[#{Thread.current.inspect}]: Got #{tries} tries left for request #{http_request.inspect} #{http_request.path}, timeout #{timeout}") if $myDEBUG
77
74
  begin
78
75
  Timeout::timeout(timeout) {
79
- @cui.error("DEBUG[#{Thread.current.inspect}]: Sending request #{http_request.inspect} for #{http_request.path}....") if $myDEBUG
80
76
  response = @http.request(http_request)
81
77
  }
82
78
  rescue Timeout::Error
83
79
  tries -= 1
84
- @cui.error("Timeout during request. #{tries} tries left")
80
+ @cui.error("Timeout during request. #{tries} tries left", true, true)
85
81
  retry if tries > 0
86
82
  raise
87
83
  rescue Exception => ex
88
- @cui.error("Caught exception #{ex} with message #{ex.message} during request. #{tries} tries left") if $myVERBOSE
84
+ @cui.error("Caught exception #{ex} with message #{ex.message} during request. #{tries} tries left", true, false)
89
85
  tries -= 1
90
86
  retry if tries > 0
91
87
  raise
92
88
  end
93
89
  code = response.code.to_i
94
- @cui.error("DEBUG[#{Thread.current.inspect}]: Response code: #{code}") if $myDEBUG
95
90
  return response if (code >= 200) and (code < 300)
96
91
  if (code >= 400) and (code < 500) # No retries for these errors...
97
92
  # Yeehaw! we need an exception for code 401 since humyo sometimes replies with it with correct authorization
98
93
  tries = 0 if (code != 401)
99
94
  end
100
95
  tries -= 1
101
- @cui.error("DEBUG[#{Thread.current.inspect}]: #{tries} tries left for this request. Retrying after sleep if > 0") if $myDEBUG
102
96
  sleep(rand) if tries > 0 # Sleep up to one second before retrying
103
97
  end
104
- @cui.error("DEBUG[#{Thread.current.inspect}]: Raising exception for failed request: #{response.code} #{response.message}") if $myDEBUG
105
98
  raise 'HTTP request failed: ' + response.code + ' ' + response.message
106
99
  }
107
100
  end
@@ -118,7 +111,6 @@ class ProxyHTTP
118
111
  get = Net::HTTP::Get.new(uri.request_uri)
119
112
  get.initialize_http_header({"User-Agent" => $options[:user_agent]})
120
113
  get.basic_auth($options[:username], $options[:password])
121
- @cui.error("DEBUG[#{Thread.current.inspect}]: Reading from #{uri.to_s}") if $myDEBUG
122
114
  begin
123
115
  response = request(get, $options[:http_timeout])
124
116
  rescue Exception => ex
@@ -142,22 +134,19 @@ class ProxyHTTP
142
134
  put.initialize_http_header({"User-Agent" => $options[:user_agent], "Content-Type" => "application/octet-stream"})
143
135
  put.basic_auth($options[:username], $options[:password])
144
136
  put.body = data
145
- @cui.error("DEBUG[#{Thread.current.inspect}]: Writing to #{uri.to_s}") if $myDEBUG
146
137
  begin
147
138
  response = request(put, 180)
148
139
  rescue RuntimeError => ex
149
140
  if ex.message == "HTTP request failed: 409 Conflict" then
150
- @cui.error("DEBUG[#{Thread.current.inspect}]: Caught a 409 Conflict error") if $myDEBUG
151
141
  if (subdir_type != type) then
152
142
  begin
153
- @cui.error("DEBUG[#{Thread.current.inspect}]: Trying to create the directory #{@url.merge(@types[type] + '/').to_s}") if $myDEBUG
154
143
  mkdir(@url.merge(@types[type] + '/'))
155
144
  rescue RuntimeError => rt
156
145
  @cui.error("DEBUG[#{Thread.current.inspect}]: Caught exception during mkdir: #{rt.message}") if $myDEBUG
157
146
  raise if rt.message[0..23] != "HTTP request failed: 405"
158
147
  end
159
148
  end
160
- @cui.error("DEBUG[#{Thread.current.inspect}]: Trying to create the directory #{@url.merge(@types[type] + '/').merge(subdir).to_s}") if $myDEBUG
149
+ @cui.message("Trying to create the directory #{@url.merge(@types[type] + '/').merge(subdir).to_s}", true, false)
161
150
  mkdir(@url.merge(@types[type] + '/').merge(subdir))
162
151
  end
163
152
  retry
@@ -166,7 +155,6 @@ class ProxyHTTP
166
155
  raise
167
156
  else
168
157
  @cache.add(type, file) if @@valid_caches.include?(type)
169
- @cui.error("DEBUG[#{Thread.current.inspect}]: Added #{file} to cache list for #{subdir_type}") if $myDEBUG
170
158
  return true
171
159
  end
172
160
  end
@@ -175,7 +163,7 @@ class ProxyHTTP
175
163
  mkcol = Net::HTTP::Mkcol.new(uri.request_uri)
176
164
  mkcol.initialize_http_header({"User-Agent" => $options[:user_agent]})
177
165
  mkcol.basic_auth($options[:username], $options[:password])
178
- @cui.error("DEBUG[#{Thread.current.inspect}]: Trying to create directory #{uri.to_s}") if $myDEBUG
166
+ @cui.message("Trying to create directory #{uri.to_s}", true, false)
179
167
  begin
180
168
  request(mkcol)
181
169
  rescue Exception => ex
@@ -11,8 +11,6 @@ require 'digest/md5'
11
11
  require 'digest/sha2'
12
12
  require 'time'
13
13
 
14
- $myDEBUG = false if not $myDEBUG
15
- $myVERBOSE = false if not $myVERBOSE
16
14
  $options = nil unless $options
17
15
 
18
16
  class SMGFile
@@ -69,33 +67,23 @@ class SMGFile
69
67
  size = 0
70
68
  md5hashing = Digest::MD5.new
71
69
  sha256hashing = Digest::SHA2.new(256)
72
- @cui.message("DEBUG[#{Thread.current.inspect}: Created hashing objects") if $myDEBUG
73
70
  chunks = ''
71
+ gc_counter = -1 # Initialize a counter for the garbage collection
74
72
  while !fd.eof?
75
- @cui.message("DEBUG[#{Thread.current.inspect}: Checked for EOF") if $myDEBUG
73
+ GC.start if ((gc_counter += 1) % 30) == 0 # Run the garbage collection every now and then
76
74
  chunk = Chunk.new
77
- @cui.message("DEBUG[#{Thread.current.inspect}: Created new chunk") if $myDEBUG
78
75
  data = fd.read($options[:chunk_size])
79
- @cui.message("DEBUG[#{Thread.current.inspect}: Read data") if $myDEBUG
80
76
  chunk.set_data(data)
81
- @cui.message("DEBUG[#{Thread.current.inspect}: Saved data in chunk") if $myDEBUG
82
77
  md5hashing << data
83
- @cui.message("DEBUG[#{Thread.current.inspect}: hashed for MD5") if $myDEBUG
84
78
  sha256hashing << data
85
- @cui.message("DEBUG[#{Thread.current.inspect}: hashed for sha256") if $myDEBUG
86
79
  size += data.length
87
- @cui.message("DEBUG[#{Thread.current.inspect}: Updated read size") if $myDEBUG
88
80
  chunk.backup! # Upload this chunk
89
- @cui.message("DEBUG[#{Thread.current.inspect}: backed up chunk") if $myDEBUG
90
81
  chunks += chunk.sha256 + '.' + chunk.md5 + "\n"
91
82
  @cui.finished_size_add(data.length)
92
83
  end
93
84
  fd.close()
94
- @cui.message("DEBUG[#{Thread.current.inspect}: Closed FD") if $myDEBUG
95
85
  md5 = md5hashing.hexdigest
96
- @cui.message("DEBUG[#{Thread.current.inspect}: Got MD5") if $myDEBUG
97
86
  sha256 = sha256hashing.hexdigest
98
- @cui.message("DEBUG[#{Thread.current.inspect}: Got sha256") if $myDEBUG
99
87
  # Build the metadata file
100
88
  @metadata = "[stat]\n"
101
89
  @metadata += "filename = " + @filename + "\n"
@@ -112,14 +100,12 @@ class SMGFile
112
100
  @metadata += "\n"
113
101
  @metadata += "[chunks]\n"
114
102
  @metadata += chunks
115
- @cui.message("Size mismatch: expected #{expected_size} but found #{size}!") if expected_size != size
103
+ @cui.message("Size mismatch: expected #{expected_size} but found #{size}!", true, true) if expected_size != size
116
104
  @size = size
117
105
  @mtime = mtime
118
- @cui.message("DEBUG[#{Thread.current.inspect}: Checking if file already exists on server") if $myDEBUG
119
106
  return true if @target.exists?(:file, "#{meta_sha256}.#{meta_md5}") # if this chunk already exists, no need to upload it
120
- @cui.message("Uploading file metadata #{@filename}: #{meta_sha256}.#{meta_md5}...") if $myDEBUG
107
+ @cui.message("Uploading file metadata #{@filename}: #{meta_sha256}.#{meta_md5}...", true, true)
121
108
  @target.write(:file, "#{meta_sha256}.#{meta_md5}", @metadata)
122
- @cui.message("DEBUG[#{Thread.current.inspect}: Uploaded file metadata") if $myDEBUG
123
109
  end
124
110
 
125
111
  def backup_dir()
@@ -141,12 +127,11 @@ class SMGFile
141
127
  @size = 0
142
128
  @mtime = mtime
143
129
  return true if @target.exists?(:file, "#{meta_sha256}.#{meta_md5}") # if this chunk already exists, no need to upload it
144
- @cui.message("Uploading directory metadata #{@filename}: #{meta_sha256}.#{meta_md5}...") if $myVERBOSE
130
+ @cui.message("Uploading directory metadata #{@filename}: #{meta_sha256}.#{meta_md5}...", true, true)
145
131
  @target.write(:file, "#{meta_sha256}.#{meta_md5}", @metadata)
146
132
  end
147
133
 
148
134
  def backup_link()
149
- @cui.message("Backing up link #{@filename}") if $myVERBOSE
150
135
  stat = @source.lstat(@filename)
151
136
  ftype = stat.ftype
152
137
  mtime = stat.mtime.utc.rfc2822
@@ -164,7 +149,7 @@ class SMGFile
164
149
  @size = 0
165
150
  @mtime = mtime
166
151
  return true if @target.exists?(:file, "#{meta_sha256}.#{meta_md5}") # if this chunk already exists, no need to upload it
167
- @cui.message("Uploading file metadata #{@filename}: #{meta_sha256}.#{meta_md5}...") if $myVERBOSE
152
+ @cui.message("Uploading file metadata #{@filename}: #{meta_sha256}.#{meta_md5}...", true, true)
168
153
  @target.write(:file, "#{meta_sha256}.#{meta_md5}", @metadata)
169
154
  end
170
155
 
@@ -218,9 +203,9 @@ class SMGFile
218
203
  md5 = md5hashing.hexdigest
219
204
  sha256 = sha256hashing.hexdigest
220
205
  if (@md5 = md5) and (@sha256 = sha256) then
221
- @cui.message("File verified")
206
+ @cui.message("File verified", true, true)
222
207
  else
223
- @cui.error("Checksum error in file #{@filename}: #{sha256}.#{md5}")
208
+ @cui.error("Checksum error in file #{@filename}: #{sha256}.#{md5}", true, true)
224
209
  end
225
210
  end
226
211
 
@@ -43,16 +43,15 @@ class Target
43
43
  else
44
44
  raise "No idea how to connect to #{$options[:target]}"
45
45
  end
46
- @cui.message("Initialized proxy as #{@proxy.class}.") if $myVERBOSE
46
+ @cui.message("Initialized proxy as #{@proxy.class}.", true, true)
47
47
  begin
48
48
  if @proxy.caching? then
49
49
  if not $options[:empty_cache] then
50
- @cui.message("Trying to restore cache...") if $myVERBOSE
50
+ @cui.message('Trying to restore cache...', true, false)
51
51
  compressed_cache_data = read(:cache, "flist")
52
52
  begin
53
53
  # Check if the data is compressed and uncompress the data
54
54
  cache_data = Zlib::Inflate.inflate(compressed_cache_data)
55
- @cui.message("Uncompressed cache data from #{compressed_cache_data.length} bytes to #{cache_data.length} bytes.")
56
55
  rescue Exception
57
56
  # Uncompress failed, so the data was probably uncompressed from the beginning.
58
57
  cache_data = compressed_cache_data
@@ -102,15 +101,15 @@ class Target
102
101
  rescue Exception
103
102
  # Seems like compression does not work. We'll just use the uncompressed data then.
104
103
  compressed_cache_data = cache_data
105
- @cui.message('Unable to compress the cache data for upload. Using uncompressed data.')
104
+ @cui.message('Unable to compress the cache data for upload. Using uncompressed data.', true, false)
106
105
  end
107
- @cui.error("DEBUG[#{Thread.current.inspect}]: Cache has a length of #{compressed_cache_data.length}. Uploading...") if $myDEBUG
106
+ @cui.message("Cache has a length of #{compressed_cache_data.length}. Uploading...", true, false)
108
107
  write(:cache, 'flist', compressed_cache_data)
109
108
  end
110
109
  end
111
110
 
112
111
  def export_key()
113
- @cui.error("DEBUG[#{Thread.current.inspect}]: Exporting keys...") if $myDEBUG
112
+ @cui.message("Exporting keys...", true, true)
114
113
  IO.popen('"' + $options[:gpg_bin] + '" ' + '--export-ownertrust', 'w+') do | gpg |
115
114
  gpg.close_write()
116
115
  trust = gpg.read()
@@ -2,6 +2,7 @@ require 'singleton'
2
2
  #noinspection RubyResolve
3
3
  require 'thread'
4
4
 
5
+ $options = nil unless $options
5
6
 
6
7
  # Usage of stdout and stderr:
7
8
  # stdout will be used for normal status messages like the status bar.
@@ -29,6 +30,7 @@ class Cui
29
30
  @changed = false
30
31
  @active = false
31
32
  @exists = true
33
+ @logfile = nil
32
34
  end
33
35
  def exists(e)
34
36
  @exists = e
@@ -66,6 +68,7 @@ class Cui
66
68
  @last_file_name = @current_file_name
67
69
  @current_file_name = file.to_str
68
70
  update
71
+ write_log("File: #{file.to_s} (#{@finished_files + 1}/#{@total_files}; #{(@finished_size/1024/1024).to_i.to_s} MB/#{(@total_size/1024/1024).to_i.to_s} MB)")
69
72
  }
70
73
  end
71
74
  def start()
@@ -108,34 +111,40 @@ class Cui
108
111
  $stdout.print(backspace + line)
109
112
  @changed = false
110
113
  end
111
- def message(text)
114
+ def message(text, logging = false, write_stdout = true)
112
115
  @mutex.synchronize {
113
- case @active
114
- when true
115
- backspace = ("\b" * @last_length)
116
- text += " " * (@last_length - text.length) if (@last_length - text.length) > 0
117
- @last_length = 0
118
- $stdout.print(backspace + text + "\n")
119
- update
120
- when false
121
- # If there's no regular update, we can just write out a new line
122
- $stdout.print("\n" + text + "\n")
116
+ write_log(text) if logging
117
+ if write_stdout then
118
+ case @active
119
+ when true
120
+ backspace = ("\b" * @last_length)
121
+ text += " " * (@last_length - text.length) if (@last_length - text.length) > 0
122
+ @last_length = 0
123
+ $stdout.print(backspace + text + "\n")
124
+ update
125
+ when false
126
+ # If there's no regular update, we can just write out a new line
127
+ $stdout.print("\n" + text + "\n")
128
+ end
123
129
  end
124
130
  }
125
131
  end
126
- def error(text)
132
+ def error(text, logging = true, write_stderr = true)
127
133
  @mutex.synchronize {
128
- case @active
129
- when true
130
- backspace = ("\b" * @last_length) # Calculate the amount of backspaces required
131
- spaces = ""
132
- spaces = " " * (@last_length - text.length) if (@last_length - text.length) > 0
133
- $stderr.print(backspace + text + spaces + "\n")
134
- @last_length = 0
135
- update
136
- when false
137
- # If there's no regular update, we can just write out a new line
138
- $stdout.print("\n" + text + "\n")
134
+ write_log(text) if logging
135
+ if write_stderr then
136
+ case @active
137
+ when true
138
+ backspace = ("\b" * @last_length) # Calculate the amount of backspaces required
139
+ spaces = ""
140
+ spaces = " " * (@last_length - text.length) if (@last_length - text.length) > 0
141
+ $stderr.print(backspace + text + spaces + "\n")
142
+ @last_length = 0
143
+ update
144
+ when false
145
+ # If there's no regular update, we can just write out a new line
146
+ $stdout.print("\n" + text + "\n")
147
+ end
139
148
  end
140
149
  }
141
150
  end
@@ -145,4 +154,12 @@ class Cui
145
154
  @update_thread.join
146
155
  @update_thread = nil
147
156
  end
157
+ def write_log(text)
158
+ return if $options[:logfile].nil?
159
+ @logfile = File.new($options[:logfile], "w:utf-8") if @logfile.nil?
160
+ date_time = Time.now.strftime('%Y-%m-%d %H:%M:%S')
161
+ text = date_time + " " + text + "\n"
162
+ @logfile.write(text)
163
+ @logfile.flush
164
+ end
148
165
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
8
- - 5
9
- version: 0.0.5
7
+ - 1
8
+ - 6
9
+ version: 0.1.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - Daniel Frank