roger 1.1.3 → 1.2.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.
- checksums.yaml +4 -4
- data/.hound.yml +2 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +1 -5
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -3
- data/Rakefile +10 -4
- data/bin/roger +1 -1
- data/doc/mockupfile.md +97 -0
- data/doc/templating.md +5 -1
- data/examples/default_template/Gemfile +1 -1
- data/lib/roger/cli.rb +41 -36
- data/lib/roger/cli/command.rb +2 -4
- data/lib/roger/cli/generate.rb +1 -0
- data/lib/roger/cli/release.rb +2 -2
- data/lib/roger/cli/serve.rb +11 -11
- data/lib/roger/cli/test.rb +6 -5
- data/lib/roger/extractor.rb +42 -43
- data/lib/roger/generators.rb +27 -19
- data/lib/roger/generators/generator.rb +7 -10
- data/lib/roger/generators/new.rb +56 -41
- data/lib/roger/generators/templates/generator.tt +5 -5
- data/lib/roger/helpers/get_callable.rb +15 -14
- data/lib/roger/helpers/logging.rb +35 -13
- data/lib/roger/mockupfile.rb +13 -23
- data/lib/roger/project.rb +41 -34
- data/lib/roger/rack/roger.rb +28 -29
- data/lib/roger/rack/sleep.rb +4 -5
- data/lib/roger/release.rb +95 -72
- data/lib/roger/release/cleaner.rb +14 -13
- data/lib/roger/release/finalizers.rb +10 -10
- data/lib/roger/release/finalizers/dir.rb +17 -19
- data/lib/roger/release/finalizers/git_branch.rb +76 -38
- data/lib/roger/release/finalizers/rsync.rb +60 -49
- data/lib/roger/release/finalizers/zip.rb +32 -29
- data/lib/roger/release/injector.rb +43 -37
- data/lib/roger/release/processors.rb +24 -22
- data/lib/roger/release/processors/mockup.rb +97 -69
- data/lib/roger/release/processors/url_relativizer.rb +57 -30
- data/lib/roger/release/scm.rb +30 -27
- data/lib/roger/release/scm/git.rb +101 -92
- data/lib/roger/resolver.rb +86 -61
- data/lib/roger/server.rb +52 -27
- data/lib/roger/template.rb +102 -74
- data/lib/roger/test.rb +16 -13
- data/lib/roger/version.rb +3 -2
- data/roger.gemspec +9 -5
- data/test/helpers/cli.rb +17 -15
- data/test/project/Gemfile +2 -2
- data/test/project/html/formats/csv.rcsv +0 -0
- data/test/project/lib/generators/test.rb +2 -3
- data/test/project/lib/tests/fail/fail.rb +5 -6
- data/test/project/lib/tests/noop/lib/cli.rb +2 -1
- data/test/project/lib/tests/noop/lib/test.rb +5 -5
- data/test/project/lib/tests/noop/noop.rb +2 -1
- data/test/project/lib/tests/succeed/succeed.rb +5 -6
- data/test/unit/cli/cli_base_test.rb +2 -3
- data/test/unit/cli/cli_generate_test.rb +9 -10
- data/test/unit/cli/cli_serve_test.rb +22 -18
- data/test/unit/cli/cli_test_test.rb +13 -15
- data/test/unit/cli/cli_version_test.rb +4 -4
- data/test/unit/generators_test.rb +8 -10
- data/test/unit/helpers/logging_test.rb +64 -0
- data/test/unit/rack/roger_test.rb +21 -0
- data/test/unit/release/cleaner_test.rb +23 -19
- data/test/unit/release/finalizers/git_branch_test.rb +2 -1
- data/test/unit/release/finalizers/zip_test.rb +48 -0
- data/test/unit/release/mockup_test.rb +48 -0
- data/test/unit/release/processors_test.rb +19 -19
- data/test/unit/release_test.rb +15 -14
- data/test/unit/resolver_test.rb +21 -14
- data/test/unit/server_test.rb +31 -0
- data/test/unit/template_test.rb +58 -36
- data/test/unit/test_test.rb +3 -2
- metadata +35 -9
- data/test/Mockupfile-syntax.rb +0 -93
@@ -1,44 +1,47 @@
|
|
1
1
|
module Roger::Release::Finalizers
|
2
|
-
|
2
|
+
# The zip finalizer
|
3
|
+
# The zip finalizer will
|
3
4
|
class Zip < Base
|
4
|
-
|
5
5
|
attr_reader :release
|
6
|
-
|
6
|
+
|
7
7
|
# @option options :prefix Prefix to put before the version (default = "html")
|
8
8
|
# @option options :zip The zip command
|
9
9
|
def call(release, options = {})
|
10
|
-
if options
|
11
|
-
options = @options.dup.update(options)
|
12
|
-
else
|
13
|
-
options = @options
|
14
|
-
end
|
15
|
-
|
16
10
|
options = {
|
17
|
-
:
|
18
|
-
:
|
19
|
-
}.update(options)
|
11
|
+
zip: "zip",
|
12
|
+
prefix: "html"
|
13
|
+
}.update(@options)
|
14
|
+
|
15
|
+
options.update(options) if options
|
20
16
|
|
21
17
|
name = [options[:prefix], release.scm.version].join("-") + ".zip"
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
begin
|
30
|
-
`#{options[:zip]} -v`
|
31
|
-
rescue Errno::ENOENT
|
32
|
-
raise RuntimeError, "Could not find zip in #{options[:zip].inspect}"
|
33
|
-
end
|
18
|
+
zip_path = release.target_path + name
|
19
|
+
|
20
|
+
release.log(self, "Finalizing release to #{zip_path}")
|
21
|
+
|
22
|
+
cleanup_existing_zip(zip_path)
|
23
|
+
|
24
|
+
check_zip_command(options[:zip])
|
34
25
|
|
35
26
|
::Dir.chdir(release.build_path) do
|
36
|
-
`#{options[:zip]} -r -9 "#{
|
27
|
+
`#{options[:zip]} -r -9 "#{zip_path}" ./*`
|
37
28
|
end
|
38
29
|
end
|
39
|
-
|
40
|
-
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def cleanup_existing_zip(path)
|
34
|
+
return unless File.exist?(path)
|
35
|
+
|
36
|
+
release.log(self, "Removing existing target #{path}")
|
37
|
+
FileUtils.rm_rf(path)
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_zip_command(command)
|
41
|
+
`#{command} -v`
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
raise "Could not find zip in #{command.inspect}"
|
44
|
+
end
|
41
45
|
end
|
42
46
|
end
|
43
|
-
|
44
|
-
Roger::Release::Finalizers.register(:zip, Roger::Release::Finalizers::Zip)
|
47
|
+
Roger::Release::Finalizers.register(:zip, Roger::Release::Finalizers::Zip)
|
@@ -1,49 +1,53 @@
|
|
1
|
-
require
|
1
|
+
require "tilt"
|
2
2
|
module Roger
|
3
|
-
|
3
|
+
# The Injector can inject variables and files into other files based on regexps.
|
4
|
+
#
|
4
5
|
# Inject VERSION / DATE (i.e. in TOC)
|
5
6
|
# r.inject({"VERSION" => release.version, "DATE" => release.date}, :into => %w{_doc/toc.html})
|
6
|
-
|
7
|
+
#
|
7
8
|
# Inject CHANGELOG
|
8
|
-
# r.inject({"CHANGELOG" => {:
|
9
|
-
|
9
|
+
# r.inject({"CHANGELOG" => {file: "", filter: BlueCloth}}, :into => %w{_doc/changelog.html})
|
10
10
|
class Release::Injector
|
11
|
-
|
12
11
|
# @example Simple variable injection (replaces [VARIABLE] into all .css files)
|
13
12
|
# {"[VARIABLE]" => "replacement"}, :into => %w{**/*.css}
|
14
13
|
#
|
15
14
|
# @example Regex variable injection (replaces all matches into test.js files)
|
16
|
-
# {/\/\*\s*\[BANNER\]\s*\*\// => "replacement"}, :into => %w{javacripts/test.js}
|
15
|
+
# {/\/\*\s*\[BANNER\]\s*\*\// => "replacement"}, :into => %w{javacripts/test.js}
|
17
16
|
#
|
18
|
-
# @example Simple variable injection with filtering (replaces [VARIABLE] with :content
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# @example Full file injection (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG.md" into _doc/changelog.html)
|
17
|
+
# @example Simple variable injection with filtering (replaces [VARIABLE] with :content
|
18
|
+
# run through the markdown processor into all .html files)
|
22
19
|
#
|
23
|
-
# {"
|
20
|
+
# {"[VARIABLE]" => {content: "# header one", processor: "md"}, :into => %w{**/*.html}
|
24
21
|
#
|
25
|
-
# @example Full file injection
|
22
|
+
# @example Full file injection (replaces all matches of [CHANGELOG] with the contents
|
23
|
+
# of "CHANGELOG.md" into _doc/changelog.html)
|
26
24
|
#
|
27
|
-
# {"CHANGELOG" => {:
|
25
|
+
# {"CHANGELOG" => {file: "CHANGELOG.md"}}, :into => %w{_doc/changelog.html}
|
28
26
|
#
|
29
|
-
#
|
27
|
+
# @example Full file injection with filtering (replaces all matches of [CHANGELOG]
|
28
|
+
# with the contents of "CHANGELOG" which ran through Markdown compresser
|
29
|
+
# into _doc/changelog.html)
|
30
|
+
#
|
31
|
+
# {"CHANGELOG" => {file: "CHANGELOG", processor: "md"}}, :into => %w{_doc/changelog.html}
|
32
|
+
#
|
33
|
+
# Processors are based on Tilt (https://github.com/rtomayko/tilt).
|
30
34
|
# Currently supported/tested processors are:
|
31
35
|
#
|
32
36
|
# * 'md' for Markdown (bluecloth)
|
33
37
|
#
|
34
38
|
# Injection files are relative to the :source_path
|
35
|
-
#
|
39
|
+
#
|
36
40
|
# @param [Hash] variables Variables to inject. See example for more info
|
37
41
|
# @option options [Array] :into An array of file globs relative to the build_path
|
38
|
-
def initialize(variables, options)
|
42
|
+
def initialize(variables, options)
|
39
43
|
@variables = variables
|
40
44
|
@options = options
|
41
45
|
end
|
42
|
-
|
46
|
+
|
43
47
|
def call(release, options = {})
|
44
48
|
@options.update(options)
|
45
49
|
files = release.get_files(@options[:into])
|
46
|
-
|
50
|
+
|
47
51
|
files.each do |f|
|
48
52
|
c = File.read(f)
|
49
53
|
injected_vars = []
|
@@ -52,12 +56,13 @@ module Roger
|
|
52
56
|
injected_vars << variable
|
53
57
|
end
|
54
58
|
end
|
55
|
-
|
56
|
-
|
59
|
+
if injected_vars.size > 0
|
60
|
+
release.log(self, "Injected variables #{injected_vars.inspect} into #{f}")
|
61
|
+
end
|
62
|
+
File.open(f, "w") { |fh| fh.write c }
|
57
63
|
end
|
58
|
-
|
59
64
|
end
|
60
|
-
|
65
|
+
|
61
66
|
def get_content(injection, release)
|
62
67
|
case injection
|
63
68
|
when String
|
@@ -68,32 +73,33 @@ module Roger
|
|
68
73
|
if injection.respond_to?(:to_s)
|
69
74
|
injection.to_s
|
70
75
|
else
|
71
|
-
|
76
|
+
fail ArgumentError, "Woah, what's this? #{injection.inspect}"
|
72
77
|
end
|
73
78
|
end
|
74
79
|
end
|
75
|
-
|
80
|
+
|
76
81
|
def get_complex_injection(injection, release)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
else
|
81
|
-
content = injection[:content]
|
82
|
-
end
|
83
|
-
|
84
|
-
raise ArgumentError, "No :content or :file specified" if !content
|
82
|
+
content = injection_content(injection, release)
|
83
|
+
|
84
|
+
fail ArgumentError, "No :content or :file specified" unless content
|
85
85
|
|
86
86
|
if injection[:processor]
|
87
87
|
if tmpl = Tilt[injection[:processor]]
|
88
|
-
(tmpl.new{ content }).render
|
88
|
+
(tmpl.new { content }).render
|
89
89
|
else
|
90
|
-
|
90
|
+
fail ArgumentError, "Unknown processor #{injection[:processor]}"
|
91
91
|
end
|
92
92
|
else
|
93
93
|
content
|
94
94
|
end
|
95
|
-
|
96
95
|
end
|
97
|
-
|
96
|
+
|
97
|
+
def injection_content(injection, release)
|
98
|
+
if injection[:file]
|
99
|
+
File.read(release.source_path + injection[:file])
|
100
|
+
else
|
101
|
+
injection[:content]
|
102
|
+
end
|
103
|
+
end
|
98
104
|
end
|
99
105
|
end
|
@@ -1,28 +1,30 @@
|
|
1
|
-
module Roger
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
raise ArgumentError, "Implement in subclass"
|
12
|
-
end
|
13
|
-
end
|
1
|
+
module Roger
|
2
|
+
class Release
|
3
|
+
# The Processors namespace
|
4
|
+
module Processors
|
5
|
+
# Abstract Processor class
|
6
|
+
class Base
|
7
|
+
def initialize(options = {})
|
8
|
+
@options = {}
|
9
|
+
@options.update(options) if options
|
10
|
+
end
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
12
|
+
def call(_release, _options = {})
|
13
|
+
fail ArgumentError, "Implement in subclass"
|
14
|
+
end
|
15
|
+
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
def self.register(name, processor)
|
18
|
+
fail ArgumentError, "Processor name '#{name.inspect}' already in use" if map.key?(name)
|
19
|
+
fail ArgumentError, "Name must be a symbol" unless name.is_a?(Symbol)
|
20
|
+
map[name] = processor
|
21
|
+
end
|
24
22
|
|
23
|
+
def self.map
|
24
|
+
@_map ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
25
28
|
end
|
26
|
-
|
27
29
|
require File.dirname(__FILE__) + "/processors/mockup"
|
28
30
|
require File.dirname(__FILE__) + "/processors/url_relativizer"
|
@@ -1,95 +1,123 @@
|
|
1
1
|
module Roger::Release::Processors
|
2
|
+
# The Mockup processor that will process all templates
|
2
3
|
class Mockup < Base
|
3
|
-
|
4
4
|
attr_accessor :project
|
5
|
-
|
6
|
-
|
5
|
+
|
6
|
+
MIME_TYPES_TO_EXTENSION = {
|
7
|
+
"text/html" => "html",
|
8
|
+
"text/css" => "css",
|
9
|
+
"application/javascript" => "js",
|
10
|
+
"text/xml" => "xml",
|
11
|
+
"application/xml" => "xml",
|
12
|
+
"text/csv" => "csv",
|
13
|
+
"application/json" => "json"
|
14
|
+
}
|
15
|
+
|
16
|
+
def initialize(options = {})
|
7
17
|
@options = {
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
18
|
+
env: {},
|
19
|
+
match: ["**/*.{html,md,html.erb}"],
|
20
|
+
skip: [/\Astylesheets/, /\Ajavascripts/]
|
11
21
|
}
|
12
|
-
|
13
|
-
@options.update(options) if options
|
22
|
+
|
23
|
+
@options.update(options) if options
|
14
24
|
end
|
15
25
|
|
16
|
-
def call(release, options={})
|
26
|
+
def call(release, options = {})
|
17
27
|
self.project = release.project
|
18
|
-
|
19
|
-
options =
|
20
|
-
|
21
|
-
options
|
22
|
-
|
23
|
-
release.log(self, "Processing mockup files")
|
24
|
-
|
25
|
-
release.log(self, " Matching: #{options[:match].inspect}", true)
|
26
|
-
release.log(self, " Skiping : #{options[:skip].inspect}", true)
|
27
|
-
release.log(self, " Env : #{options[:env].inspect}", true)
|
28
|
-
release.log(self, " Files :", true)
|
29
|
-
|
28
|
+
|
29
|
+
options = update_call_options(options)
|
30
|
+
|
31
|
+
log_call(options)
|
32
|
+
|
30
33
|
release.get_files(options[:match], options[:skip]).each do |file_path|
|
31
34
|
release.log(self, " Extract: #{file_path}", true)
|
32
35
|
self.run_on_file!(file_path, options[:env])
|
33
36
|
end
|
34
37
|
end
|
35
|
-
|
36
|
-
|
38
|
+
|
37
39
|
def run_on_file!(file_path, env = {})
|
38
|
-
template = Roger::Template.open(
|
39
|
-
|
40
|
+
template = Roger::Template.open(
|
41
|
+
file_path,
|
42
|
+
partials_path: project.partial_path,
|
43
|
+
layouts_path: project.layouts_path
|
44
|
+
)
|
45
|
+
|
40
46
|
# Clean up source file
|
41
47
|
FileUtils.rm(file_path)
|
42
|
-
|
48
|
+
|
43
49
|
# Write out new file
|
44
|
-
File.open(
|
50
|
+
File.open(target_path(file_path, template).to_s, "w") do |f|
|
51
|
+
f.write(template.render(env.dup))
|
52
|
+
end
|
45
53
|
end
|
46
|
-
|
54
|
+
|
47
55
|
# Runs the extractor on a single file and return processed source.
|
48
56
|
def extract_source_from_file(file_path, env = {})
|
49
|
-
Roger::Template.open(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
57
|
+
Roger::Template.open(
|
58
|
+
file_path,
|
59
|
+
partials_path: project.partial_path,
|
60
|
+
layouts_path: project.layouts_path
|
61
|
+
).render(env.dup)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Determines the output path for a mockup path with a certain template
|
65
|
+
#
|
66
|
+
# @return [Pathname]
|
54
67
|
def target_path(path, template)
|
55
|
-
|
56
|
-
|
57
|
-
dir = Pathname.new(File.dirname(path.to_s))
|
58
|
-
|
59
|
-
# 2. Try to figure out the extension based on the template's mime-type
|
60
|
-
mime_types = {
|
61
|
-
"text/html" => "html",
|
62
|
-
"text/css" => "css",
|
63
|
-
"application/javascript" => "js",
|
64
|
-
"text/xml" => "xml",
|
65
|
-
"application/xml" => "xml",
|
66
|
-
"text/csv" => "csv",
|
67
|
-
"application/json" => "json"
|
68
|
-
}
|
69
|
-
extension = mime_types[template.template.class.default_mime_type]
|
70
|
-
|
68
|
+
parts, dir = split_path(path)
|
69
|
+
|
71
70
|
# Always return .html directly as it will cause too much trouble otherwise
|
72
|
-
if parts.last == "html"
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
71
|
+
return Pathname.new(path) if parts.last == "html"
|
72
|
+
|
73
|
+
# Strip last extension if we have a double extension
|
74
|
+
return dir + parts[0..-2].join(".") if parts.size > 2
|
75
|
+
|
76
|
+
dir + extension_based_on_mime_type(parts, template.template.class.default_mime_type)
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def update_call_options(options)
|
82
|
+
{}.update(@options).update(options)
|
83
|
+
options[:env].update("roger.project" => project, "MOCKUP_PROJECT" => project)
|
84
|
+
options
|
85
|
+
end
|
86
|
+
|
87
|
+
def log_call(options)
|
88
|
+
release.log(self, "Processing mockup files")
|
89
|
+
|
90
|
+
release.log(self, " Matching: #{options[:match].inspect}", true)
|
91
|
+
release.log(self, " Skiping : #{options[:skip].inspect}", true)
|
92
|
+
release.log(self, " Env : #{options[:env].inspect}", true)
|
93
|
+
release.log(self, " Files :", true)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Split the path into two parts:
|
97
|
+
# 1. Filename, in an array, split by .
|
98
|
+
# 2. Pathname of directory
|
99
|
+
def split_path(path)
|
100
|
+
[
|
101
|
+
File.basename(path.to_s).split("."),
|
102
|
+
Pathname.new(File.dirname(path.to_s))
|
103
|
+
]
|
104
|
+
end
|
105
|
+
|
106
|
+
def extension_based_on_mime_type(parts, mime_type)
|
107
|
+
# 2. Try to figure out the extension based on the template's mime-type
|
108
|
+
extension = MIME_TYPES_TO_EXTENSION[mime_type]
|
109
|
+
|
110
|
+
# No matching extension, let's return path
|
111
|
+
return parts.join(".") if extension.nil?
|
112
|
+
|
113
|
+
if parts.size > 1
|
114
|
+
# Strip extension and replace with extension
|
115
|
+
(parts[0..-2] << extension).join(".")
|
79
116
|
else
|
80
|
-
|
81
|
-
|
82
|
-
if parts.size > 1
|
83
|
-
# Strip extension and replace with extension
|
84
|
-
dir + (parts[0..-2] << extension).join(".")
|
85
|
-
else
|
86
|
-
# Let's just add the extension
|
87
|
-
dir + (parts << extension).join(".")
|
88
|
-
end
|
117
|
+
# Let's just add the extension
|
118
|
+
(parts << extension).join(".")
|
89
119
|
end
|
90
|
-
end
|
91
|
-
|
120
|
+
end
|
92
121
|
end
|
93
122
|
end
|
94
|
-
|
95
|
-
Roger::Release::Processors.register(:mockup, Roger::Release::Processors::Mockup)
|
123
|
+
Roger::Release::Processors.register(:mockup, Roger::Release::Processors::Mockup)
|