groundwork 0.0.1
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/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
|
+
|