max_size_detector 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1d7c8a074c02d399dc59d47e8853b64dc442c79b849c94308796604b97a6f73f
4
+ data.tar.gz: 7cb716a30b9656bf1f4a27d33d39e4e7deaaecac4a1ef4a3572f4ee69f93b4b2
5
+ SHA512:
6
+ metadata.gz: e111c8248e0b585361418e2ed17e0a439c9b6155c58c17b11384560b50b03c75385dadfa4f74cc3ec1399785d76c9479558ecdbb78e51591887cd0349a3593ba
7
+ data.tar.gz: fbcf48a35555abc53df666832c0a6bb4a2aeee5e27e0619989b854b649613cc569c6ec2f2149a1c1c93ab7d345a943c9fa0e69470b12355adb7c696cfc6bf5f4
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "max_size_detector"
4
+
5
+ file = ARGV[0]&.strip || "input.txt"
6
+ max_size = if file.to_i.zero?
7
+ ARGV[1]&.strip || MaxSizeDetector::FILES_MAX_SIZE
8
+ else
9
+ file
10
+ end
11
+ file = "input.txt" if file.to_i.positive?
12
+
13
+ MaxSizeDetector.run(file: file, max_size: max_size)
@@ -0,0 +1,200 @@
1
+ require "json"
2
+ require "open-uri"
3
+
4
+ class MaxSizeDetector
5
+ class Base
6
+ attr_reader :input_file, :lines, :files, :directories, :output
7
+
8
+ def initialize(**opts)
9
+ filename = opts[:filename] || opts[:file]
10
+ @input_file = open(filename)
11
+ @max_size = opts[:max_size].to_i
12
+ @lines = Array.new
13
+ @files = Hash.new
14
+ @output = Hash.new
15
+
16
+ rescue => error
17
+ print " FAILED!\n#{error}"
18
+ end
19
+
20
+ def extract!
21
+ return unless @input_file
22
+
23
+ extract_lines!
24
+ extract_files!
25
+ end
26
+
27
+ def process!
28
+ return unless @input_file
29
+
30
+ files_within_max_size = extract_files_by_max_size
31
+ grouped = group_by(hash_key: :parent_directory, files: files_within_max_size)
32
+ content_to_hash!(grouped)
33
+
34
+ @output = extract_files_by_max_size(files: grouped)
35
+ output_within_max_size!
36
+ end
37
+
38
+ def show_output
39
+ JSON.pretty_generate(JSON.parse(@output.to_json))
40
+ end
41
+
42
+ protected
43
+
44
+ def extract_lines!
45
+ @lines = @input_file.readlines.map do |line|
46
+ line_str = line.to_s
47
+ line_str.end_with?("\n") ? line_str[0..-2] : line_str
48
+ end
49
+ end
50
+
51
+ def extract_files!
52
+ keys = {}
53
+ @lines.each_with_index do |line, idx|
54
+ next unless file?(line)
55
+
56
+ parts = extract_file(line)
57
+ filename = parts.keys.first
58
+ filename!(keys, filename)
59
+
60
+ file = init_file(filename)
61
+ file_hash = file[filename]
62
+ file_hash[:size] = parts[filename]
63
+
64
+ parent_directory!(file_hash, idx)
65
+
66
+ @files.merge!(file)
67
+ end
68
+ end
69
+
70
+ def output_within_max_size!
71
+ new_output = Array.new
72
+ @output.to_a.repeated_combination(2) do |combi|
73
+ a = combi.first
74
+ b = combi.last
75
+ next if a == b
76
+
77
+ a_val = a[1]
78
+ b_val = b[1]
79
+ total = a_val[:size].to_i + b_val[:size].to_i
80
+ next if total > @max_size
81
+
82
+ c = new_total = nil
83
+ @output.each do |key, val|
84
+ next unless percent_up?(val[:size].to_i + total, percent: 80)
85
+
86
+ c = [key, val]
87
+ new_total = val[:size].to_i + total
88
+ break
89
+ end
90
+
91
+ if new_total && new_total < @max_size && a[0] != c[0] && b[0] != c[0]
92
+ new_output << Hash[
93
+ a[0] => a_val,
94
+ b[0] => b_val,
95
+ c[0] => c[1],
96
+ total: new_total
97
+ ]
98
+ elsif percent_up?(total, percent: 80)
99
+ new_output << Hash[
100
+ a[0] => a_val,
101
+ b[0] => b_val,
102
+ total: total
103
+ ]
104
+ end
105
+ end
106
+
107
+ @output = new_output.sort_by { |no| -no[:total] }
108
+ end
109
+
110
+ private
111
+
112
+ def directory?(command)
113
+ return false if command.start_with?("$")
114
+
115
+ command.include?("dir ")
116
+ end
117
+
118
+ def file?(command)
119
+ return false if directory?(command) ||
120
+ command.start_with?("$")
121
+
122
+ extract_file(command).values.first.to_i.positive?
123
+ end
124
+
125
+ def sanitize_string(str)
126
+ str.delete("$").strip
127
+ end
128
+
129
+ def extract_parts(command)
130
+ sanitize_string(command).split(" ")
131
+ end
132
+
133
+ def extract_file(command)
134
+ parts = extract_parts(command)
135
+
136
+ Hash[
137
+ parts.last.to_s => parts.first.to_i
138
+ ]
139
+ end
140
+
141
+ def filename!(hash, key)
142
+ hash[key] = hash.key?(key) ? hash[key] + 1 : 1
143
+ return unless hash[key] > 1
144
+
145
+ key += "-#{hash[key]}"
146
+ end
147
+
148
+ def init_file(key)
149
+ Hash[
150
+ key => Hash[
151
+ parent_directory: nil,
152
+ ]
153
+ ]
154
+ end
155
+
156
+ def parent_directory!(file_hash, idx)
157
+ ctr = 1
158
+ while file_hash[:parent_directory].nil? do
159
+ command = sanitize_string(@lines[idx - ctr])
160
+ ctr += 1
161
+ if command == "ls"
162
+ command = sanitize_string(@lines[idx - ctr])
163
+ file_hash[:parent_directory] = command.split(" ").last.to_s
164
+ end
165
+ end
166
+ end
167
+
168
+ def group_by(files: @files, hash_key: :parent_directory)
169
+ files.group_by { |_key, val| val[hash_key] }.transform_values(&:flatten)
170
+ end
171
+
172
+ def extract_files_by_max_size(files: @files)
173
+ within_max_size = Hash.new
174
+ files.each do |key, val|
175
+ new_val = val.clone
176
+ new_val = Hash[*new_val] unless new_val.is_a?(Hash)
177
+ next if new_val[:size].to_i > @max_size
178
+
179
+ within_max_size.merge!(key => new_val)
180
+ end
181
+ within_max_size
182
+ end
183
+
184
+ def content_to_hash!(grouped)
185
+ grouped.each do |key, val|
186
+ val_h = val.each_slice(2).to_h
187
+ grouped[key] = Hash.new unless grouped[key].is_a?(Hash)
188
+ group_h = grouped[key]
189
+ group_h[:files] = val_h.map { |k, v| [k, v[:size]] }.to_h
190
+ group_h[:size] = group_h[:files].values.sum
191
+ end
192
+ end
193
+
194
+ def percent_up?(num, percent: 90)
195
+ percentage = (num.to_f / @max_size.to_f) * 100
196
+ percentage.to_i > percent
197
+ end
198
+
199
+ end
200
+ end
@@ -0,0 +1,34 @@
1
+ class MaxSizeDetector
2
+ FILES_MAX_SIZE = 100_000
3
+
4
+ def self.run(**opts)
5
+ file = opts[:file] || opts[:filename]
6
+ max_size = opts[:max_size]
7
+
8
+ print "Opening file #{file} ..."
9
+ base = Base.new(**opts)
10
+ return puts "" if base.input_file.nil?
11
+
12
+ random_done!
13
+
14
+ print "Extracting file structure ..."
15
+ base.extract!
16
+ random_done!
17
+
18
+ print "Finding directories up to #{max_size} ..."
19
+ base.process!
20
+ random_done!
21
+
22
+ puts "Output:"
23
+ puts base.show_output
24
+ end
25
+
26
+ private
27
+
28
+ def self.random_done!
29
+ sleep(rand(2..7))
30
+ print " DONE!\n"
31
+ end
32
+ end
33
+
34
+ require "max_size_detector/base"
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: max_size_detector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - MarLo MoraLes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This gem allows you to analyze an input file (contains several terminal
14
+ commands and output related to files and directories) and finally detect all directories
15
+ candidate for deletion based on the maximum size.
16
+ email: moralesmarlo@hotmail.com
17
+ executables:
18
+ - max_size_detector
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - bin/max_size_detector
23
+ - lib/max_size_detector.rb
24
+ - lib/max_size_detector/base.rb
25
+ homepage: https://rubygems.org/gems/ruby_max_size_detector
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 3.3.7
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Ruby Max Size Detector
48
+ test_files: []