piston 1.1.1 → 1.2.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 +15 -0
- data/lib/core_ext/string.rb +4 -0
- data/lib/piston/command.rb +2 -1
- data/lib/piston/commands/import.rb +3 -2
- data/lib/piston/commands/status.rb +79 -0
- data/lib/piston/commands/update.rb +42 -17
- data/lib/piston/ui/command_line.rb +1 -0
- data/lib/piston/version.rb +2 -2
- metadata +3 -2
data/CHANGELOG
CHANGED
@@ -1,4 +1,19 @@
|
|
1
1
|
*SVN*
|
2
|
+
* New status subcommand. Shows M if locally or remotely modified. Applies to
|
3
|
+
one, many, all folders. This subcommand *requires* the use of a Subversion
|
4
|
+
1.2.0 client. Thanks to Chris Wanstrath for the inspiration. His Rake
|
5
|
+
tasks are available at http://errtheblog.com/post/38.
|
6
|
+
* Minor patch by Miguel Ibero Carreras to make Subversion always use the
|
7
|
+
C locale, instead of the current one. This allows Piston to be used
|
8
|
+
with internationalized versions of Subversion. David Bittencourt later
|
9
|
+
reported the same problem. Thanks!
|
10
|
+
* Better handle how update finds it's latest local revision to prevent
|
11
|
+
conflicts. If you had never locally changed your vendor repositories,
|
12
|
+
this fix will change nothing for you. This helps prevent local conflicts
|
13
|
+
if you had ever applied a local patch.
|
14
|
+
*CAVEAT*: See the release announcement at
|
15
|
+
http://blog.teksol.info/articles/2006/11/17/piston-1-2-0-status-better-update
|
16
|
+
for a required local operation.
|
2
17
|
|
3
18
|
2006-08-30 1.1.1
|
4
19
|
* Add contrib/piston [Michael Schuerig]
|
data/lib/core_ext/string.rb
CHANGED
data/lib/piston/command.rb
CHANGED
@@ -2,7 +2,7 @@ module Piston
|
|
2
2
|
# The base class which all commands subclass to obtain services from.
|
3
3
|
class Command
|
4
4
|
attr_accessor :revision, :dry_run, :quiet, :verbose, :force, :lock,
|
5
|
-
:recursive, :logging_stream
|
5
|
+
:recursive, :logging_stream, :show_updates
|
6
6
|
|
7
7
|
# Execute this command. The arguments are pre-processed to expand any
|
8
8
|
# wildcards using Dir#[]. This is because the Windows shell does not
|
@@ -32,6 +32,7 @@ module Piston
|
|
32
32
|
command = "svn #{args.join(' ')}"
|
33
33
|
logging_stream.puts command if verbose
|
34
34
|
return if dry_run
|
35
|
+
ENV['LC_ALL'] = 'C'
|
35
36
|
result = `#{command}`
|
36
37
|
logging_stream.puts result if verbose
|
37
38
|
raise "Command #{command} resulted in an error:\n\n#{result}" unless $?.exitstatus.zero?
|
@@ -21,6 +21,7 @@ module Piston
|
|
21
21
|
info = YAML::load(svn(:info, repos))
|
22
22
|
options = [:export]
|
23
23
|
options << ['--revision', revision] if revision
|
24
|
+
options << '--quiet'
|
24
25
|
options << repos
|
25
26
|
options << dir
|
26
27
|
export = svn options
|
@@ -31,7 +32,7 @@ module Piston
|
|
31
32
|
end
|
32
33
|
|
33
34
|
# Add so we can set properties
|
34
|
-
svn :add, '--non-recursive', '--force', dir
|
35
|
+
svn :add, '--non-recursive', '--force', '--quiet', dir
|
35
36
|
|
36
37
|
# Set the properties
|
37
38
|
svn :propset, Piston::ROOT, repos, dir
|
@@ -42,7 +43,7 @@ module Piston
|
|
42
43
|
|
43
44
|
# Finish adding. If we get an error, at least the properties will be
|
44
45
|
# set and the user can handle the rest
|
45
|
-
svn :add, '--force', dir
|
46
|
+
svn :add, '--force', '--quiet', dir
|
46
47
|
|
47
48
|
logging_stream.puts "Exported r#{revision} from '#{repos}' to '#{dir}'"
|
48
49
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
module Piston
|
4
|
+
module Commands
|
5
|
+
class Status < Piston::Command
|
6
|
+
def run(args)
|
7
|
+
# First, find the list of pistoned folders
|
8
|
+
folders = svn(:propget, '--recursive', Piston::ROOT, *args)
|
9
|
+
repos = Hash.new
|
10
|
+
repo = nil
|
11
|
+
folders.each_line do |line|
|
12
|
+
next unless line =~ /(\w.*) - /
|
13
|
+
repos[$1] = Hash.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# Then, get their properties
|
17
|
+
repo = nil
|
18
|
+
svn(:proplist, '--verbose', *repos.keys).each_line do |line|
|
19
|
+
case line
|
20
|
+
when /'([^']+)'/
|
21
|
+
repo = repos[$1]
|
22
|
+
when /(piston:[-\w]+)\s*:\s*(.*)$/
|
23
|
+
repo[$1] = $2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Determine their local status
|
28
|
+
repos.each_pair do |path, props|
|
29
|
+
log = svn(:log, '--revision', "#{props[Piston::LOCAL_REV]}:HEAD", '--quiet', '--limit', '2', path)
|
30
|
+
props[:locally_modified] = 'M' if log.count("\n") > 3
|
31
|
+
end
|
32
|
+
|
33
|
+
# And their remote status, if required
|
34
|
+
repos.each_pair do |path, props|
|
35
|
+
log = svn(:log, '--revision', "#{props[Piston::REMOTE_REV]}:HEAD", '--quiet', '--limit', '2', props[Piston::ROOT])
|
36
|
+
props[:remotely_modified] = 'M' if log.count("\n") > 3
|
37
|
+
end if show_updates
|
38
|
+
|
39
|
+
# Display the results
|
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]
|
43
|
+
end
|
44
|
+
|
45
|
+
logging_stream.puts "No pistoned folders found" if repos.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.help
|
49
|
+
"Determines the current status of each pistoned directory"
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.detailed_help(stream)
|
53
|
+
stream.puts <<EOF
|
54
|
+
status: #{help}
|
55
|
+
usage: status [DIR [DIR...]]
|
56
|
+
|
57
|
+
Shows the status of one, many or all pistoned folders. The status is
|
58
|
+
returned in columns.
|
59
|
+
|
60
|
+
The first column's values are:
|
61
|
+
: Locally unchanged (space)
|
62
|
+
M: Locally modified since importing
|
63
|
+
|
64
|
+
The second column's values are blanks, unless the --show-updates is passed.
|
65
|
+
M: Remotely modified since importing
|
66
|
+
|
67
|
+
Valid options:
|
68
|
+
--show-updates : Queries the remote repositories to determine
|
69
|
+
if they have been updated from our revision.
|
70
|
+
|
71
|
+
EOF
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.aliases
|
75
|
+
%w(status st)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -22,27 +22,42 @@ module Piston
|
|
22
22
|
def update(dir)
|
23
23
|
return unless File.directory?(dir)
|
24
24
|
return skip(dir, "locked") unless svn(:propget, LOCKED, dir) == ''
|
25
|
-
status = svn
|
26
|
-
|
25
|
+
status = svn(:status, '--show-updates', dir)
|
26
|
+
new_local_rev = nil
|
27
|
+
new_status = Array.new
|
28
|
+
status.each_line do |line|
|
29
|
+
if line =~ /status.+\s(\d+)$/i then
|
30
|
+
new_local_rev = $1.to_i
|
31
|
+
else
|
32
|
+
new_status << line unless line =~ /^\?/
|
33
|
+
end
|
34
|
+
end
|
35
|
+
raise "Unable to parse status\n#{status}" unless new_local_rev
|
36
|
+
return skip(dir, "pending updates -- run \"svn update #{dir}\"\n#{new_status}") if new_status.size > 0
|
27
37
|
|
28
|
-
logging_stream.
|
38
|
+
logging_stream.puts "Processing '#{dir}'..."
|
29
39
|
repos = svn(:propget, Piston::ROOT, dir).chomp
|
30
40
|
uuid = svn(:propget, Piston::UUID, dir).chomp
|
31
41
|
remote_revision = svn(:propget, Piston::REMOTE_REV, dir).chomp.to_i
|
32
42
|
local_revision = svn(:propget, Piston::LOCAL_REV, dir).chomp.to_i
|
43
|
+
local_revision = local_revision.succ
|
33
44
|
|
45
|
+
logging_stream.puts " Fetching remote repository's latest revision and UUID"
|
34
46
|
info = YAML::load(svn(:info, repos))
|
35
47
|
return skip(dir, "Repository UUID changed\n Expected #{uuid}\n Found #{info['Repository UUID']}\n Repository: #{repos}") unless uuid == info['Repository UUID']
|
36
48
|
|
37
49
|
new_remote_rev = info['Last Changed Rev'].to_i
|
38
50
|
return skip(dir, "unchanged from revision #{remote_revision}", false) if remote_revision == new_remote_rev
|
39
51
|
|
40
|
-
info = YAML::load(svn(:info, File.join(dir, '..')))
|
41
|
-
new_local_rev = info['Revision']
|
42
|
-
|
43
52
|
revisions = (remote_revision .. (revision || new_remote_rev))
|
44
|
-
|
53
|
+
|
54
|
+
logging_stream.puts " Restoring remote repository to known state at r#{revisions.first}"
|
55
|
+
svn :checkout, '--ignore-externals', '--quiet', '--revision', revisions.first, repos, dir.tmp
|
56
|
+
|
57
|
+
logging_stream.puts " Updating remote repository to r#{revisions.last}"
|
45
58
|
updates = svn :update, '--ignore-externals', '--revision', revisions.last, dir.tmp
|
59
|
+
|
60
|
+
logging_stream.puts " Processing adds/deletes"
|
46
61
|
merges = Array.new
|
47
62
|
changes = 0
|
48
63
|
updates.each_line do |line|
|
@@ -53,34 +68,44 @@ module Piston
|
|
53
68
|
case op
|
54
69
|
when 'A'
|
55
70
|
if File.directory?(File.join(dir.tmp, file)) then
|
56
|
-
svn :mkdir, File.join(dir, file)
|
71
|
+
svn :mkdir, '--quiet', File.join(dir, file)
|
57
72
|
else
|
58
73
|
copy(dir, file)
|
59
|
-
svn :add, '--force', File.join(dir, file)
|
74
|
+
svn :add, '--quiet', '--force', File.join(dir, file)
|
60
75
|
end
|
61
76
|
when 'D'
|
62
|
-
svn :remove, '--force', File.join(dir, file)
|
77
|
+
svn :remove, '--quiet', '--force', File.join(dir, file)
|
63
78
|
else
|
64
79
|
copy(dir, file)
|
65
80
|
merges << file
|
66
81
|
end
|
67
82
|
end
|
68
83
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
84
|
+
# Determine if there are any local changes in the pistoned directory
|
85
|
+
log = svn(:log, '--quiet', '--revision', (local_revision .. new_local_rev).to_svn, '--limit', '2', dir)
|
86
|
+
|
87
|
+
# If none, we skip the merge process
|
88
|
+
if local_revision < new_local_rev && log.count("\n") > 3 then
|
89
|
+
logging_stream.puts " Merging local changes back in"
|
90
|
+
merges.each do |file|
|
91
|
+
begin
|
92
|
+
svn(:merge, '--quiet', '--revision', (local_revision .. new_local_rev).to_svn,
|
93
|
+
File.join(dir, file), File.join(dir, file))
|
94
|
+
rescue RuntimeError
|
95
|
+
next if $!.message =~ /Unable to find repository location for/
|
96
|
+
end
|
74
97
|
end
|
75
|
-
end
|
98
|
+
end
|
76
99
|
|
100
|
+
logging_stream.puts " Removing temporary files / folders"
|
77
101
|
FileUtils.rm_rf dir.tmp
|
78
102
|
|
103
|
+
logging_stream.puts " Updating Piston properties"
|
79
104
|
svn :propset, Piston::REMOTE_REV, revisions.last, dir
|
80
105
|
svn :propset, Piston::LOCAL_REV, new_local_rev, dir
|
81
106
|
svn :propset, Piston::LOCKED, revisions.last, dir if lock
|
82
107
|
|
83
|
-
logging_stream.puts "Updated to #{revisions.last} (#{changes} changes)"
|
108
|
+
logging_stream.puts " Updated to r#{revisions.last} (#{changes} changes)"
|
84
109
|
end
|
85
110
|
|
86
111
|
def copy(dir, file)
|
@@ -10,6 +10,7 @@ module Piston
|
|
10
10
|
[ '--dry-run', GetoptLong::NO_ARGUMENT ],
|
11
11
|
[ '--quiet', '-q', GetoptLong::NO_ARGUMENT ],
|
12
12
|
[ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
|
13
|
+
[ '--show-updates', '-u', GetoptLong::NO_ARGUMENT ],
|
13
14
|
[ '--lock', GetoptLong::NO_ARGUMENT ],
|
14
15
|
[ '--force', '-f', GetoptLong::NO_ARGUMENT ],
|
15
16
|
[ '--version', GetoptLong::NO_ARGUMENT ]
|
data/lib/piston/version.rb
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: piston
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2006-
|
6
|
+
version: 1.2.0
|
7
|
+
date: 2006-11-17 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
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- lib/piston/commands/import.rb
|
52
52
|
- lib/piston/commands/unlock.rb
|
53
53
|
- lib/piston/commands/convert.rb
|
54
|
+
- lib/piston/commands/status.rb
|
54
55
|
- lib/piston/ui/command_line.rb
|
55
56
|
test_files: []
|
56
57
|
|