piston 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,5 +1,11 @@
1
1
  *SVN*
2
2
 
3
+ 2007-01-22 1.3.0
4
+ * Piston status shows the revision number of locked repositories. Thanks to
5
+ Chris Wanstrath <http://errtheblog.com/>.
6
+ * New piston switch subcommand to switch repository locations. Thanks to
7
+ Greg Spurrier for the prompt which resulted in finally implementing this.
8
+
3
9
  2006-11-20 1.2.1
4
10
  * Import subcommand would fail with a "svn: Explicit target required
5
11
  ('vendor/rails' interpreted as prop value)" error. This was a minor
data/lib/piston.rb CHANGED
@@ -18,8 +18,8 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- # $HeadURL: svn://rubyforge.org/var/svn/piston/tags/1.0.1/lib/piston.rb $
22
- # $Id: piston.rb 11 2006-08-25 02:47:12Z fbos $
21
+ # $HeadURL: svn+ssh://fbos@rubyforge.org/var/svn/piston/tags/1.3.0/lib/piston.rb $
22
+ # $Id: piston.rb 70 2007-01-22 20:33:35Z fbos $
23
23
 
24
24
  require 'yaml'
25
25
  require 'uri'
@@ -30,10 +30,6 @@ Dir[File.join(PISTON_ROOT, 'core_ext', '*.rb')].each do |file|
30
30
  require file
31
31
  end
32
32
 
33
- require File.join(PISTON_ROOT, 'piston', 'command')
34
- require File.join(PISTON_ROOT, 'piston', 'command_error')
35
- require File.join(PISTON_ROOT, 'piston', 'ui', 'command_line')
36
-
37
33
  module Piston
38
34
  ROOT = "piston:root"
39
35
  UUID = "piston:uuid"
@@ -41,3 +37,7 @@ module Piston
41
37
  LOCAL_REV = "piston:local-revision"
42
38
  LOCKED = "piston:locked"
43
39
  end
40
+
41
+ require File.join(PISTON_ROOT, 'piston', 'command')
42
+ require File.join(PISTON_ROOT, 'piston', 'command_error')
43
+ require File.join(PISTON_ROOT, 'piston', 'ui', 'command_line')
@@ -38,8 +38,8 @@ module Piston
38
38
 
39
39
  # Display the results
40
40
  repos.each_pair do |path, props|
41
- logging_stream.printf "%1s%1s %s (%s)\n", props[:locally_modified],
42
- props[:remotely_modified], path, props[Piston::ROOT]
41
+ logging_stream.printf "%1s%1s %5s %s (%s)\n", props[:locally_modified],
42
+ props[:remotely_modified], props[Piston::LOCKED], path, props[Piston::ROOT]
43
43
  end
44
44
 
45
45
  logging_stream.puts "No pistoned folders found" if repos.empty?
