librarian 0.0.20 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,15 @@
1
1
  module Librarian
2
+ #
3
+ # Represents the output of the resolution process. Captures the declared
4
+ # dependencies plus the full set of resolved manifests. The sources are
5
+ # already known by the dependencies and by the resolved manifests, so they do
6
+ # not need to be captured explicitly.
7
+ #
8
+ # This representation may be produced by the resolver, may be serialized into
9
+ # a lockfile, and may be deserialized from a lockfile. It is expected that the
10
+ # lockfile is a direct representation in text of this representation, so that
11
+ # the serialization-deserialization process is just the identity function.
12
+ #
2
13
  class Resolution
3
14
  attr_reader :dependencies, :manifests, :manifests_index
4
15
 
@@ -12,13 +12,25 @@ module Librarian
12
12
  include Local
13
13
 
14
14
  class << self
15
+
15
16
  LOCK_NAME = 'GIT'
17
+
16
18
  def lock_name
17
19
  LOCK_NAME
18
20
  end
21
+
19
22
  def from_lock_options(environment, options)
20
23
  new(environment, options[:remote], options.reject{|k, v| k == :remote})
21
24
  end
25
+
26
+ def from_spec_args(environment, uri, options)
27
+ recognized_options = [:ref, :path]
28
+ unrecognized_options = options.keys - recognized_options
29
+ unrecognized_options.empty? or raise Error, "unrecognized options: #{unrecognized_options.join(", ")}"
30
+
31
+ new(environment, uri, options)
32
+ end
33
+
22
34
  end
23
35
 
