roger 0.0.1 → 0.10.0
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 +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
|