{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Stack.Unpack
  ( unpackPackages
  ) where

import Stack.Prelude
import qualified RIO.Text as T
import qualified RIO.Map as Map
import qualified RIO.Set as Set
import RIO.List (intercalate)
import RIO.Process (HasProcessContext)
import Path ((</>), parseRelDir)
import Path.IO (doesDirExist)

data UnpackException
  = UnpackDirectoryAlreadyExists (Set (Path Abs Dir))
  | CouldNotParsePackageSelectors [String]
    deriving Typeable
instance Exception UnpackException
instance Show UnpackException where
    show :: UnpackException -> String
show (UnpackDirectoryAlreadyExists Set (Path Abs Dir)
dirs) = [String] -> String
unlines
        ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String
"Unable to unpack due to already present directories:"
        String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((String
"    " String -> ShowS
forall a. [a] -> [a] -> [a]
++) ShowS -> (Path Abs Dir -> String) -> Path Abs Dir -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath) (Set (Path Abs Dir) -> [Path Abs Dir]
forall a. Set a -> [a]
Set.toList Set (Path Abs Dir)
dirs)
    show (CouldNotParsePackageSelectors [String]
strs) = [String] -> String
unlines
      ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String
"The following package selectors are not valid package names or identifiers:"
      String -> [String] -> [String]
forall a. a -> [a] -> [a]
: ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
"- " String -> ShowS
forall a. [a] -> [a] -> [a]
++) [String]
strs

-- | Intended to work for the command line command.
unpackPackages
  :: forall env. (HasPantryConfig env, HasLogFunc env, HasProcessContext env)
  => Maybe RawSnapshot -- ^ when looking up by name, take from this build plan
  -> Path Abs Dir -- ^ destination
  -> [String] -- ^ names or identifiers
  -> RIO env ()
unpackPackages :: Maybe RawSnapshot -> Path Abs Dir -> [String] -> RIO env ()
unpackPackages Maybe RawSnapshot
mSnapshot Path Abs Dir
dest [String]
input = do
    let ([String]
errs1, ([PackageName]
names, [PackageIdentifierRevision]
pirs1)) =
          ([Either PackageName PackageIdentifierRevision]
 -> ([PackageName], [PackageIdentifierRevision]))
-> ([String], [Either PackageName PackageIdentifierRevision])
-> ([String], ([PackageName], [PackageIdentifierRevision]))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Either PackageName PackageIdentifierRevision]
-> ([PackageName], [PackageIdentifierRevision])
forall a b. [Either a b] -> ([a], [b])
partitionEithers (([String], [Either PackageName PackageIdentifierRevision])
 -> ([String], ([PackageName], [PackageIdentifierRevision])))
-> ([String], [Either PackageName PackageIdentifierRevision])
-> ([String], ([PackageName], [PackageIdentifierRevision]))
forall a b. (a -> b) -> a -> b
$ [Either String (Either PackageName PackageIdentifierRevision)]
-> ([String], [Either PackageName PackageIdentifierRevision])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either String (Either PackageName PackageIdentifierRevision)]
 -> ([String], [Either PackageName PackageIdentifierRevision]))
-> [Either String (Either PackageName PackageIdentifierRevision)]
-> ([String], [Either PackageName PackageIdentifierRevision])
forall a b. (a -> b) -> a -> b
$ (String
 -> Either String (Either PackageName PackageIdentifierRevision))
-> [String]
-> [Either String (Either PackageName PackageIdentifierRevision)]
forall a b. (a -> b) -> [a] -> [b]
map String
-> Either String (Either PackageName PackageIdentifierRevision)
parse [String]
input
    [(PackageLocationImmutable, PackageIdentifier)]
locs1 <- [PackageIdentifierRevision]
-> (PackageIdentifierRevision
    -> RIO env (PackageLocationImmutable, PackageIdentifier))