24
36
  DEFAULTS = {
@@ -29,7 +41,7 @@ module Librarian
29
41
  private :environment=
30
42
  attr_reader :uri, :ref, :sha, :path
31
43
 
32
- def initialize(environment, uri, options = {})
44
+ def initialize(environment, uri, options)
33
45
  self.environment = environment
34
46
  @uri = uri
35
47
  @ref = options[:ref] || DEFAULTS[:ref]
@@ -73,7 +85,7 @@ module Librarian
73
85
  @sha = nil
74
86
  end
75
87
 
76
- def cache!(dependencies)
88
+ def cache!(names)
77
89
  unless repository.git?
78
90
  repository.path.rmtree if repository.path.exist?
79
91
  repository.path.mkpath
@@ -15,18 +15,40 @@ module Librarian
15
15
  git.clone!(repository_url)
16
16
  git
17
17
  end
18
+
19
+ def bin
20
+ @bin ||= which("git") or raise Error, "cannot find git"
21
+ end
22
+
23
+ private
24
+
25
+ # Cross-platform way of finding an executable in the $PATH.
26
+ #
27
+ # which('ruby') #=> /usr/bin/ruby
28
+ #
29
+ # From:
30
+ # https://github.com/defunkt/hub/commit/353031307e704d860826fc756ff0070be5e1b430#L2R173
31
+ def which(cmd)
32
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
33
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
34
+ path = File.expand_path(path)
35
+ exts.each do |ext|
36
+ exe = File.join(path, cmd + ext)
37
+ return exe if File.executable?(exe)
38
+ end
39
+ end
40
+ nil
41
+ end
18
42
  end
19
43
 
20
44
  include Helpers::Debug
21
45
 
22
- attr_accessor :environment
23
- private :environment=
24
- attr_reader :path
46
+ attr_accessor :environment, :path
47
+ private :environment=, :path=
25
48
 
26
49
  def initialize(environment, path)
27
50
  self.environment = environment
28
- path = Pathname.new(path)
29
- @path = path
51
+ self.path = Pathname.new(path)
30
52
  end
31
53
 
32
54
  def git?
@@ -38,57 +60,45 @@ module Librarian
38
60
  end
39
61
 
40
62
  def clone!(repository_url)
41
- within do
42
- command = "clone #{repository_url} ."
43
- run!(command)
44
- end
63
+ command = %W(clone #{repository_url} . --quiet)
64
+ run!(command, :chdir => true)
45
65
  end
46
66
 
47
67
  def checkout!(reference, options ={ })
48
- within do
49
- command = "checkout #{reference}"
50
- command << " --force" if options[:force]
51
- run!(command)
52
- end
68
+ command = %W(checkout #{reference} --quiet)
69
+ command << "--force" if options[:force]
70
+ run!(command, :chdir => true)
53
71
  end
54
72
 
55
73
  def fetch!(remote, options = { })
56
- within do
57
- command = "fetch #{remote}"
58
- command << " --tags" if options[:tags]
59
- run!(command)
60
- end
74
+ command = %W(fetch #{remote} --quiet)
75
+ command << "--tags" if options[:tags]
76
+ run!(command, :chdir => true)
61
77
  end
62
78
 
63
79
  def reset_hard!
64
- within do
65
- command = "reset --hard"
66
- run!(command)
67
- end
80
+ command = %W(reset --hard --quiet)
81
+ run!(command, :chdir => true)
68
82
  end
69
83
 
70
84
  def remote_names
71
- within do
72
- command = "remote"
73
- run!(command, false).strip.lines.map(&:strip)
74
- end
85
+ command = %W(remote)
86
+ run!(command, :chdir => true).strip.lines.map(&:strip)
75
87
  end
76
88
 
77
89
  def remote_branch_names
78
90
  remotes = remote_names.sort_by(&:length).reverse
79
91
 
80
- within do
81
- command = "branch -r"
82
- names = run!(command, false).strip.lines.map(&:strip).to_a
83
- names.each{|n| n.gsub!(/\s*->.*$/, "")}
84
- names.reject!{|n| n =~ /\/HEAD$/}
85
- Hash[remotes.map do |r|
86
- matching_names = names.select{|n| n.start_with?("#{r}/")}
87
- matching_names.each{|n| names.delete(n)}
88
- matching_names.each{|n| n.slice!(0, r.size + 1)}
89
- [r, matching_names]
90
- end]
91
- end
92
+ command = %W(branch -r)
93
+ names = run!(command, :chdir => true).strip.lines.map(&:strip).to_a
94
+ names.each{|n| n.gsub!(/\s*->.*$/, "")}
95
+ names.reject!{|n| n =~ /\/HEAD$/}
96
+ Hash[remotes.map do |r|
97
+ matching_names = names.select{|n| n.start_with?("#{r}/")}
98
+ matching_names.each{|n| names.delete(n)}
99
+ matching_names.each{|n| n.slice!(0, r.size + 1)}
100
+ [r, matching_names]
101
+ end]
92
102
  end
93
103
 
94
104
  def hash_from(remote, reference)
@@ -97,34 +107,45 @@ module Librarian
97
107
  reference = "#{remote}/#{reference}"
98
108
  end
99
109
 
100
- within do
101
- command = "rev-parse #{reference}"
102
- run!(command).strip
103
- end
110
+ command = %W(rev-parse #{reference} --quiet)
111
+ run!(command, :chdir => true).strip
104
112
  end
105
113
 
106
114
  def current_commit_hash
107
- within do
108
- command = "rev-parse HEAD"
109
- run!(command).strip!
110
- end
115
+ command = %W(rev-parse HEAD --quiet)
116
+ run!(command, :chdir => true).strip!
111
117
  end
118
+
112
119
  private
113
120
 
114
- def run!(text, quiet = true)
115
- text = "git #{text}"
116
- text << " --quiet" if quiet
117
- debug { "Running `#{text}` in #{relative_path_to(Dir.pwd)}" }
118
- out = Open3.popen3(text) do |i, o, e, t|
119
- raise StandardError, e.read unless (t ? t.value : $?).success?
120
- o.read
121
+ def bin
122
+ self.class.bin
123
+ end
124
+
125
+ def run!(args, options = { })
126
+ chdir = options.delete(:chdir)
127
+ chdir = path.to_s if chdir == true
128
+
129
+ command = [bin]
130
+ command.concat(args)
131
+
132
+ maybe_within(chdir) do
133
+ debug { "Running `#{command.join(' ')}` in #{relative_path_to(Dir.pwd)}" }
134
+ out = Open3.popen3(*command) do |i, o, e, t|
135
+ raise StandardError, e.read unless (t ? t.value : $?).success?
136
+ o.read
137
+ end
138
+ debug { " -> #{out}" } if out.size > 0
139
+ out
121
140
  end
122
- debug { " -> #{out}" } if out.size > 0
123
- out
124
141
  end
125
142
 
126
- def within
127
- Dir.chdir(path) { yield }
143
+ def maybe_within(path)
144
+ if path
145
+ Dir.chdir(path) { yield }
146
+ else
147
+ yield
148
+ end
128
149
  end
129
150
 
130
151
  end
@@ -1,3 +1,4 @@
1
+ require 'librarian/helpers/debug'
1
2
  require 'librarian/support/abstract_method'
2
3
 
3
4
  module Librarian
@@ -7,27 +8,40 @@ module Librarian
7
8
  # #environment
8
9
  module Local
9
10
 
11
+ include Helpers::Debug
10
12
  include Support::AbstractMethod
11
13
 
12
14
  abstract_method :path
13
15
 
14
- def manifests(dependency)
15
- manifest = manifest_class.create(self, dependency, filesystem_path)
16
+ def manifests(name)
17
+ manifest = Manifest.new(self, name)
16
18
  [manifest].compact
17
19
  end
18
20
 
19
21
  def manifest(name, version, dependencies)
20
- manifest = manifest_class.create(self, Dependency.new(name, nil, nil), filesystem_path)
22
+ manifest = Manifest.new(self, name)
21
23
  manifest.version = version
22
24
  manifest.dependencies = dependencies
23
25
  manifest
24
26
  end
25
27
 
26
- def manifest_search_paths(dependency)
27
- paths = [filesystem_path, filesystem_path.join(dependency.name)]
28
+ def manifest_search_paths(name)
29
+ paths = [filesystem_path, filesystem_path.join(name)]
28
30
  paths.select{|s| s.exist?}
29
31
  end
30
32
 
33
+ def found_path(name)
34
+ @_found_paths ||= { }
35
+ @_found_paths[name] ||= begin
36
+ paths = manifest_search_paths(name)
37
+ paths.find{|p| manifest?(name, p)}
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ abstract_method :manifest? # (name, path) -> boolean
44
+
31
45
  end
32
46
  end
33
47
  end
@@ -7,13 +7,25 @@ module Librarian
7
7
  include Local
8
8
 
9
9
  class << self
10
+
10
11
  LOCK_NAME = 'PATH'
12
+
11
13
  def lock_name
12
14
  LOCK_NAME
13
15
  end
16
+
14
17
  def from_lock_options(environment, options)
15
18
  new(environment, options[:remote], options.reject{|k, v| k == :remote})
16
19
  end
20
+
21
+ def from_spec_args(environment, path, options)
22
+ recognized_options = []
23
+ unrecognized_options = options.keys - recognized_options
24
+ unrecognized_options.empty? or raise Error, "unrecognized options: #{unrecognized_options.join(", ")}"
25
+
26
+ new(environment, path, options)
27
+ end
28
+
17
29
  end
18
30
 
19
31
  attr_accessor :environment
@@ -50,7 +62,7 @@ module Librarian
50
62
  def unpin!
51
63
  end
52
64
 
53
- def cache!(dependencies)
65
+ def cache!(names)
54
66
  end
55
67
 
56
68
  def filesystem_path
@@ -15,7 +15,7 @@ module Librarian
15
15
  end
16
16
 
17
17
  def read(precache_sources = [])
18
- environment.dsl_class.run(environment, path.read, precache_sources)
18
+ environment.dsl(path.read, precache_sources)
19
19
  end
20
20
 
21
21
  end
@@ -1,3 +1,3 @@
1
1
  module Librarian
2
- VERSION = "0.0.20"
2
+ VERSION = "0.0.21"
3
3
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_dependency "thor"
22
+ s.add_dependency "thor", "~> 0.15"
23
23
 
24
24
  s.add_development_dependency "rake"
25
25
  s.add_development_dependency "rspec"
@@ -22,7 +22,6 @@ module Librarian
22
22
 
23
23
  before do
24
24
  action.stub(:clean_install_path)
25
- action.stub(:clean_lockfile_path)
26
25
  end
27
26
 
28
27
  context "when the cache path is missing" do
@@ -51,7 +50,6 @@ module Librarian
51
50
 
52
51
  before do
53
52
  action.stub(:clean_cache_path)
54
- action.stub(:clean_lockfile_path)
55
53
  end
56
54
 
57
55
  context "when the install path is missing" do
@@ -96,35 +94,6 @@ module Librarian
96
94
 
97
95
  end
98
96
 
99
- describe "clearing the lockfile path" do
100
-
101
- before do
102
- action.stub(:clean_cache_path)
103
- action.stub(:clean_install_path)
104
- end
105
-
106
- context "when the lockfile path is missing" do
107
- before do
108
- env.stub_chain(:lockfile_path, :exist?) { false }
109
- end
110
-
111
- it "should not try to clear the lockfile path" do
112
- env.lockfile_path.should_receive(:rmtree).never
113
- end
114
- end
115
-
116
- context "when the lockfile path is present" do
117
- before do
118
- env.stub_chain(:lockfile_path, :exist?) { true }
119
- end
120
-
121
- it "should try to clear the lockfile path" do
122
- env.lockfile_path.should_receive(:rmtree).exactly(:once)
123
- end
124
- end
125
-
126
- end
127
-
128
97
  end
129
98
 
130
99
  end
@@ -63,8 +63,12 @@ module Librarian
63
63
 
64
64
  describe "performing the install" do
65
65
 
66
- let(:manifests) { [mock, mock, mock] }
67
- let(:sorted_manifests) { [mock, mock, mock, mock] }
66
+ def mock_manifest(i)
67
+ double(:name => "manifest-#{i}")
68
+ end
69
+
70
+ let(:manifests) { 3.times.map{|i| mock_manifest(i)} }
71
+ let(:sorted_manifests) { 4.times.map{|i| mock_manifest(i + 3)} }
68
72
  let(:install_path) { mock }
69
73
 
70
74
  before do
@@ -83,7 +87,7 @@ module Librarian
83
87
  sorted_manifests.each do |manifest|
84
88
  source = mock
85
89
  manifest.stub(:source) { source }
86
- source.should_receive(:cache!).with([manifest]).exactly(:once).ordered
90
+ source.should_receive(:cache!).with([manifest.name]).exactly(:once).ordered
87
91
  end
88
92
 
89
93
  install_path.stub(:exist?) { false }
@@ -174,6 +174,20 @@ module Librarian
174
174
 
175
175
  end
176
176
 
177
+ context "validating source options" do
178
+
179
+ it "should raise when given unrecognized optiosn options" do
180
+ expect do
181
+ env.dsl do
182
+ dep 'dependency-1',
183
+ :src => 'source-1',
184
+ :huh => 'yikes'
185
+ end
186
+ end.to raise_error(Error, %{unrecognized options: huh})
187
+ end
188
+
189
+ end
190
+
177
191
  end
178
192
 
179
193
  end