piston 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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]
@@ -2,4 +2,8 @@ class String
2
2
  def tmp
3
3
  self + ".tmp"
4
4
  end
5
+
6
+ def blank?
7
+ self.empty? || self.strip.empty?
8
+ end
5
9
  end
@@ -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 :status, '--show-updates', dir
26
- return skip(dir, "pending updates -- run \"svn update #{dir}\"") if status.split("\n").size > 1
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.print "Processing '#{dir}'... "
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
- svn :checkout, '--ignore-externals', '--revision', revisions.first, repos, dir.tmp
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
- merges.each do |file|
70
- begin
71
- svn :merge, '--quiet', '--revision', (local_revision.succ .. new_local_rev).to_svn, File.join(dir, file), File.join(dir, file)
72
- rescue RuntimeError
73
- next if $!.message =~ /Unable to find repository location for/
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 unless local_revision.succ == new_local_rev
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 ]
@@ -1,8 +1,8 @@
1
1
  module Piston
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
- MINOR = 1
5
- TINY = 1
4
+ MINOR = 2
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
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.1.1
7
- date: 2006-08-31 00:00:00 +00:00
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