groundwork 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
data/bin/groundwork CHANGED
@@ -5,86 +5,11 @@ require File.join(File.dirname(__FILE__),"..","lib","groundwork.rb")
5
5
  begin
6
6
  options = Groundwork::parse_options
7
7
 
8
- case options[:command]
8
+ raise RuntimeError.new("No command given; use \"groundwork -h\" for help") unless options[:command]
9
9
 
10
- ##################################################
11
- ### Generate #####################################
12
- ##################################################
13
- when "generate"
10
+ load File.join(File.dirname(__FILE__),"..","commands",options[:command]+".rb")
14
11
 
15
- generate_opts = Trollop::options(options[:remainder]) do
16
- banner <<-STR
17
- Usage:
18
- groundwork generate [options] filename
19
-
20
- Generates a basic .recipe.rb file, which you can modify, from the current directory
21
-
22
- Options are:
23
- STR
24
- opt :force, "Overwrite .recipe.rb file if exists", :default=>false
25
- opt :ignore, "Ignore files matching these filename patterns", :type=>:strings
26
- opt :print, "Instead of storing in a file, print the recipe to stdout", :default=>false
27
- opt :chdir, "Before running, cd to the given directory", :default=>FileUtils.pwd
28
- end
29
-
30
- recipe = ""
31
- FileUtils.cd(generate_opts[:chdir]) do
32
- recipe = Groundwork::Recipe.generate FileUtils.pwd, :ignore => generate_opts[:ignore]
33
- end
34
-
35
- if generate_opts[:print]
36
- puts recipe
37
- else
38
- name = options[:remainder].shift || "Recipe"
39
-
40
- if File.exists?(name+".recipe.rb") && !generate_opts[:force]
41
- raise RuntimeError.new("File already exists: #{name}.recipe.rb\nUse -f to overwrite")
42
- end
43
-
44
- File.open(name+".recipe.rb","w"){|f| f.print recipe}
45
- end
46
-
47
- ##################################################
48
- ### Compile ######################################
49
- ##################################################
50
- when "compile"
51
-
52
- compile_opts = Trollop::options(options[:remainder]) do
53
- banner <<-STR
54
- Usage:
55
- groundwork compile [options] filename.recipe.rb
56
-
57
- Compiles a .recipe.rb, including all referenced files into it.
58
-
59
- Options are:
60
- STR
61
- opt :force, "Overwrite .recipe file if exists", :default=>false
62
- opt :print, "Instead of storing in a file, print the recipe to stdout", :default=>false
63
- opt :chdir, "Before running, cd to the given directory", :default=>FileUtils.pwd
64
- end
65
-
66
- input = options[:remainder].shift
67
- raise RuntimeError.new("No input file given") unless input
68
- raise RuntimeError.new("Cannot open #{input}") unless File.exists?(input)
69
-
70
- compiled = ""
71
- FileUtils.cd(compile_opts[:chdir]) do
72
- compiled = Groundwork::Recipe.compile input
73
- end
74
-
75
- if compile_opts[:print]
76
- puts compiled
77
- else
78
- name = options[:remainder].shift || File.basename(input,".recipe.rb")
79
-
80
- if File.exists?(name+".recipe") && !compile_opts[:force]
81
- raise RuntimeError.new("File already exists: #{name}.recipe\nUse -f to overwrite")
82
- end
83
-
84
- File.open(name+".recipe","w"){|f| f.print compiled}
85
- end
86
- else
87
- end
12
+ Groundwork::Commands.send options[:command], options[:remainder]
88
13
  rescue
89
14
  puts $!.to_s
90
15
  end
