pivotal-piston 1.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/.gitignore +8 -0
  2. data/History.txt +11 -0
  3. data/License.txt +20 -0
  4. data/Manifest.txt +85 -0
  5. data/README.txt +136 -0
  6. data/Rakefile +4 -0
  7. data/bin/piston +5 -0
  8. data/config/hoe.rb +79 -0
  9. data/config/requirements.rb +18 -0
  10. data/lib/piston.rb +18 -0
  11. data/lib/piston/cli.rb +315 -0
  12. data/lib/piston/commands.rb +4 -0
  13. data/lib/piston/commands/base.rb +44 -0
  14. data/lib/piston/commands/import.rb +42 -0
  15. data/lib/piston/commands/info.rb +14 -0
  16. data/lib/piston/commands/lock_unlock.rb +21 -0
  17. data/lib/piston/commands/update.rb +29 -0
  18. data/lib/piston/git.rb +12 -0
  19. data/lib/piston/git/client.rb +77 -0
  20. data/lib/piston/git/commit.rb +74 -0
  21. data/lib/piston/git/repository.rb +63 -0
  22. data/lib/piston/git/working_copy.rb +86 -0
  23. data/lib/piston/repository.rb +57 -0
  24. data/lib/piston/revision.rb +53 -0
  25. data/lib/piston/svn.rb +14 -0
  26. data/lib/piston/svn/client.rb +88 -0
  27. data/lib/piston/svn/repository.rb +67 -0
  28. data/lib/piston/svn/revision.rb +74 -0
  29. data/lib/piston/svn/working_copy.rb +108 -0
  30. data/lib/piston/version.rb +9 -0
  31. data/lib/piston/working_copy.rb +183 -0
  32. data/lib/subclass_responsibility_error.rb +2 -0
  33. data/log/.gitignore +0 -0
  34. data/samples/common.rb +19 -0
  35. data/samples/import_git_git.rb +39 -0
  36. data/samples/import_git_svn.rb +36 -0
  37. data/samples/import_svn_git.rb +29 -0
  38. data/samples/import_svn_svn.rb +24 -0
  39. data/script/destroy +14 -0
  40. data/script/generate +14 -0
  41. data/script/txt2html +74 -0
  42. data/setup.rb +1585 -0
  43. data/tasks/deployment.rake +34 -0
  44. data/tasks/environment.rake +7 -0
  45. data/tasks/samples.rake +6 -0
  46. data/tasks/test.rake +69 -0
  47. data/tasks/website.rake +17 -0
  48. data/test/integration/test_git_git.rb +99 -0
  49. data/test/integration/test_git_svn.rb +121 -0
  50. data/test/integration/test_import_svn_git.rb +47 -0
  51. data/test/integration/test_import_svn_svn.rb +38 -0
  52. data/test/integration_helpers.rb +33 -0
  53. data/test/test_helper.rb +83 -0
  54. data/test/unit/git/commit/test_checkout.rb +31 -0
  55. data/test/unit/git/commit/test_each.rb +30 -0
  56. data/test/unit/git/commit/test_rememberance.rb +21 -0
  57. data/test/unit/git/commit/test_validation.rb +34 -0
  58. data/test/unit/git/repository/test_at.rb +23 -0
  59. data/test/unit/git/repository/test_basename.rb +12 -0
  60. data/test/unit/git/repository/test_branchanme.rb +15 -0
  61. data/test/unit/git/repository/test_guessing.rb +32 -0
  62. data/test/unit/git/working_copy/test_copying.rb +25 -0
  63. data/test/unit/git/working_copy/test_creation.rb +22 -0
  64. data/test/unit/git/working_copy/test_existence.rb +18 -0
  65. data/test/unit/git/working_copy/test_finalization.rb +15 -0
  66. data/test/unit/git/working_copy/test_guessing.rb +35 -0
  67. data/test/unit/git/working_copy/test_rememberance.rb +21 -0
  68. data/test/unit/svn/repository/test_at.rb +19 -0
  69. data/test/unit/svn/repository/test_basename.rb +24 -0
  70. data/test/unit/svn/repository/test_guessing.rb +45 -0
  71. data/test/unit/svn/revision/test_checkout.rb +28 -0
  72. data/test/unit/svn/revision/test_each.rb +22 -0
  73. data/test/unit/svn/revision/test_rememberance.rb +38 -0
  74. data/test/unit/svn/revision/test_validation.rb +50 -0
  75. data/test/unit/svn/working_copy/test_copying.rb +26 -0
  76. data/test/unit/svn/working_copy/test_creation.rb +16 -0
  77. data/test/unit/svn/working_copy/test_existence.rb +23 -0
  78. data/test/unit/svn/working_copy/test_externals.rb +56 -0
  79. data/test/unit/svn/working_copy/test_finalization.rb +17 -0
  80. data/test/unit/svn/working_copy/test_guessing.rb +18 -0
  81. data/test/unit/svn/working_copy/test_merging.rb +47 -0
  82. data/test/unit/svn/working_copy/test_rememberance.rb +26 -0
  83. data/test/unit/test_info.rb +37 -0
  84. data/test/unit/test_lock_unlock.rb +47 -0
  85. data/test/unit/test_repository.rb +51 -0
  86. data/test/unit/test_revision.rb +31 -0
  87. data/test/unit/working_copy/test_guessing.rb +35 -0
  88. data/test/unit/working_copy/test_info.rb +14 -0
  89. data/test/unit/working_copy/test_rememberance.rb +42 -0
  90. data/test/unit/working_copy/test_validate.rb +63 -0
  91. data/website/index.html +11 -0
  92. data/website/index.txt +39 -0
  93. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  94. data/website/stylesheets/screen.css +138 -0
  95. data/website/template.rhtml +48 -0
  96. metadata +244 -0
