roger 0.0.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +2 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +102 -0
- data/Gemfile +5 -0
- data/MIT_LICENSE +20 -0
- data/README.md +10 -10
- data/Rakefile +9 -0
- data/bin/roger +5 -0
- data/doc/cli.md +46 -0
- data/doc/mockupfile.md +3 -0
- data/doc/templating.md +88 -0
- data/examples/default_template/.gitignore +2 -0
- data/examples/default_template/CHANGELOG +0 -0
- data/examples/default_template/Gemfile +3 -0
- data/examples/default_template/Mockupfile +1 -0
- data/examples/default_template/html/.empty_directory +0 -0
- data/examples/default_template/partials/.empty_directory +0 -0
- data/lib/roger/cli/command.rb +23 -0
- data/lib/roger/cli/generate.rb +5 -0
- data/lib/roger/cli/release.rb +10 -0
- data/lib/roger/cli/serve.rb +29 -0
- data/lib/roger/cli.rb +123 -0
- data/lib/roger/extractor.rb +95 -0
- data/lib/roger/generators/generator.rb +23 -0
- data/lib/roger/generators/new.rb +67 -0
- data/lib/roger/generators/templates/generator.tt +13 -0
- data/lib/roger/generators.rb +23 -0
- data/lib/roger/mockupfile.rb +63 -0
- data/lib/roger/project.rb +92 -0
- data/lib/roger/rack/html_validator.rb +26 -0
- data/lib/roger/rack/roger.rb +52 -0
- data/lib/roger/rack/sleep.rb +21 -0
- data/lib/roger/release/cleaner.rb +47 -0
- data/lib/roger/release/finalizers/dir.rb +29 -0
- data/lib/roger/release/finalizers/git_branch.rb +92 -0
- data/lib/roger/release/finalizers/rsync.rb +77 -0
- data/lib/roger/release/finalizers/zip.rb +42 -0
- data/lib/roger/release/finalizers.rb +19 -0
- data/lib/roger/release/injector.rb +99 -0
- data/lib/roger/release/processors/mockup.rb +93 -0
- data/lib/roger/release/processors/url_relativizer.rb +45 -0
- data/lib/roger/release/processors.rb +17 -0
- data/lib/roger/release/scm/git.rb +101 -0
- data/lib/roger/release/scm.rb +32 -0
- data/lib/roger/release.rb +363 -0
- data/lib/roger/resolver.rb +119 -0
- data/lib/roger/server.rb +117 -0
- data/lib/roger/template.rb +206 -0
- data/lib/roger/w3c_validator.rb +129 -0
- data/roger.gemspec +35 -0
- data/test/Mockupfile-syntax.rb +85 -0
- data/test/project/.rvmrc +1 -0
- data/test/project/Gemfile +7 -0
- data/test/project/Gemfile.lock +38 -0
- data/test/project/Mockupfile +13 -0
- data/test/project/html/formats/erb.html.erb +5 -0
- data/test/project/html/formats/index.html +1 -0
- data/test/project/html/formats/json.json.erb +0 -0
- data/test/project/html/formats/markdown.md +3 -0
- data/test/project/html/formats/mockup.html +5 -0
- data/test/project/html/front_matter/erb.html.erb +16 -0
- data/test/project/html/front_matter/markdown.md +7 -0
- data/test/project/html/layouts/content-for.html.erb +17 -0
- data/test/project/html/layouts/erb.html.erb +19 -0
- data/test/project/html/mockup/encoding.html +3 -0
- data/test/project/html/partials/erb.html.erb +10 -0
- data/test/project/html/partials/load_path.html.erb +3 -0
- data/test/project/html/partials/mockup.html +13 -0
- data/test/project/html/static/non-relative.html.erb +9 -0
- data/test/project/html/static/relative.html.erb +9 -0
- data/test/project/layouts/test.html.erb +34 -0
- data/test/project/layouts/yield.html.erb +1 -0
- data/test/project/lib/generators/test.rb +9 -0
- data/test/project/partials/formats/erb.html.erb +1 -0
- data/test/project/partials/partials-test.html.erb +1 -0
- data/test/project/partials/test/erb.html.erb +1 -0
- data/test/project/partials/test/front_matter.html.erb +1 -0
- data/test/project/partials/test/json.json.erb +1 -0
- data/test/project/partials/test/markdown.md +1 -0
- data/test/project/partials/test/mockup.part.html +1 -0
- data/test/project/partials/test/simple.html.erb +1 -0
- data/test/project/partials2/partials2-test.html.erb +1 -0
- data/test/unit/cli_test.rb +12 -0
- data/test/unit/generators_test.rb +75 -0
- data/test/unit/release/cleaner_test.rb +47 -0
- data/test/unit/resolver_test.rb +92 -0
- data/test/unit/template_test.rb +127 -0
- metadata +202 -8
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
require File.dirname(__FILE__) + '/resolver'
|
3
|
+
|
4
|
+
module Roger
|
5
|
+
|
6
|
+
# @deprecated Don't use the extractor anymore, use release.use(:mockup, options) processor and release.use(:url_relativizer, options) processor
|
7
|
+
class Extractor
|
8
|
+
|
9
|
+
attr_reader :project, :target_path
|
10
|
+
|
11
|
+
|
12
|
+
# @param [Project] project Project object
|
13
|
+
# @param [String,Pathname] target_path Path to extract to
|
14
|
+
# @param [Hash] options Options hash
|
15
|
+
|
16
|
+
# @option options [Array] :url_attributes The element attributes to parse and relativize
|
17
|
+
# @option options [Array] :url_relativize Wether or not we should relativize
|
18
|
+
# @option options [Array] :env ENV variable to pass to template renderer.
|
19
|
+
def initialize(project, target_path, options={})
|
20
|
+
@project = project
|
21
|
+
@target_path = Pathname.new(target_path)
|
22
|
+
@resolver = Resolver.new(self.target_path)
|
23
|
+
|
24
|
+
|
25
|
+
@options = {
|
26
|
+
:url_attributes => %w{src href action},
|
27
|
+
:url_relativize => true,
|
28
|
+
:env => {}
|
29
|
+
}
|
30
|
+
|
31
|
+
@options.update(options) if options
|
32
|
+
|
33
|
+
@options[:env].update("MOCKUP_PROJECT" => project)
|
34
|
+
end
|
35
|
+
|
36
|
+
def run!
|
37
|
+
target_path = self.target_path
|
38
|
+
source_path = self.project.html_path
|
39
|
+
|
40
|
+
|
41
|
+
filter = "**/*.html"
|
42
|
+
raise ArgumentError, "Target #{target_path} already exists, please choose a new directory to extract into" if target_path.exist?
|
43
|
+
|
44
|
+
mkdir_p(target_path)
|
45
|
+
target_path = target_path.realpath
|
46
|
+
|
47
|
+
# Copy source to target first, we'll overwrite the templates later on.
|
48
|
+
cp_r(source_path.children, target_path)
|
49
|
+
|
50
|
+
Dir.chdir(source_path) do
|
51
|
+
Dir.glob(filter).each do |file_path|
|
52
|
+
self.run_on_file!(file_path, @options[:env])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def run_on_file!(file_path, env = {})
|
58
|
+
source = self.extract_source_from_file(file_path, env)
|
59
|
+
File.open(target_path + file_path,"w"){|f| f.write(source) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Runs the extractor on a single file and return processed source.
|
63
|
+
def extract_source_from_file(file_path, env = {})
|
64
|
+
source = Roger::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path).render(env.dup)
|
65
|
+
|
66
|
+
if @options[:url_relativize]
|
67
|
+
source = relativize_urls(source, file_path)
|
68
|
+
end
|
69
|
+
|
70
|
+
source
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def relativize_urls(source, file_path)
|
77
|
+
doc = Hpricot(source)
|
78
|
+
@options[:url_attributes].each do |attribute|
|
79
|
+
(doc/"*[@#{attribute}]").each do |tag|
|
80
|
+
converted_url = @resolver.url_to_relative_url(tag[attribute], file_path)
|
81
|
+
|
82
|
+
case converted_url
|
83
|
+
when String
|
84
|
+
tag[attribute] = converted_url
|
85
|
+
when nil
|
86
|
+
puts "Could not resolve link #{tag[attribute]} in #{file_path}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
doc.to_original_html
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Roger::Generators::GeneratorGenerator < Roger::Generators::Base
|
2
|
+
|
3
|
+
include Thor::Actions
|
4
|
+
|
5
|
+
desc "Create your own generator for roger"
|
6
|
+
argument :name, :type => :string, :required => true, :desc => "Name of the new generator"
|
7
|
+
argument :path, :type => :string, :required => true, :desc => "Path to generate the new generator"
|
8
|
+
# class_option :template, :type => :string, :aliases => ["-t"], :desc => "Template to use, can be a path or a git repository remote, uses built in minimal as default"
|
9
|
+
|
10
|
+
def self.source_root
|
11
|
+
File.dirname(__FILE__)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_lib_file
|
15
|
+
destination = "#{path}/#{name}_generator.rb"
|
16
|
+
template('templates/generator.tt', destination)
|
17
|
+
say "Add `require #{destination}` to your mockup file and run mockup generate #{name}."
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
Roger::Generators::Base.register Roger::Generators::GeneratorGenerator
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
class Roger::Generators::NewGenerator < Thor::Group
|
4
|
+
|
5
|
+
include Thor::Actions
|
6
|
+
|
7
|
+
desc "Create a new HTML mockup based on an existing skeleton"
|
8
|
+
argument :path, :type => :string, :required => true, :desc => "Path to generate mockup into"
|
9
|
+
class_option :template, :type => :string, :aliases => ["-t"], :desc => "Template to use, can be a path or a git repository remote, uses built in minimal as default"
|
10
|
+
|
11
|
+
attr_reader :source_paths
|
12
|
+
|
13
|
+
def setup_variables
|
14
|
+
self.destination_root = path
|
15
|
+
|
16
|
+
@source_paths = []
|
17
|
+
|
18
|
+
# Stuff to rm -rf later
|
19
|
+
@cleanup = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate_path_is_empty
|
23
|
+
if File.directory?(self.destination_root)
|
24
|
+
say "Directory #{self.destination_root} already exists, please only use this to create new mockups"
|
25
|
+
exit(1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_template_path
|
30
|
+
if options[:template]
|
31
|
+
template = options[:template]
|
32
|
+
else
|
33
|
+
template = File.dirname(__FILE__) + "/../../../examples/default_template"
|
34
|
+
end
|
35
|
+
|
36
|
+
if File.exist?(template)
|
37
|
+
say "Taking template from #{template}"
|
38
|
+
@source_paths << template
|
39
|
+
else
|
40
|
+
# Hack to create temp directory
|
41
|
+
t = Tempfile.new("htmlmockup-generate-new")
|
42
|
+
tmp_dir = Pathname.new(t.path)
|
43
|
+
t.close
|
44
|
+
t.unlink
|
45
|
+
|
46
|
+
if run("git clone --depth=1 #{Shellwords.escape(template)} #{tmp_dir}")
|
47
|
+
say "Cloned template from #{template}"
|
48
|
+
run("rm -rf #{tmp_dir + ".git"}")
|
49
|
+
@source_paths << tmp_dir.to_s
|
50
|
+
@cleanup << tmp_dir.to_s
|
51
|
+
else
|
52
|
+
say "Template path #{template} doesn't seem to be a git remote or a local path"
|
53
|
+
exit(1)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue Exception => e
|
57
|
+
puts e
|
58
|
+
puts e.backtrace.join("\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_mockup
|
62
|
+
directory(".", ".")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
Roger::Generators::Base.register Roger::Generators::NewGenerator
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class <%= name.capitalize %>Generator < Roger::Generators::Base
|
2
|
+
|
3
|
+
include Thor::Actions
|
4
|
+
|
5
|
+
desc "<%= name.capitalize %> generator helps you doing ... and ..."
|
6
|
+
argument :path, :type => :string, :required => true, :desc => "Path to generate the new generator"
|
7
|
+
|
8
|
+
def create_stuff
|
9
|
+
# your stuff
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Roger::Generators::Base.register <%= name.capitalize %>Generator
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'thor/group'
|
3
|
+
|
4
|
+
module Roger
|
5
|
+
module Generators
|
6
|
+
|
7
|
+
class Base < Cli::Command
|
8
|
+
def self.register(sub)
|
9
|
+
name = sub.to_s.sub(/Generator$/, "").sub(/^.*Generators::/,"").downcase
|
10
|
+
usage = "#{name} #{sub.arguments.map{ |arg| arg.banner }.join(" ")}"
|
11
|
+
long_desc = sub.desc || "Run #{name} generator"
|
12
|
+
|
13
|
+
Cli::Generate.register sub, name, usage, long_desc
|
14
|
+
Cli::Generate.tasks[name].options = sub.class_options if sub.class_options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Default generators
|
22
|
+
require File.dirname(__FILE__) + "/generators/new"
|
23
|
+
require File.dirname(__FILE__) + "/generators/generator"
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Roger
|
2
|
+
# Loader for mockupfile
|
3
|
+
class Mockupfile
|
4
|
+
|
5
|
+
# This is the context for the mockupfile evaluation. It should be empty except for the
|
6
|
+
# #mockup method.
|
7
|
+
class Context
|
8
|
+
|
9
|
+
def initialize(mockupfile)
|
10
|
+
@_mockupfile = mockupfile
|
11
|
+
end
|
12
|
+
|
13
|
+
def mockup
|
14
|
+
@_mockupfile
|
15
|
+
end
|
16
|
+
|
17
|
+
def binding
|
18
|
+
::Kernel.binding
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
# @attr :path [Pathname] The path of the Mockupfile for this project
|
24
|
+
attr_accessor :path, :project
|
25
|
+
|
26
|
+
def initialize(project)
|
27
|
+
@project = project
|
28
|
+
@path = Pathname.new(project.path + "Mockupfile")
|
29
|
+
end
|
30
|
+
|
31
|
+
# Actually load the mockupfile
|
32
|
+
def load
|
33
|
+
if File.exist?(@path) && !self.loaded?
|
34
|
+
@source = File.read(@path)
|
35
|
+
context = Context.new(self)
|
36
|
+
eval @source, context.binding, @path.to_s, 1
|
37
|
+
@loaded = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Wether or not the Mockupfile has been loaded
|
42
|
+
def loaded?
|
43
|
+
@loaded
|
44
|
+
end
|
45
|
+
|
46
|
+
def release
|
47
|
+
if block_given?
|
48
|
+
yield(self.project.release)
|
49
|
+
end
|
50
|
+
self.project.release
|
51
|
+
end
|
52
|
+
|
53
|
+
def serve
|
54
|
+
if block_given?
|
55
|
+
yield(self.project.server)
|
56
|
+
end
|
57
|
+
self.project.server
|
58
|
+
end
|
59
|
+
|
60
|
+
alias :server :serve
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/release"
|
2
|
+
require File.dirname(__FILE__) + "/server"
|
3
|
+
require File.dirname(__FILE__) + "/mockupfile"
|
4
|
+
|
5
|
+
module Roger
|
6
|
+
# Loader for mockupfile and project dependencies
|
7
|
+
class Project
|
8
|
+
|
9
|
+
# @attr :path [Pathname] The project path
|
10
|
+
# @attr :html_path [Pathname] The path of the HTML mockup
|
11
|
+
# @attr :partial_path [Pathname] The path for the partials for this mockup
|
12
|
+
# @attr :mockupfile [Mockupfile] The Mockupfile for this project
|
13
|
+
attr_accessor :path, :html_path, :partial_path, :layouts_path, :mockupfile
|
14
|
+
|
15
|
+
attr_accessor :shell
|
16
|
+
|
17
|
+
attr_accessor :options
|
18
|
+
|
19
|
+
def initialize(path, options={})
|
20
|
+
@path = Pathname.new(path)
|
21
|
+
|
22
|
+
@options = {
|
23
|
+
:html_path => @path + "html",
|
24
|
+
:partial_path => @path + "partials",
|
25
|
+
:layouts_path => @path + "layouts"
|
26
|
+
}
|
27
|
+
|
28
|
+
# Clumsy string to symbol key conversion
|
29
|
+
options.each{|k,v| @options[k.is_a?(String) ? k.to_sym : k] = v }
|
30
|
+
|
31
|
+
self.html_path = @options[:html_path]
|
32
|
+
self.partial_path = @options[:partials_path] || @options[:partial_path] || self.html_path + "../partials/"
|
33
|
+
self.layouts_path = @options[:layouts_path]
|
34
|
+
self.shell = @options[:shell]
|
35
|
+
|
36
|
+
load_mockup!
|
37
|
+
end
|
38
|
+
|
39
|
+
def shell
|
40
|
+
@shell ||= Thor::Base.shell.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def server
|
44
|
+
options = @options[:server] || {}
|
45
|
+
@server ||= Server.new(self, options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def release
|
49
|
+
options = @options[:release] || {}
|
50
|
+
@release ||= Release.new(self, options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def html_path=(p)
|
54
|
+
@html_path = self.realpath_or_path(p)
|
55
|
+
end
|
56
|
+
|
57
|
+
def partial_path=(p)
|
58
|
+
@partial_path = self.single_or_multiple_paths(p)
|
59
|
+
end
|
60
|
+
alias :partials_path :partial_path
|
61
|
+
alias :partials_path= :partial_path=
|
62
|
+
|
63
|
+
def layouts_path=(p)
|
64
|
+
@layouts_path = self.single_or_multiple_paths(p)
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def load_mockup!
|
70
|
+
@mockupfile = Mockupfile.new(self)
|
71
|
+
@mockupfile.load
|
72
|
+
end
|
73
|
+
|
74
|
+
def single_or_multiple_paths(p)
|
75
|
+
if p.kind_of?(Array)
|
76
|
+
p.map{|tp| self.realpath_or_path(tp) }
|
77
|
+
else
|
78
|
+
self.realpath_or_path(p)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def realpath_or_path(path)
|
83
|
+
path = Pathname.new(path)
|
84
|
+
if path.exist?
|
85
|
+
path.realpath
|
86
|
+
else
|
87
|
+
path
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
require 'rack/response'
|
3
|
+
|
4
|
+
module Roger
|
5
|
+
module Rack
|
6
|
+
class HtmlValidator
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
resp = @app.call(env)
|
13
|
+
if resp[1]["Content-Type"].to_s.include?("html")
|
14
|
+
str = ""
|
15
|
+
resp[2].each{|c| str << c}
|
16
|
+
validator = W3CValidator.new(str)
|
17
|
+
validator.validate!
|
18
|
+
if !validator.valid
|
19
|
+
env["rack.errors"].puts "Validation failed on #{env["PATH_INFO"]}: (errors: #{validator.errors}, warnings: #{validator.warnings})"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
resp
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
require 'rack/response'
|
3
|
+
require 'rack/file'
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/../resolver'
|
6
|
+
|
7
|
+
module Roger
|
8
|
+
module Rack
|
9
|
+
|
10
|
+
class Roger
|
11
|
+
|
12
|
+
attr_reader :project
|
13
|
+
|
14
|
+
def initialize(project)
|
15
|
+
@project = project
|
16
|
+
@docroot = project.html_path
|
17
|
+
|
18
|
+
@resolver = Resolver.new(@docroot)
|
19
|
+
@file_server = ::Rack::File.new(@docroot)
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
url = env["PATH_INFO"]
|
24
|
+
env["MOCKUP_PROJECT"] = project
|
25
|
+
|
26
|
+
if template_path = @resolver.url_to_path(url)
|
27
|
+
env["rack.errors"].puts "Rendering template #{template_path.inspect} (#{url.inspect})"
|
28
|
+
# begin
|
29
|
+
templ = ::Roger::Template.open(template_path, :partials_path => @project.partials_path, :layouts_path => @project.layouts_path)
|
30
|
+
mime = ::Rack::Mime.mime_type(File.extname(template_path), 'text/html')
|
31
|
+
resp = ::Rack::Response.new do |res|
|
32
|
+
res.headers["Content-Type"] = mime if mime
|
33
|
+
res.status = 200
|
34
|
+
res.write templ.render(env)
|
35
|
+
end
|
36
|
+
resp.finish
|
37
|
+
# rescue StandardError => e
|
38
|
+
# env["rack.errors"].puts "#{e.message}\n #{e.backtrace.join("\n")}\n\n"
|
39
|
+
# resp = ::Rack::Response.new do |res|
|
40
|
+
# res.status = 500
|
41
|
+
# res.write "An error occurred"
|
42
|
+
# end
|
43
|
+
# resp.finish
|
44
|
+
# end
|
45
|
+
else
|
46
|
+
env["rack.errors"].puts "Invoking file handler for #{url.inspect}"
|
47
|
+
@file_server.call(env)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Roger
|
2
|
+
module Rack
|
3
|
+
# Listens to the "sleep" parameter and sleeps the amount of seconds specified by the parameter. There is however a maximum of 5 seconds.
|
4
|
+
class Sleep
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
r = ::Rack::Request.new(env)
|
12
|
+
if r.params["sleep"]
|
13
|
+
sleeptime = [r.params["sleep"].to_i, 5].min
|
14
|
+
sleep sleeptime
|
15
|
+
end
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Roger
|
2
|
+
class Release::Cleaner
|
3
|
+
def initialize(pattern)
|
4
|
+
@pattern = pattern
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(release, options = {})
|
8
|
+
# We switch to the build path and append the globbed files for safety, so even if you manage to sneak in a
|
9
|
+
# pattern like "/**/*" it won't do you any good as it will be reappended to the path
|
10
|
+
Dir.chdir(release.build_path.to_s) do
|
11
|
+
Dir.glob(@pattern).each do |file|
|
12
|
+
path = File.join(release.build_path.to_s, file)
|
13
|
+
if is_inside_build_path(release.build_path, path)
|
14
|
+
release.log(self, "Cleaning up \"#{path}\" in build")
|
15
|
+
rm_rf(path)
|
16
|
+
else
|
17
|
+
release.log(self, "FAILED cleaning up \"#{path}\" in build")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def is_inside_build_path(build_path, path)
|
26
|
+
|
27
|
+
begin
|
28
|
+
build_path = Pathname.new(build_path).realpath.to_s
|
29
|
+
path = Pathname.new(path)
|
30
|
+
if(path.absolute?)
|
31
|
+
path = path.realpath.to_s
|
32
|
+
else
|
33
|
+
path = Pathname.new(File.join(build_path.to_s, path)).realpath.to_s
|
34
|
+
end
|
35
|
+
rescue Errno::ENOENT
|
36
|
+
# Real path does not exist
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
40
|
+
if path[build_path]
|
41
|
+
return true
|
42
|
+
else
|
43
|
+
raise RuntimeError, "Cleaning pattern is not inside build directory"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Roger::Release::Finalizers
|
4
|
+
|
5
|
+
# Finalizes the release into a directory in target_path
|
6
|
+
#
|
7
|
+
# The directory name will have the format PREFIX-VERSION
|
8
|
+
#
|
9
|
+
class Dir < Base
|
10
|
+
# @option options :prefix Prefix to put before the version (default = "html")
|
11
|
+
def call(release, options = {})
|
12
|
+
if options
|
13
|
+
options = @options.dup.update(options)
|
14
|
+
else
|
15
|
+
options = @options
|
16
|
+
end
|
17
|
+
|
18
|
+
name = [(options[:prefix] || "html"), release.scm.version].join("-")
|
19
|
+
release.log(self, "Finalizing release to #{release.target_path + name}")
|
20
|
+
|
21
|
+
if File.exist?(release.target_path + name)
|
22
|
+
release.log(self, "Removing existing target #{release.target_path + name}")
|
23
|
+
FileUtils.rm_rf(release.target_path + name)
|
24
|
+
end
|
25
|
+
|
26
|
+
FileUtils.cp_r release.build_path, release.target_path + name
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Finalizes the release into a specific branch of a repository and pushes it
|
2
|
+
#
|
3
|
+
class GitBranch < Roger::Release::Finalizers::Base
|
4
|
+
|
5
|
+
# @param Hash options The options
|
6
|
+
#
|
7
|
+
# @option options String :remote The remote repository (default is the origin of the current repository)
|
8
|
+
# @option options String :branch The remote branch (default is "gh-pages")
|
9
|
+
# @option options Boolean :cleanup Cleanup temp dir afterwards (default is true)
|
10
|
+
# @option options Boolean :push Push to remote (default is true)
|
11
|
+
def initialize(options={})
|
12
|
+
@options = {
|
13
|
+
:remote => nil,
|
14
|
+
:branch => "gh-pages",
|
15
|
+
:cleanup => true,
|
16
|
+
:push => true
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def call(release, options = {})
|
22
|
+
options = @options.dup.update(options)
|
23
|
+
git_dir = find_git_dir(release.project.path)
|
24
|
+
|
25
|
+
# 0. Get remote
|
26
|
+
unless remote = (options[:remote] || `git --git-dir=#{git_dir} config --get remote.origin.url`).strip
|
27
|
+
raise "No remote found for origin"
|
28
|
+
end
|
29
|
+
|
30
|
+
e_remote = Shellwords.escape(remote)
|
31
|
+
e_branch = Shellwords.escape(options[:branch])
|
32
|
+
|
33
|
+
tmp_dir = Pathname.new(Dir.mktmpdir)
|
34
|
+
clone_dir = tmp_dir + "clone"
|
35
|
+
|
36
|
+
# Check if remote already has branch
|
37
|
+
if `git ls-remote --heads #{e_remote} refs/heads/#{e_branch}` == ""
|
38
|
+
release.log(self, "Creating empty branch")
|
39
|
+
# Branch does not exist yet
|
40
|
+
FileUtils.mkdir(clone_dir)
|
41
|
+
Dir.chdir(clone_dir) do
|
42
|
+
`git init`
|
43
|
+
`git remote add origin #{e_remote}`
|
44
|
+
`git checkout -b #{e_branch}`
|
45
|
+
end
|
46
|
+
else
|
47
|
+
release.log(self, "Cloning existing repo")
|
48
|
+
# 1. Clone into different directory
|
49
|
+
`git clone #{e_remote} --branch #{e_branch} --single-branch #{clone_dir}`
|
50
|
+
end
|
51
|
+
|
52
|
+
release.log(self, "Working git magic in #{clone_dir}")
|
53
|
+
Dir.chdir(clone_dir) do
|
54
|
+
# 3. Copy changes
|
55
|
+
FileUtils.rm_rf("*")
|
56
|
+
FileUtils.cp_r release.build_path.to_s + "/.", clone_dir.to_s
|
57
|
+
|
58
|
+
# 4. Add all files
|
59
|
+
`git add .`
|
60
|
+
|
61
|
+
# 5. Commit
|
62
|
+
`git commit -a -m "Release #{release.scm.version}"`
|
63
|
+
|
64
|
+
# 6. Git push
|
65
|
+
if options[:push]
|
66
|
+
`git push origin #{e_branch}`
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
if options[:cleanup]
|
71
|
+
FileUtils.rm_rf(tmp_dir)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
# Find the git dir
|
79
|
+
# TODO this is just a copy from release/scm/git.rb
|
80
|
+
def find_git_dir(path)
|
81
|
+
path = Pathname.new(path).realpath
|
82
|
+
while path.parent != path && !(path + ".git").directory?
|
83
|
+
path = path.parent
|
84
|
+
end
|
85
|
+
|
86
|
+
path = path + ".git"
|
87
|
+
|
88
|
+
raise "Could not find suitable .git dir in #{path}" if !path.directory?
|
89
|
+
|
90
|
+
path
|
91
|
+
end
|
92
|
+
end
|