@@ -0,0 +1,47 @@
1
+ module Groundwork
2
+ module Commands
3
+ def self.compile args
4
+ cmd_opts = Trollop::options(args) do
5
+ banner <<-STR
6
+ Usage:
7
+ groundwork compile [options] filename.recipe.rb
8
+
9
+ Compiles a .recipe.rb, including all referenced files into it.
10
+
11
+ Options are:
12
+ STR
13
+ opt :force, "Overwrite .recipe file if exists", :default=>false
14
+ opt :print, "Instead of storing in a file, print the recipe to stdout", :default=>false
15
+ opt :chdir, "Before running, cd to the given directory", :default=>FileUtils.pwd
16
+ end
17
+
18
+ input = args.shift
19
+ raise RuntimeError.new("Cannot open #{input}") if input && !File.exists?(input)
20
+
21
+ compiled = ""
22
+ FileUtils.cd(cmd_opts[:chdir]) do
23
+ compiled = if input
24
+ Groundwork::Recipe.compile_file input
25
+ else
26
+ Groundwork::Recipe.compile STDIN.read, FileUtils.pwd
27
+ end
28
+ end
29
+
30
+ if cmd_opts[:print]
31
+ puts compiled
32
+ else
33
+ name = args.shift || if input
34
+ File.basename(input,".recipe.rb")
35
+ else
36
+ File.basename(FileUtils.pwd)
37
+ end
38
+
39
+ if File.exists?(name+".recipe") && !cmd_opts[:force]
40
+ raise RuntimeError.new("File already exists: #{name}.recipe\nUse -f to overwrite")
41
+ end
42
+
43
+ File.open(name+".recipe","w"){|f| f.print compiled}
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ module Groundwork
2
+ module Commands
3
+ def self.generate args
4
+
5
+ cmd_opts = Trollop::options(args) do
6
+ banner <<-STR
7
+ Usage:
8
+ groundwork generate [options] filename
9
+
10
+ Generates a basic .recipe.rb file, which you can modify, from the current directory
11
+
12
+ Options are:
13
+ STR
14
+ opt :force, "Overwrite .recipe.rb file if exists", :default=>false
15
+ opt :ignore, "Ignore files matching these filename patterns", :type=>:strings
16
+ opt :print, "Instead of storing in a file, print the recipe to stdout", :default=>false
17
+ opt :chdir, "Before running, cd to the given directory", :default=>FileUtils.pwd
18
+ end
19
+
20
+ recipe = ""
21
+ FileUtils.cd(cmd_opts[:chdir]) do
22
+ recipe = Groundwork::Recipe.generate FileUtils.pwd, :ignore => cmd_opts[:ignore]
23
+ end
24
+
25
+ if cmd_opts[:print]
26
+ puts recipe
27
+ else
28
+ name = args.shift || File.basename(FileUtils.pwd)
29
+
30
+ if File.exists?(name+".recipe.rb") && !cmd_opts[:force]
31
+ raise RuntimeError.new("File already exists: #{name}.recipe.rb\nUse -f to overwrite")
32
+ end
33
+
34
+ File.open(name+".recipe.rb","w"){|f| f.print recipe}
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ module Groundwork
2
+ module Commands
3
+ def self.install args
4
+ cmd_opts = Trollop::options(args) do
5
+ banner <<-STR
6
+ Usage:
7
+ groundwork install [options] filename.recipe
8
+
9
+ Installs a recipe into ~/.groundwork
10
+
11
+ Options are:
12
+ STR
13
+ opt :force, "Overwrite recipe if it already exists", :default=>false
14
+ opt :name, "Specify a name for the recipe other than the filename", :default=>false
15
+ end
16
+
17
+ file = args.shift
18
+ raise RuntimeError.new("No input file given") unless file
19
+ raise RuntimeError.new("Cannot open #{file}") unless File.exists?(file)
20
+
21
+ dot_groundwork = File.expand_path("~/.groundwork")
22
+ FileUtils.mkdir(dot_groundwork) unless File.directory?(dot_groundwork)
23
+
24
+ if File.exists?(File.join(dot_groundwork,File.basename(file))) && !cmd_opts[:force]
25
+ raise RuntimeError.new("Recipe already exists: #{File.basename(file,'.recipe')}\nUse -f to replace")
26
+ end
27
+
28
+ FileUtils.cp file, dot_groundwork
29
+ end
30
+ end
31
+ end
data/commands/list.rb ADDED
@@ -0,0 +1,16 @@
1
+ module Groundwork
2
+ module Commands
3
+ def self.list args
4
+ cmd_opts = Trollop::options(args) do
5
+ banner <<-STR
6
+ Usage:
7
+ groundwork list
8
+
9
+ Lists all installed recipes
10
+ STR
11
+ end
12
+
13
+ puts Groundwork.known_recipes.keys.join("\n")
14
+ end
15
+ end
16
+ end
data/lib/groundwork.rb CHANGED
@@ -4,175 +4,26 @@ require "erb"
4
4
  require "pathname"
5
5
  require File.join(File.dirname(__FILE__), "options.rb")
6
6
  require File.join(File.dirname(__FILE__), "tar_wrapper.rb")
7
+ require File.join(File.dirname(__FILE__), "recipe.rb")
8
+ require File.join(File.dirname(__FILE__), "recipe_class.rb")
7
9
 
8
10
  module Groundwork
