codger 0.0.1 → 0.0.2
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/README.md +17 -13
- data/lib/codger/cli.rb +31 -39
- data/lib/codger/manager.rb +63 -41
- data/lib/codger/skeleton.rb +26 -19
- data/lib/codger/version.rb +1 -1
- metadata +10 -10
data/README.md
CHANGED
@@ -9,17 +9,13 @@ Goals:
|
|
9
9
|
|
10
10
|
Put the skeleton in a git repo. Before testing it, make sure to at least `git add` the files. Then:
|
11
11
|
|
12
|
-
codger
|
13
|
-
|
14
|
-
Now, to generate code inside the current working directory, do
|
15
|
-
|
16
|
-
codger gen your-repo-name
|
12
|
+
codger gen path/to/your/repo path/to/new/project
|
17
13
|
|
18
14
|
Here's how the skeleton repo will be used:
|
19
15
|
|
20
16
|
1. If there is a script named `generate.rb` in the root directory, it will be run.
|
21
17
|
2. Files ending in `.erb` will be [interpolated](http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html) and written to the target directory.
|
22
|
-
3. Other files will be copied directly to the target directory. (Exceptions: README, README.md, README.markdown)
|
18
|
+
3. Other files will be copied directly to the target directory. (Exceptions: README, README.md, README.markdown, .gitignore)
|
23
19
|
|
24
20
|
### Parameters
|
25
21
|
|
@@ -32,23 +28,31 @@ The first time a prompt is given, the skeleton repo's README will be printed (if
|
|
32
28
|
* In a template, you can use `<%- rename "relative_path" -%>` to override the output file name.
|
33
29
|
* Use `copy "path1", "path2"` to copy files "path1" and "path2" (relative the skeleton repo's root directory) into the target directory directly. Use `copy "path1" => "newpath1"` to override the destination path in the target directory.
|
34
30
|
* Use `interpolate "path1", "path2"` to interpolate ERB files "path1" and "path2" into the target directory. As with `copy` you can use a hash to override the destination paths.
|
31
|
+
* Use `cancel` inside a template to stop its interpolation.
|
35
32
|
* Use `ignore "path1", "path2"` to prevent automatic copying or interpolation of files.
|
36
33
|
|
37
34
|
## Using Skeletons
|
38
35
|
|
39
|
-
|
36
|
+
Run in a new folder:
|
40
37
|
|
41
|
-
codger
|
38
|
+
codger gen boilerplate monumental-endeavor
|
42
39
|
|
43
|
-
|
40
|
+
Or run in the current working directory:
|
44
41
|
|
45
|
-
codger
|
42
|
+
codger gen boilerplate
|
46
43
|
|
47
|
-
|
44
|
+
### Caching
|
48
45
|
|
49
|
-
codger
|
46
|
+
codger cache git://uri/to/boilerplate.git # stores a local clone in ~/.codger/cached
|
47
|
+
codger gen boilerplate # uses the local clone (but will update it first if possible)
|
48
|
+
|
49
|
+
### Diffing
|
50
|
+
|
51
|
+
You can add the `-r` (record) option:
|
52
|
+
|
53
|
+
codger gen boilerplate -r
|
50
54
|
|
51
|
-
|
55
|
+
to have the run recorded in a file named `.codger`, so that later, after the project or the skeleton have changed, you can use
|
52
56
|
|
53
57
|
codger diff
|
54
58
|
|
data/lib/codger/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
require 'git'
|
3
5
|
require 'thor'
|
@@ -6,6 +8,23 @@ require 'yaml'
|
|
6
8
|
|
7
9
|
module Codger
|
8
10
|
class CLI < Thor
|
11
|
+
desc 'cache GENERATOR', 'keep a local clone of the generator from the given location'
|
12
|
+
def cache identifier
|
13
|
+
Manager.default.cache identifier
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'cached', 'list all cached generators'
|
17
|
+
def cached
|
18
|
+
Manager.default.settings[:cached].each do |identifier, _|
|
19
|
+
puts identifier
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'uncache GENERATOR', 'remove local clone of a generator'
|
24
|
+
def uncache identifier
|
25
|
+
Manager.default.uncache identifier
|
26
|
+
end
|
27
|
+
|
9
28
|
desc 'config [NAME [VALUE]]', 'lists, shows, or alters configuration'
|
10
29
|
def config(name = nil, value = nil)
|
11
30
|
if name
|
@@ -20,41 +39,19 @@ module Codger
|
|
20
39
|
end
|
21
40
|
end
|
22
41
|
|
23
|
-
desc '
|
24
|
-
|
25
|
-
|
26
|
-
|
42
|
+
desc 'gen GENERATOR [PATH]', 'run the specified generator at the given path or the current working directory'
|
43
|
+
method_option :record, aliases: '-r', type: :boolean, desc: 'record this run in a .codger file in the directory'
|
44
|
+
def gen identifier, path='.'
|
45
|
+
path = File.expand_path path
|
46
|
+
unless File.exists? path
|
47
|
+
FileUtils.mkdir path
|
48
|
+
Git.init path
|
27
49
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
def skeleton(location)
|
34
|
-
info = {}
|
35
|
-
if options[:test]
|
36
|
-
location = File.expand_path(location)
|
37
|
-
info[:test] = true
|
38
|
-
end
|
39
|
-
info[:git] = location
|
40
|
-
Manager.default.register options[:name], info
|
41
|
-
end
|
42
|
-
|
43
|
-
desc 'create NAME PATH', 'run the named generator in a new folder at the given path'
|
44
|
-
def create(name, path)
|
45
|
-
FileUtils.mkdir path
|
46
|
-
Git.init File.expand_path(path)
|
47
|
-
manager = Manager.new(File.join(path, '.codger'))
|
48
|
-
generator = manager.generator(manager.settings[:generators][name])
|
49
|
-
generator.run path, project_name: path.split('/').last
|
50
|
-
manager.record_run generator
|
51
|
-
end
|
52
|
-
|
53
|
-
desc 'gen NAME', 'run the named generator'
|
54
|
-
def gen(name)
|
55
|
-
generator = Manager.default.generator(Manager.default.settings[:generators][name])
|
56
|
-
generator.run(Dir.pwd)
|
57
|
-
Manager.default.record_run(generator)
|
50
|
+
manager = Manager.new File.join(path, '.codger')
|
51
|
+
generator = manager.generator identifier
|
52
|
+
puts "Running #{generator.identifier}"
|
53
|
+
generator.run path
|
54
|
+
manager.record_run generator if options[:record]
|
58
55
|
end
|
59
56
|
|
60
57
|
desc 'history', 'show the actions recorded for this directory'
|
@@ -91,10 +88,5 @@ module Codger
|
|
91
88
|
end
|
92
89
|
end
|
93
90
|
end
|
94
|
-
|
95
|
-
desc 'unregister NAME', 'unregister a code generator and delete its clone'
|
96
|
-
def unregister(name)
|
97
|
-
Manager.default.unregister name
|
98
|
-
end
|
99
91
|
end
|
100
92
|
end
|
data/lib/codger/manager.rb
CHANGED
@@ -35,8 +35,7 @@ module Codger
|
|
35
35
|
config: {
|
36
36
|
diff: 'diff -ur %SOURCE %DEST'
|
37
37
|
},
|
38
|
-
|
39
|
-
generators: {}
|
38
|
+
cached: {}
|
40
39
|
}.with_indifferent_access
|
41
40
|
if File.exists?(globals_path)
|
42
41
|
@global_settings.merge! YAML.load(File.read(globals_path))
|
@@ -44,43 +43,32 @@ module Codger
|
|
44
43
|
end
|
45
44
|
|
46
45
|
# Creates a Generator, currently always a Skeleton.
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
46
|
+
# id can be:
|
47
|
+
# * a filesystem path, which will be used directly
|
48
|
+
# * a git uri, which will be cloned to a temporary directory
|
49
|
+
# * a substring of the identifier of a cached skeleton
|
50
|
+
def generator(id)
|
51
|
+
if File.exists? id
|
52
|
+
clone = id
|
53
|
+
id = File.expand_path id
|
54
|
+
elsif cached = match_cached_identifier(id)
|
55
|
+
id, clone = cached
|
56
|
+
git = Git.open(clone)
|
57
|
+
# https://github.com/schacon/ruby-git/issues/32
|
58
|
+
begin
|
59
|
+
git.lib.send(:command, 'pull')
|
60
|
+
rescue StandardError => ex
|
61
|
+
puts "Warning: could not update cached clone: #{ex.inspect}"
|
62
|
+
end
|
63
|
+
else
|
64
|
+
clone = Dir.mktmpdir
|
65
|
+
Git.clone id, clone
|
66
|
+
at_exit do
|
67
|
+
raise "I'm scared to delete #{clone}" unless clone.size > 10 # just being paranoid before rm_rf'ing
|
68
|
+
FileUtils.rm_rf clone
|
61
69
|
end
|
62
|
-
Skeleton.new clone, info
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Load a generator for the given attributes and register it
|
67
|
-
# in the global configuration under the given name, or its default
|
68
|
-
# name if name is nil.
|
69
|
-
def register(name, info)
|
70
|
-
gen = generator(info)
|
71
|
-
@global_settings[:generators][name || gen.name] = gen.info
|
72
|
-
save_globals
|
73
|
-
end
|
74
|
-
|
75
|
-
# Given a generator name, removes it from the config, and delete its
|
76
|
-
# local clone if one exists.
|
77
|
-
def unregister(name)
|
78
|
-
info = @global_settings[:generators].delete name # TODO graciously handle it not existing
|
79
|
-
clone = @global_settings[:clones].delete info[:git]
|
80
|
-
if clone and clone.start_with? clones_base # sanity check before rm_rf
|
81
|
-
FileUtils.rm_rf clone
|
82
70
|
end
|
83
|
-
|
71
|
+
Skeleton.new clone, id
|
84
72
|
end
|
85
73
|
|
86
74
|
# Saves the tags, identifier, and params from the last run of the given generator instance
|
@@ -88,12 +76,46 @@ module Codger
|
|
88
76
|
def record_run(generator)
|
89
77
|
@project_settings[:runs] << {
|
90
78
|
tags: [generator.name] + generator.tags,
|
91
|
-
generator: generator.
|
79
|
+
generator: generator.identifier,
|
92
80
|
params: generator.params
|
93
81
|
}.with_indifferent_access
|
94
82
|
save_project
|
95
83
|
end
|
96
84
|
|
85
|
+
# Clone the specified repo into #cached_base.
|
86
|
+
def cache identifier
|
87
|
+
return if settings[:cached][identifier]
|
88
|
+
identifier = File.expand_path identifier if File.exist?(identifier) # hacky
|
89
|
+
FileUtils.mkdir_p cached_base
|
90
|
+
next_id = Dir.entries(cached_base).map(&:to_i).max + 1
|
91
|
+
clone = File.join cached_base, next_id.to_s
|
92
|
+
Git.clone identifier, clone
|
93
|
+
@global_settings[:cached][identifier] = clone
|
94
|
+
save_globals
|
95
|
+
end
|
96
|
+
|
97
|
+
# Remove the specified repo from #cached_base. identifier may
|
98
|
+
# be a substring of the desired repo.
|
99
|
+
def uncache identifier
|
100
|
+
if match = match_cached_identifier(identifier)
|
101
|
+
@global_settings[:cached].delete match[0]
|
102
|
+
clone = match[1]
|
103
|
+
raise "I'm scared to delete #{clone}" unless clone.size > 10 && clone.start_with?(cached_base) # again, paranoia
|
104
|
+
FileUtils.rm_rf clone
|
105
|
+
save_globals
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Find a cached repository with an identifier similar to
|
110
|
+
# the given one (specifically, that has the given one as a substring).
|
111
|
+
# Returns [identifier, clone]
|
112
|
+
def match_cached_identifier identifier
|
113
|
+
return nil if identifier.size < 4 # crude typo protection
|
114
|
+
settings[:cached].detect do |cached_id, clone|
|
115
|
+
cached_id.include?(identifier)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
97
119
|
# Save #project_settings.
|
98
120
|
def save_project
|
99
121
|
File.write @project_path, @project_settings.to_yaml
|
@@ -116,9 +138,9 @@ module Codger
|
|
116
138
|
File.join(codger_home, 'codger.yaml')
|
117
139
|
end
|
118
140
|
|
119
|
-
# Return the folder where
|
120
|
-
def
|
121
|
-
File.join
|
141
|
+
# Return the folder where clones can be saved - 'cached' in #codger_home.
|
142
|
+
def cached_base
|
143
|
+
File.join codger_home, 'cached'
|
122
144
|
end
|
123
145
|
|
124
146
|
# Return a merged map of #global_settings and #project_settings.
|
data/lib/codger/skeleton.rb
CHANGED
@@ -17,6 +17,7 @@ module Codger
|
|
17
17
|
#
|
18
18
|
# Methods for use in generate.rb and templates:
|
19
19
|
# * #src_path
|
20
|
+
# * #cancel
|
20
21
|
# * #copy
|
21
22
|
# * #interpolate
|
22
23
|
# * #ignore
|
@@ -26,24 +27,20 @@ module Codger
|
|
26
27
|
# skeletons this is based on the last segment of the origin
|
27
28
|
# URI or of the clone's path.
|
28
29
|
attr_reader :name
|
29
|
-
# Returns the
|
30
|
-
attr_reader :
|
30
|
+
# Returns the identifier that can (hopefully) be used to locate this skeleton in the future.
|
31
|
+
attr_reader :identifier
|
31
32
|
|
32
|
-
# Create an instance reading from the git repository at the specified
|
33
|
-
# path.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@
|
38
|
-
@git = Git.open(repo)
|
39
|
-
# https://github.com/schacon/ruby-git/issues/32
|
40
|
-
@git.lib.send(:command, 'pull') unless info[:test] # TODO needs to be OK if this fails
|
41
|
-
@name = info[:git].split('/').last.sub(/\.git\z/,'')
|
33
|
+
# Create an instance reading from the git repository at the specified (local)
|
34
|
+
# path.
|
35
|
+
def initialize clone, identifier
|
36
|
+
@identifier = identifier
|
37
|
+
@git = Git.open(clone)
|
38
|
+
@name = identifier.split('/').last.sub(/\.git\z/,'')
|
42
39
|
end
|
43
40
|
|
44
41
|
# Perform code generation using the process outlined in the class documentation.
|
45
42
|
def generate
|
46
|
-
@to_copy = @git.ls_files.keys - ['README', 'README.md', 'README.markdown', 'generate.rb']
|
43
|
+
@to_copy = @git.ls_files.keys - ['README', 'README.md', 'README.markdown', 'generate.rb', '.gitignore']
|
47
44
|
|
48
45
|
code_path = src_path('generate.rb')
|
49
46
|
if File.exists?(code_path)
|
@@ -104,12 +101,15 @@ module Codger
|
|
104
101
|
end
|
105
102
|
|
106
103
|
mappings.each do |src, dest|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
104
|
+
begin
|
105
|
+
@current_template_src = src
|
106
|
+
@current_template_dest = dest
|
107
|
+
template = ERB.new(File.read(src_path(src)), nil, '-')
|
108
|
+
ensure_folder @current_template_dest
|
109
|
+
result = template.result(binding)
|
110
|
+
File.write dest_path(@current_template_dest), result
|
111
|
+
rescue CancelInterpolation
|
112
|
+
end
|
113
113
|
@to_copy.delete src
|
114
114
|
end
|
115
115
|
end
|
@@ -121,6 +121,11 @@ module Codger
|
|
121
121
|
@current_template_dest = File.join(File.dirname(@current_template_src), dest)
|
122
122
|
end
|
123
123
|
|
124
|
+
# Stop interpolation of the current template.
|
125
|
+
def cancel
|
126
|
+
raise CancelInterpolation.new
|
127
|
+
end
|
128
|
+
|
124
129
|
# For each path or array of paths, disable implicit copying.
|
125
130
|
def ignore(*paths)
|
126
131
|
@to_copy -= paths.flatten
|
@@ -134,4 +139,6 @@ module Codger
|
|
134
139
|
end
|
135
140
|
end
|
136
141
|
end
|
142
|
+
|
143
|
+
class CancelInterpolation < StandardError; end
|
137
144
|
end
|
data/lib/codger/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
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-03-
|
12
|
+
date: 2012-03-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70203594029980 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.2.1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70203594029980
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: deep_merge
|
27
|
-
requirement: &
|
27
|
+
requirement: &70203594029380 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.0.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70203594029380
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: git
|
38
|
-
requirement: &
|
38
|
+
requirement: &70203594028620 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.2.5
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70203594028620
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: thor
|
49
|
-
requirement: &
|
49
|
+
requirement: &70203594028020 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: 0.14.6
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70203594028020
|
58
58
|
description: Manages invocation of code generators.
|
59
59
|
email:
|
60
60
|
- jacobaw@gmail.com
|