batcave 0.0.1 → 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/Gemfile +1 -0
- data/README.md +45 -6
- data/batcave.gemspec +2 -2
- data/lib/batcave/action/add.rb +43 -0
- data/lib/batcave/command/add.rb +9 -48
- data/lib/batcave/command/update.rb +9 -1
- data/lib/batcave/dsl.rb +254 -0
- data/lib/batcave/main.rb +11 -0
- data/lib/batcave/namespace.rb +1 -0
- data/lib/batcave/store.rb +74 -0
- data/lib/batcave/support/envpath.rb +14 -0
- data/lib/batcave/support/git.rb +2 -0
- data/things/dotfiles/self/THING +6 -0
- data/things/go/self/THING +8 -0
- data/things/ruby/self/THING +9 -0
- data/things/ruby/self/{name}.gemspec.erb +20 -0
- data/things/user.sh/THING +7 -0
- metadata +14 -8
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -7,10 +7,22 @@ Wikipedia on "Batcave" uses:
|
|
7
7
|
> ideal to create a stronghold for his war against crime, and has incorporated a
|
8
8
|
> plethora of equipment as well as expanding the cave for specific uses.
|
9
9
|
|
10
|
-
|
11
|
-
tools,
|
10
|
+
Frankly, I write a lot of code in a lot of languages. There's a lot of
|
11
|
+
boilerplate, tools, and scripts I copy from project to project. Debugging,
|
12
|
+
coding, documentation, tests, etc all are quite similar in goal across projects
|
13
|
+
but differ wildly in implementation. I'd like to codify most of this so that,
|
14
|
+
when switching between projects, the cost of context switching isn't as painful.
|
12
15
|
|
13
|
-
|
16
|
+
Essentially, I do roughly the same activities regardless of platform or language.
|
17
|
+
This project is an experiment in solving the above problem.
|
18
|
+
|
19
|
+
Ideally it'd be sweet if this project would also manage my workstation as well
|
20
|
+
as my projects. Dotfiles, packages, etc. I'm tired of setting this shit up or
|
21
|
+
scripting it sideways every few months.
|
22
|
+
|
23
|
+
This project may end up looking a lot like an IDE plus some config management.
|
24
|
+
|
25
|
+
## Example
|
14
26
|
|
15
27
|
Maybe, for example, I'm writing an HTTP library in Ruby, and I want to:
|
16
28
|
|
@@ -18,11 +30,38 @@ Maybe, for example, I'm writing an HTTP library in Ruby, and I want to:
|
|
18
30
|
* run tests whenever I modify the code.
|
19
31
|
* make sure all methods have docstrings (with YARD)
|
20
32
|
* have some useful debugging tools.
|
33
|
+
* generate documentation to publish online
|
21
34
|
|
22
|
-
But new projects should be easier:
|
35
|
+
But new projects should be easier, too:
|
23
36
|
|
24
37
|
* create a 'go' project with a layout that works well with 'goinstall'
|
25
|
-
* create a 'ruby' project with a standard layout, Gemfile, gemspec, etc
|
26
|
-
|
38
|
+
* create a 'ruby' project with a standard layout, Gemfile, gemspec, etc. A bin
|
39
|
+
file that uses clamp with sample flag code. A namespace file generated for
|
40
|
+
me, etc.
|
41
|
+
* automatically create basic tests
|
42
|
+
* include tools for debugging
|
27
43
|
|
28
44
|
Release management should be easier, too.
|
45
|
+
|
46
|
+
## Idea: boilerplate and project creation
|
47
|
+
|
48
|
+
* dk add thing
|
49
|
+
|
50
|
+
a 'thing' is a feature, boilerplate, some debug tool, metrics or testing tool, etc.
|
51
|
+
|
52
|
+
Example:
|
53
|
+
|
54
|
+
* dk add --name example go
|
55
|
+
* dk add ruby
|
56
|
+
|
57
|
+
Both of the above will generate boilerplate projects for their respective
|
58
|
+
languages. It currently uses git to find the root of your project directory
|
59
|
+
and puts files based from that location.
|
60
|
+
|
61
|
+
Boilerplates should include basic tests, etc.
|
62
|
+
|
63
|
+
## Other ideas in command-line form
|
64
|
+
|
65
|
+
* dk release - run tests, bump version, build package, run tests, tag it, publish
|
66
|
+
* dk add travis-ci - add .travis.yml file with language detection
|
67
|
+
* dk debug - run an application inside a debugger (gdb for c/c++, ruby's debugger or pry, etc)
|
data/batcave.gemspec
CHANGED
@@ -2,9 +2,9 @@ Gem::Specification.new do |spec|
|
|
2
2
|
files = %x{git ls-files}.split("\n")
|
3
3
|
|
4
4
|
spec.name = "batcave"
|
5
|
-
spec.version = "0.0.
|
5
|
+
spec.version = "0.0.4"
|
6
6
|
spec.summary = "Experiments in tools, boilerplatery, debugging, etc."
|
7
|
-
spec.
|
7
|
+
spec.description = spec.summary
|
8
8
|
spec.add_dependency("clamp")
|
9
9
|
spec.files = files
|
10
10
|
spec.bindir = "bin"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "batcave/namespace"
|
2
|
+
require "batcave/support/git"
|
3
|
+
|
4
|
+
class BatCave::Action::Add
|
5
|
+
include BatCave::Support::Git
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Add a new thing with some arguments.
|
10
|
+
#
|
11
|
+
# Arguments for each thing are defined in the 'THING' file for each ... thing.
|
12
|
+
def initialize(thing, args)
|
13
|
+
@logger = Cabin::Channel.get("batcave")
|
14
|
+
@thing = thing
|
15
|
+
@args = args
|
16
|
+
end # def initialize
|
17
|
+
|
18
|
+
def find_thing(thing)
|
19
|
+
# look for the 'thing/' or if it's a directory try 'thing/self/'
|
20
|
+
[ @thing, File.join(@thing, "self") ].each do |thing|
|
21
|
+
path = File.join(BatCave::THINGSDIR, thing)
|
22
|
+
config = File.join(path, "THING")
|
23
|
+
return config if File.exists?(config)
|
24
|
+
end
|
25
|
+
|
26
|
+
puts "Could not find any thing '#{@thing}'"
|
27
|
+
return false
|
28
|
+
end # def find_thing
|
29
|
+
|
30
|
+
def execute
|
31
|
+
config = find_thing(@thing)
|
32
|
+
return 1 if config == false
|
33
|
+
dsl = BatCave::DSL.new(config, @thing, @args)
|
34
|
+
dsl.execute
|
35
|
+
|
36
|
+
# TODO(sissel): Record that we've added this thing.
|
37
|
+
puts "Adding #{dsl.environment}/#{@thing}"
|
38
|
+
store = BatCave::Store.new
|
39
|
+
store.store(dsl)
|
40
|
+
end # def execute
|
41
|
+
|
42
|
+
public(:initialize, :execute)
|
43
|
+
end # class BatCave::Action::Add
|
data/lib/batcave/command/add.rb
CHANGED
@@ -1,63 +1,24 @@
|
|
1
1
|
require "clamp"
|
2
2
|
require "batcave/namespace"
|
3
|
-
require "batcave/
|
3
|
+
require "batcave/action/add"
|
4
|
+
require "batcave/dsl"
|
5
|
+
require "batcave/store"
|
4
6
|
require "fileutils"
|
5
7
|
|
8
|
+
# TODO(sissel): Need to track what we've added so we can sync later.
|
9
|
+
|
6
10
|
class BatCave::Command::Add < Clamp::Command
|
7
|
-
include BatCave::Support::Git
|
8
11
|
|
12
|
+
# TODO(sissel): Move this to the 'thing' DSL
|
9
13
|
option ["-n", "--name"], "NAME",
|
10
14
|
"the application or library name", :attribute_name => :name
|
11
15
|
|
12
16
|
parameter "THING",
|
13
17
|
"The thing to add to your batcave", :attribute_name => :thing
|
14
18
|
|
15
|
-
|
16
|
-
# TODO(sissel): Move this stuff into a proper batcave library
|
17
|
-
|
18
|
-
found = false
|
19
|
-
# look for the 'thing/' or if it's a directory try 'thing/self/'
|
20
|
-
[ @thing, File.join(@thing, "self") ].each do |thing|
|
21
|
-
path = File.join(BatCave::THINGSDIR, thing)
|
22
|
-
config = File.join(path, "THING")
|
23
|
-
if File.exists?(config)
|
24
|
-
found = true
|
25
|
-
use(path)
|
26
|
-
break
|
27
|
-
end
|
28
|
-
end
|
19
|
+
parameter "[THINGARGS] ...", "arguments to pass to the thing", :attribute_name => :args
|
29
20
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
21
|
+
def execute
|
22
|
+
BatCave::Action::Add.new(@thing, @args).execute
|
33
23
|
end # def execute
|
34
|
-
|
35
|
-
def use(dir)
|
36
|
-
config = File.join(dir, "THING")
|
37
|
-
paths = Dir.glob(File.join(dir, "**", "*"))
|
38
|
-
|
39
|
-
paths.each do |path|
|
40
|
-
next if path == config # skip the 'THING' file
|
41
|
-
localpath = File.join(project_root, path[dir.length + 1 .. -1])
|
42
|
-
|
43
|
-
if localpath.include?("{name}")
|
44
|
-
if @name.nil?
|
45
|
-
raise "Path requires '--name' flag to be set: #{localpath.inspect}"
|
46
|
-
end
|
47
|
-
localpath.gsub!("{name}", @name)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Replace '{...}' in localpath
|
51
|
-
|
52
|
-
# TODO(sissel): if this is a directory, create it.
|
53
|
-
# TODO(sissel): if this a file, copy it.
|
54
|
-
if File.directory?(path)
|
55
|
-
FileUtils.mkdir_p(localpath) unless File.directory?(localpath)
|
56
|
-
else
|
57
|
-
localdir = File.dirname(localpath)
|
58
|
-
FileUtils.mkdir_p(localdir) unless File.directory?(localdir)
|
59
|
-
FileUtils.cp(path, localpath)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
24
|
end
|
@@ -1,8 +1,16 @@
|
|
1
1
|
require "clamp"
|
2
2
|
require "batcave/namespace"
|
3
|
+
require "batcave/command/add"
|
3
4
|
|
4
5
|
class BatCave::Command::Update < Clamp::Command
|
6
|
+
parameter "ENVIRONMENT", "The environment to update (user, project, etc)",
|
7
|
+
:attribute_name => :environment
|
8
|
+
|
5
9
|
def execute
|
6
|
-
|
10
|
+
store = BatCave::Store.new
|
11
|
+
store.each(@environment) do |thing, settings|
|
12
|
+
args = settings["args"]
|
13
|
+
BatCave::Action::Add.new(thing, args).execute
|
14
|
+
end
|
7
15
|
end
|
8
16
|
end
|
data/lib/batcave/dsl.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
require "batcave/namespace"
|
2
|
+
require "batcave/support/envpath"
|
3
|
+
require "fileutils" # stdlib
|
4
|
+
require "cabin" # gem 'cabin'
|
5
|
+
require "erb" # stdlib
|
6
|
+
|
7
|
+
# TODO(sissel): DSL is a poor name for this class. Fix it later.
|
8
|
+
# TODO(sissel): Split the 'THING' processor from the 'Thing' instances
|
9
|
+
class BatCave::DSL
|
10
|
+
include BatCave::Support::Git
|
11
|
+
include BatCave::Support::EnvPath
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def initialize(configfile, thing, args)
|
16
|
+
@args = args
|
17
|
+
@thing = thing
|
18
|
+
@configfile = configfile
|
19
|
+
@logger = Cabin::Channel.get("batcave")
|
20
|
+
|
21
|
+
# Default environment is project.
|
22
|
+
@environment = :project
|
23
|
+
# Update all files by default
|
24
|
+
@create_only = []
|
25
|
+
|
26
|
+
@target ||= path(@environment)
|
27
|
+
@sourcedir = File.dirname(@configfile)
|
28
|
+
@sync = true
|
29
|
+
|
30
|
+
# Make this 'thing' argument into a command by
|
31
|
+
# dynamically making a new subclass of Clamp::Command
|
32
|
+
@command = Class.new(Clamp::Command).new("<internal dsl thing>")
|
33
|
+
class << @command
|
34
|
+
def execute
|
35
|
+
# nothing to do, we just want to parse flags.
|
36
|
+
end
|
37
|
+
end
|
38
|
+
binding.eval(File.read(@configfile), @configfile)
|
39
|
+
end # def initialize
|
40
|
+
|
41
|
+
# Declare options for this thing. This block will be executed
|
42
|
+
# in the context of a Clamp::Command, so anything valid in a
|
43
|
+
# Clamp::Command definition is valid here. The options will
|
44
|
+
# be parsed immediately after this block is evaluated.
|
45
|
+
#
|
46
|
+
# Example:
|
47
|
+
#
|
48
|
+
# options do
|
49
|
+
# parameter "SOURCE", "The source to use", :attribute_name => :foo
|
50
|
+
# end
|
51
|
+
def options(&block)
|
52
|
+
@command.class.instance_eval(&block)
|
53
|
+
@command.run(@args)
|
54
|
+
|
55
|
+
# Copy related instance variables from the Clamp::Command to this object.
|
56
|
+
@command.instance_variables.each do |ivar|
|
57
|
+
# Skip ones that are part of the Command normally (not attributes)
|
58
|
+
next if [:@invocation_path, :@context, :@remaining_arguments].include?(ivar)
|
59
|
+
instance_variable_set(ivar, @command.instance_variable_get(ivar))
|
60
|
+
end
|
61
|
+
end # def options
|
62
|
+
|
63
|
+
# Set the source to use for this thing
|
64
|
+
def source(upstream)
|
65
|
+
root = File.join(ENV["HOME"], ".batcave", "upstream")
|
66
|
+
FileUtils.mkdir_p(root)
|
67
|
+
Dir.chdir(root) do
|
68
|
+
if !File.directory?(@thing)
|
69
|
+
cmd = "git clone #{upstream} #{@thing}"
|
70
|
+
else
|
71
|
+
#cmd = "cd #{@thing}; git fetch origin master; git reset --hard origin/master"
|
72
|
+
cmd = "cd #{@thing}; git pull origin master"
|
73
|
+
end
|
74
|
+
|
75
|
+
@logger.info("Running", :command => cmd)
|
76
|
+
system(cmd)
|
77
|
+
if $?.exitstatus != 0
|
78
|
+
# TODO(sissel): Do something better than aborting
|
79
|
+
raise "Command exited #{$?.exitstatus}: #{cmd}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
@sourcedir = File.join(root, @thing)
|
83
|
+
end # def source
|
84
|
+
|
85
|
+
def target(directory)
|
86
|
+
@target = directory
|
87
|
+
end # def target
|
88
|
+
|
89
|
+
# Do path expansion.
|
90
|
+
#
|
91
|
+
# If the path is /foo/bar/{name}
|
92
|
+
# and @names is ["one", "two"], then this will:
|
93
|
+
#
|
94
|
+
# * yield "/foo/bar/one"
|
95
|
+
# * yield "/foo/bar/two"
|
96
|
+
#
|
97
|
+
# A {foo} will check both @foo and @foos
|
98
|
+
def expand(paths, &block)
|
99
|
+
skip_re = /(^|\/)\.(\.|git|svn)/
|
100
|
+
paths.each do |path|
|
101
|
+
next if skip_re.match(path)
|
102
|
+
# find all {...} in the string
|
103
|
+
tokens = path.scan(/{[^}]+}/)
|
104
|
+
if tokens.include?("{name}")
|
105
|
+
names = []
|
106
|
+
names << @name if instance_variable_defined?(:@name)
|
107
|
+
names += @names if instance_variable_defined?(:@names)
|
108
|
+
|
109
|
+
if names.empty?
|
110
|
+
message = [
|
111
|
+
"No {name} known, can't expand #{path}",
|
112
|
+
"maybe add this to your THING file: ",
|
113
|
+
"",
|
114
|
+
"options do",
|
115
|
+
" parameter 'NAME', 'The {name} value', :attribute_name => :name",
|
116
|
+
"end"
|
117
|
+
].join("\n")
|
118
|
+
raise message
|
119
|
+
end
|
120
|
+
|
121
|
+
names.each do |name|
|
122
|
+
yield path, path.gsub("{name}", name)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
yield path, path
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end # def expand
|
129
|
+
|
130
|
+
def create_only(*paths)
|
131
|
+
if paths.first.is_a?(Array)
|
132
|
+
paths = paths.first
|
133
|
+
end
|
134
|
+
|
135
|
+
@create_only = paths
|
136
|
+
end # def create_only
|
137
|
+
|
138
|
+
# Sync two paths
|
139
|
+
def sync
|
140
|
+
if !instance_variable_defined?(:@sourcedir)
|
141
|
+
@logger.error("Can't sync, no source defined")
|
142
|
+
return
|
143
|
+
end
|
144
|
+
|
145
|
+
paths = Dir.glob(File.join(@sourcedir, "**", "*"), File::FNM_DOTMATCH)
|
146
|
+
expand(paths) do |source, target|
|
147
|
+
next if source == @configfile # skip the 'THING' file
|
148
|
+
originalpath = source[@sourcedir.length + 1 .. -1]
|
149
|
+
localpath = File.join(path(@environment), target[@sourcedir.length + 1 .. -1])
|
150
|
+
|
151
|
+
if localpath =~ /\.erb$/
|
152
|
+
localpath = localpath[0...-4]
|
153
|
+
use_erb = true
|
154
|
+
else
|
155
|
+
use_erb = false
|
156
|
+
end
|
157
|
+
|
158
|
+
# TODO(sissel): if this is a directory, create it.
|
159
|
+
# TODO(sissel): if this a file, copy it.
|
160
|
+
if File.directory?(source)
|
161
|
+
FileUtils.mkdir_p(localpath) unless File.directory?(localpath)
|
162
|
+
else
|
163
|
+
localdir = File.dirname(localpath)
|
164
|
+
FileUtils.mkdir_p(localdir) unless File.directory?(localdir)
|
165
|
+
|
166
|
+
if @create_only.include?(originalpath) and File.exists?(localpath)
|
167
|
+
@logger.info("Skipping existing file due to 'create_only': #{localpath}")
|
168
|
+
else
|
169
|
+
if use_erb
|
170
|
+
erb = ERB.new(File.read(source))
|
171
|
+
@logger.info("Generating ", :source => source, :target => localpath)
|
172
|
+
File.open(localpath, "w+") do |fd|
|
173
|
+
# Make all ivars available as names in the templates, so I can just do
|
174
|
+
# <%= name %> instead of <%= @name %>
|
175
|
+
ivar = IvarBinding.new(self)
|
176
|
+
fd.write(erb.result(ivar.binding))
|
177
|
+
end
|
178
|
+
else
|
179
|
+
@logger.info("Copying", :source => source, :target => localpath)
|
180
|
+
FileUtils.cp(source, localpath)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end # def sync
|
186
|
+
|
187
|
+
# Set the environment this thing is operating in.
|
188
|
+
#
|
189
|
+
# Valid environments are: :system, :user, :project, :path
|
190
|
+
#
|
191
|
+
# This helps hint batcave update operations so you can just update your user,
|
192
|
+
# project, etc, instead of everything at once.
|
193
|
+
def environment(env=nil)
|
194
|
+
if !env.nil?
|
195
|
+
@environment = env
|
196
|
+
end
|
197
|
+
return @environment
|
198
|
+
end # def environment
|
199
|
+
|
200
|
+
def thing
|
201
|
+
return @thing
|
202
|
+
end # def thing
|
203
|
+
|
204
|
+
def to_hash
|
205
|
+
return {
|
206
|
+
"args" => @args
|
207
|
+
}
|
208
|
+
end # def to_yaml
|
209
|
+
|
210
|
+
def execute
|
211
|
+
sync if @sync
|
212
|
+
end
|
213
|
+
|
214
|
+
def nosync
|
215
|
+
@sync = false
|
216
|
+
end # def nosync
|
217
|
+
|
218
|
+
# Metaprogramming to provide instance variables from a class as
|
219
|
+
# local-variable-like things in a binding. For use with ERB and such.
|
220
|
+
#
|
221
|
+
# This is a fun hack.
|
222
|
+
class IvarBinding
|
223
|
+
def initialize(object)
|
224
|
+
# Make a new Object subclass
|
225
|
+
klass = Class.new(Object)
|
226
|
+
|
227
|
+
# Find all instance variables in 'object' and make
|
228
|
+
# them methods in our new class. Each method will
|
229
|
+
# simply return that named instance variable.
|
230
|
+
object.instance_variables.each do |ivar|
|
231
|
+
meth = ivar.to_s.gsub("@", "")
|
232
|
+
klass.instance_eval do
|
233
|
+
define_method(meth) do
|
234
|
+
object.instance_variable_get(ivar)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Make a method that returns the binding for this class
|
240
|
+
klass.instance_eval do
|
241
|
+
define_method(:_binding) do
|
242
|
+
return binding
|
243
|
+
end
|
244
|
+
end
|
245
|
+
@instance = klass.new
|
246
|
+
end # def initialize
|
247
|
+
|
248
|
+
def binding
|
249
|
+
return @instance._binding
|
250
|
+
end # def binding
|
251
|
+
end # class IvarBinding
|
252
|
+
|
253
|
+
public(:initialize, :execute, :environment, :thing, :to_hash)
|
254
|
+
end # class BatCave::DSL
|
data/lib/batcave/main.rb
CHANGED
@@ -2,8 +2,19 @@ require "clamp"
|
|
2
2
|
require "batcave/namespace"
|
3
3
|
require "batcave/command/add"
|
4
4
|
require "batcave/command/update"
|
5
|
+
require "cabin"
|
5
6
|
|
6
7
|
class BatCave::Main < Clamp::Command
|
8
|
+
option ["-v", "--verbose"], :flag, "enable verbose logging" do
|
9
|
+
require "logger"
|
10
|
+
logger = Cabin::Channel.get("batcave")
|
11
|
+
p Cabin::Channel.get("batcave").object_id
|
12
|
+
p Cabin::Channel.get("batcave").object_id
|
13
|
+
p Cabin::Channel.get("batcave").object_id
|
14
|
+
logger.subscribe(Logger.new(STDOUT))
|
15
|
+
logger.level = :info
|
16
|
+
end
|
17
|
+
|
7
18
|
# Add something to your bat cave.
|
8
19
|
subcommand "add", "Add something to your batcave", BatCave::Command::Add
|
9
20
|
|
data/lib/batcave/namespace.rb
CHANGED
@@ -0,0 +1,74 @@
|
|
1
|
+
require "batcave/namespace"
|
2
|
+
require "batcave/support/git"
|
3
|
+
require "batcave/support/envpath"
|
4
|
+
require "yaml"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
class BatCave::Store
|
8
|
+
include BatCave::Support::Git
|
9
|
+
include BatCave::Support::EnvPath
|
10
|
+
|
11
|
+
def lock(path, &block)
|
12
|
+
lockfile = "#{path}.lock"
|
13
|
+
File.open(lockfile, "a+") do |lockfd|
|
14
|
+
locked = lockfd.flock(File::LOCK_EX | File::LOCK_NB)
|
15
|
+
if !locked
|
16
|
+
info = lockfd.read
|
17
|
+
raise "Store is currently locked, cannot write to it. (info: #{info})"
|
18
|
+
end
|
19
|
+
lockfd.rewind
|
20
|
+
lockfd.write("pid:$$")
|
21
|
+
lockfd.flush
|
22
|
+
|
23
|
+
block.call
|
24
|
+
end
|
25
|
+
|
26
|
+
# This step is not required for flock(2) to work, but it should help to
|
27
|
+
# keep users from being confused.
|
28
|
+
File.delete(lockfile)
|
29
|
+
end # def lock
|
30
|
+
|
31
|
+
def store(dsl)
|
32
|
+
basedir = path(dsl.environment)
|
33
|
+
manifest_path = File.join(basedir, ".batcave", "manifest")
|
34
|
+
FileUtils.mkdir_p(File.join(basedir, ".batcave"))
|
35
|
+
|
36
|
+
lock(manifest_path) do
|
37
|
+
manifest = load(manifest_path)
|
38
|
+
# Store this thing.
|
39
|
+
manifest["things"][dsl.thing] = dsl.to_hash
|
40
|
+
|
41
|
+
# Write the manifest to a tmpfile and rename it.
|
42
|
+
tmpfile = manifest_path + ".tmp"
|
43
|
+
File.open(tmpfile, "w") do |tmp|
|
44
|
+
tmp.write(manifest.to_yaml)
|
45
|
+
tmp.flush
|
46
|
+
end
|
47
|
+
File.rename(tmpfile, manifest_path)
|
48
|
+
end
|
49
|
+
end # def store
|
50
|
+
|
51
|
+
def each(environment, &block)
|
52
|
+
basedir = path(environment)
|
53
|
+
manifest_path = File.join(basedir, ".batcave", "manifest")
|
54
|
+
manifest = load(manifest_path)
|
55
|
+
manifest["things"].each do |thing|
|
56
|
+
yield thing
|
57
|
+
end
|
58
|
+
end # def each
|
59
|
+
|
60
|
+
def load(manifest_path)
|
61
|
+
manifest = {}
|
62
|
+
if File.exists?(manifest_path)
|
63
|
+
fd = File.new(manifest_path, "a+")
|
64
|
+
# Load the current manifest so we can modify it
|
65
|
+
manifest = YAML.load(fd.read)
|
66
|
+
manifest = {} if !manifest
|
67
|
+
fd.close
|
68
|
+
end
|
69
|
+
|
70
|
+
# Handle empty manifest. (YAML.load returns false for empty files)
|
71
|
+
manifest["things"] ||= {}
|
72
|
+
return manifest
|
73
|
+
end # def manifest
|
74
|
+
end # class BatCave::Store
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "batcave/namespace"
|
2
|
+
|
3
|
+
module BatCave::Support::EnvPath
|
4
|
+
def path(environment)
|
5
|
+
case environment.to_sym
|
6
|
+
when :user
|
7
|
+
return ENV["HOME"]
|
8
|
+
when :project
|
9
|
+
return project_root
|
10
|
+
else
|
11
|
+
raise "Unsupported environment '#{environment}'"
|
12
|
+
end
|
13
|
+
end # def path
|
14
|
+
end
|
data/lib/batcave/support/git.rb
CHANGED
@@ -2,10 +2,12 @@ require "batcave/namespace"
|
|
2
2
|
|
3
3
|
module BatCave::Support::Git
|
4
4
|
def project_root
|
5
|
+
return @project_root if instance_variable_defined?(:@project_root)
|
5
6
|
root = %x{git rev-parse --show-toplevel}.chomp
|
6
7
|
if $?.exitstatus != 0
|
7
8
|
raise "'git rev-parse --show-toplevel' failed. No project root found. Is this in a git clone?"
|
8
9
|
end
|
10
|
+
@project_root = root
|
9
11
|
return root
|
10
12
|
end # def project_root
|
11
13
|
end # class BatCave::Support::Git
|
data/things/go/self/THING
CHANGED
data/things/ruby/self/THING
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
files = %x{git ls-files}
|
3
|
+
|
4
|
+
spec.name = "<%= name %>"
|
5
|
+
spec.version = "0.0.1"
|
6
|
+
spec.summary = "<%= name %>"
|
7
|
+
spec.description = "<%= name %>"
|
8
|
+
spec.license = "none chosen yet"
|
9
|
+
|
10
|
+
# Note: You should set the version explicitly.
|
11
|
+
spec.add_dependency "cabin", ">0" # for logging. apache 2 license
|
12
|
+
spec.files = files
|
13
|
+
spec.require_paths << "lib"
|
14
|
+
spec.bindir = "bin"
|
15
|
+
|
16
|
+
spec.authors = ["<%= %x{git config --global user.name}.chomp %>"]
|
17
|
+
spec.email = ["<%= %x{git config --global user.email}.chomp %>"]
|
18
|
+
#spec.homepage = "..."
|
19
|
+
end
|
20
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: batcave
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: clamp
|
16
|
-
requirement: &
|
16
|
+
requirement: &4815200 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,8 +21,8 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
-
description:
|
24
|
+
version_requirements: *4815200
|
25
|
+
description: Experiments in tools, boilerplatery, debugging, etc.
|
26
26
|
email: jls@semicomplete.com
|
27
27
|
executables:
|
28
28
|
- dk
|
@@ -35,11 +35,16 @@ files:
|
|
35
35
|
- README.md
|
36
36
|
- batcave.gemspec
|
37
37
|
- bin/dk
|
38
|
+
- lib/batcave/action/add.rb
|
38
39
|
- lib/batcave/command/add.rb
|
39
40
|
- lib/batcave/command/update.rb
|
41
|
+
- lib/batcave/dsl.rb
|
40
42
|
- lib/batcave/main.rb
|
41
43
|
- lib/batcave/namespace.rb
|
44
|
+
- lib/batcave/store.rb
|
45
|
+
- lib/batcave/support/envpath.rb
|
42
46
|
- lib/batcave/support/git.rb
|
47
|
+
- things/dotfiles/self/THING
|
43
48
|
- things/go/self/THING
|
44
49
|
- things/go/self/src/{name}/{name}.go
|
45
50
|
- things/ruby/self/Gemfile
|
@@ -47,6 +52,8 @@ files:
|
|
47
52
|
- things/ruby/self/test/all.rb
|
48
53
|
- things/ruby/self/test/docs.rb
|
49
54
|
- things/ruby/self/test/testing.rb
|
55
|
+
- things/ruby/self/{name}.gemspec.erb
|
56
|
+
- things/user.sh/THING
|
50
57
|
homepage: https://github.com/jordansissel/batcave
|
51
58
|
licenses: []
|
52
59
|
post_install_message:
|
@@ -67,9 +74,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
74
|
version: '0'
|
68
75
|
requirements: []
|
69
76
|
rubyforge_project:
|
70
|
-
rubygems_version: 1.8.
|
77
|
+
rubygems_version: 1.8.16
|
71
78
|
signing_key:
|
72
79
|
specification_version: 3
|
73
|
-
summary:
|
80
|
+
summary: Experiments in tools, boilerplatery, debugging, etc.
|
74
81
|
test_files: []
|
75
|
-
has_rdoc:
|