realityforge-piston 1.4.1

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.
@@ -0,0 +1,81 @@
1
+ 1.4.1 (Pending)
2
+
3
+ 1.4.0 (2008-02-07)
4
+ * New piston diff subcommand, implemented by Graeme Mathieson.
5
+ http://rubyforge.org/tracker/index.php?func=detail&aid=17116&group_id=2105&atid=8179
6
+ * Per http://rubyforge.org/tracker/?func=detail&atid=8179&aid=10717&group_id=2105
7
+ Don't set LC_ALL, but set LANGUAGE so that repositories with foreign
8
+ characters can be used. Thanks go to Per Wigren.
9
+
10
+ 1.3.3 (2007-03-22)
11
+ * Repaired problems with import subcommand. Wrote specifications to prevent
12
+ the same failure mode again.
13
+
14
+ 1.3.2 (2007-03-09)
15
+ * piston switch had a bad constant access which caused failures.
16
+
17
+ 1.3.1 (2007-03-09)
18
+ * piston switch would fail if the branch from which we are reading had been
19
+ deleted.
20
+ * piston switch had a major bug. It did not update the piston:root property
21
+ to remember the new repository root. Reported and fixed by Graeme
22
+ Mathieson.
23
+ * piston switch errors out early if not provided with the right arguments.
24
+ Thanks to Graeme Mathieson for the info and patch.
25
+ * New internal command parser. No visible external changes.
26
+
27
+ 1.3.0 (2007-01-22)
28
+ * Piston status shows the revision number of locked repositories. Thanks to
29
+ Chris Wanstrath <http://errtheblog.com/>.
30
+ * New piston switch subcommand to switch repository locations. Thanks to
31
+ Greg Spurrier for the prompt which resulted in finally implementing this.
32
+
33
+ 1.2.1 (2006-11-20)
34
+ * Import subcommand would fail with a "svn: Explicit target required
35
+ ('vendor/rails' interpreted as prop value)" error. This was a minor
36
+ error in the import code. Reported by Daniel N.
37
+ * The import subcommand could import another revision than what was intended,
38
+ if HEAD was updated while the import is in progress.
39
+
40
+ 1.2.0 (2006-11-17)
41
+ * New status subcommand. Shows M if locally or remotely modified. Applies to
42
+ one, many, all folders. This subcommand *requires* the use of a Subversion
43
+ 1.2.0 client. Thanks to Chris Wanstrath for the inspiration. His Rake
44
+ tasks are available at http://errtheblog.com/post/38.
45
+ * Minor patch by Miguel Ibero Carreras to make Subversion always use the
46
+ C locale, instead of the current one. This allows Piston to be used
47
+ with internationalized versions of Subversion. David Bittencourt later
48
+ reported the same problem. Thanks!
49
+ * Better handle how update finds it's latest local revision to prevent
50
+ conflicts. If you had never locally changed your vendor repositories,
51
+ this fix will change nothing for you. This helps prevent local conflicts
52
+ if you had ever applied a local patch.
53
+ *CAVEAT*: See the release announcement at
54
+ http://blog.teksol.info/articles/2006/11/17/piston-1-2-0-status-better-update
55
+ for a required local operation.
56
+
57
+ 1.1.1 (2006-08-30)
58
+ * Add contrib/piston [Michael Schuerig]
59
+ * Non-recursively add the root directory of the managed folder then set Piston
60
+ properties before adding the contents of the managed folder. This is to
61
+ help ease work along if an inconsistent EOL is encountered during the
62
+ import. The user can finish the import by svn add'ing the rest of the
63
+ folder until all files are added. Piston properties will already have been
64
+ set.
65
+
66
+ 1.1.0 (2006-08-26)
67
+ * New 'convert' subcommand converts existing svn:externals to Piston managed
68
+ folders. Thanks to Dan Kubb for the idea.
69
+ * update now recursively finds the folders to process. It bases it's search
70
+ on the presence or absence of the piston:root property.
71
+ * Changed lock and unlock messages to be more detailed.
72
+
73
+ 1.0.1 (2006-08-24)
74
+ * Corrected minor bug where the core extensions were in core_ext/core_ext
75
+ instead of being in core_ext.
76
+ * Require the parent working copy path be at HEAD before importing / updating.
77
+ * Don't do unnecessary merges if the file had not changed prior to the update.
78
+ * During the update, if adding a folder, do an svn mkdir instead of a cp_r.
79
+
80
+ 1.0.0 (2006-08-24)
81
+ * Initial version
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2006 Francois Beausoleil <francois@teksol.info>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,134 @@
1
+ Piston is a utility that eases vendor branch management.
2
+ This is similar to <tt>svn:externals</tt>, except you have a local copy of
3
+ the files, which you can modify at will. As long as the changes are
4
+ mergeable, you should have no problems.
5
+
6
+ This tool has a similar purpose than svnmerge.py which you can find in the
7
+ contrib/client-side folder of the main Subversion repository at
8
+ http://svn.collab.net/repos/svn/trunk/contrib/client-side/svnmerge.py.
9
+ The main difference is that Piston is designed to work with remote
10
+ repositories. Another tool you might want to look at, SVK, which you can find
11
+ at http://svk.elixus.org/.
12
+
13
+ From Wikipedia's Piston page (http://en.wikipedia.org/wiki/Piston):
14
+ In general, a piston is a sliding plug that fits closely inside the bore
15
+ of a cylinder.
16
+
17
+ Its purpose is either to change the volume enclosed by the cylinder, or
18
+ to exert a force on a fluid inside the cylinder.
19
+
20
+ For this utility, I retain the second meaning, "to exert a force on a fluid
21
+ inside the cylinder." Piston forces the content of a remote repository
22
+ location back into our own.
23
+
24
+
25
+ = Installation
26
+
27
+ Nothing could be simpler:
28
+
29
+ $ gem install --include-dependencies piston
30
+
31
+
32
+ = Usage
33
+
34
+ First, you need to import the remote repository location:
35
+
36
+ $ piston import http://dev.rubyonrails.org/svn/rails/trunk vendor/rails
37
+ Exported r4720 from 'http://dev.rubyonrails.org/svn/rails/trunk' to 'vendor/rails'
38
+
39
+ $ svn commit -m "Importing local copy of Rails"
40
+
41
+ When you want to get the latest changes from the remote repository location:
42
+
43
+ $ piston update vendor/rails
44
+ Updated 'vendor/rails' to r4720.
45
+
46
+ $ svn commit -m "Updates vendor/rails to the latest revision"
47
+
48
+ You can prevent a local Piston-managed folder from updating by using the
49
+ +lock+ subcommand:
50
+
51
+ $ piston lock vendor/rails
52
+ 'vendor/rails' locked at r4720.
53
+
54
+ When you want to update again, you unlock:
55
+
56
+ $ piston unlock vendor/rails
57
+ 'vendor/rails' unlocked.
58
+
59
+ If the branch you are following moves, you should use the switch subcommand:
60
+
61
+ $ piston import http://dev.rubyonrails.org/svn/rails/branches/1-2-pre-release vendor/rails
62
+ $ svn commit vendor/rails
63
+
64
+ # Vendor branch is renamed, let's follow it
65
+ $ piston switch http://dev.rubyonrails.org/svn/rails/branches/1-2-stable vendor/rails
66
+
67
+
68
+ = Contributions
69
+
70
+ == Bash Shell Completion Script
71
+
72
+ Michael Schuerig contributed a Bash shell completion script. You should copy
73
+ +contrib/piston+ from your gem repository to the appropriate folder. Michael
74
+ said:
75
+
76
+ I've put together a bash completion function for piston. On Debian, I
77
+ just put it in /etc/bash_completion.d, alternatively, the contents can
78
+ be copied to ~/.bash_completion. I don't know how things are organized
79
+ on other Unix/Linux systems.
80
+
81
+
82
+ = Caveats
83
+
84
+ == Speed
85
+
86
+ This tool is SLOW. The update process particularly so. I use a brute force
87
+ approach. Subversion cannot merge from remote repositories, so instead I
88
+ checkout the folder at the initial revision, and then run svn update and
89
+ parse the results of that to determine what changes have occured.
90
+
91
+ If a local copy of a file was changed, it's changes will be merged back in.
92
+ If that introduces a conflict, Piston will not detect it. The commit will be
93
+ rejected by Subversion anyway.
94
+
95
+ == Copies / Renames
96
+
97
+ Piston *does not* track copies. Since Subversion does renames in two
98
+ phases (copy + delete), that is what Piston does.
99
+
100
+ == Local Operations Only
101
+
102
+ Piston only works if you have a working copy. It also never commits your
103
+ working copy directly. You are responsible for reviewing the changes and
104
+ applying any pending fixes.
105
+
106
+ == Remote Repository UUID
107
+
108
+ Piston caches the remote repository UUID, allowing it to know if the remote
109
+ repos is still the same. Piston refuses to work against a different
110
+ repository than the one we checked out from originally.
111
+
112
+
113
+ = Subversion Properties Used
114
+
115
+ * <tt>piston:uuid</tt>: The remote repository's UUID, which we always confirm
116
+ before doing any operations.
117
+ * <tt>piston:root</tt>: The repository root URL from which this Piston folder
118
+ was exported from.
119
+ * <tt>piston:remote-revision</tt>: The <tt>Last Changed Rev</tt> of the remote
120
+ repository.
121
+ * <tt>piston:local-revision</tt>: The <tt>Last Changed Rev</tt> of the Piston
122
+ managed folder, to enable us to know if we need to do any merging.
123
+ * <tt>piston:locked</tt>: The revision at which this folder is locked. If
124
+ this property is set and non-blank, Piston will skip the folder with
125
+ an appropriate message.
126
+
127
+
128
+ = Dependencies
129
+
130
+ Piston depends on the following libraries:
131
+
132
+ * yaml
133
+ * uri
134
+ * fileutils
@@ -0,0 +1,25 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'spec/rake/spectask'
5
+ require File.join(File.dirname(__FILE__), 'lib', 'piston', 'version')
6
+
7
+ gem_spec = Gem::Specification.load(File.expand_path('piston.gemspec', File.dirname(__FILE__)))
8
+
9
+ Spec::Rake::SpecTask.new(:spec) do |spec|
10
+ spec.libs << 'lib' << 'spec'
11
+ spec.spec_files = FileList['specs/**/*_spec.rb']
12
+ end
13
+
14
+ task :default => :spec
15
+
16
+ desc "Generate RDoc documentation in rdoc/"
17
+ Rake::RDocTask.new :rdoc do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = gem_spec.name
20
+ rdoc.options = gem_spec.rdoc_options.clone
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ rdoc.rdoc_files.include gem_spec.extra_rdoc_files
23
+ end
24
+
25
+ Rake::GemPackageTask.new(gem_spec).define
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rubygems'
5
+ rescue LoadError
6
+ # no rubygems to load, so we fail silently
7
+ end
8
+
9
+ require 'piston'
10
+ PistonCommandLineProcessor.parse_and_execute
@@ -0,0 +1,43 @@
1
+ have piston &&
2
+ _piston()
3
+ {
4
+ local cur prev commands options command
5
+
6
+ COMPREPLY=()
7
+ cur=${COMP_WORDS[COMP_CWORD]}
8
+
9
+ commands='update convert help unlock lock import switch'
10
+
11
+ if [[ $COMP_CWORD -eq 1 ]] ; then
12
+ if [[ "$cur" == -* ]]; then
13
+ COMPREPLY=( $( compgen -W '--version' -- $cur ) )
14
+ else
15
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
16
+ fi
17
+ else
18
+
19
+ prev=${COMP_WORDS[COMP_CWORD-1]}
20
+ command=${COMP_WORDS[1]}
21
+
22
+ if [[ "$cur" == -* ]]; then
23
+ case $command in
24
+ @(update|import))
25
+ options='-r --revision --lock --verbose'
26
+ ;;
27
+ esac
28
+ options="$options --verbose"
29
+
30
+ COMPREPLY=( $( compgen -W "$options" -- $cur ) )
31
+ else
32
+ if [[ "$command" == @(help|h|\?) ]]; then
33
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
34
+ else
35
+ _filedir
36
+ fi
37
+ fi
38
+ fi
39
+
40
+ return 0
41
+ }
42
+
43
+ [ -n "${have:-}" ] && complete -F _piston $default piston
@@ -0,0 +1,5 @@
1
+ class Range
2
+ def to_svn
3
+ to_s.gsub(/\.{2,3}/, ':')
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class String
2
+ def tmp
3
+ self + ".tmp"
4
+ end
5
+
6
+ def blank?
7
+ self.empty? || self.strip.empty?
8
+ end
9
+ end
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2006 Francois Beausoleil <francois@teksol.info>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ # $HeadURL: svn+ssh://rubyforge.org/var/svn/piston/tags/1.4.0/lib/piston.rb $
22
+ # $Id: piston.rb 139 2008-02-07 15:28:24Z fbos $
23
+
24
+ require 'yaml'
25
+ require 'uri'
26
+ require 'fileutils'
27
+
28
+ PISTON_ROOT = File.dirname(__FILE__)
29
+ Dir[File.join(PISTON_ROOT, 'core_ext', '*.rb')].each do |file|
30
+ require file
31
+ end
32
+
33
+ require "piston/version"
34
+ require "piston/command"
35
+ require "piston/command_error"
36
+
37
+ require "transat/parser"
38
+ Dir[File.join(PISTON_ROOT, "piston", "commands", "*.rb")].each do |file|
39
+ require file.gsub(PISTON_ROOT, "")[1..-4]
40
+ end
41
+
42
+ module Piston
43
+ ROOT = "piston:root"
44
+ UUID = "piston:uuid"
45
+ REMOTE_REV = "piston:remote-revision"
46
+ LOCAL_REV = "piston:local-revision"
47
+ LOCKED = "piston:locked"
48
+ end
49
+
50
+ PistonCommandLineProcessor = Transat::Parser.new do
51
+ program_name "Piston"
52
+ version [Piston::VERSION::STRING]
53
+
54
+ option :verbose, :short => :v, :default => true, :message => "Show subversion commands and results as they are executed"
55
+ option :quiet, :short => :q, :default => false, :message => "Do not output any messages except errors"
56
+ option :revision, :short => :r, :param_name => "REVISION", :type => :int
57
+ option :show_updates, :short => :u, :message => "Query the remote repository for out of dateness information"
58
+ option :lock, :short => :l, :message => "Close down and lock the imported directory from further changes"
59
+ option :dry_run, :message => "Does not actually execute any commands"
60
+ option :force, :message => "Force the command to run, even if Piston thinks it would cause a problem"
61
+
62
+ command :switch, Piston::Commands::Switch, :valid_options => %w(lock dry_run force revision quiet verbose)
63
+ command :update, Piston::Commands::Update, :valid_options => %w(lock dry_run force revision quiet verbose)
64
+ command :diff, Piston::Commands::Diff, :valid_options => %w(lock dry_run force revision quiet verbose)
65
+ command :import, Piston::Commands::Import, :valid_options => %w(lock dry_run force revision quiet verbose)
66
+ command :convert, Piston::Commands::Convert, :valid_options => %w(lock verbose dry_run)
67
+ command :unlock, Piston::Commands::Unlock, :valid_options => %w(force dry_run verbose)
68
+ command :lock, Piston::Commands::Lock, :valid_options => %w(force dry_run revision verbose)
69
+ command :status, Piston::Commands::Status, :valid_options => %w(show_updates verbose)
70
+ end
@@ -0,0 +1,68 @@
1
+ require "piston"
2
+
3
+ module Piston
4
+ # The base class which all commands subclass to obtain services from.
5
+ class Command
6
+ attr_accessor :revision, :dry_run, :quiet, :verbose, :force, :lock,
7
+ :recursive, :show_updates
8
+ attr_reader :args
9
+ attr_writer :logging_stream
10
+
11
+ def initialize(non_options, options)
12
+ @args = non_options
13
+
14
+ # Because the Windows shell does not process wildcards, we must do it
15
+ # here ourselves
16
+ @args.collect! do |arg|
17
+ next arg unless arg =~ /[*?]/
18
+ Dir[arg]
19
+ end
20
+
21
+ options.each do |option, value|
22
+ self.send("#{option}=", value)
23
+ end
24
+ end
25
+
26
+ # Run a Subversion command using the shell. If the Subversion command
27
+ # returns an existstatus different from zero, a RuntimeError is raised.
28
+ def svn(*args)
29
+ args = args.flatten.compact.map do |arg|
30
+ if arg.to_s =~ /[ *?@]/ then
31
+ %Q("#{arg}")
32
+ else
33
+ arg
34
+ end
35
+ end
36
+
37
+ command = "svn #{args.join(' ')}"
38
+ logging_stream.puts command if verbose
39
+ return if dry_run
40
+ ENV['LANGUAGE'] = 'en_US'
41
+ result = `#{command}`
42
+ logging_stream.puts result if verbose
43
+ raise "Command #{command} resulted in an error:\n\n#{result}" unless $?.exitstatus.zero?
44
+ result
45
+ end
46
+
47
+ # Returns an IO-like object to which all information should be logged.
48
+ def logging_stream
49
+ @logging_stream ||= $stdout
50
+ end
51
+
52
+ def skip(dir, msg, header=true)
53
+ logging_stream.print "Skipping '#{dir}': " if header
54
+ logging_stream.puts msg
55
+ end
56
+
57
+ def find_targets
58
+ targets = Array.new
59
+ svn(:propget, '--recursive', Piston::ROOT).each_line do |line|
60
+ next unless line =~ /^([^ ]+)\s-\s.*$/
61
+ targets << $1
62
+ end
63
+
64
+ targets
65
+ end
66
+
67
+ end
68
+ end