9
- class Recipe
10
- def initialize &block
11
- if block_given?
12
- instance_eval &block
13
- end
14
- end
15
-
16
- def tar= data
17
- @tar = TarWrapper.new(data)
18
- end
19
-
20
- # Creates a directory. If a block is passed,
21
- # the block will be run inside that directory
22
- def directory *name, &block
23
- FileUtils.mkdir_p File.join(name)
24
- if block_given?
25
- FileUtils.cd File.join(name), &block
26
- end
27
- end
28
-
29
- # If opts is a string, it's the contents of the file, verbatim
30
- # If opts is a hash, it must contain either:
31
- # * :from, copies the text of the given filename verbatim
32
- # * :from_erb, uses the text of the filename as an erb template
33
- # * :erb, uses the given string as an erb template
34
- def file name, opts = nil
35
- name = File.join(name)
36
- File.open(File.join(name),"w") do |file|
37
- if opts.is_a? String
38
- file.print opts
39
- elsif opts.is_a? Hash
40
- file.print( if opts[:from]
41
- read_file opts[:from]
42
- elsif opts[:from_erb]
43
- ERB.new(read_file(opts[:from_erb])).result(binding)
44
- elsif opts[:erb]
45
- ERB.new(opts[:erb]).result(binding)
46
- end )
47
- elsif opts.nil?
48
- # write nothing
49
- else
50
- raise ArgumentError.new
51
- end
52
- end
53
- end
54
-
55
- # When you compile a recipe, it runs it to determine which files to bake in.
56
- # If you have a file that might not be generated by running your script with
57
- # no options, you can call possible on it to ensure it gets baked into
58
- # the script. This function only has an effect during compilation, it does
59
- # nothing when the script is actually run.
60
- def possible name ; end
61
-
62
- # Takes a block and lists the files that that block will require as templates.
63
- # See Groundwork::Recipe#possible
64
- def self.required_files &block
65
- dummy = Object.new
66
- files = []
67
-
68
- class << dummy
69
- attr_reader :files
70
-
71
- def directory *args
72
- yield if block_given?
73
- end
74
-
75
- def file name, opts=nil
76
- @files << opts[:from] if opts[:from]
77
- @files << opts[:from_erb] if opts[:from_erb]
78
- end
79
-
80
- def possible name
81
- @files << name
82
- end
83
-
84
- def method_missing *args ; end
85
- end
86
11
 
87
- dummy.instance_variable_set "@files", []
88
- dummy.instance_eval &block
89
-
90
- dummy.files
91
- end
92
-
93
- # Takes a script file, finds the files it requires (paths relative to the script file),
94
- # reads/tars them and returns a string containing the script and the TAR blob, ready
95
- # to write to a file
96
- def self.compile script_file
97
- script = File.read(script_file)
98
- out = StringIO.new
99
- data = nil
100
-
101
- FileUtils.cd(File.dirname(script_file)) do
102
- files = required_files do
103
- eval script
104
- end
105
-
106
- data = TarWrapper.compress files
107
- end
108
-
109
- out.puts "if $0==__FILE__"
110
- out.puts " require 'rubygems'"
111
- out.puts " require 'groundwork'"
112
- out.puts "end"
113
- out.puts ""
114
- out.puts script
115
- out.puts ""
116
- out.puts "__END__"
117
- out.puts data
118
-
119
- out.string
120
- end
121
-
122
- # Takes a filename and runs the script contained in it. The file should be
123
- # the results of Groundwork::Recipe#compile
124
- def self.run script_file
125
- (script, data) = File.read(script_file).split("\n__END__\n")
126
-
127
- Groundwork::Recipe.new do
128
- self.tar = data
129
- eval script
130
- end
12
+ # Return a hash of all known recipes, the included ones and the ones in .groundwork
13
+ def self.known_recipes
14
+ recipes = {}
15
+ Dir[File.join(File.dirname(__FILE__),"..","recipes","*.recipe")].each do |recipe|
16
+ recipes[File.basename(recipe,".recipe")] = recipe
131
17
  end
132
18
 
133
- # Generate a tree of file and directory calls that would create the given
134
- # directory
135
- def self.generate dir = FileUtils.pwd, options = {}
136
- base = Pathname.new dir
137
-
138
- handle_dir = lambda do |d, output, indent|
139
- FileUtils.cd d do
140
- Dir["*"].each do |file|
141
- rel = Pathname.new(File.join(FileUtils.pwd,file))
142
- relpath = rel.relative_path_from(base).to_s
143
-
144
- next if options[:ignore] && options[:ignore].any?{|p| File.fnmatch(p,relpath) }
19
+ dot_groundwork = File.expand_path("~/.groundwork")
145
20
 
