groundwork 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []