repertoire 0.1.2 → 0.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.
Files changed (47) hide show
  1. data/History.txt +15 -0
  2. data/Manifest.txt +23 -10
  3. data/README.txt +31 -6
  4. data/Rakefile +2 -1
  5. data/lib/repertoire/compat.rb +4 -3
  6. data/lib/repertoire/{media/exceptions → exceptions}/checkout_failed.rb +0 -0
  7. data/lib/repertoire/exceptions/program_not_found.rb +1 -1
  8. data/lib/repertoire/{media/exceptions → exceptions}/repository_exists.rb +0 -0
  9. data/lib/repertoire/{media/exceptions → exceptions}/update_failed.rb +0 -0
  10. data/lib/repertoire/exceptions.rb +3 -0
  11. data/lib/repertoire/media/exceptions/unknown_media.rb +3 -1
  12. data/lib/repertoire/media/exceptions.rb +0 -3
  13. data/lib/repertoire/{extensions → media/extensions}/meta/object.rb +5 -5
  14. data/lib/repertoire/media/extensions/meta.rb +1 -0
  15. data/lib/repertoire/media/extensions.rb +1 -0
  16. data/lib/repertoire/media/media.rb +2 -115
  17. data/lib/repertoire/media/type.rb +87 -69
  18. data/lib/repertoire/media/types/git.rb +7 -7
  19. data/lib/repertoire/media/types/hg.rb +30 -0
  20. data/lib/repertoire/media/types/rsync.rb +5 -7
  21. data/lib/repertoire/media/types/svn.rb +5 -7
  22. data/lib/repertoire/media/types.rb +1 -2
  23. data/lib/repertoire/repertoire.rb +102 -6
  24. data/lib/repertoire/repository.rb +78 -18
  25. data/lib/repertoire/version.rb +2 -1
  26. data/spec/compat_spec.rb +31 -0
  27. data/{test/test_repertoire.rb → spec/helpers/repository/.hg/.keep} +0 -0
  28. data/spec/helpers/repository/dir/file.txt +1 -0
  29. data/spec/helpers/repository/dir/file2.txt +1 -0
  30. data/spec/helpers/repository/file.txt +1 -0
  31. data/spec/helpers/repository.rb +1 -0
  32. data/spec/media/media_spec.rb +79 -0
  33. data/spec/media/type_spec.rb +36 -0
  34. data/spec/media/types/git_spec.rb +17 -0
  35. data/spec/media/types/hg_spec.rb +13 -0
  36. data/spec/media/types/rsync_spec.rb +17 -0
  37. data/spec/media/types/svn_spec.rb +17 -0
  38. data/spec/repertoire_spec.rb +9 -0
  39. data/spec/repository_spec.rb +78 -0
  40. data/spec/spec_helper.rb +7 -0
  41. data/tasks/spec.rb +9 -0
  42. metadata +31 -18
  43. data/lib/repertoire/extensions/meta.rb +0 -1
  44. data/lib/repertoire/extensions/uri.rb +0 -26
  45. data/lib/repertoire/extensions.rb +0 -1
  46. data/lib/repertoire/media/types/cvs.rb +0 -31
  47. data/lib/repertoire/media/types/darcs.rb +0 -30
@@ -1,5 +1,4 @@
1
- require 'repertoire/media/types/cvs'
2
- require 'repertoire/media/types/darcs'
1
+ require 'repertoire/media/types/hg'
3
2
  require 'repertoire/media/types/git'
4
3
  require 'repertoire/media/types/svn'
5
4
  require 'repertoire/media/types/rsync'
@@ -1,24 +1,120 @@
1
+ require 'repertoire/exceptions/repository_exists'
2
+ require 'repertoire/exceptions/checkout_failed'
3
+ require 'repertoire/exceptions/update_failed'
4
+ require 'repertoire/repository'
1
5
  require 'repertoire/media'
2
6
 
7
+ require 'fileutils'
8
+
3
9
  module Repertoire
4
10
  #
5
- # See Media.checkout.
11
+ # Checkout the repository at the specified _options_. If a _block_
12
+ # is given, it will be passed a newly created Repository object
13
+ # for the checked out repository.
14
+ #
15
+ # _options_ must contain the following key:
16
+ # <tt>:uri</tt>:: The URI of the repository to checkout.
17
+ #
18
+ # _options_ may also contain the additional keys:
19
+ # <tt>:path</tt>:: Path to checkout the repository to.
20
+ # <tt>:media</tt>:: The media type of the repository. Defaults to the
21
+ # value of Media.get_for_uri.
22
+ # <tt>:into</tt>:: Checkout the repository into the given directory.
23
+ # Cannot be used with <tt>:path</tt>.
6
24
  #
