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 +6 -0
- data/lib/piston.rb +6 -6
- data/lib/piston/commands/status.rb +2 -2
- data/lib/piston/commands/switch.rb +144 -0
- data/lib/piston/commands/update.rb +1 -1
- data/lib/piston/version.rb +2 -2
- metadata +4 -3
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
|
22
|
-
# $Id: piston.rb
|
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
|
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
|
data/lib/piston/version.rb
CHANGED
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.
|
7
|
-
date:
|
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
|