-
-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ronin compress
command
#184
base: main
Are you sure you want to change the base?
Conversation
@postmodern 0.1 version of this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Submitted a bunch of comments and suggestions. There's multiple ways we could implement this command. This is a good start!
# | ||
# [FILE ...] Optional file(s) to compress | ||
# | ||
class Compress < StringMethodsCommand |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we only want to support processing files, then probably want to inherit from FileProcessorCommand
, and define a process_input(io)
method to compress the input File or from stdin
.
If we do want to support accepting arbitrary Strings (ex: ronin compress --string "hello world"
), then we should inherit from StringProcessorCommand
.
StringMethodsCommand
is more meant to be used by commands which simply map options to certain monkey-patch methods that are added to String
(ex: ronin decode --base64
-> String#base64_decode
).
lib/ronin/cli/commands/compress.rb
Outdated
option :gzip, short: '-g', | ||
desc: 'gzip compresses the data' do | ||
@format = :gzip | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to support --gzip
, we should also support a --zlib
option. ronin-support
also happens to have a Ronin::Support::Compression::Zlib
module we can use.
lib/ronin/cli/commands/compress.rb
Outdated
# | ||
# The compression format. | ||
# | ||
# @return Symbol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to explicitly list the possible values @return [:gzip, :tar, :zip]
.
lib/ronin/cli/commands/compress.rb
Outdated
end | ||
|
||
def extension | ||
return "gz" if @format == :gzip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably set an @ext
instance variable in the option blocks, along with @format
. This way we follow the "Tell, don't ask" principle.
lib/ronin/cli/commands/compress.rb
Outdated
end | ||
|
||
def process_file(file) | ||
compression_class.send(@format, "#{file}.#{extension}") do |c| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename @format
to @method
or @compression_method
if we're going to send()
it.
lib/ronin/cli/commands/compress.rb
Outdated
|
||
def process_file(file) | ||
compression_class.send(@format, "#{file}.#{extension}") do |c| | ||
c.write File.read(file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The files being compressed could be very very large. Probably more efficient to open the input file and read chunks of data from it using input.readpartial(4096)
and write those to the output stream.
lib/ronin/cli/commands/compress.rb
Outdated
end | ||
|
||
def process_file(file) | ||
compression_class.send(@format, "#{file}.#{extension}") do |c| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here's a question, if you gave this command the --zip
option and multiple files, would the user expect each file to be compressed into it's own .zip
file, or all files to be compressed into one zip file?
@AI-Mozi what do you think about adding separate |
It's definitely a good idea! |
lib/ronin/cli/commands/compress.rb
Outdated
option :name, short: '-n', | ||
value: { | ||
type: String | ||
}, | ||
desc: 'compressed file name' do |name| | ||
@compressed_file_name = name | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should add an option for specifying compressed file name.
lib/ronin/cli/commands/compress.rb
Outdated
# The path to the file. | ||
# | ||
def process_file(file) | ||
raise "Files can be compressed using gzip only" if @compression_method != :gzip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we raise an error, or just print some message and return?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call print_error
and exit(1)
, or call print_error
and return
if you think the error can be printed but the command should continue processing arguments.
lib/ronin/cli/commands/compress.rb
Outdated
rescue EOFError | ||
rescue IOError => e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rubocop does not like empty rescue :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, there should be no IO errors when reading the file. I suspect file.eof?
should make the rescue
s unnecessary.
lib/ronin/cli/commands/compress.rb
Outdated
|
||
Ronin::Support::Compression.gzip(compressed_file_name) do |gz| | ||
files.each do |file| | ||
File.open(file, 'rb') do |f| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid single letter block arguments. Rename file
to like path
or file_path
, and f
to file
or io
.
lib/ronin/cli/commands/compress.rb
Outdated
rescue EOFError | ||
rescue IOError => e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, there should be no IO errors when reading the file. I suspect file.eof?
should make the rescue
s unnecessary.
lib/ronin/cli/commands/compress.rb
Outdated
if files.empty? | ||
super(*files) | ||
else | ||
raise "Files can be compressed using gzip only" if @compression_method != :gzip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do a print_error
and call exit(1)
if invalid combinations of options or arguments are given.
lib/ronin/cli/commands/compress.rb
Outdated
# The compressed string. | ||
# | ||
def process_string(string) | ||
string.send(@compression_method) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to avoid calling the monkey-patched methods when possible. Might be better to do Support::Compression.send(@compression_method,string)
.
lib/ronin/cli/commands/compress.rb
Outdated
# @return String | ||
# | ||
def compressed_file_name | ||
@compressed_file_name || "ronin_compressed_#{Time.now.to_i}.gz" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd get rid of the timestamp, or maybe add an option for it. I think a ronin compress
command should behave exactly like gzip
and just append the .gz
extension on the given file name.
lib/ronin/cli/commands/compress.rb
Outdated
# The path to the file. | ||
# | ||
def process_file(file) | ||
raise "Files can be compressed using gzip only" if @compression_method != :gzip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call print_error
and exit(1)
, or call print_error
and return
if you think the error can be printed but the command should continue processing arguments.
lib/ronin/cli/commands/compress.rb
Outdated
if files.empty? | ||
super(*files) | ||
else | ||
raise "Files can be compressed using gzip only" if @compression_method != :gzip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could support compressing files using SupportCompression.zlib_deflate
. Just read the entire file using File.read
, compress the String, and write it back out using File.binwrite
.
lib/ronin/cli/commands/compress.rb
Outdated
else | ||
raise "Files can be compressed using gzip only" if @compression_method != :gzip | ||
|
||
Ronin::Support::Compression.gzip(compressed_file_name) do |gz| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also why are there two Ronin::Support::Compression.gzip(compressed_file_name)
blocks? One in run
and another in process_file
?
lib/ronin/cli/commands/compress.rb
Outdated
# File arguments. | ||
# | ||
def run(*files) | ||
if files.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be unless files.empty?
or if !files.empty?
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it like if there is file given as an argument, compress it, otherwise go to StringProcessorCommand#run
else
statement and process @input_values
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh.. now that I read it, it works different than i thought 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm maybe it might be easier to just write all files and strings into a common Support::Compression::GZip
output stream? Although, we would have to have different logic for the Compression::Zlib
code.
Another idea would be to define separate process_file
and process_string
methods. The process_file
method would read the File
and write the gziped/zlib'ed output to a .gz
or .zlib
file. The process_string
method would instead gzip/zlib compress a String and write it to stdout
; maybe also support a common --output
option?
@postmodern It's been a while. I did some changes. Let me know what do you thing and we can discuss that later :D |
@AI-Mozi I'm not sure about how the I do however think there should be a single |
#145