groundwork 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/groundwork +26 -0
- data/lib/groundwork.rb +175 -0
- data/lib/options.rb +32 -0
- data/lib/tar_wrapper.rb +33 -0
- metadata +91 -0
data/bin/groundwork
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__),"..","lib","groundwork.rb")
|
4
|
+
|
5
|
+
begin
|
6
|
+
options = Groundwork::parse_options
|
7
|
+
|
8
|
+
case options[:command]
|
9
|
+
when "generate"
|
10
|
+
generate_opts = Trollop::options(options[:remainder]) do
|
11
|
+
opt :force, :default=>false
|
12
|
+
end
|
13
|
+
|
14
|
+
name = options[:remainder].shift || "Recipe"
|
15
|
+
|
16
|
+
if File.exists?(name+".recipe") && !generate_opts[:force]
|
17
|
+
raise RuntimeError.new("File already exists: #{name}.recipe")
|
18
|
+
end
|
19
|
+
|
20
|
+
recipe = Groundwork::Recipe.generate
|
21
|
+
File.open(name+".recipe","w"){|f| f.print recipe}
|
22
|
+
else
|
23
|
+
end
|
24
|
+
rescue
|
25
|
+
puts $!.to_s
|
26
|
+
end
|
data/lib/groundwork.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "trollop"
|
3
|
+
require "erb"
|
4
|
+
require "pathname"
|
5
|
+
require File.join(File.dirname(__FILE__), "options.rb")
|
6
|
+
require File.join(File.dirname(__FILE__), "tar_wrapper.rb")
|
7
|
+
|
8
|
+
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
|
+
|
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 'kickstart'"
|
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
|
131
|
+
end
|
132
|
+
|
133
|
+
# Generate a tree of file and directory calls that would create the given
|
134
|
+
# directory
|
135
|
+
def self.generate dir = FileUtils.pwd
|
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
|
+
if File.directory? file
|
142
|
+
if Dir[File.join(file,"*")].empty?
|
143
|
+
output.puts((" "*indent)+"directory \"#{file}\"")
|
144
|
+
else
|
145
|
+
output.puts("")
|
146
|
+
output.puts((" "*indent)+"directory \"#{file}\" do")
|
147
|
+
handle_dir[file, output, indent+2]
|
148
|
+
output.puts((" "*indent)+"end")
|
149
|
+
output.puts("")
|
150
|
+
end
|
151
|
+
else
|
152
|
+
rel = Pathname.new(File.join(FileUtils.pwd,file))
|
153
|
+
relpath = rel.relative_path_from(base).to_s
|
154
|
+
output.puts((" "*indent)+"file \"#{file}\", :from => \"#{relpath}\"")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
str = StringIO.new
|
161
|
+
handle_dir[dir, str, 0]
|
162
|
+
str.string.gsub(/\n\n+/,"\n\n") # Collapse adjacent blank lines
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def read_file name
|
168
|
+
if @tar
|
169
|
+
@tar[name]
|
170
|
+
else
|
171
|
+
File.read(name)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
data/lib/options.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "abbrev"
|
2
|
+
|
3
|
+
module Groundwork
|
4
|
+
def self.parse_options opts=ARGV
|
5
|
+
global_opts = Trollop::options(opts) do
|
6
|
+
banner "Groundwork"
|
7
|
+
version "0.0.1"
|
8
|
+
stop_on_unknown
|
9
|
+
end
|
10
|
+
|
11
|
+
cmd=short_for(opts.shift)
|
12
|
+
|
13
|
+
return({ :options=>global_opts,
|
14
|
+
:command=>cmd,
|
15
|
+
:remainder=>opts
|
16
|
+
})
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.short_for cmd_start, all_commands=["generate"]
|
20
|
+
return cmd_start unless cmd_start
|
21
|
+
return cmd_start if all_commands.index(cmd_start)
|
22
|
+
|
23
|
+
completions = all_commands.abbrev(cmd_start)
|
24
|
+
if completions[cmd_start]
|
25
|
+
completions[cmd_start]
|
26
|
+
elsif completions.values.uniq.empty?
|
27
|
+
raise RuntimeError.new("Unknown command \"#{cmd_start}\".")
|
28
|
+
else
|
29
|
+
raise RuntimeError.new("\"#{cmd_start}\" is ambiguous. Which did you mean:\n\t"+cmd_poss.join("\n\t"))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/tar_wrapper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "archive/tar/minitar"
|
3
|
+
require "base64"
|
4
|
+
|
5
|
+
class Groundwork::TarWrapper
|
6
|
+
include Archive::Tar
|
7
|
+
|
8
|
+
# Takes a base64-encoded, tarred string
|
9
|
+
def initialize encoded
|
10
|
+
tar = Base64.decode64(encoded)
|
11
|
+
@files = {}
|
12
|
+
Minitar::Reader.new(StringIO.new(tar)).each do |entry|
|
13
|
+
next unless entry.file?
|
14
|
+
@files[entry.full_name] = entry.read
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def [] name
|
19
|
+
@files[name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.compress files
|
23
|
+
string = StringIO.new
|
24
|
+
output = Minitar::Output.new(string)
|
25
|
+
|
26
|
+
files.each do |file|
|
27
|
+
Minitar.pack_file(file, output)
|
28
|
+
end
|
29
|
+
|
30
|
+
output.close
|
31
|
+
Base64.encode64 string.string
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: groundwork
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Andrews, Ross
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-02-23 00:00:00 -06:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: trollop
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 10
|
30
|
+
- 2
|
31
|
+
version: 1.10.2
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: archive-tar-minitar
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
- 5
|
44
|
+
- 2
|
45
|
+
version: 0.5.2
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: Create scripts that describe the groundwork for laying out your projects, and generate project frameworks
|
49
|
+
email: randrews@geekfu.org
|
50
|
+
executables:
|
51
|
+
- groundwork
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files: []
|
55
|
+
|
56
|
+
files:
|
57
|
+
- lib/groundwork.rb
|
58
|
+
- lib/tar_wrapper.rb
|
59
|
+
- lib/options.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: https://github.com/randrews/groundwork
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project: groundwork
|
86
|
+
rubygems_version: 1.3.6
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: A project scaffolding generator
|
90
|
+
test_files: []
|
91
|
+
|