librarian 0.0.20 → 0.0.21

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.
@@ -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