7
25
  def Repertoire.checkout(options={},&block)
8
- Media.checkout(options,&block)
26
+ unless options[:uri]
27
+ raise(ArgumentError,"the :uri option must be specified",caller)
28
+ end
29
+
30
+ uri = options[:uri].to_s
31
+ path = options[:path]
32
+ into = options[:into]
33
+ media = options[:media]
34
+
35
+ unless path
36
+ if into
37
+ into = File.expand_path(into)
38
+
39
+ unless File.directory?(into)
40
+ FileUtils.mkdir_p(into)
41
+ end
42
+
43
+ path = File.join(into,Repository.name(uri))
44
+ else
45
+ path = Repository.name(uri)
46
+ end
47
+ end
48
+
49
+ path = File.expand_path(path)
50
+ if File.exists?(path)
51
+ raise(RepositoryExists,"the repository #{path.dump} already exists",caller)
52
+ end
53
+
54
+ if media
55
+ handler = Media.get(media)
56
+ else
57
+ handler = Media.guess_from_uri(uri)
58
+ end
59
+
60
+ begin
61
+ handler.checkout(uri,path)
62
+ rescue CommandFailed
63
+ raise(CheckoutFailed,"failed to checkout the repository located at #{uri.dump}",caller)
64
+ end
65
+
66
+ return Repository.new(path,handler,&block)
9
67
  end
10
68
 
11
69
  #
12
- # See Media.update.
70
+ # Update the repository with the specified _options_. If a _block_
71
+ # is given, it will be passed a newly created Repository object
72
+ # for the updated repository.
73
+ #
74
+ # _options_ must contain the following keys:
75
+ # <tt>:path</tt>:: The path of the repository to update.
76
+ #
77
+ # _options_ may also contain the additional keys:
78
+ # <tt>:uri</tt>:: The URI to update against.
79
+ # <tt>:media</tt>:: The type of the repository. Defaults to
80
+ # Media.guess_from_uri if <tt>:uri</tt> is given,
81
+ # otherwise Media.guess_from_path.
13
82
  #
14
83
  def Repertoire.update(options={},&block)
15
- Media.update(options,&block)
84
+ unless options[:path]
85
+ raise(ArgumentError,"the :path option must be specified",caller)
86
+ end
87
+
88
+ path = File.expand_path(options[:path])
89
+ uri = options[:uri]
90
+ media = options[:media]
91
+
92
+ if media
93
+ handler = Media.get(media)
94
+ elsif uri
95
+ handler = Media.guess_from_uri(uri)
96
+ else
97
+ handler = Media.guess_from_path(path)
98
+ end
99
+
100
+ begin
101
+ handler.update(path,uri)
102
+ rescue CommandFailed
103
+ raise(UpdateFailed,"failed to update the repository at #{path.dump}",caller)
104
+ end
105
+
106
+ return Repository.new(path,handler,&block)
16
107
  end
17
108
 
18
109
  #
19
- # See Media.delete.
110
+ # Delete the repository at the specified _path_. If a _block_ is
111
+ # given, it will be passed the _path_ before it is deleted.
20
112
  #
21
113
  def Repertoire.delete(path,&block)
22
- Media.delete(path,&block)
114
+ path = File.expand_path(path)
115
+
116
+ block.call(path) if block
117
+ FileUtils.rm_r(path,:force => true, :secure => true)
118
+ return nil
23
119
  end
24
120
  end
@@ -1,4 +1,7 @@
1
1
  require 'repertoire/media'
2
+ require 'repertoire/repository'
3
+
4
+ require 'uri'
2
5
 
3
6
  module Repertoire
4
7
  class Repository
@@ -16,31 +19,93 @@ module Repertoire
16
19
  #
17
20
  # Repository.new('path/to/repo',Media::SVN)
18
21
  #
19
- # Repository.new('path/to/svn_repo',Media::SVN) do |dir|
20
- # puts dir['**/']
22
+ # Repository.new('path/to/svn_repo',Media::SVN) do |repo|
23
+ # puts repo['**/']
21
24
  # end
22
25
  #
23
26
  def initialize(path,media=nil,&block)
24
27
  @path = File.expand_path(path)
25
- @media = nil
26
28
 