-> RIO env [(PackageLocationImmutable, PackageIdentifier)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [PackageIdentifierRevision]
pirs1 ((PackageIdentifierRevision
  -> RIO env (PackageLocationImmutable, PackageIdentifier))
 -> RIO env [(PackageLocationImmutable, PackageIdentifier)])
-> (PackageIdentifierRevision
    -> RIO env (PackageLocationImmutable, PackageIdentifier))
-> RIO env [(PackageLocationImmutable, PackageIdentifier)]
forall a b. (a -> b) -> a -> b
$ \PackageIdentifierRevision
pir -> do
      PackageLocationImmutable
loc <- (CompletePackageLocation -> PackageLocationImmutable)
-> RIO env CompletePackageLocation
-> RIO env PackageLocationImmutable
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CompletePackageLocation -> PackageLocationImmutable
cplComplete (RIO env CompletePackageLocation
 -> RIO env PackageLocationImmutable)
-> RIO env CompletePackageLocation
-> RIO env PackageLocationImmutable
forall a b. (a -> b) -> a -> b
$ RawPackageLocationImmutable -> RIO env CompletePackageLocation
forall env.
(HasPantryConfig env, HasLogFunc env, HasProcessContext env) =>
RawPackageLocationImmutable -> RIO env CompletePackageLocation
completePackageLocation (RawPackageLocationImmutable -> RIO env CompletePackageLocation)
-> RawPackageLocationImmutable -> RIO env CompletePackageLocation
forall a b. (a -> b) -> a -> b
$ PackageIdentifierRevision
-> Maybe TreeKey -> RawPackageLocationImmutable
RPLIHackage PackageIdentifierRevision
pir Maybe TreeKey
forall a. Maybe a
Nothing
      (PackageLocationImmutable, PackageIdentifier)
-> RIO env (PackageLocationImmutable, PackageIdentifier)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PackageLocationImmutable
loc, PackageLocationImmutable -> PackageIdentifier
packageLocationIdent PackageLocationImmutable
loc)
    ([String]
errs2, [(PackageLocationImmutable, PackageIdentifier)]
locs2) <- [Either String (PackageLocationImmutable, PackageIdentifier)]
-> ([String], [(PackageLocationImmutable, PackageIdentifier)])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either String (PackageLocationImmutable, PackageIdentifier)]
 -> ([String], [(PackageLocationImmutable, PackageIdentifier)]))
-> RIO
     env [Either String (PackageLocationImmutable, PackageIdentifier)]
