crush-rb 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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/crush +138 -0
  3. metadata +46 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0d986921915063502f6e16d91852096ade00ddff463a6970ce2be18b630ca2b6
4
+ data.tar.gz: 58cb0eba18e0513c3df831a1a1aa76188923e259352478220707cb41ed9d562a
5
+ SHA512:
6
+ metadata.gz: a3efb8b4698d71f3142e05ff360443ccb981358922f275e88b86a5b5fa08f4e6c8d65a5f2ceb9df93c4f14587b38279fa61eeffa754f6fc597c517c37757fdf8
7
+ data.tar.gz: a20ad3ac2b93e58a99d955382c3be501472cfbc71d49fd9144c4fd06befaac21865d636ba8b9c82ec48459b54f2c6946c42e004dbedda73f98668e5966965986
data/bin/crush ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tmpdir'
4
+
5
+ VERBOSE = !%w[0 false].include?(ENV.fetch('VERBOSE', '0'))
6
+
7
+ def dbg(msg = nil)
8
+ warn(msg || yield) if VERBOSE
9
+ end
10
+
11
+ def usage!(exit_code: 0)
12
+ method(exit_code.zero? ? :puts : :warn)
13
+ .call("Usage: crush [SWITCHES] path/to/directory/to/compress\n\t-h,--help:\tShow this message")
14
+ exit(exit_code)
15
+ end
16
+
17
+ dbg { "VERBOSE=#{ENV.fetch('VERBOSE')}; verbose mode is enabled" }
18
+
19
+ usage! if %w[-h --help].any? { |help_opt| ARGV.include?(help_opt) }
20
+ usage!(exit_code: 1) unless ARGV.size == 1
21
+
22
+ source = ARGV.first
23
+ dbg("Source file/directory: #{source}")
24
+ unless File.exist?(source)
25
+ warn("File does not exist: #{source}")
26
+ exit(1)
27
+ end
28
+
29
+ # Base class of all 3 archive options
30
+ class Archive
31
+ attr_accessor :target_directory, :source
32
+
33
+ def initialize(target_directory, source)
34
+ self.target_directory = target_directory
35
+ self.source = source
36
+ end
37
+
38
+ def basename
39
+ File.basename(source)
40
+ end
41
+
42
+ def ext
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def target_file
47
+ "#{basename}.tar.#{ext}"
48
+ end
49
+
50
+ def target_path
51
+ File.join(target_directory, target_file)
52
+ end
53
+
54
+ def compression_option
55
+ raise NotImplementedError
56
+ end
57
+
58
+ def log
59
+ File.join(target_directory, "#{ext}.log")
60
+ end
61
+
62
+ def size
63
+ File.size(target_path)
64
+ end
65
+
66
+ def compress!
67
+ dbg("[#{self.class}] Starting compression")
68
+ success = system("tar -c#{compression_option}vf #{target_path} #{source} 2> #{log}")
69
+ dbg("[#{self.class}] Compression attempt complete: #{success ? :success : :failure}")
70
+ return self if success
71
+
72
+ warn("Error compressing #{source} to #{self.class} format")
73
+ begin
74
+ warn(File.read(log))
75
+ rescue StandardError
76
+ warn("Could not read log file #{log}")
77
+ end
78
+ exit(2)
79
+ end
80
+
81
+ def move_to!(dir)
82
+ dbg("[#{self.class}] Moving #{target_path} to #{dir}")
83
+ File.rename(target_path, File.join(dir, File.basename(target_file)))
84
+ end
85
+ end
86
+
87
+ # Compress using gzip
88
+ class Gzip < Archive
89
+ def ext
90
+ :gz
91
+ end
92
+
93
+ def compression_option
94
+ :z
95
+ end
96
+ end
97
+
98
+ # Compress using gzip
99
+ class Bzip2 < Archive
100
+ def ext
101
+ :bz2
102
+ end
103
+
104
+ def compression_option
105
+ :j
106
+ end
107
+ end
108
+
109
+ # Compress using gzip
110
+ class Xz < Archive
111
+ def ext
112
+ :xz
113
+ end
114
+
115
+ def compression_option
116
+ :J
117
+ end
118
+ end
119
+
120
+ FORMATS = [Gzip, Bzip2, Xz].freeze
121
+
122
+ result = nil
123
+
124
+ Dir.mktmpdir do |tempdir_path|
125
+ dbg("Working in temporary directory #{tempdir_path}")
126
+
127
+ archives = FORMATS.map { |archive_class| archive_class.new(tempdir_path, source) }
128
+
129
+ threads = archives.map { |archive| Thread.new { archive.compress! } }
130
+ threads.each(&:join)
131
+ archives.each { |archive| dbg("#{archive.target_file}:\tSize=#{archive.size}") }
132
+ smallest, _others = archives.sort_by(&:size)
133
+ dbg("Keeping #{smallest.target_file}")
134
+ smallest.move_to!(Dir.pwd)
135
+ result = smallest.target_file
136
+ end
137
+
138
+ puts result
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crush-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexandre Ignjatovic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-05-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Run several flavors of compression to keep only the most space efficient
14
+ one
15
+ email: alexnadre.ignjatovic@gmail.com
16
+ executables:
17
+ - crush
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - bin/crush
22
+ homepage: https://github.com/bankair/crush-rb
23
+ licenses:
24
+ - MIT
25
+ metadata:
26
+ source_code_uri: https://github.com/bankair/crush-rb
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 3.2.0
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubygems_version: 3.5.7
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: Optimize your archive storage efficiency
46
+ test_files: []