27
- if media
28
- if File.directory?(File.join(path,media.directory))
29
- @media = media
30
- end
29
+ begin
30
+ @media = (media || Media.guess_from_path(@path))
31
+ rescue Media::UnknownMedia
32
+ @media = nil
31
33
  end
32
34
 
33
35
  block.call(self) if block
34
36
  end
35
37
 
38
+ #
39
+ # Returns the +basename+ of the specified _uri_, unless the +basename+ is
40
+ # +'trunk'+ then the +basename+ of the parent directory within the _uri_
41
+ # is returned.
42
+ #
43
+ # Repertoire.name('http://www.today.com/is/now')
44
+ # # => "now"
45
+ #
46
+ # Repertoire.name('svn://svn.repo.com/var/svn/awesome/trunk')
47
+ # # => "awesome"
48
+ #
49
+ def Repository.name(uri)
50
+ uri = URI(uri.to_s)
51
+
52
+ if uri.path.empty?
53
+ path = File::SEPARATOR
54
+ else
55
+ path = File.expand_path(uri.path)
56
+ end
57
+
58
+ name = File.basename(path)
59
+
60
+ if name == 'trunk'
61
+ name = File.basename(File.dirname(path))
62
+ elsif name =~ /\.git$/
63
+ name.gsub!(/\.git$/,'')
64
+ end
65
+
66
+ if (name.empty? || name == File::SEPARATOR)
67
+ name = uri.host
68
+ end
69
+
70
+ return name
71
+ end
72
+
73
+ #
74
+ # Returns the name of the media used for the repository. If the media
75
+ # could not be guessed, +nil+ will be returned.
76
+ #
77
+ def media_name
78
+ return @media.name if @media
79
+ return nil
80
+ end
81
+
82
+ #
83
+ # Update the repository.
84
+ #
85
+ def update(uri=nil)
86
+ if @media
87
+ @media.update(uri)
88
+ return true
89
+ end
90
+
91
+ return false
92
+ end
93
+
94
+ #
95
+ # Delete the repository.
96
+ #
97
+ def delete
98
+ Repertoire.delete(@path)
99
+ end
100
+
36
101
  #
37
102
  # Similar to <tt>Dir.glob</tt>, except the media's directory is omitted
38
103
  # from the returned results. If a _block_ is given, it will be passed
39
104
  # each resulting path.
40
105
  #
41
- # dir = Directory.new('path/to/my_svn')
42
- # dir.glob('sub_path/.svn/*') # => []
43
- # dir.glob('sub_path/**/') # => [...]
106
+ # repo = Repository.new('path/to/my_svn')
107
+ # repo.glob('sub_path/.svn/*') # => []
108
+ # repo.glob('sub_path/**/') # => [...]
44
109
  #
45
110
  def glob(pattern,flags=0,&block)
46
111
  pattern = File.expand_path(File.join(@path,pattern))
@@ -90,12 +155,7 @@ module Repertoire
90
155
  !(directories(sub_path).empty?)
91
156
  end
92
157
 
93
- #
94
- # See glob.
95
- #
96
- def [](pattern='')
97
- glob(pattern)
98
- end
158
+ alias [] glob
99
159
 
100
160
  #
101
161
  # Returns the path of the directory in +String+ form.
@@ -113,8 +173,8 @@ module Repertoire
113
173
  def filter(paths)
114
174
  return paths unless @media
115
175
 
116
- return paths.select do |path|
117
- !(path.split(File::SEPARATOR).include?(@media.directory))
176
+ return paths.reject do |path|
177
+ path.split(File::SEPARATOR).include?(@media.directory)
118
178
  end
119
179
  end
120
180
 
@@ -1,3 +1,4 @@
1
1
  module Repertoire
2
- VERSION = '0.1.2'
2
+ # Repertoire version
3
+ VERSION = '0.2.0'
3
4
  end
