1{-# LANGUAGE OverloadedStrings, Rank2Types #-}
19import Control.Monad (foldM)
20import Control.Concurrent (forkIO, newEmptyMVar, putMVar, readMVar)
21import qualified Data.Map as Map
23import qualified System.Directory as Dir
24import System.FilePath ((</>))
26import qualified Deps.Registry as Registry
27import qualified Deps.Website as Website
28import qualified Elm.Constraint as C
29import qualified Elm.Package as Pkg
30import qualified Elm.Outline as Outline
31import qualified Elm.Version as V
34import qualified Json.Decode as D
35import qualified Reporting.Exit as Exit
48 -> (State -> a -> (State -> IO b) -> IO b)
50 -> (Exit.Solver -> IO b)
57 { _cache :: Stuff.PackageCache
58 , _connection :: Connection
59 , _registry :: Registry.Registry
60 , _constraints :: Map.Map (Pkg.Name, V.Version) Constraints
66 { _elm :: C.Constraint
67 , _deps :: Map.Map Pkg.Name C.Constraint
88-- VERIFY -- used by Elm.Details
92 Details V.Version (Map.Map Pkg.Name C.Constraint)
95verify :: Stuff.PackageCache -> Connection -> Registry.Registry -> Map.Map Pkg.Name C.Constraint -> IO (Result (Map.Map Pkg.Name Details))
96verify cache connection registry constraints =
97 case try constraints of
99 solver (State cache connection registry Map.empty)
100 (\s a _ -> return $ Ok (Map.mapWithKey (addDeps s) a))
101 (\_ -> return $ noSolution connection)
102 (\e -> return $ Err e)
105addDeps :: State -> Pkg.Name -> V.Version -> Details
106addDeps (State _ _ _ constraints) name vsn =
107 case Map.lookup (name, vsn) constraints of
108 Just (Constraints _ deps) -> Details vsn deps
109 Nothing -> error "compiler bug manifesting in Deps.Solver.addDeps"
112noSolution :: Connection -> Result a
113noSolution connection =
115 Online _ -> NoSolution
116 Offline -> NoOfflineSolution
120-- ADD TO APP - used in Install
125 { _old :: Map.Map Pkg.Name V.Version
126 , _new :: Map.Map Pkg.Name V.Version
127 , _app :: Outline.AppOutline
131addToApp :: Stuff.PackageCache -> Connection -> Registry.Registry -> Pkg.Name -> Outline.AppOutline -> IO (Result AppSolution)
132addToApp cache connection registry pkg outline@(Outline.AppOutline _ _ direct indirect testDirect testIndirect) =
134 allIndirects = Map.union indirect testIndirect
135 allDirects = Map.union direct testDirect
136 allDeps = Map.union allDirects allIndirects
138 attempt toConstraint deps =
139 try (Map.insert pkg C.anything (Map.map toConstraint deps))
143 ( attempt C.exactly allDeps )
144 [ attempt C.exactly allDirects
145 , attempt C.untilNextMinor allDirects
146 , attempt C.untilNextMajor allDirects
147 , attempt (\_ -> C.anything) allDirects
151 solver (State cache connection registry Map.empty)
152 (\s a _ -> return $ Ok (toApp s pkg outline allDeps a))
153 (\_ -> return $ noSolution connection)
154 (\e -> return $ Err e)
157toApp :: State -> Pkg.Name -> Outline.AppOutline -> Map.Map Pkg.Name V.Version -> Map.Map Pkg.Name V.Version -> AppSolution
158toApp (State _ _ _ constraints) pkg (Outline.AppOutline elm srcDirs direct _ testDirect _) old new =
160 d = Map.intersection new (Map.insert pkg V.one direct)
161 i = Map.difference (getTransitive constraints new (Map.toList d) Map.empty) d
162 td = Map.intersection new (Map.delete pkg testDirect)
163 ti = Map.difference new (Map.unions [d,i,td])
165 AppSolution old new (Outline.AppOutline elm srcDirs d i td ti)
168getTransitive :: Map.Map (Pkg.Name, V.Version) Constraints -> Map.Map Pkg.Name V.Version -> [(Pkg.Name,V.Version)] -> Map.Map Pkg.Name V.Version -> Map.Map Pkg.Name V.Version
169getTransitive constraints solution unvisited visited =
174 info@(pkg,vsn) : infos ->
175 if Map.member pkg visited
176 then getTransitive constraints solution infos visited
179 newDeps = _deps (constraints ! info)
180 newUnvisited = Map.toList (Map.intersection solution (Map.difference newDeps visited))
181 newVisited = Map.insert pkg vsn visited
183 getTransitive constraints solution infos $
184 getTransitive constraints solution newUnvisited newVisited
191try :: Map.Map Pkg.Name C.Constraint -> Solver (Map.Map Pkg.Name V.Version)
193 exploreGoals (Goals constraints Map.empty)
202 { _pending :: Map.Map Pkg.Name C.Constraint
203 , _solved :: Map.Map Pkg.Name V.Version
207exploreGoals :: Goals -> Solver (Map.Map Pkg.Name V.Version)
208exploreGoals (Goals pending solved) =
209 case Map.minViewWithKey pending of
213 Just ((name, constraint), otherPending) ->
214 do let goals1 = Goals otherPending solved
215 let addVsn = addVersion goals1 name
216 (v,vs) <- getRelevantVersions name constraint
217 goals2 <- oneOf (addVsn v) (map addVsn vs)
221addVersion :: Goals -> Pkg.Name -> V.Version -> Solver Goals
222addVersion (Goals pending solved) name version =
223 do (Constraints elm deps) <- getConstraints name version
226 do newPending <- foldM (addConstraint solved) pending (Map.toList deps)
227 return (Goals newPending (Map.insert name version solved))
232addConstraint :: Map.Map Pkg.Name V.Version -> Map.Map Pkg.Name C.Constraint -> (Pkg.Name, C.Constraint) -> Solver (Map.Map Pkg.Name C.Constraint)
233addConstraint solved unsolved (name, newConstraint) =
234 case Map.lookup name solved of
236 if C.satisfies newConstraint version
241 case Map.lookup name unsolved of
243 return $ Map.insert name newConstraint unsolved
245 Just oldConstraint ->
246 case C.intersect oldConstraint newConstraint of
250 Just mergedConstraint ->
251 if oldConstraint == mergedConstraint
253 else return (Map.insert name mergedConstraint unsolved)
257-- GET RELEVANT VERSIONS
260getRelevantVersions :: Pkg.Name -> C.Constraint -> Solver (V.Version, [V.Version])
261getRelevantVersions name constraint =
262 Solver $ \state@(State _ _ registry _) ok back _ ->
263 case Registry.getVersions name registry of
264 Just (Registry.KnownVersions newest previous) ->
265 case filter (C.satisfies constraint) (newest:previous) of
267 v:vs -> ok state (v,vs) back
277getConstraints :: Pkg.Name -> V.Version -> Solver Constraints
278getConstraints pkg vsn =
279 Solver $ \state@(State cache connection registry cDict) ok back err ->
280 do let key = (pkg, vsn)
281 case Map.lookup key cDict of
286 do let toNewState cs = State cache connection registry (Map.insert key cs cDict)
287 let home = Stuff.package cache pkg vsn
288 let path = home </> "elm.json"
289 outlineExists <- File.exists path
292 do bytes <- File.readUtf8 path
293 case D.fromByteString constraintsDecoder bytes of
297 ok (toNewState cs) cs back
300 do srcExists <- Dir.doesDirectoryExist (Stuff.package cache pkg vsn </> "src")
302 then ok (toNewState cs) cs back
307 err (Exit.SolverBadCacheData pkg vsn)
314 do result <- Http.get manager (Website.metadata pkg vsn "elm.json") [] id (return . Right)
317 err (Exit.SolverBadHttp httpProblem)
320 case D.fromByteString constraintsDecoder body of
322 do Dir.createDirectoryIfMissing True home
323 File.writeUtf8 path body
324 ok (toNewState cs) cs back
327 err (Exit.SolverBadHttpData pkg vsn)
330-- TODO write constraintsDecoder to be a bit faster
332constraintsDecoder :: D.Decoder () Constraints
334 do outline <- D.mapError (const ()) Outline.decoder
336 Outline.Pkg (Outline.PkgOutline _ _ _ _ _ deps _ elmConstraint) ->
337 return (Constraints elmConstraint deps)
348 Env Stuff.PackageCache Http.Manager Connection Registry.Registry
351initEnv :: IO (Either Exit.RegistryProblem Env)
353 do mvar <- newEmptyMVar
354 _ <- forkIO $ putMVar mvar =<< Http.getManager
355 cache <- Stuff.getPackageCache
356 maybeRegistry <- Registry.read cache
357 manager <- readMVar mvar
359 case maybeRegistry of
361 do eitherRegistry <- Registry.fetch manager cache
362 case eitherRegistry of
363 Right latestRegistry ->
364 return $ Right $ Env cache manager (Online manager) latestRegistry
367 return $ Left $ problem
369 Just cachedRegistry ->
370 do eitherRegistry <- Registry.update manager cache cachedRegistry
371 case eitherRegistry of
372 Right latestRegistry ->
373 return $ Right $ Env cache manager (Online manager) latestRegistry
376 return $ Right $ Env cache manager Offline cachedRegistry
383instance Functor Solver where
384 fmap func (Solver solver) =
385 Solver $ \state ok back err ->
387 okA stateA arg backA = ok stateA (func arg) backA
389 solver state okA back err
392instance Applicative Solver where
394 Solver $ \state ok back _ -> ok state a back
396 (<*>) (Solver solverFunc) (Solver solverArg) =
397 Solver $ \state ok back err ->
399 okF stateF func backF =
401 okA stateA arg backA = ok stateA (func arg) backA
403 solverArg stateF okA backF err
405 solverFunc state okF back err
408instance Monad Solver where
410 Solver $ \state ok back _ -> ok state a back
412 (>>=) (Solver solverA) callback =
413 Solver $ \state ok back err ->
417 Solver solverB -> solverB stateA ok backA err
419 solverA state okA back err
422oneOf :: Solver a -> [Solver a] -> Solver a
423oneOf solver@(Solver solverHead) solvers =
429 Solver $ \state0 ok back err ->
433 (Solver solverTail) = oneOf s ss
435 solverTail state1 ok back err
437 solverHead state0 ok tryTail err
442 Solver $ \state _ back _ -> back state
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list