146
- if File.directory? file
147
- if Dir[File.join(file,"*")].empty?
148
- output.puts((" "*indent)+"directory \"#{file}\"")
149
- else
150
- output.puts("")
151
- output.puts((" "*indent)+"directory \"#{file}\" do")
152
- handle_dir[file, output, indent+2]
153
- output.puts((" "*indent)+"end")
154
- output.puts("")
155
- end
156
- else
157
- output.puts((" "*indent)+"file \"#{file}\", :from => \"#{relpath}\"")
158
- end
159
- end
160
- end
21
+ if File.directory?(dot_groundwork)
22
+ Dir[File.join(dot_groundwork,"*.recipe")].each do |recipe|
23
+ recipes[File.basename(recipe,".recipe")] = recipe
161
24
  end
162
-
163
- str = StringIO.new
164
- handle_dir[dir, str, 0]
165
- str.string.gsub(/\n\n+/,"\n\n") # Collapse adjacent blank lines
166
25
  end
167
26
 
168
- private
169
-
170
- def read_file name
171
- if @tar
172
- @tar[name]
173
- else
174
- File.read(name)
175
- end
176
- end
27
+ recipes
177
28
  end
178
29
  end
data/lib/options.rb CHANGED
@@ -1,17 +1,26 @@
1
1
  require "abbrev"
2
2
 
3
3
  module Groundwork
4
+ GROUNDWORK_VERSION = File.read(File.join(File.dirname(__FILE__), "..", "VERSION"))
5
+ COMMANDS = Dir[File.join(File.dirname(__FILE__),"..","commands","*.rb")].map{|file| File.basename(file,".rb") }
6
+
4
7
  def self.parse_options opts=ARGV
5
8
  global_opts = Trollop::options(opts) do
6
9
  banner <<-STR
7
10
  Usage:
8
- groundwork [global_options] command [command_options]
11
+ groundwork [global_options] <command> [command_options]
12
+
13
+ Commands:
14
+ generate - Generate a recipe for the current directory
15
+ compile - Compile a .recipe.rb file into a .recipe
16
+ install - Install a compiled .recipe file into ~/.groundwork
17
+ list - List all recipes
9
18
 
10
- Currently, the only implemented commands are "generate", which generates a recipe for the current directory, and "compile", which compiles a recipe with all the files it references.
19
+ Use "groundwork <command> -h" for command-specific help
11
20
 
12
- Options are:
21
+ Global options are:
13
22
  STR
14
- version "0.0.3"
23
+ version GROUNDWORK_VERSION
15
24
  stop_on_unknown
16
25
  end
17
26
 
@@ -23,7 +32,7 @@ STR
23
32
  })
24
33
  end
25
34
 
26
- def self.short_for cmd_start, all_commands=["generate", "compile"]
35
+ def self.short_for cmd_start, all_commands=(COMMANDS | known_recipes.keys)
27
36
  return cmd_start unless cmd_start
28
37
  return cmd_start if all_commands.index(cmd_start)
29
38
 