@@ -0,0 +1,31 @@
1
+ require 'repertoire/compat'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Compat do
6
+ it "should have a list of directories that contain programs" do
7
+ Compat.paths.any? { |dir|
8
+ File.directory?(dir)
9
+ }.should == true
10
+ end
11
+
12
+ it "should be able to find programs" do
13
+ File.executable?(Compat.find_program('dir')).should == true
14
+ end
15
+
16
+ it "should be able to run programs" do
17
+ Compat.sh('dir').should_not == false
18
+ end
19
+
20
+ it "should raise ProgramNotFound when running missing programs" do
21
+ lambda {
22
+ Compat.sh('obviously_not_there')
23
+ }.should raise_error(ProgramNotFound)
24
+ end
25
+
26
+ it "should raise CommandFailed when the program fails" do
27
+ lambda {
28
+ Compat.sh('dir','obviously_missing_dir')
29
+ }.should raise_error(CommandFailed)
30
+ end
31
+ end
@@ -0,0 +1 @@
1
+ hello again
@@ -0,0 +1 @@
1
+ hello yet again
@@ -0,0 +1 @@
1
+ hello
@@ -0,0 +1 @@
1
+ REPOSITORY_PATH = File.join(File.dirname(__FILE__),'repository')
@@ -0,0 +1,79 @@
1
+ require 'repertoire/media'
2
+
3
+ describe Media do
4
+ it "should have media types" do
5
+ Media.types.should_not be_empty
6
+ end
7
+
8
+ it "should support Rsync media" do
9
+ Media.supports?('rsync').should == true
10
+ end
11
+
12
+ it "should support SubVersion media" do
13
+ Media.supports?('svn').should == true
14
+ end
15
+
16
+ it "should support Mercurial media" do
17
+ Media.supports?('hg').should == true
18
+ end
19
+
20
+ it "should support Git media" do
21
+ Media.supports?('git').should == true
22
+ end
23
+
24
+ it "should provide access to media types via Symbols" do
25
+ Media.get(:svn).should == Media::SVN
26
+ end
27
+
28
+ it "should provide access to media types via Strings" do
29
+ Media.get('svn').should == Media::SVN
30
+ end
31
+
32
+ it "should raise an UnknownMedia exception for missing Media" do
33
+ lambda {
34
+ Media.get('nothing')
35
+ }.should raise_error(Media::UnknownMedia)
36
+ end
37
+
38
+ it "should provide URI schemes which represent media types" do
39
+ Media.schemes.should_not be_empty
40
+ end
41
+
42
+ it "should support the svn: URI scheme" do
43
+ Media.supports_scheme?('svn').should == true
44
+ end
45
+
46
+ it "should support the svn+ssh: URI scheme" do
47
+ Media.supports_scheme?('svn+ssh').should == true
48
+ end
49
+
50
+ it "should support the git: URI scheme" do
51
+ Media.supports_scheme?('git').should == true
52
+ end
53
+
54
+ it "should provide directory names which are used by media types" do
55
+ Media.directories.should_not be_empty
56
+ end
57
+
58
+ it "should recognize the .svn directory" do
59
+ Media.recognizes_directory?('.svn').should == true
60
+ end
61
+
62
+ it "should recognize the .hg directory" do
63
+ Media.recognizes_directory?('.hg').should == true
64
+ end
65
+
66
+ it "should recognize the .git directory" do
67
+ Media.recognizes_directory?('.git').should == true
68
+ end
69
+
70
+ it "should guess media types via a URI" do
71
+ Media.guess_from_uri('svn+ssh://www.example.com/').should == Media::SVN
72
+ end
73
+
74
+ it "should raise an UnknownMedia exception for unknown URIs" do
75
+ lambda {
76
+ Media.guess_from_uri('new://www.example.com/')
77
+ }.should raise_error(Media::UnknownMedia)
78
+ end
79
+ end
@@ -0,0 +1,36 @@
1
+ require 'repertoire/media/type'
2
+
3
+ require 'spec_helper'
4
+ require 'tmpdir'
5
+
6
+ describe Media::Type do
7
+ it "should have a default name" do
8
+ Media::Type.name.should be_nil
9
+ end
10
+
11
+ it "should have default schemes" do
12
+ Media::Type.schemes.should be_empty
13
+ end
14
+
15
+ it "should have a default directory" do
16
+ Media::Type.directory.should be_nil
17
+ end
18
+
19
+ it "should be able to change the current working directory" do
20
+ current = Dir.pwd
21
+ Media::Type.cd(Dir.tmpdir)
22
+
23
+ Dir.pwd.should == Dir.tmpdir
24
+ Dir.chdir(current)
25
+ end
26
+
27
+ it "should be able to switch the current working directory" do
28
+ current = Dir.pwd
29
+
30
+ Media::Type.switch_dir(Dir.tmpdir) do
31
+ Dir.pwd.should == Dir.tmpdir
32
+ end
33
+
34
+ Dir.pwd.should == current
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ require 'repertoire/media/types/git'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Media::Git do
6
+ it "should have a name" do
7
+ Media::Git.name.should == :git
8
+ end
9
+
10
+ it "should have recognized schemes" do
11
+ Media::Git.schemes.should == ['git']
12
+ end
13
+
14
+ it "should recognize a directory" do
15
+ Media::Git.directory.should == '.git'
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require 'repertoire/media/types/hg'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Media::Hg do
6
+ it "should have a name" do
7
+ Media::Hg.name.should == :hg
8
+ end
9
+
10
+ it "should recognize a directory" do
11
+ Media::Hg.directory.should == '.hg'
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'repertoire/media/types/rsync'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Media::Rsync do
6
+ it "should have a name" do
7
+ Media::Rsync.name.should == :rsync
8
+ end
9
+
10
+ it "should have recognized schemes" do
11
+ Media::Rsync.schemes.should == ['rsync']
12
+ end
13
+
14
+ it "should not recognize a directory" do
15
+ Media::Rsync.directory.should be_nil
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'repertoire/media/types/svn'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Media::SVN do
6
+ it "should have a name" do
7
+ Media::SVN.name.should == :svn
8
+ end
9
+
10
+ it "should have recognized schemes" do
11
+ Media::SVN.schemes.should == ['svn', 'svn+ssh']
12
+ end
13
+
14
+ it "should recognize a directory" do
15
+ Media::SVN.directory.should == '.svn'
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ require 'repertoire/version'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Repertoire do
6
+ it "should have a VERSION constant" do
7
+ Repertoire.const_defined?('VERSION').should == true
8
+ end
9
+ end
@@ -0,0 +1,78 @@
1
+ require 'repertoire/repository'
2
+ require 'repertoire/media/types/hg'
3
+
4
+ require 'spec_helper'
5
+ require 'helpers/repository'
6
+
7
+ describe Repository do
8
+ describe "name" do
9
+ before(:all) do
10
+ @host = 'www.example.com'
11
+ @url_prefix = "http://#{@host}"
12
+ end
13
+
14
+ it "should return a repository name from a URI" do
15
+ Repository.name("#{@url_prefix}/repo").should == 'repo'
16
+ end
17
+
18
+ it "should ignore trunk/ postfixes" do
19
+ Repository.name("#{@url_prefix}/repo/trunk").should == 'repo'
20
+ end
21
+
22
+ it "should ignore .git postfixes" do
23
+ Repository.name("#{@url_prefix}/repo.git").should == 'repo'
24
+ end
25
+
26
+ it "should use the hostname if the URI path is empty" do
27
+ Repository.name(@url_prefix).should == @host
28
+ end
29
+
30
+ it "should use the hostname if the URI path is the root" do
31
+ Repository.name("#{@url_prefix}/").should == @host
32
+ end
33
+
34
+ it "should use the hostname if the URI path becomes empty" do
35
+ Repository.name("#{@url_prefix}/trunk").should == @host
36
+ end
37
+
38
+ it "should prevent against directory traversal" do
39
+ Repository.name("#{@url_prefix}/..").should == @host
40
+ end
41
+ end
42
+
43
+ describe "file access" do
44
+ before(:all) do
45
+ @repo = Repository.new(REPOSITORY_PATH,Media::Hg)
46
+ end
47
+
48
+ it "should have paths" do
49
+ paths = @repo.glob('**/*').map { |path| File.basename(path) }
50
+
51
+ paths.include?('file.txt').should == true
52
+ paths.include?('dir').should == true
53
+ paths.include?('file2.txt').should == true
54
+ end
55
+
56
+ it "should have top level files" do
57
+ @repo.files.map { |path| File.basename(path) }.should == [
58
+ 'file.txt'
59
+ ]
60
+ end
61
+
62
+ it "should have top level directories" do
63
+ @repo.directories.map { |path| File.basename(path) }.should == [
64
+ 'dir'
65
+ ]
66
+ end
67
+ end
68
+
69
+ it "should be able to guess the media typa from the path" do
70
+ repo = Repository.new(REPOSITORY_PATH)
71
+ repo.media.should == Media::Hg
72
+ end
73
+
74
+ it "should provide the media name of the repository" do
75
+ repo = Repository.new(REPOSITORY_PATH,Media::Hg)
76
+ repo.media_name.should == :hg
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>=1.1.3'
3
+ require 'spec'
4
+
5
+ require 'repertoire/version'
6
+
7
+ include Repertoire
data/tasks/spec.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ desc "Run all specifications"
4
+ Spec::Rake::SpecTask.new(:spec) do |t|
5
+ t.libs += ['lib', 'spec']
6
+ t.spec_opts = ['--colour', '--format', 'specdoc']
7
+ end
8
+
9
+ task :default => :spec