@@ -0,0 +1,144 @@
1
+ module Piston
2
+ module Commands
3
+ class Switch < Piston::Command
4
+ def run(args)
5
+ new_root, dir = args.shift, args.shift
6
+ raise Piston::CommandError, "Expected two arguments only to switch. Unrecognized arguments: #{args.inspect}" unless args.empty?
7
+ switch(dir, new_root)
8
+ end
9
+
10
+ def switch(dir, new_repos)
11
+ return unless File.directory?(dir)
12
+ return skip(dir, "locked") unless svn(:propget, LOCKED, dir) == ''
13
+ status = svn(:status, '--show-updates', dir)
14
+ new_local_rev = nil
15
+ new_status = Array.new
16
+ status.each_line do |line|
17
+ if line =~ /status.+\s(\d+)$/i then
18
+ new_local_rev = $1.to_i
19
+ else
20
+ new_status << line unless line =~ /^\?/
21
+ end
22
+ end
23
+ raise "Unable to parse status\n#{status}" unless new_local_rev
24
+ return skip(dir, "pending updates -- run \"svn update #{dir}\"\n#{new_status}") if new_status.size > 0
25
+
26
+ logging_stream.puts "Processing '#{dir}'..."
27
+ repos = svn(:propget, Piston::ROOT, dir).chomp
28
+ uuid = svn(:propget, Piston::UUID, dir).chomp
29
+ remote_revision = svn(:propget, Piston::REMOTE_REV, dir).chomp.to_i
30
+ local_revision = svn(:propget, Piston::LOCAL_REV, dir).chomp.to_i
31
+ local_revision = local_revision.succ
32
+
33
+ new_info = YAML::load(svn(:info, new_repos))
34
+ raise Piston::CommandError unless uuid == new_info['Repository UUID']
35
+
36
+ logging_stream.puts " Fetching remote repository's latest revision and UUID"
37
+ info = YAML::load(svn(:info, repos))
38
+ return skip(dir, "Repository UUID changed\n Expected #{uuid}\n Found #{info['Repository UUID']}\n Repository: #{repos}") unless uuid == info['Repository UUID']
39
+
40
+ new_remote_rev = new_info['Last Changed Rev'].to_i
41
+ return skip(dir, "unchanged from revision #{remote_revision}", false) if remote_revision == new_remote_rev
42
+
43
+ revisions = (remote_revision .. (revision || new_remote_rev))
44
+
45
+ logging_stream.puts " Restoring remote repository to known state at r#{revisions.first}"
46
+ svn :checkout, '--ignore-externals', '--quiet', '--revision', revisions.first, repos, dir.tmp
47
+
48
+ logging_stream.puts " Updating remote repository to #{new_repos}@#{revisions.last}"
49
+ updates = svn :switch, '--revision', revisions.last, new_repos, dir.tmp
50
+
51
+ logging_stream.puts " Processing adds/deletes"
52
+ merges = Array.new
53
+ changes = 0
54
+ updates.each_line do |line|
55
+ next unless line =~ %r{^([A-Z]).*\s+#{Regexp.escape(dir.tmp)}[\\/](.+)$}
56
+ op, file = $1, $2
57
+ changes += 1
58
+
59
+ case op
60
+ when 'A'
61
+ if File.directory?(File.join(dir.tmp, file)) then
62
+ svn :mkdir, '--quiet', File.join(dir, file)
63
+ else
64
+ copy(dir, file)
65
+ svn :add, '--quiet', '--force', File.join(dir, file)
66
+ end
67
+ when 'D'
68
+ svn :remove, '--quiet', '--force', File.join(dir, file)
69
+ else
70
+ copy(dir, file)
71
+ merges << file
72
+ end
73
+ end
74
+
75
+ # Determine if there are any local changes in the pistoned directory
76
+ log = svn(:log, '--quiet', '--revision', (local_revision .. new_local_rev).to_svn, '--limit', '2', dir)
77
+
78
+ # If none, we skip the merge process
79
+ if local_revision < new_local_rev && log.count("\n") > 3 then
80
+ logging_stream.puts " Merging local changes back in"
81
+ merges.each do |file|
82
+ begin
83
+ svn(:merge, '--quiet', '--revision', (local_revision .. new_local_rev).to_svn,
84
+ File.join(dir, file), File.join(dir, file))
85
+ rescue RuntimeError
86
+ next if $!.message =~ /Unable to find repository location for/
87
+ end
88
+ end
89
+ end
90
+
91
+ logging_stream.puts " Removing temporary files / folders"
92
+ FileUtils.rm_rf dir.tmp
93
+
94
+ logging_stream.puts " Updating Piston properties"
95
+ svn :propset, Piston::REMOTE_REV, revisions.last, dir
96
+ svn :propset, Piston::LOCAL_REV, new_local_rev, dir
97
+ svn :propset, Piston::LOCKED, revisions.last, dir if lock
98
+
99
+ logging_stream.puts " Updated to r#{revisions.last} (#{changes} changes)"
100
+ end
101
+
102
+ def copy(dir, file)
103
+ FileUtils.cp(File.join(dir.tmp, file), File.join(dir, file))
104
+ end
105
+
106
+ def skip(dir, msg, header=true)
107
+ logging_stream.print "Skipping '#{dir}': " if header
108
+ logging_stream.puts msg
109
+ end
110
+
111
+ def self.help
112
+ "Switches a single directory to a new repository root"
113
+ end
114
+
115
+ def self.detailed_help(stream)
116
+ stream.puts <<EOF
117
+ switch: #{help}
118
+ usage: switch NEW_REPOSITORY_ROOT DIR
119
+
120
+ This operation changes the remote location from A to B, keeping local
121
+ changes. If any local modifications were done, they will be preserved.
122
+ If merge conflicts occur, they will not be taken care of, and your subsequent
123
+ commit will fail.
124
+
125
+ Piston will refuse to update a folder if it has pending updates. Run
126
+ 'svn update' on the target folder to update it before running Piston
127
+ again.
128
+
129
+ Valid options:
130
+ -r [--revision] arg : Update to ARG instead of HEAD
131
+ --lock : Close down and lock the folder from future
132
+ updates immediately
133
+ --verbose : Show Subversion commands and results as they
134
+ are executed
135
+
136
+ EOF
137
+ end
138
+
139
+ def self.aliases
140
+ %w(switch sw)
141
+ end
142
+ end
143
+ end
144
+ end
@@ -21,7 +21,7 @@ module Piston
21
21
 
22
22
  def update(dir)
23
23
  return unless File.directory?(dir)
24
- return skip(dir, "locked") unless svn(:propget, LOCKED, dir) == ''
24
+ return skip(dir, "locked") unless svn(:propget, Piston::LOCKED, dir) == ''
25
25
  status = svn(:status, '--show-updates', dir)
26
26
  new_local_rev = nil
27
27
  new_status = Array.new
@@ -1,8 +1,8 @@
1
1
  module Piston
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
- MINOR = 2
5
- TINY = 1
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.9.0.8
3
3
  specification_version: 1
4
4
  name: piston
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.2.1
7
- date: 2006-11-20 00:00:00 +00:00
6
+ version: 1.3.0
7
+ date: 2007-01-22 00:00:00 +00:00
8
8
  summary: Piston is a utility that enables merge tracking of remote repositories.
9
9
  require_paths:
10
10
  - lib
@@ -45,6 +45,7 @@ files:
45
45
  - lib/piston/command_error.rb
46
46
  - lib/piston/command.rb
47
47
  - lib/piston/version.rb
48
+ - lib/piston/commands/switch.rb
48
49
  - lib/piston/commands/update.rb
49
50
  - lib/piston/commands/help.rb
50
51
  - lib/piston/commands/lock.rb