nake 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,9 +2,9 @@ h1. About
2
2
 
3
3
  Nake is light-weight and highly flexible Rake replacement with much better arguments parsing.
4
4
 
5
- You might be wondering why to write yet another fucking task manager when we have Rake, Thor and others. Well, because all of them sucks. For example Rake, anyone is actually using its CLI arguments, because it sucks so much, that everyone rather write @ENV=test VERSION=10 rake db:migrate@. It has not just shitty API for defining CLI arguments, but also it is using very weird and totally non-unix syntax like @rake db:migrate[test,10]@. This syntax isn't just non-standard, but also some shells has @[]@ as special characters, so you actually has to escape it.
5
+ You might be wondering why to write yet another fucking task manager when we have Rake, Thor and others. Well, because all of them suck. For example Rake, anyone is actually using its CLI arguments, because it sucks so much, that everyone rather write @ENV=test VERSION=10 rake db:migrate@. It has not just shitty API for defining CLI arguments, but also it is using very weird and totally non-unix syntax like @rake db:migrate[test,10]@. This syntax isn't just non-standard, but also some shells has @[]@ as special characters, so you actually has to escape it.
6
6
 
7
- Sounds terrible? Well and it's not all! Let's take a look at this "example":http://gist.github.com/263325, as you can see if you have argument path and you let it empty, than it takes environment variable @$PATH@! I contact Jim Weirich about this issue and he never replied, so he probably thinks it's fine. Fair enough, but I won't work with such tool.
7
+ Sounds terrible? Well and it's not all! Let's take a look at this "example":http://gist.github.com/263325, as you can see if you have argument path and you let it empty, than it takes environment variable @$PATH@! I contact Jim Weirich so I hope he will remove this awful bug, but hey, it's pretty bad anyway.
8
8
 
9
9
  h1. Features
10
10
 
@@ -20,6 +20,38 @@ h1. Usage
20
20
 
21
21
  First of all there is a bunch of "examples":github.com/botanicus/nake/tree/master/examples, so you can try them. All these scripts are executable, so just run @./executable/basic.rb -T@ and that's it!
22
22
 
23
+ h1. Documentation
24
+
25
+ h2. Tasks
26
+
27
+ h3. Options parsing
28
+
29
+ h2. File Tasks
30
+
31
+ h2. Task Helpers
32
+
33
+ h2. Available Tasks
34
+
35
+ h3. Built-in Tasks
36
+
37
+ - @-T@
38
+ - @-H@
39
+ - @-i@
40
+
41
+ h3. File @nake/tasks/bundle@
42
+
43
+ This file contains only @bundle@ task which will load bundler @--no-cached@
44
+
45
+ h3. File @nake/tasks/clean@
46
+
47
+ h3. File @nake/tasks/gem@
48
+
49
+ h3. File @nake/tasks/release@
50
+
51
+ h3. File @nake/tasks/rip@
52
+
53
+ h3. File @nake/tasks/spec@
54
+
23
55
  h1. Links
24
56
 
25
57
  * "RDoc.info API Docs":http://rdoc.info/projects/botanicus/nake
data/TODO.txt CHANGED
@@ -1,7 +1,9 @@
1
+ - task#setup (see Desktop/nake-setup.rb)
2
+ - yardoc
3
+ - specs
1
4
  - fix interactive task, it doesn't work so far
2
5
  - better argv parsing maybe, task(:spec) do |*paths, options| is fine, but task(:spec) do |path, options| will fail if no path specified ... but actually task(:spec) do |path = "spec", options| might be fine, try it ... BTW task(["-i", "--interactive"]) do |task, *args, options| doesn't work ... putting options as a first argument should solve everything, but it's not very intuitive :/
3
- - it might be worthy to steal filelist from Rake
4
6
  - how to solve args inheriting (like if we have task release which depends on task build which takes a gemspec as an argument)
5
7
  - benchmarks against rake
