# frozen_string_literal: true
#
# Copyright (c) 2021-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-core is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-core is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-core. If not, see .
#
require 'ronin/core/cli/command'
require 'command_kit/colors'
require 'fileutils'
require 'erb'
module Ronin
module Core
module CLI
#
# Adds generator methods to a command.
#
# ## Example
#
# class Gen < Command
#
# include Core::Generator
#
# template_dir File.join(ROOT,'data','templates')
#
# argument :path, desc: 'The path of the script to genereate'
#
# def run(path)
# erb 'script.rb.erb', path
# end
#
# end
#
module Generator
include CommandKit::Colors
#
# Adds {ClassMethods} to the class.
#
# @param [Class] command
# The command class which is including {Generator}.
#
# @api private
#
def self.included(command)
command.extend ClassMethods
end
#
# Class-methods.
#
module ClassMethods
#
# Gets or sets the template directory.
#
# @param [String, nil] path
# If a path is given, the template directory will be set.
#
# @return [String]
# The set template directory.
#
# @raise [NotImplementedError]
# The class did not set {template_dir}.
#
# @example
# template_dir File.join(__dir__,'..','..','..','..','data','templates','thing')
#
def template_dir(path=nil)
if path
@template_dir = File.expand_path(path)
else
@template_dir || (superclass.template_dir if superclass.kind_of?(ClassMethods))
end
end
end
# The directory to read files from.
#
# @return [String]
attr_reader :template_dir
#
# Initializes the command.
#
# @param [Hash{Symbol => Object}] kwargs
# Additional keyword arguments for `initialize`.
#
# @raise [NotImplementedError]
# The class did not set the {template_dir} path.
#
def initialize(**kwargs)
super(**kwargs)
unless (@template_dir = self.class.template_dir)
raise(NotImplementedError,"#{self.class} did not define template_dir")
end
end
#
# Prints an generator action to STDOUT.
#
# @param [Symbol] command
# The command that represents the generator action.
#
# @param [String] source
# The optional source file being copied or rendered.
#
# @param [String] dest
# The file or directory path being created or modified.
#
def print_action(command,source=nil,dest)
line = String.new
line << "\t" << colors.bold(colors.green(command))
line << "\t" << colors.green(source) if source
line << "\t" << colors.green(dest) if dest
puts(line)
end
#
# Creates an empty directory.
#
# @param [String] path
# The relative path of the directory to be created.
#
def mkdir(path)
print_action 'mkdir', path
FileUtils.mkdir_p(path)
end
#
# Creates an empty file.
#
# @param [String] path
# The relative path of the empty file to be created.
#
def touch(path)
print_action 'touch', path
FileUtils.touch(path)
end
#
# Changes the permissions of a file or directory.
#
# @param [String, Integer] mode
# The chmod String (ex: `"+x"`) or octal mask.
#
# @param [String] path
# The path to the file or directory.
#
def chmod(mode,path)
print_action "chmod", path
FileUtils.chmod(mode,path)
end
#
# Copies a file in.
#
# @param [String] source
# The file within the {template_dir} to copy in.
#
# @param [String] dest
# The destination path to copy the file to.
#
def cp(source,dest)
print_action 'cp', source, dest
FileUtils.cp(File.join(@template_dir,source),dest)
end
#
# Copies a directory in.
#
# @param [String] source
# The relative path to the directory within the {template_dir}.
#
# @param [String] dest
# The destination path to copy the directory to.
#
def cp_r(source,dest)
print_action "cp -r", source, dest
FileUtils.cp_r(File.join(@template_dir,source),dest)
end
#
# Renders a file using an `.erb` template in the {template_dir}.
#
# @param [String] source
# The relative path to the file. The `.erb` template will be derived
# from the file path by appending the `.erb` file extension.
#
# @param [String, nil] dest
# The destination path to write the rendered file to.
# If no destination path is given, the result of the rendered `.erb`
# template will be returned.
#
def erb(source,dest=nil)
if dest
print_action 'erb', source, dest
end
source_path = File.join(@template_dir,source)
return super(source_path,dest)
end
#
# Runs a command.
#
# @param [String] command
# The command name to execute.
#
# @param [Array] arguments
# Additional arguments for the command.
#
# @return [Boolean, nil]
# Indicates whether the command successfully executed or not.
#
def sh(command,*arguments)
print_action "run", [command, *arguments].join(' ')
system(command,*arguments)
end
end
end
end
end