storazzo 0.0.5 → 0.0.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/ricdisk-magic.rb +395 -0
  3. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b6f11122ebdc242a695b25dee97fc6d09d2059df95f7318b42679a66ccfd9c3
4
- data.tar.gz: '045047399e27b7b9bf55ae5230babb9443dd5903adbabcdf562f16eec1e1b258'
3
+ metadata.gz: 06f3ee99606822e20e1d8410578fd8194b416f9ccdcc4cf2a17d1b7a44e09d45
4
+ data.tar.gz: c92b3712561fb31e049052f35ffe500800b5dab6537eb0cb8f2313e898b2558d
5
5
  SHA512:
6
- metadata.gz: 618bfb7e3664ae8fe0f8429e1c8527aec76bdfd5c37f4cc1693ebfbc41ba94bd0235c13738479f3f2ea31da593d1483ca2c25881edd3be1a8757f2cf3b892fbf
7
- data.tar.gz: 37e515b93523cc8b0b31791152edff586d3a8dfd5490b7b889b0595dbea31ac2a69a2b4b7cdd2c37187fbe545b133921333185ea1a1e48136aead9fc073df49a
6
+ metadata.gz: 3c05485035eee8f1092a8c8c05a765f3d1492233ec22b8bf3539ad82bc6ded2cc46cbaacb49bb86539fdea6ee48c8a99c491a6daab1f0b3f6d408af48f610669
7
+ data.tar.gz: 79c252ed51045da677895a8c5e891de78e7490354212eaa4a93594914734ee66eff0423e643aecb3d476b5d8c2367f6900bd625a21e7bbc9f0cf0a3a790397ed
@@ -0,0 +1,395 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #require 'google/protobuf'
4
+ #require_relative '../etc/protos/out/ricdisk_pb'
5
+ require 'yaml'
6
+ require 'socket'
7
+ require 'optparse' # http://ruby.about.com/od/advancedruby/a/optionparser.htm
8
+ require 'storazzo'
9
+ # required to have methods wiothout self.
10
+ extend Storazzo::Colors
11
+
12
+ if RUBY_VERSION.split('.')[0] == 1
13
+ puts "Refusing to launch a script form Ruby 1. Sorry Ric, its 2020 damn it!"
14
+ exit 2020
15
+ end
16
+
17
+ $PROG_VER = '0.3'
18
+ $DEBUG = false
19
+
20
+ HISTORY = <<-BIG_LONG_MULTILINE
21
+ 2022-07-11 v0.3 Ported from private files in GIC into storazzo (open source on gitHub) and cleaned up italian and libs
22
+ 2022-07-DD v0.2 Some private stuff on GIC
23
+ BIG_LONG_MULTILINE
24
+
25
+ =begin
26
+
27
+ ############################################################
28
+ @author: Riccardo Carlesso
29
+ @email: riccardo.carlesso@gmail.com
30
+ @maturity: development
31
+ @language: Ruby
32
+ @synopsis: Brief Description here
33
+ @tags: development, rcarlesso, test
34
+ @description: See description
35
+ ############################################################
36
+
37
+ =end
38
+
39
+
40
+ $myconf = {
41
+ :app_name => "RicDisk Magic should be sth like #{$0}",
42
+ :description => "
43
+ This program is loosely inspired to ricdisk-magic.sh but its much better.
44
+ Idea di base: trovare tutti le directory con file ricdisk e da esso estrarre info e magari METTERE info.
45
+ Il tutto condito con un bel protobuf e un'entita che metto in Lib.
46
+ ".strip.gsub(/^\s+/, "").gsub(/\s+$/, ""),
47
+ # TODO move to some class default
48
+ :media_dirs => %w{ /media/riccardo/ /Volumes/ /mnt/ ~/git/storazzo/test/ /sobenme/giusto/per/imparare/ad/ammutolire/gli/errori/ },
49
+ :mount_types => %w{ vfat ntfs },
50
+ }
51
+ $stats_file = "ricdisk_stats_v11.rds"
52
+ $gcs_bucket = 'palladius'
53
+
54
+ # This template from scripta.rb. from 2.1.0 removed aby ric gem dependency.
55
+ # 2022-04-26 2.1.1 Added more colors
56
+ # 2022-04-26 2.1.0 Historical momemnt: removed gem 'ric' dependency
57
+ $TEMPLATE_VER = '2.1.1'
58
+
59
+ # copied from https://dev.to/ayushn21/how-to-generate-yaml-from-ruby-objects-without-type-annotations-4fli
60
+ module Hashify
61
+ # Classes that include this module can exclude certain
62
+ # instance variable from its hash representation by overriding
63
+ # this method
64
+ def ivars_excluded_from_hash
65
+ [ 'this_doesnt_exist' ]
66
+ end
67
+
68
+ def to_hash
69
+ hash = {}
70
+ excluded_ivars = ivars_excluded_from_hash
71
+
72
+ # Iterate over all the instance variables and store their
73
+ # names and values in a hash
74
+ instance_variables.each do |var|
75
+ next if excluded_ivars.include? var.to_s
76
+
77
+ value = instance_variable_get(var)
78
+ value = value.map(&:to_hash) if value.is_a? Array
79
+
80
+ hash[var.to_s.delete("@")] = value
81
+ end
82
+
83
+ return hash
84
+ end
85
+
86
+ def to_yaml
87
+ to_hash.to_yaml
88
+ end
89
+ end
90
+
91
+ # TODO move to lib/ric_disk/
92
+ class RicDisk
93
+ VERSION = "1.0"
94
+ include Hashify
95
+ extend Storazzo::Colors
96
+
97
+
98
+ # todo substitute wqith protobuf..
99
+ attr_accessor :name, :description, :ricdisk_file, :local_mountpoint, :wr
100
+
101
+ def self.interesting_mount_points(opts={})
102
+ #https://unix.stackexchange.com/questions/177014/showing-only-interesting-mount-points-filtering-non-interesting-types
103
+ `mount | grep -Ev 'type (proc|sysfs|tmpfs|devpts|debugfs|rpc_pipefs|nfsd|securityfs|fusectl|devtmpfs) '`.split(/\n+/)
104
+ end
105
+
106
+ def initialize(path, ricdisk_file)
107
+ @local_mountpoint = path
108
+ @description = "This is an automated RicDisk description from v.#{VERSION}. Riccardo feel free to edit away with characteristicshs of this device.. Created on #{Time.now}'"
109
+ @ricdisk_version = VERSION
110
+ @ricdisk_file = ricdisk_file
111
+ #@questo_non_esiste = :sobenme
112
+ @label = path.split("/").last
113
+ @name = path.split("/").last
114
+ @wr = File.writable?("#{path}/#{ricdisk_file}" ) # .writeable?
115
+ @tags = 'ricdisk'
116
+ find_info_from_mount(path)
117
+ find_info_from_df()
118
+ end
119
+
120
+ def ricdisk_absolute_path
121
+ @local_mountpoint + "/" + @ricdisk_file
122
+ end
123
+
124
+ def add_tag(tag)
125
+ @tags += ", #{tag}"
126
+ end
127
+
128
+ # might have other things in the future...
129
+ def find_info_from_mount(path)
130
+ mount_table_lines = interesting_mount_points()
131
+ mount_line = nil
132
+ mount_table_lines.each do |line|
133
+ next if line =~ /^map /
134
+ dev, on, mount_path, mode = line.split(/ /)
135
+ if mount_path==path
136
+ mount_line = line
137
+ else
138
+ @info_from_mount = false
139
+ end
140
+ end
141
+ @info_from_mount = ! (mount_line.nil?)
142
+ if @info_from_mount
143
+ #@mount_line = mount_line
144
+ @description += "\nMount line:\n" + mount_line
145
+ @remote_mountpoint = mount_line.split(/ /)[0]
146
+ @fstype = mount_line.split(/ /)[3].gsub(/[\(,]/, '')
147
+ add_tag(:synology) if @remote_mountpoint.match('1.0.1.10')
148
+ end
149
+ end
150
+
151
+ def find_info_from_df()
152
+ path = @local_mountpoint
153
+ df_info = `df -h "#{path}"`
154
+ @df_info = df_info
155
+ lines = df_info.split(/\n+/)
156
+ raise "I need exactly TWO lines! Or no info is served here..." unless lines.size == 2
157
+ mount, @size_readable, used_size, avail_size, @disk_utilization, other = lines[1].split(/\s+/) # second line..
158
+ end
159
+
160
+
161
+
162
+ def self.sbrodola_ricdisk(subdir)
163
+ # given a path, if .ricdisk exists i do stuff with it..
164
+ disk_info = nil
165
+ unless self.ok_dir?(subdir)
166
+ puts("Nothing for me here. Existing")
167
+ return
168
+ end
169
+ if File.exists?( "#{subdir}/.ricdisk") and File.empty?( "#{subdir}/.ricdisk")
170
+ deb("Interesting1. Empty file! Now I write YAML with it.")
171
+ disk_info = RicDisk.new(subdir, '.ricdisk')
172
+ #puts(x)
173
+ #puts(yellow x.to_yaml)
174
+ end
175
+ if File.exists?( "#{subdir}/.ricdisk.yaml") and File.empty?( "#{subdir}/.ricdisk.yaml")
176
+ deb("Interesting2. Empty file! TODO write YAML with it.")
177
+ disk_info = RicDisk.new(subdir, '.ricdisk.yaml')
178
+ # todo write
179
+ #puts(x)
180
+ puts(yellow disk_info.to_yaml)
181
+ end
182
+ if disk_info
183
+ if File.empty?(disk_info.ricdisk_absolute_path) and (disk_info.wr)
184
+ puts(green("yay, we can now write the file '#{disk_info.ricdisk_absolute_path}' (which is R/W, I just checked!) with proper YAML content.."))
185
+ ret = File.write(disk_info.ricdisk_absolute_path, disk_info.to_yaml)
186
+ puts("Written file! ret=#{ret}")
187
+ else
188
+ puts(red("Nope, qualcosa non va.. #{File.empty?(disk_info.ricdisk_absolute_path)}"))
189
+ puts("File size: #{File.size(disk_info.ricdisk_absolute_path)}")
190
+ end
191
+ end
192
+ if File.exists?( "#{subdir}/.ricdisk") and ! File.empty?( "#{subdir}/.ricdisk")
193
+ puts("Config File found with old-style name: '#{subdir}/.ricdisk' !")
194
+ #puts(white `cat "#{subdir}/.ricdisk"`)
195
+ end
196
+ end
197
+
198
+ # separiamo cosi usiamo meglio...
199
+ def self.ok_dir?(subdir)
200
+ File.exists?( "#{subdir}/.ricdisk") or File.exists?( "#{subdir}/.ricdisk.yaml")
201
+ end
202
+
203
+ def self.obsolescence_seconds file_path
204
+ creation_time = File.stat(file_path).ctime
205
+ deb("[obsolescence_seconds] File #{file_path}: #{creation_time} - #{(Time.now - creation_time)} seconds ago")
206
+ (Time.now - creation_time).to_i
207
+ end
208
+ def self.obsolescence_days(file_path)
209
+ return obsolescence_seconds(file_path) / 86400
210
+ end
211
+
212
+ def self.backquote_execute(cmd)
213
+ # executed a command wrapped by dryrun though
214
+ return "DRYRUN backquote_execute(#{cmd})" if $opts[:dryrun]
215
+ `#{cmd}`
216
+ end
217
+
218
+ def self.upload_to_gcs(file, opts={})
219
+ deb("upload_to_gcs(#{file}). TODO(ricc) after breafast upload to GCS : #{file}")
220
+ mount_name = file.split('/')[-2]
221
+ filename = "#{mount_name}-#{File.basename file}"
222
+ hostname = Socket.gethostname[/^[^.]+/]
223
+ command = "gsutil cp '#{file}' gs://#{$gcs_bucket}/backup/ricdisk-magic/#{ hostname }-#{filename}"
224
+ deb("Command: #{command}")
225
+ ret = backquote_execute(command)
226
+ # if $opts[:debug] do
227
+ # puts "+ Current list of files:"
228
+ # ret = backquote_execute("gsutil ls -al gs://#{$gcs_bucket}/backup/ricdisk-magic/")
229
+ # puts ret
230
+ # end
231
+ ret
232
+ end
233
+
234
+ # Create RDS file.
235
+ def self.calculate_stats_files(dir, opts={})
236
+ opts_upload_to_gcs = opts.fetch :upload_to_gcs, true
237
+ full_file_path = "#{dir}/#{$stats_file}"
238
+
239
+ puts("calculate_stats_files(#{white dir}): #{white full_file_path}")
240
+ puts "TEST1 DIR EXISTS: #{dir} -> #{Dir.directory? dir}"
241
+ Dir.chdir(dir)
242
+ if File.exists?(full_file_path) and ($opts[:force] == false)
243
+ puts "File '#{$stats_file}' exists already." # - now should see if its too old, like more than 1 week old"
244
+ # TODO check for file time...
245
+ print "Lines found: #{yellow `wc -l "#{full_file_path}" `.chomp }. File obsolescence (days): #{yellow obsolescence_days(full_file_path)}."
246
+ if obsolescence_days(full_file_path) > 7
247
+ puts("*** ACHTUNG *** FIle is pretty old. You might consider rotating: #{yellow "mv #{full_file_path} #{full_file_path}_old"}. Or invoke with --force")
248
+ end
249
+ upload_to_gcs(full_file_path) if opts_upload_to_gcs
250
+ else
251
+ puts "Crunching data stats from '#{dir}' into '#{$stats_file}' ... please bear with me.. [maybe file didnt exist, maybe $opts[:force] is true]"
252
+ command = "find . -print0 | xargs -0 stats-with-md5.rb --no-color | tee '#{full_file_path}'"
253
+ puts("[#{`pwd`.chomp}] Executing: #{azure command}")
254
+ ret = backquote_execute command
255
+ puts "Done. #{ret.split("\n").count} files processed."
256
+ end
257
+ end
258
+
259
+ def self.find_active_dirs(base_dirs=nil, also_mountpoints=true)
260
+ base_dirs = $myconf[:media_dirs] if base_dirs.nil?
261
+ active_dirs = []
262
+ base_dirs.each do |ugly_dir|
263
+ # https://stackoverflow.com/questions/1899072/getting-a-list-of-folders-in-a-directory#:~:text=Dir.chdir(%27/destination_directory%27)%0ADir.glob(%27*%27).select%20%7B%7Cf%7C%20File.directory%3F%20f%7D
264
+ dir = File.expand_path(ugly_dir)
265
+ begin
266
+ x=[]
267
+ # puts "TEST2 DIR EXISTS: #{dir} -> #{Dir.exists?(dir)}"
268
+ unless Dir.exists?(dir)
269
+ deb "Dir doesnt exist, skipping: #{dir}"
270
+ next
271
+ end
272
+ Dir.chdir(dir)
273
+ x = Dir.glob('*').select {|f| File.directory? f}
274
+ subdirs = x.map{|subdir| "#{dir}#{subdir}"}
275
+ subdirs.each{|subdir|
276
+ #puts `ls -al "#{subdir}"`
277
+ active_dirs << subdir if self.ok_dir?(subdir)
278
+ }
279
+ #puts(white x)
280
+ rescue Exception => e # optionally: `rescue Exception => ex`
281
+ puts "Exception: '#{e}'"
282
+ ensure # will always get executed
283
+ #deb 'Always gets executed.'
284
+ #x = []
285
+ end
286
+ end
287
+
288
+ if also_mountpoints
289
+ =begin
290
+ Example output from mount:
291
+
292
+ devfs on /dev (devfs, local, nobrowse)
293
+ /dev/disk3s6 on /System/Volumes/VM (apfs, local, noexec, journaled, noatime, nobrowse)
294
+ /dev/disk3s2 on /System/Volumes/Preboot (apfs, local, journaled, nobrowse)
295
+ /dev/disk3s4 on /System/Volumes/Update (apfs, local, journaled, nobrowse)
296
+ /dev/disk1s2 on /System/Volumes/xarts (apfs, local, noexec, journaled, noatime, nobrowse)
297
+ /dev/disk1s1 on /System/Volumes/iSCPreboot (apfs, local, journaled, nobrowse)
298
+ /dev/disk1s3 on /System/Volumes/Hardware (apfs, local, journaled, nobrowse)
299
+ /dev/disk3s5 on /System/Volumes/Data (apfs, local, journaled, nobrowse, protect)
300
+ map auto_home on /System/Volumes/Data/home (autofs, automounted, nobrowse)
301
+ //riccardo@1.0.1.10/video on /Volumes/video (afpfs, nodev, nosuid, mounted by ricc)
302
+ //riccardo@1.0.1.10/photo on /Volumes/photo (afpfs, nodev, nosuid, mounted by ricc)
303
+ =end
304
+ # add directories from current mountpoints...
305
+ mount_table_lines = interesting_mount_points()
306
+ mount_table_lines.each{|line|
307
+ next if line =~ /^map /
308
+ dev, on, path, mode = line.split(/ /)
309
+ #puts line
310
+ #deb yellow(path)
311
+ active_dirs << path if self.ok_dir?(path)
312
+ }
313
+ end
314
+ active_dirs.uniq!
315
+ puts("find_active_dirs(): found dirs " + green(active_dirs))
316
+ return active_dirs
317
+ end
318
+
319
+
320
+ end
321
+
322
+ def usage(comment=nil)
323
+ puts white($optparse.banner)
324
+ puts($optparse.summarize)
325
+ puts("Description: " + gray($myconf[:description]))
326
+ puts red(comment) if comment
327
+ #puts "Description: #{ $myconf[:description] }"
328
+ exit 13
329
+ end
330
+
331
+ # include it in main if you want a custome one
332
+ def init() # see lib_autoinit in lib/util.rb
333
+ $opts = {}
334
+ # setting defaults
335
+ $opts[:verbose] = false
336
+ $opts[:dryrun] = false
337
+ $opts[:debug] = false
338
+ $opts[:force] = false
339
+
340
+ $optparse = OptionParser.new do |opts|
341
+ opts.banner = "#{$0} v.#{$PROG_VER}\n Usage: #{File.basename $0} [options] file1 file2 ..."
342
+ opts.on( '-d', '--debug', 'enables debug (DFLT=false)' ) { $opts[:debug] = true ; $DEBUG = true }
343
+ opts.on( '-f', '--force', 'force stuff (DFLT=false)' ) { $opts[:force] = true }
344
+ opts.on( '-h', '--help', 'Display this screen' ) { usage }
345
+ #opts.on( '-j', '--jabba', 'Activates my Jabber powerful CLI' ) { $opts[:jabba] = true }
346
+ opts.on( '-n', '--dryrun', "Don't really execute code" ) { $opts[:dryrun] = true }
347
+ opts.on( '-l', '--logfile FILE', 'Write log to FILE' ) {|file| $opts[:logfile] = file }
348
+ opts.on( '-v', '--verbose', 'Output more information' ) { $opts[:verbose] = true}
349
+ end
350
+ $optparse.parse!
351
+ end
352
+
353
+ def real_program
354
+ deb("Hello world from a templated '#{yellow $0 }'")
355
+ deb "+ Options are: #{gray $opts}"
356
+ deb "+ Depured args: #{azure ARGV}"
357
+ deb "+ Script-specifig super-cool conf: #{green $prog_conf_d}"
358
+ deb "+ Your configuration: #{purple $myconf.inspect}"
359
+
360
+ # Your code goes here...
361
+ puts white("Hello world from #{$myconf[:app_name]}!")
362
+ puts "Description: '''#{white $myconf[:description] }'''"
363
+
364
+ if ARGV == [] # empty -> ALL
365
+ dirs = RicDisk.find_active_dirs()
366
+ dirs.each {|dir|
367
+ RicDisk.sbrodola_ricdisk(dir)
368
+ RicDisk.calculate_stats_files(dir) # dir is inutile
369
+ } # TODO refactor in option sbrodola_afterwards=true. :)
370
+ else
371
+ deb "I consider ARGV come la lista di directories da parsare :)"
372
+ dirs = RicDisk.find_active_dirs()
373
+ ARGV.each{ |dir|
374
+ dir = File.expand_path(dir)
375
+ if dirs.include?(dir)
376
+ deb "Legit dir: #{green dir}"
377
+ RicDisk.sbrodola_ricdisk(dir)
378
+ RicDisk.calculate_stats_files(dir) # dir is inutile
379
+ else
380
+ deb "Figghiu ri buttana: doesnt exist #{red dir}"
381
+ end
382
+ }
383
+ end
384
+ end
385
+
386
+ def main(filename)
387
+ deb "I'm called by #{white filename}"
388
+ deb "HISTORY: #{gray HISTORY}"
389
+ #deb "To remove this shit, just set $DEBUG=false :)"
390
+ init # Enable this to have command line parsing capabilities!
391
+ #warn "[warn] template v#{$TEMPLATE_VER }: proviamo il warn che magari depreca il DEB"
392
+ real_program
393
+ end
394
+
395
+ main(__FILE__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: storazzo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Riccardo Carlesso
@@ -10,12 +10,14 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2022-07-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: A simple hello world gem.. for now. Then... more!
13
+ description: A simple gem to manage your external hard drives and extract MD5 and
14
+ common stuff from them.
14
15
  email: name dot surname at popular Google-owned Mail
15
16
  executables: []
16
17
  extensions: []
17
18
  extra_rdoc_files: []
18
19
  files:
20
+ - bin/ricdisk-magic.rb
19
21
  - lib/storazzo.rb
20
22
  - lib/storazzo/colors.rb
21
23
  - lib/storazzo/translator.rb