data/lib/recipe.rb ADDED
@@ -0,0 +1,65 @@
1
+ module Groundwork
2
+ class Recipe
3
+ def initialize &block
4
+ if block_given?
5
+ instance_eval &block
6
+ end
7
+ end
8
+
9
+ def tar= data
10
+ @tar = TarWrapper.new(data)
11
+ end
12
+
13
+ # Creates a directory. If a block is passed,
14
+ # the block will be run inside that directory
15
+ def directory *name, &block
16
+ FileUtils.mkdir_p File.join(name)
17
+ if block_given?
18
+ FileUtils.cd File.join(name), &block
19
+ end
20
+ end
21
+
22
+ # If opts is a string, it's the contents of the file, verbatim
23
+ # If opts is a hash, it must contain either:
24
+ # * :from, copies the text of the given filename verbatim
25
+ # * :from_erb, uses the text of the filename as an erb template
26
+ # * :erb, uses the given string as an erb template
27
+ def file name, opts = nil
28
+ name = File.join(name)
29
+ File.open(File.join(name),"w") do |file|
30
+ if opts.is_a? String
31
+ file.print opts
32
+ elsif opts.is_a? Hash
33
+ file.print( if opts[:from]
34
+ read_file opts[:from]
35
+ elsif opts[:from_erb]
36
+ ERB.new(read_file(opts[:from_erb])).result(binding)
37
+ elsif opts[:erb]
38
+ ERB.new(opts[:erb]).result(binding)
39
+ end )
40
+ elsif opts.nil?
41
+ # write nothing
42
+ else
43
+ raise ArgumentError.new
44
+ end
45
+ end
46
+ end
47
+
48
+ # When you compile a recipe, it runs it to determine which files to bake in.
49
+ # If you have a file that might not be generated by running your script with
50
+ # no options, you can call possible on it to ensure it gets baked into
51
+ # the script. This function only has an effect during compilation, it does
52
+ # nothing when the script is actually run.
53
+ def possible name ; end
54
+
55
+ private
56
+
57
+ def read_file name
58
+ if @tar
59
+ @tar[name]
60
+ else
61
+ File.read(name)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,111 @@
1
+ module Groundwork
2
+ class Recipe
3
+ class << self
4
+
5
+ # Takes a block and lists the files that that block will require as templates.
6
+ # See Groundwork::Recipe#possible
7
+ def required_files &block
8
+ dummy = Object.new
9
+ files = []
10
+
11
+ class << dummy
12
+ attr_reader :files
13
+
14
+ def directory *args
15
+ yield if block_given?
16
+ end
17
+
18
+ def file name, opts=nil
19
+ @files << opts[:from] if opts[:from]
20
+ @files << opts[:from_erb] if opts[:from_erb]
21
+ end
22
+
23
+ def possible name
24
+ @files << name
25
+ end
26
+
27
+ def method_missing *args ; end
28
+ end
29
+
30
+ dummy.instance_variable_set "@files", []
31
+ dummy.instance_eval &block
32
+
33
+ dummy.files
34
+ end
35
+
36
+ def compile_file filename
37
+ compile File.read(filename), File.dirname(filename)
38
+ end
39
+
40
+ # Takes a script file, finds the files it requires (paths relative to the script file),
41
+ # reads/tars them and returns a string containing the script and the TAR blob, ready
42
+ # to write to a file
43
+ def compile script, in_directory
44
+ out = StringIO.new
45
+ data = nil
46
+
47
+ FileUtils.cd(in_directory) do
48
+ files = required_files do
49
+ eval script
50
+ end
51
+
52
+ data = TarWrapper.compress files
53
+ end
54
+
55
+ out.puts script
56
+ out.puts ""
57
+ out.puts "__END__"
58
+ out.puts data
59
+
60
+ out.string
61
+ end
62
+
63
+ # Takes a filename and runs the script contained in it. The file should be
64
+ # the results of Groundwork::Recipe#compile
65
+ def run script_file
66
+ (script, data) = File.read(script_file).split("\n__END__\n")
67
+
68
+ Groundwork::Recipe.new do
69
+ self.tar = data
70
+ eval script
71
+ end
72
+ end
73
+
74
+ # Generate a tree of file and directory calls that would create the given
75
+ # directory
76
+ def generate dir = FileUtils.pwd, options = {}
77
+ base = Pathname.new dir
78
+
79
+ handle_dir = lambda do |d, output, indent|
80
+ FileUtils.cd d do
81
+ Dir["*"].each do |file|
82
+ rel = Pathname.new(File.join(FileUtils.pwd,file))
83
+ relpath = rel.relative_path_from(base).to_s
84
+
85
+ next if options[:ignore] && options[:ignore].any?{|p| File.fnmatch(p,relpath) }
86
+
87
+ if File.directory? file
88
+ if Dir[File.join(file,"*")].empty?
89
+ output.puts((" "*indent)+"directory \"#{file}\"")
90
+ else
91
+ output.puts("")
92
+ output.puts((" "*indent)+"directory \"#{file}\" do")
93
+ handle_dir[file, output, indent+2]
94
+ output.puts((" "*indent)+"end")
95
+ output.puts("")
96
+ end
97
+ else
98
+ output.puts((" "*indent)+"file \"#{file}\", :from => \"#{relpath}\"")
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ str = StringIO.new
105
+ handle_dir[dir, str, 0]
106
+ str.string.gsub(/\n\n+/,"\n\n") # Collapse adjacent blank lines
107
+ end
108
+
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ file "hello.rb", <<-STR
2
+ puts "Hello, world!"
3
+ STR
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 3
9
- version: 0.0.3
8
+ - 4
9
+ version: 0.0.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Andrews, Ross
@@ -54,9 +54,17 @@ extensions: []
54
54
  extra_rdoc_files: []
55
55
 
56
56
  files:
57
+ - VERSION
57
58
  - lib/groundwork.rb
58
- - lib/tar_wrapper.rb
59
59
  - lib/options.rb
60
+ - lib/recipe.rb
61
+ - lib/recipe_class.rb
62
+ - lib/tar_wrapper.rb
63
+ - commands/compile.rb
64
+ - commands/generate.rb
65
+ - commands/install.rb
66
+ - commands/list.rb
67
+ - recipes/hello.recipe
60
68
  has_rdoc: true
61
69
  homepage: https://github.com/randrews/groundwork
62
70
  licenses: []