lib/klipp.rb in klipp-0.0.1 vs lib/klipp.rb in klipp-0.2.0
- old
+ new
@@ -1,135 +1,191 @@
-require 'klipp/buffered_output'
-require 'klipp/version'
+require 'ptools'
+require 'formatador'
+require 'colorize'
+require 'fileutils'
+require 'grit'
+require 'highline/import'
+
+require 'template'
require 'klipp/configuration'
-require 'klipp/token'
-require 'klipp/template'
+require 'klipp/version'
require 'klipp/parameter_list'
-require 'klipp/project'
-require 'colorize'
+require 'klipp/creator'
module Klipp
- extend BufferedOutput::ClassMethods
- def self.display_exception exception
- if exception.is_a? HelpRequest
- help = exception
- else
- help = HelpRequest.new exception.message, true
- help.set_backtrace(exception.backtrace)
- end
+ class Hint < StandardError
+ end
- buffer_puts help.message
- exit help.exit_status
+ def self.env
+ @@env ||= StringInquirer.new('prod')
end
+ def self.env=(env)
+ @@env = env
+ end
+
def self.route(*argv)
- @params = Klipp::ParameterList.new(argv)
- command = @params.shift_argument
+ params = Klipp::ParameterList.new(argv)
+ command = params.shift_argument;
+ commands = {
+ prepare: lambda { cli_prepare(params) },
+ create: lambda { cli_create(params) },
+ template: lambda { Template.route(*params) }
+ }
case command
- when 'version'
- version
- when 'list'
- list
- when 'prepare'
- prepare @params.first
- when 'create'
- create @params.first
when nil
- raise HelpRequest.new('Use one of the commands below to start with klipp.', false, true)
+ raise Klipp::Hint.new "Add a command to `klipp [#{commands.keys.join('|')}]`"
else
- raise "Unknown command: #{command}"
+ if commands[command.to_sym]
+ commands[command.to_sym].call
+ else
+ raise "Unknown command `klipp #{command}`"
+ end
end
-
+ 0 # exit code
rescue Exception => e
- display_exception e
+ case e
+ when Klipp::Hint
+ Formatador.display_line("[yellow][?] #{e.message}[/]")
+ else
+ Formatador.display_line("[red][!] #{e.message}[/]")
+ Formatador.display_line(e.backtrace[0..10].join("\n"))
+ end
+ 1 # exit code
end
- def self.version
- buffer_puts Klipp::VERSION
- end
+ def self.cli_prepare(params=[])
+ params = Klipp::ParameterList.new(params)
+ template = params.shift_argument
+ raise Klipp::Hint.new("Add a template name to `klipp prepare [template]`. Use `klipp template list` to see your options.") unless template
- def self.list
- files = template_files
+ spec = Template::Spec.from_file Template::Spec.spec_path_for_identifier(template)
+ filename = 'Klippfile'
- raise "No templates found. Create a template directory and .yml file in #{Klipp::Configuration.templates_dir}" unless files.length > 0
+ force = params.splice_option('-f')
+ will_overwrite = File.exists?(filename) && force
- buffer_puts("Available templates for use with #{'klipp prepare'.yellow} or #{'klipp create'.yellow}:\n\n")
- files.each do |file|
- buffer_puts(" * #{File.basename(file, '.*').green}")
- end
- end
+ raise "#{filename} already exists, not overwriting. Use -f to force overwriting." if File.exists?(filename) && !force
- def self.prepare(template_name)
- raise HelpRequest.new 'Add a template name to the `prepare` command.' unless template_name
+ File.write('Klippfile', spec.klippfile)
- template = Klipp::Template.new(Klipp::Configuration.templates_dir, template_name)
- raise "#{template.klippfile} already exists. Delete it if you want to prepare a new template." if File.exists? template.klippfile
- IO.write(template.klippfile, template.generated_klippfile)
+ Formatador.display_line("[green][√] Prepared #{filename} #{'again' if will_overwrite}.[/]")
+
+ capture_stdout {
+ `open -a TextMate #{filename} 2>&1` if File.exists?(filename)
+ }
+
+ if $? && $?.exitstatus > 0
+ `open -t #{filename}` if File.exists?(filename)
+ end
end
- def self.create(template_name)
- if template_name
- klippfile = File.join(Dir.pwd, "#{template_name}.klippfile")
+ def self.cli_create(params, highline = nil)
+ params = Klipp::ParameterList.new(params)
+ if (interactive_identifier = params.shift_argument)
+ creator = Klipp::Creator.from_user_input(interactive_identifier, highline)
+ puts()
else
- klippfile = Dir.glob(File.join(Dir.pwd, '*.klippfile')).first
- template_name = File.basename(klippfile, File.extname(klippfile)) if klippfile
+ creator = Klipp::Creator.from_file File.join(Dir.pwd, 'Klippfile')
end
+ spec_path = Template::Spec.spec_path_for_identifier creator.identifier
+ spec = Template::Spec.from_file spec_path
+ spec.set_token_values(creator.tokens, params.splice_option('-v'))
- template = Klipp::Template.new(Klipp::Configuration.templates_dir, template_name)
+ block_actions = spec.block_actions_under_git && git_repository?
+ if spec.pre_actions.count > 0
+ if block_actions
+ Formatador.display_line("[yellow][i][/] Git repository found, not running pre-actions (see .klippspec).")
+ puts()
+ else
+ run_actions(spec.pre_actions) if Klipp.env.prod?
+ Formatador.display_line("[green][√] Pre-actions complete.[/]")
+ puts()
+ end
+ end
- if klippfile
- # load token values from klippfile
- template.load_klippfile klippfile
- elsif template_name
- # ask for token values with highline
- raise "Direct user input not yet supported. Use #{'klipp prepare'.yellow} to prepare a .klippfile"
- else
- raise "Add a template name to the `create` command, or use #{'klipp prepare'.yellow} to prepare a .klippfile"
+ force = params.splice_option('-f')
+
+ source_dir = File.dirname(Template::Spec.spec_path_for_identifier creator.identifier)
+ target_dir = Dir.pwd
+
+ source_files = Dir.glob(File.join(source_dir, '**', '*'), File::FNM_DOTMATCH).reject { |f| f == spec_path }
+
+ result = source_files.map do |source_file|
+ spec.transfer_file source_file, spec.target_file(source_dir, source_file, target_dir), force
end
- project = Klipp::Project.new(template)
- project.create
- end
+ verbose = params.splice_option '-v'
- private
+ Formatador.display_line("[green][√] Creation completed using template #{Template::Spec.expand_identifier creator.identifier}. #{'Run `klipp create -v` to see what files were created.' unless verbose}[/]")
+ puts()
- def self.template_files
- Dir.glob File.join(Klipp::Configuration.templates_dir, '*.yml')
- end
+ if (verbose)
+ strip = File.dirname(Dir.pwd)+File::SEPARATOR
+ result.each { |r| Formatador.display_line(r.gsub(strip, '')) unless File.directory? r }
+ puts()
+ end
-end
+ if spec.post_actions.count > 0
+ if block_actions
+ Formatador.display_line("[yellow][i][/] Git repository found, not running post-actions (see .klippspec).")
+ puts()
+ else
+ run_actions(spec.post_actions) if Klipp.env.prod?
+ Formatador.display_line("[green][√] Post-actions complete.[/]")
+ puts()
+ end
+ end
-class HelpRequest < StandardError
- def initialize(msg, unknown=false, show_title=false)
- @unknown = unknown
- @show_title = show_title
- super(msg)
+ Formatador.display_line("[green][√] Done.[/]")
end
- def message
- if @unknown
- "[!] #{super.to_s}".red+"\n\n#{commands}\n\n#{self.backtrace.join("\n")}"
- else
- "#{@show_title ? title+"\n\n" : ''}"+"[?] #{super.to_s}".yellow+"\n\n#{commands}"
- end
+ def self.git_repository?
+ `git rev-parse --is-inside-work-tree 2>&1`.match /true/
end
- def title
- "\033[1mKlipp\033[22m, Xcode templates for the rest of us. Version: #{Klipp::VERSION}"
+ def self.run_actions(actions)
+ count = actions.count()
+ puts()
+ actions.each do |action|
+ Formatador.display_line("[yellow][i][/] Running `#{action}`...")
+ puts()
+ system(action) if Klipp.env.prod?
+ puts()
+ #IO.popen(action, :err=>[:child, :out]) { |f| puts ' '+f.read.gsub("\n", "\n ") }
+ raise "Error running action `#{action}`." if $? && $?.exitstatus > 0
+ end
end
+end
- def commands
- commands = [
- version: 'Display the Klipp version number.',
- list: "List all available klipp templates in #{Klipp::Configuration.templates_dir}",
- prepare: 'Prepare a .klippfile to edit in your favorite text editor.',
- create: 'Create a project based on the template name or .klippfile in the current directory'
- ]
- command_list = commands.map { |cmd| cmd.map { |key, summary| " * klipp #{key.to_s.ljust(10).green} #{summary}" } }.join("\n")
- "Commands:\n\n#{command_list}"
+class StringInquirer < String
+ def method_missing(method_name, *arguments)
+ if method_name.to_s[-1,1] == '?'
+ self == method_name.to_s[0..-2]
+ else
+ super
+ end
end
+end
- def exit_status
- @unknown ? 2 : 1
+def capture_stdout
+ old_stdout = STDOUT.clone
+ pipe_r, pipe_w = IO.pipe
+ pipe_r.sync = true
+ output = ''
+ reader = Thread.new do
+ begin
+ loop do
+ output << pipe_r.readpartial(1024)
+ end
+ rescue EOFError
+ end
end
+ STDOUT.reopen pipe_w
+ yield
+ensure
+ STDOUT.reopen old_stdout
+ pipe_w.close
+ reader.join
+ return output
end
\ No newline at end of file