piston 1.2.1 → 1.3.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.
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