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