@@ -0,0 +1,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ Dir["#{dir}/commands/**/*.rb"].each do |f|
3
+ require f.gsub("#{File.expand_path("#{File.dirname(f)}/../..")}/", "")
4
+ end
@@ -0,0 +1,44 @@
1
+ module Piston
2
+ module Commands
3
+ class Base
4
+ class << self
5
+ def logger
6
+ @@logger ||= Log4r::Logger["main"]
7
+ end
8
+ end
9
+
10
+ attr_reader :options
11
+
12
+ def initialize(options={})
13
+ @options = options
14
+ logger.debug {"#{self.class.name} with options #{options.inspect}"}
15
+ end
16
+
17
+ def verbose
18
+ @options[:verbose]
19
+ end
20
+
21
+ def force
22
+ @options[:force]
23
+ end
24
+
25
+ def quiet
26
+ @options[:quiet]
27
+ end
28
+
29
+ def logger
30
+ self.class.logger
31
+ end
32
+
33
+ def guess_wc(wcdir)
34
+ Piston::WorkingCopy.guess(wcdir)
35
+ end
36
+
37
+ def working_copy!(wcdir)
38
+ wc = guess_wc(wcdir)
39
+ wc.validate!
40
+ wc
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,42 @@
1
+ require "piston/commands/base"
2
+
3
+ module Piston
4
+ module Commands
5
+ class Import < Piston::Commands::Base
6
+ attr_reader :options
7
+
8
+ def repository_type
9
+ options[:repository_type]
10
+ end
11
+
12
+ def select_repository(repository_url)
13
+ if repository_type then
14
+ logger.info {"Forced repository type to #{repository_type}"}
15
+ repository_class_name = "Piston::#{repository_type.downcase.capitalize}::Repository"
16
+ repository_class = repository_class_name.constantize
17
+ repository_class.new(repository_url)
18
+ else
19
+ logger.info {"Guessing the repository type"}
20
+ Piston::Repository.guess(repository_url)
21
+ end
22
+ end
23
+
24
+ def run(repository_url, target_revision, wcdir)
25
+ repository = select_repository(repository_url)
26
+ revision = repository.at(target_revision)
27
+
28
+ wcdir = File.expand_path(wcdir.nil? ? repository.basename : wcdir)
29
+ logger.info {"Guessing the working copy type"}
30
+ logger.debug {"repository_url: #{repository_url.inspect}, target_revision: #{target_revision.inspect}, wcdir: #{wcdir.inspect}"}
31
+ working_copy = guess_wc(wcdir)
32
+
33
+ if working_copy.exist? && !force then
34
+ logger.fatal "Path #{working_copy} already exists and --force not given. Aborting..."
35
+ abort
36
+ end
37
+
38
+ working_copy.import(revision, options[:lock])
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,14 @@
1
+ require "piston/commands/base"
2
+
3
+ module Piston
4
+ module Commands
5
+ class Info < Piston::Commands::Base
6
+ attr_reader :options
7
+
8
+ def run(wcdir)
9
+ working_copy = working_copy!(wcdir)
10
+ working_copy.info.to_yaml
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ require "piston/commands/base"
2
+
3
+ module Piston
4
+ module Commands
5
+ class LockUnlock < Piston::Commands::Base
6
+ attr_reader :options
7
+
8
+ def run(wcdir, lock)
9
+ working_copy = working_copy!(wcdir)
10
+
11
+ values = working_copy.recall
12
+ values["lock"] = lock
13
+ working_copy.remember(values, values["handler"])
14
+ working_copy.finalize
15
+
16
+ text = lock ? "Locked" : "Unlocked"
17
+ logger.info "#{text} #{working_copy} against automatic updates"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ require "piston/commands/base"
2
+
3
+ module Piston
4
+ module Commands
5
+ class Update < Piston::Commands::Base
6
+ # +wcdir+ is the working copy we're going to change.
7
+ # +to+ is the new target revision we want to be at after update returns.
8
+ def run(wcdir, to)
9
+ working_copy = working_copy!(wcdir)
10
+
11
+ logger.debug {"Recalling previously saved values"}
12
+ values = working_copy.recall
13
+
14
+ repository_class = values["repository_class"]
15
+ repository_url = values["repository_url"]
16
+ repository = repository_class.constantize.new(repository_url)
17
+ from_revision = repository.at(values["handler"])
18
+ to_revision = repository.at(to)
19
+
20
+ logger.debug {"Validating that #{from_revision} exists and is capable of performing the update"}
21
+ from_revision.validate!
22
+
23
+ logger.info {"Updating from #{from_revision} to #{to_revision}"}
24
+
25
+ working_copy.update(to_revision, options[:lock])
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/piston/git.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "piston/git/client"
2
+ require "piston/git/repository"
3
+ require "piston/git/commit"
4
+ require "piston/git/working_copy"
5
+
6
+ module Piston
7
+ module Git
8
+ URL = "url"
9
+ COMMIT = "commit"
10
+ BRANCH = "branch"
11
+ end
12
+ end
@@ -0,0 +1,77 @@
1
+ require "singleton"
2
+
3
+ module Piston
4
+ module Git
5
+ class Client
6
+ include Singleton
7
+
8
+ class CommandError < RuntimeError; end
9
+ class Failed < CommandError; end
10
+ class BadCommand < CommandError; end
11
+
12
+ def logger
13
+ @logger ||= Log4r::Logger["handler::client"]
14
+ end
15
+
16
+ def out_logger
17
+ @out_logger ||= Log4r::Logger["handler::client::out"]
18
+ end
19
+
20
+ def git(*args)
21
+ run_cmd :git, *args
22
+ end
23
+
24
+ private
25
+ def run_cmd(executable, *args)
26
+ args.collect! {|arg| arg =~ /\s|\*|\?|"|\n|\r/ ? %Q('#{arg}') : arg}
27
+ args.collect! {|arg| arg ? arg : '""'}
28
+ cmd = %Q|#{executable} #{args.join(' ')}|
29
+ logger.debug {"> " + cmd}
30
+
31
+ original_language = ENV["LANGUAGE"]
32
+ begin
33
+ ENV["LANGUAGE"] = "C"
34
+ value = run_real(cmd)
35
+ out_logger.info {"< " + value} unless (value || "").strip.empty?
36
+ return value
37
+ ensure
38
+ ENV["LANGUAGE"] = original_language
39
+ end
40
+ end
41
+
42
+ begin
43
+ raise LoadError, "Not implemented on Win32 machines" if RUBY_PLATFORM =~ /mswin32/
44
+
45
+ begin
46
+ require "rubygems"
47
+ rescue LoadError
48
+ # NOP -- attempt to load without Rubygems
49
+ end
50
+
51
+ require "open4"
52
+
53
+ def run_real(cmd)
54
+ begin
55
+ pid, stdin, stdout, stderr = Open4::popen4(cmd)
56
+ _, cmdstatus = Process.waitpid2(pid)
57
+ return stdout.read if cmd =~ /status/ && cmdstatus.exitstatus == 1
58
+ raise CommandError, "#{cmd.inspect} exited with status: #{cmdstatus.exitstatus}\n#{stderr.read}" unless cmdstatus.success?
59
+ return stdout.read
60
+ rescue Errno::ENOENT
61
+ raise BadCommand, cmd.inspect
62
+ end
63
+ end
64
+
65
+ rescue LoadError
66
+ # On platforms where open4 is unavailable, we fallback to running using
67
+ # the backtick method of Kernel.
68
+ def run_real(cmd)
69
+ out = `#{cmd}`
70
+ raise BadCommand, cmd.inspect if $?.exitstatus == 127
71
+ raise Failed, "#{cmd.inspect} exited with status: #{$?.exitstatus}" unless $?.success?
72
+ out
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,74 @@
1
+ require "piston/git/client"
2
+ require "piston/revision"
3
+ require "fileutils"
4
+
5
+ module Piston
6
+ module Git
7
+ class Commit < Piston::Revision
8
+ class InvalidCommit < RuntimeError; end
9
+ class Gone < InvalidCommit; end
10
+
11
+ alias_method :commit, :revision
12
+ attr_reader :sha1
13
+
14
+ def client
15
+ @client ||= Piston::Git::Client.instance
16
+ end
17
+
18
+ def git(*args)
19
+ client.git(*args)
20
+ end
21
+
22
+ def recalled_commit_id
23
+ recalled_values[Piston::Git::COMMIT]
24
+ end
25
+
26
+ def validate!
27
+ begin
28
+ data = git("ls-remote", @repository.url)
29
+ self
30
+ rescue Piston::Git::Client::CommandError
31
+ raise Piston::Git::Commit::Gone, "Repository at #{@repository.url} does not exist anymore"
32
+ end
33
+ end
34
+
35
+ def name
36
+ commit[0,7]
37
+ end
38
+
39
+ def branch_name
40
+ "my-#{commit}"
41
+ end
42
+
43
+ def checkout_to(dir)
44
+ super
45
+ git(:clone, repository.url, @dir)
46
+ Dir.chdir(@dir) do
47
+ logger.debug {"in dir #{@dir}"}
48
+ git(:checkout, "-b", branch_name, commit)
49
+ response = git(:log, "-n", "1")
50
+ @sha1 = $1 if response =~ /commit\s+([a-f\d]{40})/i
51
+ end
52
+
53
+ def remember_values
54
+ { Piston::Git::COMMIT => @sha1, Piston::Git::BRANCH => commit }
55
+ end
56
+
57
+ def each
58
+ raise ArgumentError, "Never cloned + checked out" if @dir.nil?
59
+ @dir.find do |path|
60
+ Find.prune if path.to_s =~ %r{/[.]git}
61
+ next if @dir == path
62
+ next if File.directory?(path)
63
+ yield path.relative_path_from(@dir)
64
+ end
65
+ end
66
+
67
+ def copy_to(relpath, abspath)
68
+ Pathname.new(abspath).dirname.mkpath
69
+ FileUtils.cp(@dir + relpath, abspath)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,63 @@
1
+ require "piston/git/commit"
2
+ require "uri"
3
+
4
+ module Piston
5
+ module Git
6
+ class Repository < Piston::Repository
7
+ Piston::Repository.add_handler self
8
+
9
+ class << self
10
+ def understands_url?(url)
11
+ uri = URI.parse(url) rescue nil
12
+ return true if uri && %w(git).include?(uri.scheme)
13
+
14
+ begin
15
+ response = git("ls-remote", "--heads", url.sub(/\?.+$/, ""))
16
+ return false if response.nil? || response.strip.chomp.empty?
17
+ !!(response =~ /[a-f\d]{40}\s/)
18
+ rescue Piston::Git::Client::CommandError
19
+ false
20
+ end
21
+ end
22
+
23
+ def client
24
+ @@client ||= Piston::Git::Client.instance
25
+ end
26
+
27
+ def git(*args)
28
+ client.git(*args)
29
+ end
30
+
31
+ def repository_type
32
+ 'git'
33
+ end
34
+ end
35
+
36
+ attr_reader :branchname
37
+
38
+ def initialize(url)
39
+ @branchname = url.split("?")[1]
40
+ super(url.sub(/\?.+$/, ""))
41
+ end
42
+
43
+ def git(*args)
44
+ self.class.git(*args)
45
+ end
46
+
47
+ def at(commit)
48
+ case commit
49
+ when Hash
50
+ Piston::Git::Commit.new(self, commit[Piston::Git::COMMIT])
51
+ when :head
52
+ Piston::Git::Commit.new(self, "HEAD")
53
+ else
54
+ Piston::Git::Commit.new(self, commit)
55
+ end
56
+ end
57
+
58
+ def basename
59
+ self.url.split("/").last.sub(".git", "")
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ require "piston/working_copy"
2
+ require "piston/git/client"
3
+
4
+ module Piston
5
+ module Git
6
+ class WorkingCopy < Piston::WorkingCopy
7
+ # Register ourselves as a handler for working copies
8
+ Piston::WorkingCopy.add_handler self
9
+
10
+ class << self
11
+ def understands_dir?(dir)
12
+ path = dir
13
+ begin
14
+ begin
15
+ logger.debug {"git status on #{path}"}
16
+ Dir.chdir(path) do
17
+ response = git(:status)
18
+ return true if response =~ /# On branch /
19
+ end
20
+ rescue Errno::ENOENT
21
+ # NOP, we assume this is simply because the folder hasn't been created yet
22
+ path = path.parent
23
+ retry unless path.to_s == "/"
24
+ return false
25
+ end
26
+ rescue Piston::Git::Client::BadCommand
27
+ # NOP, as we return false below
28
+ rescue Piston::Git::Client::CommandError
29
+ # This is certainly not a Git repository
30
+ false
31
+ end
32
+
33
+ false
34
+ end
35
+
36
+ def client
37
+ @@client ||= Piston::Git::Client.instance
38
+ end
39
+
40
+ def git(*args)
41
+ client.git(*args)
42
+ end
43
+ end
44
+
45
+ def git(*args)
46
+ self.class.git(*args)
47
+ end
48
+
49
+ def create
50
+ path.mkpath rescue nil
51
+ end
52
+
53
+ def exist?
54
+ path.directory?
55
+ end
56
+
57
+ def finalize
58
+ Dir.chdir(path) { git(:add, ".") }
59
+ end
60
+
61
+ protected
62
+ def do_update(to, lock)
63
+ puts "tmpdir: #{to.dir}"
64
+ puts "exist? #{to.dir.exist?}"
65
+ puts "file? #{to.dir.file?}"
66
+ puts "directory? #{to.dir.directory?}"
67
+ path.children.reject {|item| ['.git', '.piston.yml'].include?(item.basename.to_s)}.each do |item|
68
+ puts "rm -rf #{item}"
69
+ FileUtils.rm_rf(item)
70
+ end
71
+ to.dir.children.reject {|item| item.basename.to_s == '.git'}.each do |item|
72
+ puts "cp -r #{item} #{path}"
73
+ FileUtils.cp_r(item, path)
74
+ end
75
+ Dir.chdir(path) do
76
+ repository = to.repository
77
+ remember(
78
+ {:repository_url => repository.url, :lock => lock, :repository_class => repository.class.name},
79
+ to.remember_values
80
+ )
81
+ git(:add, ".")
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end