Skip to content

Commit fac08bc

Browse files
authored
Automatic unlock on install and update (#337)
1 parent aca9ce5 commit fac08bc

File tree

5 files changed

+67
-23
lines changed

5 files changed

+67
-23
lines changed

spec/integration/install_spec.cr

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,26 +188,31 @@ describe "install" do
188188
end
189189
end
190190

191-
it "fails to install when dependency requirement changed" do
191+
it "fails to install when dependency requirement changed in production" do
192192
metadata = {dependencies: {web: "2.0.0"}}
193193
lock = {web: "1.0.0"}
194194

195195
with_shard(metadata, lock) do
196-
ex = expect_raises(FailedCommand) { run "shards install --no-color" }
196+
ex = expect_raises(FailedCommand) { run "shards install --no-color --production" }
197197
ex.stdout.should contain("Outdated shard.lock")
198198
ex.stderr.should be_empty
199199
refute_installed "web"
200200
end
201201
end
202202

203-
it "install subdependency of new dependency respecting lock" do
204-
create_git_repository "c"
205-
create_git_release "c", "0.1.0", "name: c\nversion: 0.1.0\ndependencies:\n d:\n git: #{git_path("d")}\n version: 0.1.0\n"
206-
create_git_release "c", "0.2.0", "name: c\nversion: 0.2.0\ndependencies:\n d:\n git: #{git_path("d")}\n version: 0.2.0\n"
207-
create_git_repository "d"
208-
create_git_release "d", "0.1.0", "name: d\nversion: 0.1.0\n"
209-
create_git_release "d", "0.2.0", "name: d\nversion: 0.2.0\n"
203+
it "updates when dependency requirement changed" do
204+
metadata = {dependencies: {web: "2.0.0"}}
205+
lock = {web: "1.0.0"}
210206

207+
with_shard(metadata, lock) do
208+
run "shards install"
209+
210+
assert_installed "web", "2.0.0"
211+
assert_locked "web", "2.0.0"
212+
end
213+
end
214+
215+
it "install subdependency of new dependency respecting lock" do
211216
metadata = {dependencies: {c: "*", d: "*"}}
212217
lock = {d: "0.1.0"}
213218

spec/integration/spec_helper.cr

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ private def setup_repositories
8585
create_git_release "binary", "0.1.0", "name: binary\nversion: 0.1.0\nexecutables:\n - foobar\n - baz\n"
8686
create_file "binary", "bin/foo", "echo 'FOO'", perm: 0o755
8787
create_git_release "binary", "0.2.0", "name: binary\nversion: 0.2.0\nexecutables:\n - foobar\n - baz\n - foo"
88+
89+
create_git_repository "c"
90+
create_git_release "c", "0.1.0", "name: c\nversion: 0.1.0\ndependencies:\n d:\n git: #{git_path("d")}\n version: 0.1.0\n"
91+
create_git_release "c", "0.2.0", "name: c\nversion: 0.2.0\ndependencies:\n d:\n git: #{git_path("d")}\n version: 0.2.0\n"
92+
create_git_repository "d"
93+
create_git_release "d", "0.1.0", "name: d\nversion: 0.1.0\n"
94+
create_git_release "d", "0.2.0", "name: d\nversion: 0.2.0\n"
8895
end
8996

9097
private def assert(value, message, file, line)

spec/integration/update_spec.cr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ describe "update" do
5454
end
5555
end
5656

57+
it "unlocks subdependency" do
58+
metadata = {dependencies: {c: "*"}}
59+
lock = {c: "0.1.0", d: "0.1.0"}
60+
61+
with_shard(metadata, lock) do
62+
run "shards update c"
63+
64+
assert_installed "c", "0.2.0"
65+
assert_installed "d", "0.2.0"
66+
end
67+
end
68+
5769
it "updates specified dependencies" do
5870
metadata = {dependencies: {web: "*", orm: "*", optional: "*"}}
5971
lock = {web: "1.0.0", orm: "0.4.0", optional: "0.2.0"}

src/commands/install.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module Shards
1919
packages = handle_resolver_errors { solver.solve }
2020
return if packages.empty?
2121

22-
if lockfile?
22+
if lockfile? && Shards.production?
2323
validate(packages)
2424
end
2525

@@ -40,14 +40,14 @@ module Shards
4040
else
4141
raise InvalidLock.new # unknown lock resolver
4242
end
43-
elsif Shards.production?
43+
else
4444
raise LockConflict.new("can't install new dependency #{package.name} in production")
4545
end
4646
end
4747
end
4848

4949
private def validate_locked_version(package, version)
50-
return if Shards.production? && package.version == version
50+
return if package.version == version
5151
return if Versions.matches?(version, package.spec.version)
5252
raise LockConflict.new("#{package.name} requirements changed")
5353
end

src/molinillo_solver.cr

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,27 @@ module Shards
1414
def prepare(@development = true)
1515
end
1616

17+
private def add_lock(base, lock_index, name)
18+
if lock = lock_index.delete(name)
19+
resolver = Shards.find_resolver(lock)
20+
21+
if version = lock["version"]?
22+
spec = resolver.spec(version)
23+
elsif commit = lock["commit"]?
24+
spec = resolver.spec(commit)
25+
lock["version"] = "#{spec.version}+git.commit.#{commit}"
26+
else
27+
return
28+
end
29+
30+
base.add_vertex(lock.name, lock, true)
31+
32+
spec.dependencies.each do |dep|
33+
add_lock(base, lock_index, dep.name)
34+
end
35+
end
36+
end
37+
1738
def solve : Array(Package)
1839
deps = if @development
1940
@spec.dependencies + @spec.development_dependencies
@@ -23,18 +44,16 @@ module Shards
2344

2445
base = Molinillo::DependencyGraph(Dependency, Dependency).new
2546
if locks = @locks
26-
locks.each do |lock|
27-
if version = lock["version"]?
28-
dep = deps.find { |d| d.name == lock.name }
29-
next if dep && !Versions.matches?(version, dep.version)
30-
end
47+
lock_index = locks.to_h { |d| {d.name, d} }
48+
49+
deps.each do |dep|
50+
if lock = lock_index[dep.name]?
51+
if version = lock["version"]?
52+
next unless Versions.matches?(version, dep.version)
53+
end
3154

32-
if commit = lock["commit"]?
33-
resolver = Shards.find_resolver(lock)
34-
spec = resolver.spec(commit)
35-
lock["version"] = "#{spec.version}+git.commit.#{commit}"
55+
add_lock(base, lock_index, dep.name)
3656
end
37-
base.add_vertex(lock.name, lock, true)
3857
end
3958
end
4059

@@ -45,6 +64,7 @@ module Shards
4564

4665
packages = [] of Package
4766
result.each do |v|
67+
next unless v.payload
4868
spec = v.payload.as?(Spec) || raise "BUG: returned graph payload was not a Spec"
4969
v.requirements.each do |dependency|
5070
unless dependency.name == spec.name
@@ -140,7 +160,7 @@ module Shards
140160
# to [HEAD], we must resolve the refs to an actual version:
141161
versions_for_refs("HEAD", dependency, resolver)
142162
else
143-
matching
163+
matching.uniq
144164
end
145165
end
146166

0 commit comments

Comments
 (0)