Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions shard.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
name: teeplate
version: 0.4.5
version: 0.5.0

authors:
- mosop

crystal: 0.21.1
crystal: 0.24.1

development_dependencies:
have_files:
github: mosop/have_files
version: ~> 0.3.3
github: amberframework/have_files
version: ~> 0.4.0
stdio:
github: mosop/stdio
version: ~> 0.1.2
Expand Down
2 changes: 1 addition & 1 deletion src/lib.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ require "base64"
require "colorize"
require "ecr/macros"
require "process"
require "./version"
require "./teeplate/*"
require "./lib/as_data_entry"
require "./lib/*"
7 changes: 3 additions & 4 deletions src/lib/file_entry_collector.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ module Teeplate

def each_file(abs, rel, &block : String, String ->)
Dir.open(abs) do |d|
d.each do |entry|
if entry != "." && entry != ".."
each_file abs, rel, entry, &block
end
d.each_child do |entry|
each_file abs, rel, entry, &block
end
end
end
Expand All @@ -27,6 +25,7 @@ module Teeplate
end

@entries : Array(AsDataEntry)?

def entries
@entries ||= begin
a = [] of AsDataEntry
Expand Down
22 changes: 22 additions & 0 deletions src/lib/file_tree.cr
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
module Teeplate
# Collects template files from a local directory.
abstract class FileTree

# Array of paths to skip when performing destroy
@skip_on_destroy = [] of String

# Collects and embeds template files.
#
# It runs another macro process that collects template files and embeds the files as code.
macro directory(dir)
{{ run(__DIR__ + "/file_tree/macros/directory", dir.id) }}
end

# Skip directory/file at the given path. The path is relative to the out_dir.
def skip_on_destroy(path)
@skip_on_destroy.push(path)
end

@file_entries : Array(AsDataEntry)?
# Returns collected file entries.
def file_entries : Array(AsDataEntry)
Expand All @@ -28,13 +37,26 @@ module Teeplate
renderer
end

# Destroy the rendered files.
def destroy(out_dir, force : Bool = false, interactive : Bool = false, interact : Bool = false, list : Bool = false, color : Bool = false, per_entry : Bool = false, quit : Bool = true)
renderer = Renderer.new(out_dir, force: force, interact: interactive || interact, list: list, color: color, per_entry: per_entry, quit: quit)
renderer << destroy_file_entries
renderer.destroy(@skip_on_destroy)
renderer
end

# Returns file entries to be rendered.
#
# This method just returns the `#file_entries` method's result. To filter entries, override this method.
def rendered_file_entries
file_entries
end

# :nodoc:
def destroy_file_entries
file_entries
end

# :nodoc:
def ____collect_files(files)
end
Expand Down
8 changes: 3 additions & 5 deletions src/lib/file_tree/macros/directory.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ require "base64"

def each_file(abs, rel, &block : String, String ->)
Dir.open(abs) do |d|
d.each do |entry|
if entry != "." && entry != ".."
each_file abs, rel, entry, &block
end
d.each_child do |entry|
each_file abs, rel, entry, &block
end
end
end
Expand Down Expand Up @@ -39,7 +37,7 @@ end
def pack_blob(sb, abs, rel)
STDOUT << "\n____files << ::Teeplate::Base64Data.new(\"#{rel}\", "
io = IO::Memory.new
File.open(abs){|f| IO.copy(f, io)}
File.open(abs) { |f| IO.copy(f, io) }
if io.size > 0
STDOUT << "#{io.size}_u64, <<-EOS\n"
Base64.encode io, STDOUT
Expand Down
85 changes: 85 additions & 0 deletions src/lib/renderer.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ module Teeplate
# :nodoc:
getter data_entries = [] of AsDataEntry

# :nodoc:
getter? pending_destroy = false

# :nodoc:
getter entries = [] of RenderingEntry

Expand Down Expand Up @@ -97,5 +100,87 @@ module Teeplate
@quitted = true
end
end

# Destroy templates.
#
# If passing paths as skip, these paths will be skipped in the destroy process, and thus will remain on the
# file system
def destroy(skip : Array(String)?)
@pending_destroy = true
begin
if @interactive
@entries.each do |entry|
entry.destroy(should_destroy?(entry))
end
elsif should_destroy_all?(@entries)
@entries.each do |entry|
entry.destroy(should_skip_on_destroy?(entry, skip))
end
end
rescue ex : Quit
@quitted = true
end
end

# Confirm whether the user wants to destroy a singe file.
def should_destroy?(entry : RenderingEntry)
STDOUT.puts "Destroy #{entry.out_path}? (y/n)"

loop do
case input = ::STDIN.gets.to_s.strip.downcase
when "y"
return true
when "n"
return false
end
end
end

# Confirm whether or not the user wishes to destroy multiple files.
def should_destroy_all?(entries : Array(RenderingEntry))
return should_destroy?(entries.first) if entries.size == 1

STDOUT.puts "Destroy all the following files? (y/n)"

entries.each do |entry|
STDOUT.puts entry.out_path
end

loop do
case input = ::STDIN.gets.to_s.strip.downcase
when "y"
return true
when "n"
return false
end
end
end

# Determine whether a file should be skipped upon performing #destroy, based on the
# provided array of paths to skip.
def should_skip_on_destroy?(file : RenderingEntry, skip : Array(String)?) : Bool
skip_file = false

skip_path_parts : Array(String)?
entry_path_parts : Array(String)?
entry_path_parts = file.out_path.split("/")

skip.each do |skip_path|
skip_path_parts = skip_path.split("/")

skip_path_parts.unshift(entry_path_parts.first)
skip_path_parts.each_with_index do |part, i|
if i + 1 > entry_path_parts.size
skip_file = false
break
end
skip_file = part.downcase == entry_path_parts[i].downcase
end

break if skip_file
end

skip_file
end
end
end
19 changes: 17 additions & 2 deletions src/lib/rendering_entry.cr
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ module Teeplate
end
end

# :nodoc:
def destroy(skip? = false)
unless skip?
begin
File.delete out_path
list_if_any "destroyed ", :red
rescue
list_if_any "skipped ", :yellow
end
else
list_if_any "skipped ", :yellow
end
end

# :nodoc:
def set_perm
if perm = @data.perm? && File.file?(out_path)
Expand Down Expand Up @@ -125,6 +139,7 @@ module Teeplate
return :keep if !@renderer.interactive? || @renderer.keeps_all?
return modifies?("#{local_path} is a symlink...", diff: false) if File.symlink?(out_path)
return :modify if appends?
return :destroy if @renderer.pending_destroy?
return :none if identical?
modifies?("#{local_path} already exists...", diff: true)
end
Expand Down Expand Up @@ -200,9 +215,9 @@ module Teeplate
end
begin
if !GIT.empty?
Process.new(GIT, ["diff", "--no-index", "--", out_path, "-"], shell: true, input: r, output: true, error: true).wait
Process.new(GIT, ["diff", "--no-index", "--", out_path, "-"], shell: true, input: r, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit).wait
elsif !DIFF.empty?
Process.new(DIFF, ["-u", out_path, "-"], shell: true, input: r, output: true, error: true).wait
Process.new(DIFF, ["-u", out_path, "-"], shell: true, input: r, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit).wait
else
STDOUT.puts "No diff command is installed."
end
Expand Down
2 changes: 1 addition & 1 deletion src/version.cr → src/teeplate/version.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Teeplate
VERSION = "0.4.5"
VERSION = "0.5.0"
end