-> RIO
     env ([String], [(PackageLocationImmutable, PackageIdentifier)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (PackageName
 -> RIO
      env (Either String (PackageLocationImmutable, PackageIdentifier)))
-> [PackageName]
-> RIO
     env [Either String (PackageLocationImmutable, PackageIdentifier)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse PackageName
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
toLoc [PackageName]
names
    case [String]
errs1 [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
errs2 of
      [] -> () -> RIO env ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      [String]
errs -> UnpackException -> RIO env ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (UnpackException -> RIO env ()) -> UnpackException -> RIO env ()
forall a b. (a -> b) -> a -> b
$ [String] -> UnpackException
CouldNotParsePackageSelectors [String]
errs
    Map PackageLocationImmutable (Path Abs Dir)
locs <- [(PackageLocationImmutable, Path Abs Dir)]
-> Map PackageLocationImmutable (Path Abs Dir)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(PackageLocationImmutable, Path Abs Dir)]
 -> Map PackageLocationImmutable (Path Abs Dir))
-> RIO env [(PackageLocationImmutable, Path Abs Dir)]
-> RIO env (Map PackageLocationImmutable (Path Abs Dir))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((PackageLocationImmutable, PackageIdentifier)
 -> RIO env (PackageLocationImmutable, Path Abs Dir))
-> [(PackageLocationImmutable, PackageIdentifier)]
-> RIO env [(PackageLocationImmutable, Path Abs Dir)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM
          (\(PackageLocationImmutable
pir, PackageIdentifier
ident) -> do
              Path Rel Dir
suffix <- String -> RIO env (Path Rel Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel Dir)
parseRelDir (String -> RIO env (Path Rel Dir))
-> String -> RIO env (Path Rel Dir)
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> String
packageIdentifierString PackageIdentifier
ident
              (PackageLocationImmutable, Path Abs Dir)
-> RIO env (PackageLocationImmutable, Path Abs Dir)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PackageLocationImmutable
pir, Path Abs Dir
dest Path Abs Dir -> Path Rel Dir -> Path Abs Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
suffix)
          )
          ([(PackageLocationImmutable, PackageIdentifier)]
locs1 [(PackageLocationImmutable, PackageIdentifier)]
-> [(PackageLocationImmutable, PackageIdentifier)]
-> [(PackageLocationImmutable, PackageIdentifier)]
forall a. [a] -> [a] -> [a]
++ [(PackageLocationImmutable, PackageIdentifier)]
locs2)

    [Path Abs Dir]
alreadyUnpacked <- (Path Abs Dir -> RIO env Bool)
-> [Path Abs Dir] -> RIO env [Path Abs Dir]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM Path Abs Dir -> RIO env Bool
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m Bool
doesDirExist ([Path Abs Dir] -> RIO env [Path Abs Dir])
-> [Path Abs Dir] -> RIO env [Path Abs Dir]
forall a b. (a -> b) -> a -> b
$ Map PackageLocationImmutable (Path Abs Dir) -> [Path Abs Dir]
forall k a. Map k a -> [a]
Map.elems Map PackageLocationImmutable (Path Abs Dir)
locs

    Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([Path Abs Dir] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Path Abs Dir]
alreadyUnpacked) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        UnpackException -> RIO env ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (UnpackException -> RIO env ()) -> UnpackException -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Set (Path Abs Dir) -> UnpackException
UnpackDirectoryAlreadyExists (Set (Path Abs Dir) -> UnpackException)
-> Set (Path Abs Dir) -> UnpackException
forall a b. (a -> b) -> a -> b
$ [Path Abs Dir] -> Set (Path Abs Dir)
forall a. Ord a => [a] -> Set a
Set.fromList [Path Abs Dir]
alreadyUnpacked

    [(PackageLocationImmutable, Path Abs Dir)]
-> ((PackageLocationImmutable, Path Abs Dir) -> RIO env ())
-> RIO env ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Map PackageLocationImmutable (Path Abs Dir)
-> [(PackageLocationImmutable, Path Abs Dir)]
forall k a. Map k a -> [(k, a)]
Map.toList Map PackageLocationImmutable (Path Abs Dir)
locs) (((PackageLocationImmutable, Path Abs Dir) -> RIO env ())
 -> RIO env ())
-> ((PackageLocationImmutable, Path Abs Dir) -> RIO env ())
-> RIO env ()
forall a b. (a -> b) -> a -> b
$ \(PackageLocationImmutable
loc, Path Abs Dir
dest') -> do
      Path Abs Dir -> PackageLocationImmutable -> RIO env ()
forall env.
(HasPantryConfig env, HasLogFunc env, HasProcessContext env) =>
Path Abs Dir -> PackageLocationImmutable -> RIO env ()
unpackPackageLocation Path Abs Dir
dest' PackageLocationImmutable
loc
      Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        Utf8Builder
"Unpacked " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        PackageLocationImmutable -> Utf8Builder
forall a. Display a => a -> Utf8Builder
display PackageLocationImmutable
loc Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        Utf8Builder
" to " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
dest')
  where
    toLoc :: PackageName
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
toLoc | Just RawSnapshot
snapshot <- Maybe RawSnapshot
mSnapshot = RawSnapshot
-> PackageName
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
toLocSnapshot RawSnapshot
snapshot
          | Bool
otherwise = PackageName
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
toLocNoSnapshot

    toLocNoSnapshot :: PackageName -> RIO env (Either String (PackageLocationImmutable, PackageIdentifier))
    toLocNoSnapshot :: PackageName
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
toLocNoSnapshot PackageName
name = do
      Maybe PackageLocationImmutable
mloc1 <- RequireHackageIndex
-> PackageName
-> UsePreferredVersions
-> RIO env (Maybe PackageLocationImmutable)
forall env.
(HasPantryConfig env, HasLogFunc env, HasProcessContext env) =>
RequireHackageIndex
-> PackageName
-> UsePreferredVersions
-> RIO env (Maybe PackageLocationImmutable)
getLatestHackageLocation RequireHackageIndex
YesRequireHackageIndex PackageName
name UsePreferredVersions
UsePreferredVersions
      Maybe PackageLocationImmutable
mloc <-
        case Maybe PackageLocationImmutable
mloc1 of
          Just PackageLocationImmutable
_ -> Maybe PackageLocationImmutable
-> RIO env (Maybe PackageLocationImmutable)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe PackageLocationImmutable
mloc1
          Maybe PackageLocationImmutable
Nothing -> do
            DidUpdateOccur
updated <- Maybe Utf8Builder -> RIO env DidUpdateOccur
forall env.
(HasPantryConfig env, HasLogFunc env) =>
Maybe Utf8Builder -> RIO env DidUpdateOccur
updateHackageIndex (Maybe Utf8Builder -> RIO env DidUpdateOccur)
-> Maybe Utf8Builder -> RIO env DidUpdateOccur
forall a b. (a -> b) -> a -> b
$ Utf8Builder -> Maybe Utf8Builder
forall a. a -> Maybe a
Just (Utf8Builder -> Maybe Utf8Builder)
-> Utf8Builder -> Maybe Utf8Builder
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Could not find package " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (PackageName -> String
packageNameString PackageName
name) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
", updating"
            case DidUpdateOccur
