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.
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