roger 0.0.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +2 -0
  3. data/.travis.yml +12 -0
  4. data/CHANGELOG.md +102 -0
  5. data/Gemfile +5 -0
  6. data/MIT_LICENSE +20 -0
  7. data/README.md +10 -10
  8. data/Rakefile +9 -0
  9. data/bin/roger +5 -0
  10. data/doc/cli.md +46 -0
  11. data/doc/mockupfile.md +3 -0
  12. data/doc/templating.md +88 -0
  13. data/examples/default_template/.gitignore +2 -0
  14. data/examples/default_template/CHANGELOG +0 -0
  15. data/examples/default_template/Gemfile +3 -0
  16. data/examples/default_template/Mockupfile +1 -0
  17. data/examples/default_template/html/.empty_directory +0 -0
  18. data/examples/default_template/partials/.empty_directory +0 -0
  19. data/lib/roger/cli/command.rb +23 -0
  20. data/lib/roger/cli/generate.rb +5 -0
  21. data/lib/roger/cli/release.rb +10 -0
  22. data/lib/roger/cli/serve.rb +29 -0
  23. data/lib/roger/cli.rb +123 -0
  24. data/lib/roger/extractor.rb +95 -0
  25. data/lib/roger/generators/generator.rb +23 -0
  26. data/lib/roger/generators/new.rb +67 -0
  27. data/lib/roger/generators/templates/generator.tt +13 -0
  28. data/lib/roger/generators.rb +23 -0
  29. data/lib/roger/mockupfile.rb +63 -0
  30. data/lib/roger/project.rb +92 -0
  31. data/lib/roger/rack/html_validator.rb +26 -0
  32. data/lib/roger/rack/roger.rb +52 -0
  33. data/lib/roger/rack/sleep.rb +21 -0
  34. data/lib/roger/release/cleaner.rb +47 -0
  35. data/lib/roger/release/finalizers/dir.rb +29 -0
  36. data/lib/roger/release/finalizers/git_branch.rb +92 -0
  37. data/lib/roger/release/finalizers/rsync.rb +77 -0
  38. data/lib/roger/release/finalizers/zip.rb +42 -0
  39. data/lib/roger/release/finalizers.rb +19 -0
  40. data/lib/roger/release/injector.rb +99 -0
  41. data/lib/roger/release/processors/mockup.rb +93 -0
  42. data/lib/roger/release/processors/url_relativizer.rb +45 -0
  43. data/lib/roger/release/processors.rb +17 -0
  44. data/lib/roger/release/scm/git.rb +101 -0
  45. data/lib/roger/release/scm.rb +32 -0
  46. data/lib/roger/release.rb +363 -0
  47. data/lib/roger/resolver.rb +119 -0
  48. data/lib/roger/server.rb +117 -0
  49. data/lib/roger/template.rb +206 -0
  50. data/lib/roger/w3c_validator.rb +129 -0
  51. data/roger.gemspec +35 -0
  52. data/test/Mockupfile-syntax.rb +85 -0
  53. data/test/project/.rvmrc +1 -0
  54. data/test/project/Gemfile +7 -0
  55. data/test/project/Gemfile.lock +38 -0
  56. data/test/project/Mockupfile +13 -0
  57. data/test/project/html/formats/erb.html.erb +5 -0
  58. data/test/project/html/formats/index.html +1 -0
  59. data/test/project/html/formats/json.json.erb +0 -0
  60. data/test/project/html/formats/markdown.md +3 -0
  61. data/test/project/html/formats/mockup.html +5 -0
  62. data/test/project/html/front_matter/erb.html.erb +16 -0
  63. data/test/project/html/front_matter/markdown.md +7 -0
  64. data/test/project/html/layouts/content-for.html.erb +17 -0
  65. data/test/project/html/layouts/erb.html.erb +19 -0
  66. data/test/project/html/mockup/encoding.html +3 -0
  67. data/test/project/html/partials/erb.html.erb +10 -0
  68. data/test/project/html/partials/load_path.html.erb +3 -0
  69. data/test/project/html/partials/mockup.html +13 -0
  70. data/test/project/html/static/non-relative.html.erb +9 -0
  71. data/test/project/html/static/relative.html.erb +9 -0
  72. data/test/project/layouts/test.html.erb +34 -0
  73. data/test/project/layouts/yield.html.erb +1 -0
  74. data/test/project/lib/generators/test.rb +9 -0
  75. data/test/project/partials/formats/erb.html.erb +1 -0
  76. data/test/project/partials/partials-test.html.erb +1 -0
  77. data/test/project/partials/test/erb.html.erb +1 -0
  78. data/test/project/partials/test/front_matter.html.erb +1 -0
  79. data/test/project/partials/test/json.json.erb +1 -0
  80. data/test/project/partials/test/markdown.md +1 -0
  81. data/test/project/partials/test/mockup.part.html +1 -0
  82. data/test/project/partials/test/simple.html.erb +1 -0
  83. data/test/project/partials2/partials2-test.html.erb +1 -0
  84. data/test/unit/cli_test.rb +12 -0
  85. data/test/unit/generators_test.rb +75 -0
  86. data/test/unit/release/cleaner_test.rb +47 -0
  87. data/test/unit/resolver_test.rb +92 -0
  88. data/test/unit/template_test.rb +127 -0
  89. 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