updated of
              DidUpdateOccur
UpdateOccurred -> RequireHackageIndex
-> PackageName
-> UsePreferredVersions
-> RIO env (Maybe PackageLocationImmutable)
forall env.
(HasPantryConfig env, HasLogFunc env, HasProcessContext env) =>
RequireHackageIndex
-> PackageName
-> UsePreferredVersions
-> RIO env (Maybe PackageLocationImmutable)
getLatestHackageLocation RequireHackageIndex
YesRequireHackageIndex PackageName
name UsePreferredVersions
UsePreferredVersions
              DidUpdateOccur
NoUpdateOccurred -> Maybe PackageLocationImmutable
-> RIO env (Maybe PackageLocationImmutable)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe PackageLocationImmutable
forall a. Maybe a
Nothing
      case Maybe PackageLocationImmutable
mloc of
        Maybe PackageLocationImmutable
Nothing -> do
          [PackageName]
candidates <- PackageName -> RIO env [PackageName]
forall env.
(HasPantryConfig env, HasLogFunc env) =>
PackageName -> RIO env [PackageName]
getHackageTypoCorrections PackageName
name
          Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String (PackageLocationImmutable, PackageIdentifier)
 -> RIO
      env (Either String (PackageLocationImmutable, PackageIdentifier)))
-> Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall a b. (a -> b) -> a -> b
$ String
-> Either String (PackageLocationImmutable, PackageIdentifier)
forall a b. a -> Either a b
Left (String
 -> Either String (PackageLocationImmutable, PackageIdentifier))
-> String
-> Either String (PackageLocationImmutable, PackageIdentifier)
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
            [ String
"Could not find package "
            , PackageName -> String
packageNameString PackageName
name
            , String
" on Hackage"
            , if [PackageName] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PackageName]
candidates
                then String
""
                else String
". Perhaps you meant: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((PackageName -> String) -> [PackageName] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map PackageName -> String
packageNameString [PackageName]
candidates)
            ]
        Just PackageLocationImmutable
loc -> Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String (PackageLocationImmutable, PackageIdentifier)
 -> RIO
      env (Either String (PackageLocationImmutable, PackageIdentifier)))
-> Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall a b. (a -> b) -> a -> b
$ (PackageLocationImmutable, PackageIdentifier)
-> Either String (PackageLocationImmutable, PackageIdentifier)
forall a b. b -> Either a b
Right (PackageLocationImmutable
loc, PackageLocationImmutable -> PackageIdentifier
packageLocationIdent PackageLocationImmutable
loc)

    toLocSnapshot :: RawSnapshot -> PackageName -> RIO env (Either String (PackageLocationImmutable, PackageIdentifier))
    toLocSnapshot :: RawSnapshot
-> PackageName
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
toLocSnapshot RawSnapshot
snapshot PackageName
name =
        case PackageName
-> Map PackageName RawSnapshotPackage -> Maybe RawSnapshotPackage
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup PackageName
name (RawSnapshot -> Map PackageName RawSnapshotPackage
rsPackages RawSnapshot
snapshot) of
          Maybe RawSnapshotPackage
