Skip to content

Commit ea53d28

Browse files
authored
Do not constrain (but do warn) the version for local packages (#1391)
1 parent 6aed923 commit ea53d28

File tree

11 files changed

+120
-4
lines changed

11 files changed

+120
-4
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
Bugfixes:
1111
* Preserve TTY properties for child processes in `spago run` (#1341)
1212
* Do not repeatedly request the same log line from the Registry server (#1381)
13+
* Fix solver failing for local packages in `extraPackages` with version constraints (#1338)
14+
- Solver now widens ranges for non-registry extra packages so they are always accepted
15+
- Warns when a local package's `publish.version` doesn't match the declared constraint
1316

1417
## [1.0.3] - 2026-02-01
1518

src/Spago/Command/Fetch.purs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -782,13 +782,21 @@ getTransitiveDeps workspacePackage = do
782782
getTransitiveDepsFromRegistry :: forall a. Map PackageName Range -> PackageMap -> Spago (FetchEnv a) (Map PackageName Version)
783783
getTransitiveDepsFromRegistry depsRanges extraPackages = do
784784
let
785+
-- Widen ranges for non-registry extra packages (local/git/workspace overrides).
786+
widenIfExtra :: Map PackageName Range -> Map PackageName Range
787+
widenIfExtra = mapWithIndex \name range ->
788+
case Map.lookup name extraPackages of
789+
Just (RegistryVersion _) -> range
790+
Just _ -> Config.widestRange
791+
Nothing -> range
792+
785793
loader :: PackageName -> Spago (FetchEnv a) (Map Version (Map PackageName Range))
786794
loader packageName = do
787795
-- First look up in the extra packages, as they are the workspace ones, and overrides
788796
case Map.lookup packageName extraPackages of
789797
Just p -> do
790798
deps <- getPackageDependencies packageName p
791-
let coreDeps = deps <#> _.core # fromMaybe Map.empty
799+
let coreDeps = widenIfExtra $ deps <#> _.core # fromMaybe Map.empty
792800
pure $ Map.singleton (getVersionFromPackage p) coreDeps
793801
Nothing -> do
794802
maybeMetadata <- Registry.getMetadata packageName
@@ -798,10 +806,26 @@ getTransitiveDepsFromRegistry depsRanges extraPackages = do
798806
Left _err -> []
799807
map (Map.fromFoldable :: Array _ -> Map _ _) $ for versions \v -> do
800808
maybeManifest <- Registry.getManifestFromIndex packageName v
801-
let deps = fromMaybe Map.empty $ map (_.dependencies <<< unwrap) maybeManifest
809+
let deps = widenIfExtra $ fromMaybe Map.empty $ map (_.dependencies <<< unwrap) maybeManifest
802810
pure (Tuple v deps)
803811

804-
maybePlan <- Registry.Solver.loadAndSolve loader depsRanges
812+
-- Warn when a non-registry extra package's version doesn't match the declared constraint
813+
for_ (Map.toUnfoldable (Map.intersectionWith Tuple depsRanges extraPackages) :: Array _)
814+
\(Tuple name (Tuple range pkg)) -> case pkg of
815+
RegistryVersion _ -> pure unit
816+
_ -> do
817+
maybeVersion <- extraPackageVersion pkg
818+
case maybeVersion of
819+
Just version | not (Range.includes range version) ->
820+
logWarn $ "Extra package " <> PackageName.print name <> " has version "
821+
<> Version.print version
822+
<> ", which doesn't satisfy constraint "
823+
<> Range.print range
824+
_ -> pure unit
825+
826+
let widenedDepsRanges = widenIfExtra depsRanges
827+
828+
maybePlan <- Registry.Solver.loadAndSolve loader widenedDepsRanges
805829

806830
case maybePlan of
807831
Left errs -> die
@@ -901,6 +925,19 @@ getVersionFromPackage = case _ of
901925
RegistryVersion v -> v
902926
_ -> unsafeFromRight $ Version.parse "0.0.0"
903927

928+
-- | Extract the version from a non-registry package's config if available.
929+
extraPackageVersion :: forall a. Package -> Spago (FetchEnv a) (Maybe Version)
930+
extraPackageVersion = case _ of
931+
RegistryVersion v -> pure $ Just v
932+
WorkspacePackage wp -> pure $ wp.package.publish <#> _.version
933+
LocalPackage p -> do
934+
result <- Config.readConfig (Path.global p.path </> "spago.yaml")
935+
pure $ case result of
936+
Right { yaml: { package: Just { publish: Just { version } } } } -> Just version
937+
_ -> Nothing
938+
-- Git packages would require cloning to read their config, so no version warning is possible.
939+
GitPackage _ -> pure Nothing
940+
904941
notInPackageSetError :: PackageName -> TransitiveDepsResult -> TransitiveDepsResult
905942
notInPackageSetError dep result = result
906943
{ errors { notInPackageSet = Set.insert dep result.errors.notInPackageSet } }
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package:
2+
name: consumer
3+
dependencies:
4+
- local-lib-match: ">=1.0.0 <2.0.0"
5+
- local-lib-mismatch: ">=2.0.0 <3.0.0"
6+
- local-lib-no-version: ">=5.0.0 <6.0.0"
7+
8+
workspace:
9+
extraPackages:
10+
local-lib-match:
11+
path: ../local-lib-match
12+
local-lib-mismatch:
13+
path: ../local-lib-mismatch
14+
local-lib-no-version:
15+
path: ../local-lib-no-version
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module Main where
2+
3+
import LocalLibMatch as Match
4+
import LocalLibMismatch as Mismatch
5+
import LocalLibNoVersion as NoVersion
6+
7+
match :: String
8+
match = Match.hello
9+
10+
mismatch :: String
11+
mismatch = Mismatch.hello
12+
13+
noVersion :: String
14+
noVersion = NoVersion.hello
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package:
2+
name: local-lib-match
3+
dependencies: []
4+
publish:
5+
version: 1.0.0
6+
license: MIT
7+
8+
workspace: {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module LocalLibMatch where
2+
3+
hello :: String
4+
hello = "Hello from local-lib-match"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package:
2+
name: local-lib-mismatch
3+
dependencies: []
4+
publish:
5+
version: 1.0.0
6+
license: MIT
7+
8+
workspace: {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module LocalLibMismatch where
2+
3+
hello :: String
4+
hello = "Hello from local-lib-mismatch"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package:
2+
name: local-lib-no-version
3+
dependencies: []
4+
5+
workspace: {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module LocalLibNoVersion where
2+
3+
hello :: String
4+
hello = "Hello from local-lib-no-version"

0 commit comments

Comments
 (0)