6
- - maybe some of: fileutils extensions, multitask, rule, file, directory (from rake, see http://rake.rubyforge.org/files/doc/rakefile_rdoc.html)
8
+ - maybe some of: fileutils extensions, multitask, rule (from rake, see http://rake.rubyforge.org/files/doc/rakefile_rdoc.html)
7
9
  - some default tasks like nake/tasks/package, nake/tasks/clean, nake/tasks/yardoc, nake/tasks/spec, nake/tasks/bundle
data/bin/nake CHANGED
@@ -3,13 +3,71 @@
3
3
  $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4
4
 
5
5
  require "nake"
6
+ require "nake/args"
7
+ require "nake/helpers"
6
8
 
9
+ # TODO: what if I want to run:
10
+ # ./bin/nake -T
11
+ # ./bin/nake --verbose -T
12
+ # ./examples/flags.rb --verbose
13
+
14
+ # First file in arguments is separator between args for nake and for task
15
+ # If there is no file in the arguments
16
+ # co kdyz omezim tasky na list etc a nebudou moct mit --task etc?
17
+ # nake --verbose list arg1 arg2 --with-something
18
+ # => zmizi potreba aliasu
19
+ # => potreba API pro mapovani na -T etc
20
+ # Nake.args["-T"] = Nake::Task[:tasks]
21
+
22
+ # !!!!!! --verbose neni runable task to jen switchuje naky shity, takze -T by melo fungovat tak, ze naplni Nake.parse[:task] s taskem co se ma runnout
7
23
  # First argument has to be path to file with your tasks
8
- load ARGV.first
9
24
 
10
- # Parse arguments and run tasks
25
+ # parse arguments
26
+ begin
27
+ Nake.parse
28
+ rescue Exception => exception
29
+ puts "~ Arguments parsed into #{Nake.parse.inspect.green}"
30
+ puts "Exception occured during parsing arguments"
31
+ print_exception_with_backtrace_and_abort(exception)
32
+ else
33
+ if Nake.parse[:nake].include?("--debug") # Nake.debug isn't initialized yet
34
+ puts "~ Arguments parsed into #{Nake.parse.inspect.green}"
35
+ end
36
+ end
37
+
38
+ # load task file
39
+ if Nake.parse[:file]
40
+ begin
41
+ load Nake.parse[:file]
42
+ rescue Exception => exception
43
+ print_exception_with_backtrace_and_abort(exception)
44
+ end
45
+ else
46
+ abort "You have to specify a file with tasks"
47
+ end
48
+
49
+ # run arguments
50
+ # yes, arguments has to run after the task file is loaded
51
+ begin
52
+ original_args = Nake.parse.dup
53
+ Nake.run_args
54
+ rescue SystemExit => exception
55
+ exit exception.status
56
+ rescue Exception => exception
57
+ puts "~ Arguments parsed into #{Nake.parse.inspect.green}"
58
+ puts "Exception occured setting nake flags"
59
+ print_exception_with_backtrace_and_abort(exception)
60
+ else
61
+ if Nake.debug && Nake.parse != original_args
62
+ puts "~ Arguments changed into #{Nake.parse.inspect.green}"
63
+ end
64
+ end
65
+
66
+ # run tasks
11
67
  begin
12
- Nake.run(ARGV[1..-1])
13
- rescue TaskNotFound, ConfigurationError => exception
14
- abort "[#{"ERROR".red}] #{exception.message}"
68
+ Nake.run_task
69
+ rescue SystemExit => exception
70
+ exit exception.status
71
+ rescue Exception => exception
72
+ print_exception_with_backtrace_and_abort(exception)
15
73
  end
@@ -0,0 +1,12 @@
1
+ #!./bin/nake
2
+
3
+ # Arguments might be considered as a light-weight variant to tasks
4
+ # There are two ways how you can use tasks:
5
+ # 1) as a filter, just set a variable --debug
6
+ # 2) add your own functionality and then use exit
7
+ # 3) just set the task which will run afterwards
8
+ Nake.args["-H", "--help"] = lambda { Kernel.abort("This is my customized help!") }
9
+ Nake.args["-T", "--tasks"] = lambda { Nake.parse[:task].clear.push("tasks") }
10
+ Nake.args["--debug", "--no-debug"] = lambda { |key, value| Nake.debug = value }
11
+
12
+ # TODO: execution order, argument helper + args passing to the proc
@@ -0,0 +1,18 @@
1
+ #!./bin/nake
2
+
3
+ begin
4
+ require "recho"
5
+ rescue LoadError
6
+ raise LoadError, "This task require recho gem!"
7
+ end
8
+
9
+ directory "tmp"
10
+ directory "tmp/www"
11
+
12
+ file("tmp/restart.txt", "tmp") do |path|
13
+ touch path
14
+ end
15
+
16
+ file "tmp/www/index.html", "tmp/www" do |path|
17
+ echo("<html>Hello World!</html>") > path
18
+ end
@@ -0,0 +1,15 @@
1
+ #!./bin/nake --verbose
2
+
3
+ # This example document how you can change different flags
4
+ # - specify these flags in shebang
5
+ # - use API directly
6
+ # - ./examples/flags --verbose
7
+ Nake.verbose = false
8
+
9
+ task(:setup) do
10
+ puts "Setting environment ..."
11
+ end
12
+
13
+ task(:build, :setup) do
14
+ puts "Building ..."
15
+ end
@@ -1,27 +1,99 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "nake/argv"
4
3
  require "nake/task"
5
4
 
6
5
  module Nake
7
- VERSION ||= "0.0.3"
8
- TaskNotFound ||= Class.new(StandardError)
9
- ConfigurationError ||= Class.new(StandardError)
6
+ VERSION ||= "0.0.5"
7
+ def self.verbose
8
+ @@verbose
9
+ rescue NameError
10
+ @@verbose = true
11
+ end
12
+
13
+ def self.verbose=(boolean)
14
+ @@verbose = boolean
15
+ end
16
+
17
+ def self.debug
18
+ @@debug
19
+ rescue NameError
20
+ @@debug = true
21
+ end
10
22
 
11
- def self.run(args = ARGV)
12
- name = args.shift
23
+ def self.debug=(boolean)
24
+ @@debug = boolean
25
+ end
26
+
27
+ # I was drunk so you might found this code not very clear. But it's clear for me and it works.
28
+ def self.args
29
+ @@args ||= begin
30
+ Hash.new.tap do |hash|
31
+ hash.define_singleton_method(:[]) do |name|
32
+ names, value = self.find { |names, block| names.include?(name) }
33
+ return value
34
+ end
35
+
36
+ hash.define_singleton_method(:[]=) do |*names, proc|
37
+ super(names, proc)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.parse(args = ARGV)
44
+ @result ||= begin
45
+ args.inject(Hash.new) do |hash, argument|
46
+ hash[:nake] ||= Array.new
47
+ hash[:task] ||= Array.new
48
+ hash[:file] ||= "tasks.rb" if File.exist?("tasks.rb")
49
+ if argument.match(/^-/) && hash[:task].empty?
50
+ hash[:nake].push(argument)
51
+ elsif File.exist?(argument)
52
+ hash[:file] = argument
53
+ else
54
+ hash[:task].push(argument)
55
+ end
56
+ hash
57
+ end
58
+ end
59
+ end
60
+
61
+ def self.run_args
62
+ # TODO: proceed --debug and --verbose first! ... to by slo tak, ze by se iterovalo pres Nake.args a pokud je to pritomno tak proved
63
+ Nake.parse[:nake].each do |argument|
64
+ unless self.args[argument]
65
+ abort "Unrecognized argument: #{argument}"
66
+ end
67
+ name, value = ArgvParser.parse(argument)
68
+ if name
69
+ info "Invoking argument #{argument} with #{name} = #{value}"
70
+ self.args[argument].call(name, value)
71
+ else
72
+ info "Invoking argument #{argument} without any arguments"
73
+ self.args[argument].call
74
+ end
75
+ end
76
+ end
77
+
78
+ # Run first task
79
+ #
80
+ # @raise [TaskNotFound]
81
+ # @example
82
+ # Nake.run(["release"])
83
+ # @since 0.0.1
84
+ # @author Jakub Stastny
85
+ def self.run_task
86
+ name, *args = Nake.parse[:task]
13
87
  task = Task[name]
14
- if name && task.nil?
15
- raise TaskNotFound, "Task with name #{name} doesn't exist"
16
- elsif name.nil? && task.nil?
88
+ if name.nil?
17
89
  raise TaskNotFound, "You have to specify a task you want to run!"
90
+ elsif task.nil?
91
+ raise TaskNotFound, "Task with name #{name} doesn't exist"
92
+ else
93
+ task.run(args)
18
94
  end
19
- opts = args.extend(ArgvParsingMixin).extract!
20
- task.call(args, opts)
21
95
  end
22
96
  end
23
97
 
24
98
  require "nake/dsl"
25
99
  require "nake/helpers"
26
- require "nake/tasks"
27
- require "nake/colors"
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require "nake/dsl"
4
+
5
+ argument("-H", "--help") do
6
+ Kernel.abort "Use #{$0} -T for list of all available tasks or -i for interactive session"
7
+ end
8
+
9
+ argument("-T", "--tasks") do |pattern = nil|
10
+ tasks, options = Task.tasks.select { |name, task| not task.hidden? }.sort.partition { |key, value| not key.match(/^-/) }
11
+ arguments = Nake.args.sort
12
+
13
+ puts "\n#{"===".yellow} #{"Available tasks".magenta} #{"===".yellow}"
14
+ if tasks.empty?
15
+ puts "No tasks defined"
16
+ else
17
+ tasks.each do |name, task|
18
+ puts "#{name.green} #{task.dependencies.join(", ")} # #{task.description || "no description yet"}"
19
+ end
20
+ end
21
+
22
+ puts "\n#{"===".yellow} #{"Available arguments".magenta} #{"===".yellow}"
23
+ if arguments.empty?
24
+ puts "No arguments defined"
25
+ else
26
+ arguments.each do |names, proc|
27
+ puts "#{names.join(" or ").green}" # TODO: description
28
+ end
29
+ end
30
+ exit
31
+ end
32
+
33
+ argument("-i", "--interactive") do |task = nil|
34
+ ARGV.clear # otherwise IRB will parse it
35
+
36
+ require "irb"
37
+ begin
38
+ require "irb/readline"
39
+ rescue LoadError
40
+ warn "Code completion via readline isn't available"
41
+ end
42
+
43
+ if task
44
+ Task[task].tap { |task| task.call(*args, options) }
45
+ end
46
+
47
+ IRB.start
48
+ exit!
49
+ end
50
+
51
+ Nake.args["--verbose", "--no-verbose"] = lambda { |key, value| Nake.verbose = value }
52
+ Nake.args["--debug", "--no-debug"] = lambda { |key, value| Nake.debug = value }
@@ -1,29 +1,47 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Nake
4
- module ArgvParsingMixin
5
- def extract!
6
- self.inject(Hash.new) do |options, argument|
7
- case argument
8
- when /^--no-([^=]+)$/ # --no-git-repository
9
- options[$1.gsub("-", "_").to_sym] = false
10
- self.delete(argument)
11
- when /^--([^=]+)$/ # --git-repository
12
- options[$1.gsub("-", "_").to_sym] = true
13
- self.delete(argument)
14
- when /^--([^=]+)=([^,]+)$/ # --controller=post
15
- key, value = $1, $2
16
- options[key.gsub("-", "_").to_sym] = value.dup
17
- self.delete(argument)
18
- when /^--([^=]+)=(.+)$/ # --controllers=posts,comments
19
- key, value = $1, $2
20
- options[key.gsub("-", "_").to_sym] = value.split(",")
21
- self.delete(argument)
22
- else
23
- # just extract options and ignore others
4
+ module ArgvParser
5
+ def self.extract!(args)
6
+ args.dup.inject(Hash.new) do |options, argument|
7
+ key, value = self.parse(argument)
8
+ if key
9
+ options[key] = value
10
+ args.delete(argument)
24
11
  end
25
12
  options
26
13
  end
27
14
  end
15
+
16
+ def self.extract(args)
17
+ args.inject(Hash.new) do |options, argument|
18
+ key, value = self.parse(argument)
19
+ if key
20
+ options[key] = value
21
+ end
22
+ options
23
+ end
24
+ end
25
+
26
+ def self.parse!(argument)
27
+ self.parse(argument) || raise("Argument #{argument} can't be parsed!")
28
+ end
29
+
30
+ def self.parse(argument)
31
+ case argument
32
+ when /^--no-([^=]+)$/ # --no-git-repository
33
+ return [$1.gsub("-", "_").to_sym, false]
34
+ when /^--([^=]+)$/ # --git-repository
35
+ return [$1.gsub("-", "_").to_sym, true]
36
+ when /^--([^=]+)=([^,]+)$/ # --controller=post
37
+ key, value = $1, $2
38
+ return [key.gsub("-", "_").to_sym, value.dup]
39
+ when /^--([^=]+)=(.+)$/ # --controllers=posts,comments
40
+ key, value = $1, $2
41
+ return [key.gsub("-", "_").to_sym, value.split(",")]
42
+ else
43
+ return false
44
+ end
45
+ end
28
46
  end
29
47
  end
@@ -1,9 +1,15 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require "nake"
3
4
  require "nake/task"
5
+ require "nake/file_task"
4
6
 
5
7
  class Object
6
8
  include Nake
9
+ def argument(*names, &block)
10
+ Nake.args[*names] = block
11
+ end
12
+
7
13
  # Rake-style task definition
8
14
  # task(:release, :build) do |task|
9
15
  # # task definition
@@ -17,4 +23,24 @@ class Object
17
23
  end
18
24
  end
19
25
  end
26
+
27
+ def file(path, *dependencies, &block)
28
+ if block.nil?
29
+ FileTask.new(path, *dependencies)
30
+ else
31
+ FileTask.new(path, *dependencies) do |task|
32
+ task.define(&block)
33
+ end
34
+ end
35
+ end
36
+
37
+ def directory(path)
38
+ FileTask.new(path) do |task|
39
+ task.hidden = true # do not show in list
40
+ task.description = "Create directory #{path}"
41
+ task.define do
42
+ mkdir_p path
43
+ end
44
+ end
45
+ end
20
46
  end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require "nake/task"
4
+
5
+ module Nake
6
+ class FileTask < Task
7
+ alias_method :path, :name
8
+ # FileTask can depend on tasks, other file tasks or just files.
9
+ # If a file task depends on a task, this task isn't supposed to change anything what ...
10
+ # ... if it's changing something, make sure the changing task is actually called before the file tasks are executed
11
+ # If the task is changing something so the file will be generated in all cases, you should rather to use normal task
12
+ # If there are some dependencies on files
13
+ # FileTask.new("www/index.html") do |task|
14
+ # task.file_dependencies.push(*FileList["images/**/*"])
15
+ # task.dependencies.push("www") # www task exist
16
+ # end
17
+ def call(args = Array.new, options = Hash.new)
18
+ will_run = true
19
+ unless self.dependencies.empty?
20
+ info "Invoking file task #{name}"
21
+ will_run = self.invoke_dependencies(*args, options)
22
+ end
23
+ if will_run && ! self.blocks.empty?
24
+ note "Executing file task #{name} with arguments #{args.inspect} and options #{options.inspect}"
25
+ debug "Config #{self.config.inspect}"
26
+ self.blocks.each do |block|
27
+ block.call(self.path, *args, options)
28
+ end
29
+ else
30
+ warn "File task #{name} won't be executed"
31
+ end
32
+ end
33
+
34
+ protected
35
+ # task will be executed just if
36
+ def will_run?
37
+ file_tasks = self.dependencies.select { |name| self.class[name] }
38
+ file_tasks.any? do |path|
39
+
40
+ end
41
+ end
42
+
43
+ def task_will_run?(path)
44
+ File.exist?(path) || File.mtime(path) < File.mtime(self.name)
45
+ end
46
+
47
+ # return true if the task need to be executed, false otherwise
48
+ def invoke_dependencies(*args, options)
49
+ self.dependencies.each do |name|
50
+ if task = self.class[name] # first try if there is a task with given name
51
+ task.call(*args, options) # TODO: what about arguments?
52
+ elsif File.exist?(name) # if not, then fallback to file
53
+ task_will_run?(name)
54
+ else
55
+ raise TaskNotFound, "Task with name #{name} doesn't exist"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,21 +1,65 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "fileutils"
4
+ require "nake/colors"
4
5
 
5
6
  module Nake
6
7
  module TaskHelpers
7
8
  include FileUtils
8
- alias_method :run, :`
9
+ def run(*parts)
10
+ puts parts.join(" ").cyan
11
+ system(*parts)
12
+ end
9
13
 
10
14
  # return true if process suceeded, false otherwise
11
15
  # sh "ls -a"
12
16
  # sh "ls", "-a"
13
17
  def sh(*parts)
14
18
  puts "#{"$".magenta} #{parts.join(" ").cyan}"
15
- run "#{parts.shift} #{parts.join(" ")}"
16
- $?.success?
19
+ system("sh", "-c", *parts)
20
+ end
21
+
22
+ # zsh "ls .*(.)"
23
+ def zsh(*parts)
24
+ puts "#{"%".magenta} #{parts.join(" ").cyan}"
25
+ system("zsh", "-c", *parts)
26
+ end
27
+ end
28
+
29
+ module PrintHelpers
30
+ def info(message)
31
+ puts "~ #{message}".cyan if Nake.verbose
32
+ end
33
+
34
+ def note(message)
35
+ puts "~ #{message}".green if Nake.verbose
36
+ end
37
+
38
+ def warn(message)
39
+ Kernel.warn("~ #{message.yellow}") if Nake.debug
40
+ end
41
+
42
+ def debug(message)
43
+ STDERR.puts("~ #{message.yellow}") if Nake.debug
44
+ end
45
+
46
+ def error(message)
47
+ STDERR.puts "~ #{message}".red
48
+ end
49
+
50
+ def abort(message)
51
+ Kernel.abort "[#{"ERROR".red}] #{message}"
52
+ end
53
+
54
+ def print_exception_and_abort(exception)
55
+ abort exception.message
56
+ end
57
+
58
+ def print_exception_with_backtrace_and_abort(exception)
59
+ abort [exception.message, exception.backtrace.join("\n- ")].join("\n")
17
60
  end
18
61
  end
19
62
  end
20
63
 
21
64
  Object.send(:include, Nake::TaskHelpers)
65
+ Object.send(:include, Nake::PrintHelpers)
@@ -1,8 +1,12 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "nake/colors"
4
+ require "nake/argv"
4
5
 
5
6
  module Nake
7
+ TaskNotFound ||= Class.new(StandardError)
8
+ ConfigurationError ||= Class.new(StandardError)
9
+
6
10
  class Task
7
11
  def self.[](name)
8
12
  name = name.to_s
@@ -30,7 +34,7 @@ module Nake
30
34
  task && task.setup(*dependencies, &block) || super(name, *dependencies, &block)
31
35
  end
32
36
 
33
- attr_accessor :name, :description, :dependencies, :hidden
37
+ attr_accessor :name, :description, :dependencies, :hidden, :original_args
34
38
  attr_reader :blocks, :aliases
35
39
  def initialize(name, *dependencies, &block)
36
40
  @aliases, @hidden = Array.new, false
@@ -48,8 +52,14 @@ module Nake
48
52
  end
49
53
 
50
54
  def config
51
- @config ||= Hash.new do |hash, key|
52
- raise ConfigurationError, "Configuration key #{key} in task #{name} doesn't exist"
55
+ @config ||= begin
56
+ Hash.new do |hash, key|
57
+ raise ConfigurationError, "Configuration key #{key} in task #{name} doesn't exist"
58
+ end.tap do |hash|
59
+ hash.define_singleton_method(:declare) do |*keys|
60
+ keys.each { |key| self[key] = nil }
61
+ end
62
+ end
53
63
  end
54
64
  end
55
65
 
@@ -67,18 +77,33 @@ module Nake
67
77
  @hidden
68
78
  end
69
79
 
80
+ def run(args)
81
+ self.original_args = args
82
+ options = ArgvParser.extract!(args)
83
+ self.call(args, options)
84
+ end
85
+
70
86
  # NOTE: the reason why we don't have splat for args is that when we have Task["-T"]
71
87
  # which doesn't have any args and options, we wall just call it without any arguments,
72
88
  # but when we use splat, then we will have to call it at least with Hash.new for options
73
89
  def call(args = Array.new, options = Hash.new)
74
90
  unless self.dependencies.empty?
75
- puts "~ Invoking task #{name}".cyan
91
+ info "Invoking task #{name}"
76
92
  self.invoke_dependencies(*args, options)
77
93
  end
78
94
  unless self.blocks.empty?
79
- puts "~ Executing task #{name} with arguments #{args.inspect} and options #{options.inspect}".green
95
+ note "Executing task #{name} with arguments #{args.inspect} and options #{options.inspect}"
96
+ debug "Config #{self.config.inspect}"
80
97
  self.blocks.each do |block|
81
- if block.arity.eql?(0)
98
+ # we can't use arity, because it returns 0 for lambda { |options = Hash.new| }.arity
99
+ # if we define method with one optional argument, it will returns -1
100
+
101
+ if RUBY_VERSION >= "1.9.2"
102
+ raise ArgumentError, "Task can't take block arguments" if args.length + 1 > block.parameters.select { |type, name| type.eql?(:req) || type.eql?(:opt) }.length
103
+ raise ArgumentError, "Task can't take block arguments" if block.parameters.any? { |type, name| type.eql?(:block) }
104
+ end
105
+
106
+ if RUBY_VERSION >= "1.9.2" && block.parameters.empty?
82
107
  block.call
83
108
  else
84
109
  block.call(*args, options)
@@ -87,6 +112,12 @@ module Nake
87
112
  end
88
113
  end
89
114
 
115
+ def reset!
116
+ self.dependencies.clear
117
+ self.blocks.clear
118
+ self.aliases.clear
119
+ end
120
+
90
121
  protected
91
122
  def invoke_dependencies(*args, options)
92
123
  self.dependencies.each do |name|
@@ -1,9 +1,18 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require "nake/task"
4
+
3
5
  # NOTE: if you have bundler bundled locally, just
4
6
  # add bundler/lib into $: and this task will work
5
- Task.new(:bundle) do |task|
7
+ Nake::Task.new(:bundle) do |task|
6
8
  task.description = "Install your gems locally from gems/cache via bundler"
9
+
10
+ # define bundler method, so we can test it
11
+ task.define_singleton_method(:bundler) do
12
+ @bundler ||= Gem::Commands::BundleCommand.new
13
+ end
14
+
15
+ # task definition
7
16
  task.define do |*args, options|
8
17
  require 'rubygems'
9
18
  require 'rubygems/command'
@@ -15,7 +24,7 @@ Task.new(:bundle) do |task|
15
24
  abort "You have to have bundler installed!"
16
25
  end
17
26
 
18
- args.push("--cached")
19
- Gem::Commands::BundleCommand.new.invoke(*args)
27
+ args.push("--cached") unless options.delete[:cached]
28
+ self.bundler.invoke(*task.original_args)
20
29
  end
21
30
  end
@@ -6,6 +6,12 @@ require "nake/tasks/clean"
6
6
  # register gem files for cleaning
7
7
  Task[:clean].config[:files].push(*Dir["*.gem"])
8
8
 
9
+ module Nake::PackageMixin
10
+ def gem_name
11
+ "#{Task[:release].config[:name]}-#{Task[:release].config[:version]}.gem"
12
+ end
13
+ end
14
+
9
15
  # require "nake/tasks/gem"
10
16
  # Task[:build].config[:gemspec] = Dir["*.gemspec"]
11
17
  Task.new(:build) do |task|
@@ -13,3 +19,11 @@ Task.new(:build) do |task|
13
19
  sh "gem build #{task.config[:gemspec]}"
14
20
  end
15
21
  end
22
+
23
+ Task.new(:install, :build) do |task|
24
+ task.extend(PackageMixin)
25
+ task.description = "Install"
26
+ task.define do
27
+ sh "gem install #{self.gem_name}"
28
+ end
29
+ end
@@ -35,9 +35,9 @@ end
35
35
  Task.new("release:gemcutter") do |task|
36
36
  task.description = "Push gem to Gemcutter"
37
37
  task.dependencies = [:clean, :build]
38
+ task.extend(PackageMixin)
38
39
  task.define do
39
- task.config[:gem] = "#{Task[:release].config[:name]}-#{Task[:release].config[:version]}.gem"
40
40
  puts "Pushing to Gemcutter ..."
41
- sh "gem push #{task.config[:gem]}"
41
+ sh "gem push #{self.gem_name}"
42
42
  end
43
43
  end
@@ -1,25 +1,33 @@
1
1
  # encoding: utf-8
2
2
 
3
- dependencies = FileList["vendor/*/.git"].sub(/\/\.git$/, "")
4
-
5
- desc "Regenerate deps.rip"
6
- file "deps.rip" => dependencies do
7
- commits = Hash.new
8
- commits = dependencies.inject(Hash.new) do |hash, path|
9
- Dir.chdir(path) do
10
- revision = %x(git show | head -1).chomp.sub("commit ", "")
11
- hash[File.basename(path)] = revision
12
- hash
13
- end
14
- end
15
- template = File.read("deps.rip.rbe")
16
- deps_rip = eval("%Q{#{template}}")
17
- File.open("deps.rip", "w") do |file|
18
- file.puts(deps_rip)
19
- end
20
- sh "chmod +x deps.rip"
21
- sh "git commit deps.rip -m 'Updated deps.rip'"
3
+ begin
4
+ require "recho"
5
+ rescue LoadError
6
+ raise LoadError, "This task require recho gem!"
22
7
  end
23
8
 
9
+ require "nake/file_task"
10
+
11
+ # FileTask["deps.rip"].config[:versions] = {rack: "1.0.1", media_path: "SHA1"}
12
+
24
13
  # register task
25
- Task[:release].dependencies.unshift("deps.rip")
14
+ #Task[:release].dependencies.unshift("deps.rip")
15
+
16
+ # deps.rip.str:
17
+ ##!/usr/bin/env rip install
18
+ #
19
+ ## Syntax:
20
+ ## repository [tag or commit to install]
21
+ #git://github.com/botanicus/media-path.git %{media_path}
22
+ #git://github.com/rack/rack.git %{rack}
23
+
24
+ FileTask.new("deps.rip", "deps.rip.str") do |task|
25
+ task.config[:versions] = Hash.new
26
+ task.description = "Regenerate deps.rip"
27
+ task.define do
28
+ data = File.read("deps.rip.str")
29
+ dependencies = "%Q{#{data}}" % task.config[:versions]
30
+ FileUtils.echo("deps.str") > dependencies
31
+ sh "chmod +x deps.rip"
32
+ end
33
+ end
File without changes
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "../../spec_helper"
4
+ require "nake/tasks/bundle"
5
+
6
+ describe "Task bundle" do
7
+ before(:each) do
8
+ @task = Nake::Task[:bundle]
9
+ @bundler = Object.new.define_singleton_method(:invoke) { |*args| args }
10
+ @task.define_singleton_method(:bundler) { @bundler }
11
+ end
12
+
13
+ it "should invoke bundler with --cached by default" do
14
+ @task.call.should include("--cached")
15
+ end
16
+
17
+ it "should invoke bundler without --cached if --no-cached argument is provided" do
18
+ @task.call(cached: false).should_not include("--cached")
19
+ end
20
+
21
+ it "should not pass --no-cached argument to bundler" do
22
+ @task.call(cached: false).should_not include("--no-cached")
23
+ end
24
+
25
+ it "should pass all other arguments to bundler" do
26
+ @task.call("--only", "development").should eql(["--only", "development"])
27
+ end
28
+ end
data/tasks.rb CHANGED
@@ -5,7 +5,18 @@ require "nake/tasks/gem"
5
5
  require "nake/tasks/spec"
6
6
  require "nake/tasks/release"
7
7
 
8
+ begin
9
+ load "code-cleaner.nake"
10
+ rescue LoadError
11
+ warn "If you want to contribute to nake, you have to install code-cleaner gem and then run ./tasks.rb hooks:whitespace:install to get Git pre-commit hook for removing trailing whitespace and improving code quality in general."
12
+ end
13
+
8
14
  Task[:build].config[:gemspec] = "nake.gemspec"
9
15
  Task[:prerelease].config[:gemspec] = "nake.pre.gemspec"
10
16
  Task[:release].config[:name] = "nake"
11
17
  Task[:release].config[:version] = Nake::VERSION
18
+
19
+ Nake::Task["hooks:whitespace:install"].tap do |task|
20
+ task.config[:encoding] = "utf-8"
21
+ task.config[:whitelist] = '(bin/[^/]+|.+\.(rb|rake|nake|thor|task))$'
22
+ end
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
- date: 2009-12-26 00:00:00 +00:00
11
+ date: 2009-12-29 00:00:00 +01:00
12
12
  default_executable: nake
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
@@ -33,19 +33,24 @@ files:
33
33
  - bin/nake
34
34
  - CHANGELOG
35
35
  - examples/args.rb
36
+ - examples/arguments.rb
36
37
  - examples/basic.rb
37
38
  - examples/complex.rb
38
39
  - examples/configuration.rb
39
40
  - examples/default.rb
40
41
  - examples/default_proc.rb
41
42
  - examples/dependencies.rb
43
+ - examples/file.rb
44
+ - examples/flags.rb
42
45
  - examples/helpers.rb
43
46
  - examples/invoking.rb
44
47
  - examples/options.rb
45
48
  - examples/script.rb
49
+ - lib/nake/args.rb
46
50
  - lib/nake/argv.rb
47
51
  - lib/nake/colors.rb
48
52
  - lib/nake/dsl.rb
53
+ - lib/nake/file_task.rb
49
54
  - lib/nake/helpers.rb
50
55
  - lib/nake/task.rb
51
56
  - lib/nake/tasks/bundle.rb
@@ -54,7 +59,6 @@ files:
54
59
  - lib/nake/tasks/release.rb
55
60
  - lib/nake/tasks/rip.rb
56
61
  - lib/nake/tasks/spec.rb
57
- - lib/nake/tasks.rb
58
62
  - lib/nake.rb
59
63
  - LICENSE
60
64
  - nake.gemspec
@@ -64,13 +68,16 @@ files:
64
68
  - spec/nake/argv_spec.rb
65
69
  - spec/nake/colors_spec.rb
66
70
  - spec/nake/dsl_spec.rb
71
+ - spec/nake/file_task_spec.rb
67
72
  - spec/nake/helpers_spec.rb
68
73
  - spec/nake/task_spec.rb
74
+ - spec/nake/tasks/bundle_spec.rb
69
75
  - spec/nake/tasks_spec.rb
70
76
  - spec/nake_spec.rb
71
77
  - spec/spec.opts
72
78
  - spec/spec_helper.rb
73
79
  - tasks.rb
80
+ - tmp/restart.txt
74
81
  - TODO.txt
75
82
  has_rdoc: true
76
83
  homepage: http://github.com/botanicus/nake
@@ -1,49 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "nake/dsl"
4
-
5
- task(["-H", "--help"]) do
6
- abort "\nUse #{$0} -T for list of all available tasks or -i for interactive session"
7
- end
8
-
9
- task(["-T", "--tasks"]) do |pattern, options = Hash.new|
10
- tasks, options = Task.tasks.select { |name, task| not task.hidden? }.sort.partition { |key, value| not key.match(/^-/) }
11
-
12
- puts "\n#{"===".yellow} #{"Available tasks".magenta} #{"===".yellow}"
13
- if tasks.empty?
14
- puts "No tasks defined"
15
- else
16
- tasks.each do |name, task|
17
- puts "#{name.green} #{task.dependencies.join(", ")} # #{task.description || "no description yet"}"
18
- end
19
- end
20
-
21
- puts "\n#{"===".yellow} #{"Available options".magenta} #{"===".yellow}"
22
- if options.empty?
23
- puts "No options defined"
24
- else
25
- options.each do |name, task|
26
- puts "#{name.green} #{task.dependencies.join(", ")} # #{task.description || "no description yet"}"
27
- end
28
- end
29
- end
30
-
31
- # TODO: this doesn't work so far
32
- task(["-i", "--interactive"]) do |*args, options|
33
- require "irb"
34
- begin
35
- require "irb/readline"
36
- rescue LoadError
37
- warn "Code completion via readline isn't available"
38
- end
39
-
40
- unless args.empty?
41
- task = Task[args.shift]
42
- task.call(*args, options)
43
- end
44
-
45
- IRB.start
46
- end
47
-
48
- Task["-T"].hidden = true
49
- Task["-H"].hidden = true