Nothing ->
            Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String (PackageLocationImmutable, PackageIdentifier)
 -> RIO
      env (Either String (PackageLocationImmutable, PackageIdentifier)))
-> Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall a b. (a -> b) -> a -> b
$ String
-> Either String (PackageLocationImmutable, PackageIdentifier)
forall a b. a -> Either a b
Left (String
 -> Either String (PackageLocationImmutable, PackageIdentifier))
-> String
-> Either String (PackageLocationImmutable, PackageIdentifier)
forall a b. (a -> b) -> a -> b
$ String
"Package does not appear in snapshot: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageName -> String
packageNameString PackageName
name
          Just RawSnapshotPackage
sp -> do
            PackageLocationImmutable
loc <- CompletePackageLocation -> PackageLocationImmutable
cplComplete (CompletePackageLocation -> PackageLocationImmutable)
-> RIO env CompletePackageLocation
-> RIO env PackageLocationImmutable
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RawPackageLocationImmutable -> RIO env CompletePackageLocation
forall env.
(HasPantryConfig env, HasLogFunc env, HasProcessContext env) =>
RawPackageLocationImmutable -> RIO env CompletePackageLocation
completePackageLocation (RawSnapshotPackage -> RawPackageLocationImmutable
rspLocation RawSnapshotPackage
sp)
            Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String (PackageLocationImmutable, PackageIdentifier)
 -> RIO
      env (Either String (PackageLocationImmutable, PackageIdentifier)))
-> Either String (PackageLocationImmutable, PackageIdentifier)
-> RIO
     env (Either String (PackageLocationImmutable, PackageIdentifier))
forall a b. (a -> b) -> a -> b
$ (PackageLocationImmutable, PackageIdentifier)
-> Either String (PackageLocationImmutable, PackageIdentifier)
forall a b. b -> Either a b
Right (PackageLocationImmutable
loc, PackageLocationImmutable -> PackageIdentifier
packageLocationIdent PackageLocationImmutable
loc)

    -- Possible future enhancement: parse names as name + version range
    parse :: String
-> Either String (Either PackageName PackageIdentifierRevision)
parse String
s =
        case String -> Maybe PackageName
parsePackageName (Text -> String
T.unpack Text
t) of
            Just PackageName
x -> Either PackageName PackageIdentifierRevision
-> Either String (Either PackageName PackageIdentifierRevision)
forall a b. b -> Either a b
Right (Either PackageName PackageIdentifierRevision
 -> Either String (Either PackageName PackageIdentifierRevision))
-> Either PackageName PackageIdentifierRevision
-> Either String (Either PackageName PackageIdentifierRevision)
forall a b. (a -> b) -> a -> b
$ PackageName -> Either PackageName PackageIdentifierRevision
forall a b. a -> Either a b
Left PackageName
x
            Maybe PackageName
Nothing ->
                case Text -> Either PantryException PackageIdentifierRevision
parsePackageIdentifierRevision Text
t of
                    Right PackageIdentifierRevision
x -> Either PackageName PackageIdentifierRevision
-> Either String (Either PackageName PackageIdentifierRevision)
forall a b. b -> Either a b
Right (Either PackageName PackageIdentifierRevision
 -> Either String (Either PackageName PackageIdentifierRevision))
-> Either PackageName PackageIdentifierRevision
-> Either String (Either PackageName PackageIdentifierRevision)
forall a b. (a -> b) -> a -> b
$ PackageIdentifierRevision
-> Either PackageName PackageIdentifierRevision
forall a b. b -> Either a b
Right PackageIdentifierRevision
x
                    Left PantryException
_ -> String
-> Either String (Either PackageName PackageIdentifierRevision)
forall a b. a -> Either a b
Left (String
 -> Either String (Either PackageName PackageIdentifierRevision))
-> String
-> Either String (Either PackageName PackageIdentifierRevision)
forall a b. (a -> b) -> a -> b
$ String
"Could not parse as package name or identifier: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s
      where
        t :: Text
t = String -> Text
T.pack String
s