packages feed

cabal-cache 1.0.0.1 → 1.0.0.2

raw patch · 48 files changed

+1292/−944 lines, 48 filesdep +antiope-optparse-applicativedep +http-clientdep +stmdep ~antiope-coredep ~antiope-s3PVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: antiope-optparse-applicative, http-client, stm

Dependency ranges changed: antiope-core, antiope-s3

API changes (from Hackage documentation)

- HaskellWorks.Ci.Assist.Core: Absent :: Presence
- HaskellWorks.Ci.Assist.Core: PackageInfo :: CompilerId -> PackageId -> PackageDir -> Tagged ConfPath Presence -> [Library] -> PackageInfo
- HaskellWorks.Ci.Assist.Core: Present :: Presence
- HaskellWorks.Ci.Assist.Core: Tagged :: a -> t -> Tagged a t
- HaskellWorks.Ci.Assist.Core: [$sel:compilerId:PackageInfo] :: PackageInfo -> CompilerId
- HaskellWorks.Ci.Assist.Core: [$sel:confPath:PackageInfo] :: PackageInfo -> Tagged ConfPath Presence
- HaskellWorks.Ci.Assist.Core: [$sel:libs:PackageInfo] :: PackageInfo -> [Library]
- HaskellWorks.Ci.Assist.Core: [$sel:packageDir:PackageInfo] :: PackageInfo -> PackageDir
- HaskellWorks.Ci.Assist.Core: [$sel:packageId:PackageInfo] :: PackageInfo -> PackageId
- HaskellWorks.Ci.Assist.Core: [$sel:tag:Tagged] :: Tagged a t -> t
- HaskellWorks.Ci.Assist.Core: [$sel:value:Tagged] :: Tagged a t -> a
- HaskellWorks.Ci.Assist.Core: data PackageInfo
- HaskellWorks.Ci.Assist.Core: data Presence
- HaskellWorks.Ci.Assist.Core: data Tagged a t
- HaskellWorks.Ci.Assist.Core: getPackages :: FilePath -> PlanJson -> IO [PackageInfo]
- HaskellWorks.Ci.Assist.Core: instance (Control.DeepSeq.NFData a, Control.DeepSeq.NFData t) => Control.DeepSeq.NFData (HaskellWorks.Ci.Assist.Core.Tagged a t)
- HaskellWorks.Ci.Assist.Core: instance (GHC.Classes.Eq a, GHC.Classes.Eq t) => GHC.Classes.Eq (HaskellWorks.Ci.Assist.Core.Tagged a t)
- HaskellWorks.Ci.Assist.Core: instance (GHC.Show.Show a, GHC.Show.Show t) => GHC.Show.Show (HaskellWorks.Ci.Assist.Core.Tagged a t)
- HaskellWorks.Ci.Assist.Core: instance Control.DeepSeq.NFData HaskellWorks.Ci.Assist.Core.PackageInfo
- HaskellWorks.Ci.Assist.Core: instance Control.DeepSeq.NFData HaskellWorks.Ci.Assist.Core.Presence
- HaskellWorks.Ci.Assist.Core: instance GHC.Classes.Eq HaskellWorks.Ci.Assist.Core.PackageInfo
- HaskellWorks.Ci.Assist.Core: instance GHC.Classes.Eq HaskellWorks.Ci.Assist.Core.Presence
- HaskellWorks.Ci.Assist.Core: instance GHC.Generics.Generic (HaskellWorks.Ci.Assist.Core.Tagged a t)
- HaskellWorks.Ci.Assist.Core: instance GHC.Generics.Generic HaskellWorks.Ci.Assist.Core.PackageInfo
- HaskellWorks.Ci.Assist.Core: instance GHC.Generics.Generic HaskellWorks.Ci.Assist.Core.Presence
- HaskellWorks.Ci.Assist.Core: instance GHC.Show.Show HaskellWorks.Ci.Assist.Core.PackageInfo
- HaskellWorks.Ci.Assist.Core: instance GHC.Show.Show HaskellWorks.Ci.Assist.Core.Presence
- HaskellWorks.Ci.Assist.Core: loadPlan :: IO (Either String PlanJson)
- HaskellWorks.Ci.Assist.Core: relativePaths :: FilePath -> PackageInfo -> [TarGroup]
- HaskellWorks.Ci.Assist.GhcPkg: init :: FilePath -> IO ()
- HaskellWorks.Ci.Assist.GhcPkg: recache :: FilePath -> IO ()
- HaskellWorks.Ci.Assist.GhcPkg: runGhcPkg :: [String] -> IO ()
- HaskellWorks.Ci.Assist.GhcPkg: testAvailability :: IO ()
- HaskellWorks.Ci.Assist.Hash: hashStorePath :: String -> String
- HaskellWorks.Ci.Assist.IO.Console: hPrint :: (MonadIO m, Show a) => Handle -> a -> m ()
- HaskellWorks.Ci.Assist.IO.Console: hPutStrLn :: MonadIO m => Handle -> Text -> m ()
- HaskellWorks.Ci.Assist.IO.Console: print :: (MonadIO m, Show a) => a -> m ()
- HaskellWorks.Ci.Assist.IO.Console: putStrLn :: MonadIO m => Text -> m ()
- HaskellWorks.Ci.Assist.IO.Error: exceptFatal :: MonadIO m => ExceptT String m a -> ExceptT String m a
- HaskellWorks.Ci.Assist.IO.Error: exceptWarn :: MonadIO m => ExceptT String m a -> ExceptT String m a
- HaskellWorks.Ci.Assist.IO.Error: maybeToExcept :: Monad m => String -> Maybe a -> ExceptT String m a
- HaskellWorks.Ci.Assist.IO.Error: maybeToExceptM :: Monad m => String -> m (Maybe a) -> ExceptT String m a
- HaskellWorks.Ci.Assist.IO.File: copyDirectoryRecursive :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()
- HaskellWorks.Ci.Assist.IO.File: listMaybeDirectory :: MonadIO m => FilePath -> ExceptT String m [FilePath]
- HaskellWorks.Ci.Assist.IO.Lazy: createLocalDirectoryIfMissing :: (MonadCatch m, MonadIO m) => Location -> m ()
- HaskellWorks.Ci.Assist.IO.Lazy: firstExistingResource :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => Env -> [Location] -> m (Maybe Location)
- HaskellWorks.Ci.Assist.IO.Lazy: headS3Uri :: (MonadResource m, MonadCatch m) => Env -> S3Uri -> m (Either String HeadObjectResponse)
- HaskellWorks.Ci.Assist.IO.Lazy: linkOrCopyResource :: MonadUnliftIO m => Env -> Location -> Location -> ExceptT String m ()
- HaskellWorks.Ci.Assist.IO.Lazy: readResource :: MonadResource m => Env -> Location -> m (Maybe ByteString)
- HaskellWorks.Ci.Assist.IO.Lazy: resourceExists :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => Env -> Location -> m Bool
- HaskellWorks.Ci.Assist.IO.Lazy: writeResource :: MonadUnliftIO m => Env -> Location -> ByteString -> m ()
- HaskellWorks.Ci.Assist.IO.Tar: TarGroup :: FilePath -> [FilePath] -> TarGroup
- HaskellWorks.Ci.Assist.IO.Tar: [basePath] :: TarGroup -> FilePath
- HaskellWorks.Ci.Assist.IO.Tar: [entryPaths] :: TarGroup -> [FilePath]
- HaskellWorks.Ci.Assist.IO.Tar: createTar :: MonadIO m => FilePath -> [TarGroup] -> ExceptT String m ()
- HaskellWorks.Ci.Assist.IO.Tar: data TarGroup
- HaskellWorks.Ci.Assist.IO.Tar: extractTar :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()
- HaskellWorks.Ci.Assist.IO.Tar: instance Control.DeepSeq.NFData HaskellWorks.Ci.Assist.IO.Tar.TarGroup
- HaskellWorks.Ci.Assist.IO.Tar: instance GHC.Classes.Eq HaskellWorks.Ci.Assist.IO.Tar.TarGroup
- HaskellWorks.Ci.Assist.IO.Tar: instance GHC.Generics.Generic HaskellWorks.Ci.Assist.IO.Tar.TarGroup
- HaskellWorks.Ci.Assist.IO.Tar: instance GHC.Show.Show HaskellWorks.Ci.Assist.IO.Tar.TarGroup
- HaskellWorks.Ci.Assist.Location: (<.>) :: IsPath a s => a -> s -> a
- HaskellWorks.Ci.Assist.Location: (</>) :: IsPath a s => a -> s -> a
- HaskellWorks.Ci.Assist.Location: Local :: FilePath -> Location
- HaskellWorks.Ci.Assist.Location: S3 :: S3Uri -> Location
- HaskellWorks.Ci.Assist.Location: class IsPath a s | a -> s
- HaskellWorks.Ci.Assist.Location: data Location
- HaskellWorks.Ci.Assist.Location: infixr 5 </>
- HaskellWorks.Ci.Assist.Location: infixr 7 <.>
- HaskellWorks.Ci.Assist.Location: instance (a Data.Type.Equality.~ GHC.Types.Char) => HaskellWorks.Ci.Assist.Location.IsPath [a] [a]
- HaskellWorks.Ci.Assist.Location: instance GHC.Classes.Eq HaskellWorks.Ci.Assist.Location.Location
- HaskellWorks.Ci.Assist.Location: instance GHC.Generics.Generic HaskellWorks.Ci.Assist.Location.Location
- HaskellWorks.Ci.Assist.Location: instance GHC.Show.Show HaskellWorks.Ci.Assist.Location.Location
- HaskellWorks.Ci.Assist.Location: instance HaskellWorks.Ci.Assist.Location.IsPath Antiope.S3.Types.S3Uri Data.Text.Internal.Text
- HaskellWorks.Ci.Assist.Location: instance HaskellWorks.Ci.Assist.Location.IsPath Data.Text.Internal.Text Data.Text.Internal.Text
- HaskellWorks.Ci.Assist.Location: instance HaskellWorks.Ci.Assist.Location.IsPath HaskellWorks.Ci.Assist.Location.Location Data.Text.Internal.Text
- HaskellWorks.Ci.Assist.Location: instance Network.AWS.Data.Text.ToText HaskellWorks.Ci.Assist.Location.Location
- HaskellWorks.Ci.Assist.Location: toLocation :: Text -> Maybe Location
- HaskellWorks.Ci.Assist.Metadata: createMetadata :: MonadIO m => FilePath -> PackageInfo -> [(Text, ByteString)] -> m TarGroup
- HaskellWorks.Ci.Assist.Metadata: deleteMetadata :: MonadIO m => FilePath -> m ()
- HaskellWorks.Ci.Assist.Metadata: loadMetadata :: MonadIO m => FilePath -> m (Map Text ByteString)
- HaskellWorks.Ci.Assist.Metadata: metaDir :: String
- HaskellWorks.Ci.Assist.Options: readOrFromTextOption :: (Read a, FromText a) => Mod OptionFields a -> Parser a
- HaskellWorks.Ci.Assist.Show: tshow :: Show a => a -> Text
- HaskellWorks.Ci.Assist.Text: maybeStripPrefix :: Text -> Text -> Text
- HaskellWorks.Ci.Assist.Types: Package :: Text -> Text -> Text -> Text -> Maybe Text -> Maybe Text -> Package
- HaskellWorks.Ci.Assist.Types: PlanJson :: Text -> [Package] -> PlanJson
- HaskellWorks.Ci.Assist.Types: [$sel:compilerId:PlanJson] :: PlanJson -> Text
- HaskellWorks.Ci.Assist.Types: [$sel:componentName:Package] :: Package -> Maybe Text
- HaskellWorks.Ci.Assist.Types: [$sel:id:Package] :: Package -> Text
- HaskellWorks.Ci.Assist.Types: [$sel:installPlan:PlanJson] :: PlanJson -> [Package]
- HaskellWorks.Ci.Assist.Types: [$sel:name:Package] :: Package -> Text
- HaskellWorks.Ci.Assist.Types: [$sel:packageType:Package] :: Package -> Text
- HaskellWorks.Ci.Assist.Types: [$sel:style:Package] :: Package -> Maybe Text
- HaskellWorks.Ci.Assist.Types: [$sel:version:Package] :: Package -> Text
- HaskellWorks.Ci.Assist.Types: data Package
- HaskellWorks.Ci.Assist.Types: data PlanJson
- HaskellWorks.Ci.Assist.Types: instance Data.Aeson.Types.FromJSON.FromJSON HaskellWorks.Ci.Assist.Types.Package
- HaskellWorks.Ci.Assist.Types: instance Data.Aeson.Types.FromJSON.FromJSON HaskellWorks.Ci.Assist.Types.PlanJson
- HaskellWorks.Ci.Assist.Types: instance GHC.Classes.Eq HaskellWorks.Ci.Assist.Types.Package
- HaskellWorks.Ci.Assist.Types: instance GHC.Classes.Eq HaskellWorks.Ci.Assist.Types.PlanJson
- HaskellWorks.Ci.Assist.Types: instance GHC.Generics.Generic HaskellWorks.Ci.Assist.Types.Package
- HaskellWorks.Ci.Assist.Types: instance GHC.Generics.Generic HaskellWorks.Ci.Assist.Types.PlanJson
- HaskellWorks.Ci.Assist.Types: instance GHC.Show.Show HaskellWorks.Ci.Assist.Types.Package
- HaskellWorks.Ci.Assist.Types: instance GHC.Show.Show HaskellWorks.Ci.Assist.Types.PlanJson
- HaskellWorks.Ci.Assist.Version: archiveVersion :: IsString s => s
+ App.Commands.Options.Types: [$sel:awsLogLevel:SyncFromArchiveOptions] :: SyncFromArchiveOptions -> Maybe LogLevel
+ App.Commands.Options.Types: [$sel:awsLogLevel:SyncToArchiveOptions] :: SyncToArchiveOptions -> Maybe LogLevel
+ HaskellWorks.CabalCache.AWS.Env: awsLogger :: Maybe LogLevel -> LogLevel -> ByteString -> IO ()
+ HaskellWorks.CabalCache.Concurrent.DownloadQueue: anchor :: PackageId -> Map ConsumerId ProviderId -> Map ConsumerId ProviderId
+ HaskellWorks.CabalCache.Concurrent.DownloadQueue: createDownloadQueue :: [(ProviderId, ConsumerId)] -> STM DownloadQueue
+ HaskellWorks.CabalCache.Concurrent.Type: DownloadQueue :: TVar (Relation ConsumerId ProviderId) -> TVar (Set PackageId) -> DownloadQueue
+ HaskellWorks.CabalCache.Concurrent.Type: [$sel:tDependencies:DownloadQueue] :: DownloadQueue -> TVar (Relation ConsumerId ProviderId)
+ HaskellWorks.CabalCache.Concurrent.Type: [$sel:tUploading:DownloadQueue] :: DownloadQueue -> TVar (Set PackageId)
+ HaskellWorks.CabalCache.Concurrent.Type: data DownloadQueue
+ HaskellWorks.CabalCache.Concurrent.Type: instance GHC.Generics.Generic HaskellWorks.CabalCache.Concurrent.Type.DownloadQueue
+ HaskellWorks.CabalCache.Concurrent.Type: type ConsumerId = PackageId
+ HaskellWorks.CabalCache.Concurrent.Type: type PackageId = Text
+ HaskellWorks.CabalCache.Concurrent.Type: type ProviderId = PackageId
+ HaskellWorks.CabalCache.Core: Absent :: Presence
+ HaskellWorks.CabalCache.Core: PackageInfo :: CompilerId -> PackageId -> PackageDir -> Tagged ConfPath Presence -> [Library] -> PackageInfo
+ HaskellWorks.CabalCache.Core: Present :: Presence
+ HaskellWorks.CabalCache.Core: Tagged :: a -> t -> Tagged a t
+ HaskellWorks.CabalCache.Core: [$sel:compilerId:PackageInfo] :: PackageInfo -> CompilerId
+ HaskellWorks.CabalCache.Core: [$sel:confPath:PackageInfo] :: PackageInfo -> Tagged ConfPath Presence
+ HaskellWorks.CabalCache.Core: [$sel:libs:PackageInfo] :: PackageInfo -> [Library]
+ HaskellWorks.CabalCache.Core: [$sel:packageDir:PackageInfo] :: PackageInfo -> PackageDir
+ HaskellWorks.CabalCache.Core: [$sel:packageId:PackageInfo] :: PackageInfo -> PackageId
+ HaskellWorks.CabalCache.Core: [$sel:tag:Tagged] :: Tagged a t -> t
+ HaskellWorks.CabalCache.Core: [$sel:value:Tagged] :: Tagged a t -> a
+ HaskellWorks.CabalCache.Core: data PackageInfo
+ HaskellWorks.CabalCache.Core: data Presence
+ HaskellWorks.CabalCache.Core: data Tagged a t
+ HaskellWorks.CabalCache.Core: getPackages :: FilePath -> PlanJson -> IO [PackageInfo]
+ HaskellWorks.CabalCache.Core: instance (Control.DeepSeq.NFData a, Control.DeepSeq.NFData t) => Control.DeepSeq.NFData (HaskellWorks.CabalCache.Core.Tagged a t)
+ HaskellWorks.CabalCache.Core: instance (GHC.Classes.Eq a, GHC.Classes.Eq t) => GHC.Classes.Eq (HaskellWorks.CabalCache.Core.Tagged a t)
+ HaskellWorks.CabalCache.Core: instance (GHC.Show.Show a, GHC.Show.Show t) => GHC.Show.Show (HaskellWorks.CabalCache.Core.Tagged a t)
+ HaskellWorks.CabalCache.Core: instance Control.DeepSeq.NFData HaskellWorks.CabalCache.Core.PackageInfo
+ HaskellWorks.CabalCache.Core: instance Control.DeepSeq.NFData HaskellWorks.CabalCache.Core.Presence
+ HaskellWorks.CabalCache.Core: instance GHC.Classes.Eq HaskellWorks.CabalCache.Core.PackageInfo
+ HaskellWorks.CabalCache.Core: instance GHC.Classes.Eq HaskellWorks.CabalCache.Core.Presence
+ HaskellWorks.CabalCache.Core: instance GHC.Generics.Generic (HaskellWorks.CabalCache.Core.Tagged a t)
+ HaskellWorks.CabalCache.Core: instance GHC.Generics.Generic HaskellWorks.CabalCache.Core.PackageInfo
+ HaskellWorks.CabalCache.Core: instance GHC.Generics.Generic HaskellWorks.CabalCache.Core.Presence
+ HaskellWorks.CabalCache.Core: instance GHC.Show.Show HaskellWorks.CabalCache.Core.PackageInfo
+ HaskellWorks.CabalCache.Core: instance GHC.Show.Show HaskellWorks.CabalCache.Core.Presence
+ HaskellWorks.CabalCache.Core: loadPlan :: IO (Either String PlanJson)
+ HaskellWorks.CabalCache.Core: relativePaths :: FilePath -> PackageInfo -> [TarGroup]
+ HaskellWorks.CabalCache.Data.Relation: Relation :: Map a (Set b) -> Map b (Set a) -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: data Relation a b
+ HaskellWorks.CabalCache.Data.Relation: delete :: (Ord a, Ord b) => a -> b -> Relation a b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: domain :: Relation a b -> Set a
+ HaskellWorks.CabalCache.Data.Relation: empty :: Relation a b
+ HaskellWorks.CabalCache.Data.Relation: fromList :: (Ord a, Ord b) => [(a, b)] -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: insert :: (Ord a, Ord b) => a -> b -> Relation a b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: null :: Relation a b -> Bool
+ HaskellWorks.CabalCache.Data.Relation: range :: Relation a b -> Set b
+ HaskellWorks.CabalCache.Data.Relation: restrictDomain :: (Ord a, Ord b) => Set a -> Relation a b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: restrictRange :: (Ord a, Ord b) => Set b -> Relation a b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: singleton :: a -> b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: toList :: Relation a b -> [(a, b)]
+ HaskellWorks.CabalCache.Data.Relation: withoutDomain :: (Ord a, Ord b) => Set a -> Relation a b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation: withoutRange :: (Ord a, Ord b) => Set b -> Relation a b -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation.Type: Relation :: Map a (Set b) -> Map b (Set a) -> Relation a b
+ HaskellWorks.CabalCache.Data.Relation.Type: [domain] :: Relation a b -> Map a (Set b)
+ HaskellWorks.CabalCache.Data.Relation.Type: [range] :: Relation a b -> Map b (Set a)
+ HaskellWorks.CabalCache.Data.Relation.Type: data Relation a b
+ HaskellWorks.CabalCache.Data.Relation.Type: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (HaskellWorks.CabalCache.Data.Relation.Type.Relation a b)
+ HaskellWorks.CabalCache.Data.Relation.Type: instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (HaskellWorks.CabalCache.Data.Relation.Type.Relation a b)
+ HaskellWorks.CabalCache.Data.Relation.Type: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (HaskellWorks.CabalCache.Data.Relation.Type.Relation a b)
+ HaskellWorks.CabalCache.Data.Relation.Type: instance GHC.Generics.Generic (HaskellWorks.CabalCache.Data.Relation.Type.Relation a b)
+ HaskellWorks.CabalCache.GhcPkg: init :: FilePath -> IO ()
+ HaskellWorks.CabalCache.GhcPkg: recache :: FilePath -> IO ()
+ HaskellWorks.CabalCache.GhcPkg: runGhcPkg :: [String] -> IO ()
+ HaskellWorks.CabalCache.GhcPkg: testAvailability :: IO ()
+ HaskellWorks.CabalCache.Hash: hashStorePath :: String -> String
+ HaskellWorks.CabalCache.IO.Console: hPrint :: (MonadIO m, Show a) => Handle -> a -> m ()
+ HaskellWorks.CabalCache.IO.Console: hPutStrLn :: MonadIO m => Handle -> Text -> m ()
+ HaskellWorks.CabalCache.IO.Console: print :: (MonadIO m, Show a) => a -> m ()
+ HaskellWorks.CabalCache.IO.Console: putStrLn :: MonadIO m => Text -> m ()
+ HaskellWorks.CabalCache.IO.Error: exceptFatal :: MonadIO m => ExceptT String m a -> ExceptT String m a
+ HaskellWorks.CabalCache.IO.Error: exceptWarn :: MonadIO m => ExceptT String m a -> ExceptT String m a
+ HaskellWorks.CabalCache.IO.Error: maybeToExcept :: Monad m => String -> Maybe a -> ExceptT String m a
+ HaskellWorks.CabalCache.IO.Error: maybeToExceptM :: Monad m => String -> m (Maybe a) -> ExceptT String m a
+ HaskellWorks.CabalCache.IO.File: copyDirectoryRecursive :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()
+ HaskellWorks.CabalCache.IO.File: listMaybeDirectory :: MonadIO m => FilePath -> ExceptT String m [FilePath]
+ HaskellWorks.CabalCache.IO.Lazy: createLocalDirectoryIfMissing :: (MonadCatch m, MonadIO m) => Location -> m ()
+ HaskellWorks.CabalCache.IO.Lazy: firstExistingResource :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => Env -> [Location] -> m (Maybe Location)
+ HaskellWorks.CabalCache.IO.Lazy: headS3Uri :: (MonadResource m, MonadCatch m) => Env -> S3Uri -> m (Either String HeadObjectResponse)
+ HaskellWorks.CabalCache.IO.Lazy: linkOrCopyResource :: MonadUnliftIO m => Env -> Location -> Location -> ExceptT String m ()
+ HaskellWorks.CabalCache.IO.Lazy: readResource :: MonadResource m => Env -> Location -> m (Maybe ByteString)
+ HaskellWorks.CabalCache.IO.Lazy: resourceExists :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => Env -> Location -> m Bool
+ HaskellWorks.CabalCache.IO.Lazy: writeResource :: MonadUnliftIO m => Env -> Location -> ByteString -> m ()
+ HaskellWorks.CabalCache.IO.Tar: TarGroup :: FilePath -> [FilePath] -> TarGroup
+ HaskellWorks.CabalCache.IO.Tar: [basePath] :: TarGroup -> FilePath
+ HaskellWorks.CabalCache.IO.Tar: [entryPaths] :: TarGroup -> [FilePath]
+ HaskellWorks.CabalCache.IO.Tar: createTar :: MonadIO m => FilePath -> [TarGroup] -> ExceptT String m ()
+ HaskellWorks.CabalCache.IO.Tar: data TarGroup
+ HaskellWorks.CabalCache.IO.Tar: extractTar :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()
+ HaskellWorks.CabalCache.IO.Tar: instance Control.DeepSeq.NFData HaskellWorks.CabalCache.IO.Tar.TarGroup
+ HaskellWorks.CabalCache.IO.Tar: instance GHC.Classes.Eq HaskellWorks.CabalCache.IO.Tar.TarGroup
+ HaskellWorks.CabalCache.IO.Tar: instance GHC.Generics.Generic HaskellWorks.CabalCache.IO.Tar.TarGroup
+ HaskellWorks.CabalCache.IO.Tar: instance GHC.Show.Show HaskellWorks.CabalCache.IO.Tar.TarGroup
+ HaskellWorks.CabalCache.Location: (<.>) :: IsPath a s => a -> s -> a
+ HaskellWorks.CabalCache.Location: (</>) :: IsPath a s => a -> s -> a
+ HaskellWorks.CabalCache.Location: Local :: FilePath -> Location
+ HaskellWorks.CabalCache.Location: S3 :: S3Uri -> Location
+ HaskellWorks.CabalCache.Location: class IsPath a s | a -> s
+ HaskellWorks.CabalCache.Location: data Location
+ HaskellWorks.CabalCache.Location: infixr 5 </>
+ HaskellWorks.CabalCache.Location: infixr 7 <.>
+ HaskellWorks.CabalCache.Location: instance (a Data.Type.Equality.~ GHC.Types.Char) => HaskellWorks.CabalCache.Location.IsPath [a] [a]
+ HaskellWorks.CabalCache.Location: instance GHC.Classes.Eq HaskellWorks.CabalCache.Location.Location
+ HaskellWorks.CabalCache.Location: instance GHC.Generics.Generic HaskellWorks.CabalCache.Location.Location
+ HaskellWorks.CabalCache.Location: instance GHC.Show.Show HaskellWorks.CabalCache.Location.Location
+ HaskellWorks.CabalCache.Location: instance HaskellWorks.CabalCache.Location.IsPath Antiope.S3.Types.S3Uri Data.Text.Internal.Text
+ HaskellWorks.CabalCache.Location: instance HaskellWorks.CabalCache.Location.IsPath Data.Text.Internal.Text Data.Text.Internal.Text
+ HaskellWorks.CabalCache.Location: instance HaskellWorks.CabalCache.Location.IsPath HaskellWorks.CabalCache.Location.Location Data.Text.Internal.Text
+ HaskellWorks.CabalCache.Location: instance Network.AWS.Data.Text.ToText HaskellWorks.CabalCache.Location.Location
+ HaskellWorks.CabalCache.Location: toLocation :: Text -> Maybe Location
+ HaskellWorks.CabalCache.Metadata: createMetadata :: MonadIO m => FilePath -> PackageInfo -> [(Text, ByteString)] -> m TarGroup
+ HaskellWorks.CabalCache.Metadata: deleteMetadata :: MonadIO m => FilePath -> m ()
+ HaskellWorks.CabalCache.Metadata: loadMetadata :: MonadIO m => FilePath -> m (Map Text ByteString)
+ HaskellWorks.CabalCache.Metadata: metaDir :: String
+ HaskellWorks.CabalCache.Options: readOrFromTextOption :: (Read a, FromText a) => Mod OptionFields a -> Parser a
+ HaskellWorks.CabalCache.Show: tshow :: Show a => a -> Text
+ HaskellWorks.CabalCache.Text: maybeStripPrefix :: Text -> Text -> Text
+ HaskellWorks.CabalCache.Types: Package :: Text -> Text -> Text -> Text -> Maybe Text -> Maybe Text -> Maybe [PackageId] -> Package
+ HaskellWorks.CabalCache.Types: PlanJson :: Text -> [Package] -> PlanJson
+ HaskellWorks.CabalCache.Types: [$sel:compilerId:PlanJson] :: PlanJson -> Text
+ HaskellWorks.CabalCache.Types: [$sel:componentName:Package] :: Package -> Maybe Text
+ HaskellWorks.CabalCache.Types: [$sel:depends:Package] :: Package -> Maybe [PackageId]
+ HaskellWorks.CabalCache.Types: [$sel:id:Package] :: Package -> Text
+ HaskellWorks.CabalCache.Types: [$sel:installPlan:PlanJson] :: PlanJson -> [Package]
+ HaskellWorks.CabalCache.Types: [$sel:name:Package] :: Package -> Text
+ HaskellWorks.CabalCache.Types: [$sel:packageType:Package] :: Package -> Text
+ HaskellWorks.CabalCache.Types: [$sel:style:Package] :: Package -> Maybe Text
+ HaskellWorks.CabalCache.Types: [$sel:version:Package] :: Package -> Text
+ HaskellWorks.CabalCache.Types: data Package
+ HaskellWorks.CabalCache.Types: data PlanJson
+ HaskellWorks.CabalCache.Types: instance Data.Aeson.Types.FromJSON.FromJSON HaskellWorks.CabalCache.Types.Package
+ HaskellWorks.CabalCache.Types: instance Data.Aeson.Types.FromJSON.FromJSON HaskellWorks.CabalCache.Types.PlanJson
+ HaskellWorks.CabalCache.Types: instance GHC.Classes.Eq HaskellWorks.CabalCache.Types.Package
+ HaskellWorks.CabalCache.Types: instance GHC.Classes.Eq HaskellWorks.CabalCache.Types.PlanJson
+ HaskellWorks.CabalCache.Types: instance GHC.Generics.Generic HaskellWorks.CabalCache.Types.Package
+ HaskellWorks.CabalCache.Types: instance GHC.Generics.Generic HaskellWorks.CabalCache.Types.PlanJson
+ HaskellWorks.CabalCache.Types: instance GHC.Show.Show HaskellWorks.CabalCache.Types.Package
+ HaskellWorks.CabalCache.Types: instance GHC.Show.Show HaskellWorks.CabalCache.Types.PlanJson
+ HaskellWorks.CabalCache.Types: type PackageId = Text
+ HaskellWorks.CabalCache.Version: archiveVersion :: IsString s => s
- App.Commands.Options.Types: SyncFromArchiveOptions :: Region -> Location -> FilePath -> Maybe String -> Int -> SyncFromArchiveOptions
+ App.Commands.Options.Types: SyncFromArchiveOptions :: Region -> Location -> FilePath -> Maybe String -> Int -> Maybe LogLevel -> SyncFromArchiveOptions
- App.Commands.Options.Types: SyncToArchiveOptions :: Region -> Location -> FilePath -> Maybe String -> Int -> SyncToArchiveOptions
+ App.Commands.Options.Types: SyncToArchiveOptions :: Region -> Location -> FilePath -> Maybe String -> Int -> Maybe LogLevel -> SyncToArchiveOptions

Files

cabal-cache.cabal view
@@ -1,7 +1,7 @@ cabal-version:          2.2  name:                   cabal-cache-version:                1.0.0.1+version:                1.0.0.2 synopsis:               CI Assistant for Haskell projects description:            CI Assistant for Haskell projects.  Implements package caching. homepage:               https://github.com/haskell-works/cabal-cache@@ -17,42 +17,45 @@   type: git   location: https://github.com/haskell-works/cabal-cache -common base                 { build-depends: base                 >= 4.7        && < 5      }+common base                           { build-depends: base                           >= 4.7        && < 5      } -common aeson                { build-depends: aeson                >= 1.4.2.0    && < 1.5    }-common amazonka             { build-depends: amazonka             >= 1.6.1      && < 1.7    }-common amazonka-core        { build-depends: amazonka-core        >= 1.6.1      && < 1.7    }-common amazonka-s3          { build-depends: amazonka-s3          >= 1.6.1      && < 1.7    }-common antiope-core         { build-depends: antiope-core         >= 7.0.0      && < 8      }-common antiope-s3           { build-depends: antiope-s3           >= 7.0.0      && < 8      }-common bytestring           { build-depends: bytestring           >= 0.10.8.2   && < 0.11   }-common conduit-extra        { build-depends: conduit-extra        >= 1.3.1.1    && < 1.4    }-common cryptonite           { build-depends: cryptonite           >= 0.25       && < 1      }-common containers           { build-depends: containers           >= 0.6.0.1    && < 0.7    }-common deepseq              { build-depends: deepseq              >= 1.4.4.0    && < 1.5    }-common directory            { build-depends: directory            >= 1.3.3.0    && < 1.4    }-common exceptions           { build-depends: exceptions           >= 0.10.1     && < 0.11   }-common filepath             { build-depends: filepath             >= 1.3        && < 1.5    }-common generic-lens         { build-depends: generic-lens         >= 1.1.0.0    && < 1.2    }-common hedgehog             { build-depends: hedgehog             >= 0.5        && < 0.7    }-common hspec                { build-depends: hspec                >= 2.4        && < 3      }-common http-types           { build-depends: http-types           >= 0.12.3     && < 0.13   }-common hw-hedgehog          { build-depends: hw-hedgehog          >= 0.1.0.3    && < 0.2    }-common hw-hspec-hedgehog    { build-depends: hw-hspec-hedgehog    >= 0.1.0.4    && < 0.2    }-common lens                 { build-depends: lens                 >= 4.17       && < 5      }-common mtl                  { build-depends: mtl                  >= 2.2.2      && < 2.3    }-common optparse-applicative { build-depends: optparse-applicative >= 0.14       && < 0.15   }-common process              { build-depends: process              >= 1.6.5.0    && < 1.7    }-common raw-strings-qq       { build-depends: raw-strings-qq       >= 1.1        && < 2      }-common resourcet            { build-depends: resourcet            >= 1.2.2      && < 1.3    }-common selective            { build-depends: selective            >= 0.1.0      && < 0.2    }-common stringsearch         { build-depends: stringsearch         >= 0.3.6.6    && < 0.4    }-common tar                  { build-depends: tar                  >= 0.5.1.0    && < 0.6    }-common temporary            { build-depends: temporary            >= 1.3        && < 1.4    }-common text                 { build-depends: text                 >= 1.2.3.1    && < 1.3    }-common time                 { build-depends: time                 >= 1.4        && < 1.10   }-common unliftio             { build-depends: unliftio             >= 0.2.10     && < 0.3    }-common zlib                 { build-depends: zlib                 >= 0.6.2      && < 0.7    }+common aeson                          { build-depends: aeson                          >= 1.4.2.0    && < 1.5    }+common amazonka                       { build-depends: amazonka                       >= 1.6.1      && < 1.7    }+common amazonka-core                  { build-depends: amazonka-core                  >= 1.6.1      && < 1.7    }+common amazonka-s3                    { build-depends: amazonka-s3                    >= 1.6.1      && < 1.7    }+common antiope-core                   { build-depends: antiope-core                   >= 7.0.1      && < 8      }+common antiope-optparse-applicative   { build-depends: antiope-optparse-applicative   >= 7.0.1      && < 8      }+common antiope-s3                     { build-depends: antiope-s3                     >= 7.0.1      && < 8      }+common bytestring                     { build-depends: bytestring                     >= 0.10.8.2   && < 0.11   }+common conduit-extra                  { build-depends: conduit-extra                  >= 1.3.1.1    && < 1.4    }+common cryptonite                     { build-depends: cryptonite                     >= 0.25       && < 1      }+common containers                     { build-depends: containers                     >= 0.6.0.1    && < 0.7    }+common deepseq                        { build-depends: deepseq                        >= 1.4.4.0    && < 1.5    }+common directory                      { build-depends: directory                      >= 1.3.3.0    && < 1.4    }+common exceptions                     { build-depends: exceptions                     >= 0.10.1     && < 0.11   }+common filepath                       { build-depends: filepath                       >= 1.3        && < 1.5    }+common generic-lens                   { build-depends: generic-lens                   >= 1.1.0.0    && < 1.2    }+common hedgehog                       { build-depends: hedgehog                       >= 0.5        && < 0.7    }+common hspec                          { build-depends: hspec                          >= 2.4        && < 3      }+common http-client                    { build-depends: http-client                    >= 0.5.14     && < 0.7    }+common http-types                     { build-depends: http-types                     >= 0.12.3     && < 0.13   }+common hw-hedgehog                    { build-depends: hw-hedgehog                    >= 0.1.0.3    && < 0.2    }+common hw-hspec-hedgehog              { build-depends: hw-hspec-hedgehog              >= 0.1.0.4    && < 0.2    }+common lens                           { build-depends: lens                           >= 4.17       && < 5      }+common mtl                            { build-depends: mtl                            >= 2.2.2      && < 2.3    }+common optparse-applicative           { build-depends: optparse-applicative           >= 0.14       && < 0.15   }+common process                        { build-depends: process                        >= 1.6.5.0    && < 1.7    }+common raw-strings-qq                 { build-depends: raw-strings-qq                 >= 1.1        && < 2      }+common resourcet                      { build-depends: resourcet                      >= 1.2.2      && < 1.3    }+common selective                      { build-depends: selective                      >= 0.1.0      && < 0.2    }+common stm                            { build-depends: stm                            >= 2.5.0.0    && < 3      }+common stringsearch                   { build-depends: stringsearch                   >= 0.3.6.6    && < 0.4    }+common tar                            { build-depends: tar                            >= 0.5.1.0    && < 0.6    }+common temporary                      { build-depends: temporary                      >= 1.3        && < 1.4    }+common text                           { build-depends: text                           >= 1.2.3.1    && < 1.3    }+common time                           { build-depends: time                           >= 1.4        && < 1.10   }+common unliftio                       { build-depends: unliftio                       >= 0.2.10     && < 0.3    }+common zlib                           { build-depends: zlib                           >= 0.6.2      && < 0.7    }  common config   default-language:     Haskell2010@@ -64,6 +67,7 @@           , amazonka-core           , amazonka-s3           , antiope-core+          , antiope-optparse-applicative           , antiope-s3           , bytestring           , conduit-extra@@ -74,6 +78,7 @@           , exceptions           , filepath           , generic-lens+          , http-client           , http-types           , lens           , mtl@@ -81,12 +86,12 @@           , process           , resourcet           , selective+          , stm           , stringsearch           , tar           , temporary           , text           , time-                   , unliftio           , zlib   other-modules:        Paths_cabal_cache@@ -100,21 +105,26 @@       App.Commands.SyncToArchive       App.Commands.Version       App.Static-      HaskellWorks.Ci.Assist.Core-      HaskellWorks.Ci.Assist.Hash-      HaskellWorks.Ci.Assist.IO.Console-      HaskellWorks.Ci.Assist.GhcPkg-      HaskellWorks.Ci.Assist.IO.Error-      HaskellWorks.Ci.Assist.IO.File-      HaskellWorks.Ci.Assist.IO.Lazy-      HaskellWorks.Ci.Assist.IO.Tar-      HaskellWorks.Ci.Assist.Location-      HaskellWorks.Ci.Assist.Metadata-      HaskellWorks.Ci.Assist.Options-      HaskellWorks.Ci.Assist.Show-      HaskellWorks.Ci.Assist.Text-      HaskellWorks.Ci.Assist.Types-      HaskellWorks.Ci.Assist.Version+      HaskellWorks.CabalCache.AWS.Env+      HaskellWorks.CabalCache.Concurrent.DownloadQueue+      HaskellWorks.CabalCache.Concurrent.Type+      HaskellWorks.CabalCache.Core+      HaskellWorks.CabalCache.Data.Relation+      HaskellWorks.CabalCache.Data.Relation.Type+      HaskellWorks.CabalCache.GhcPkg+      HaskellWorks.CabalCache.Hash+      HaskellWorks.CabalCache.IO.Console+      HaskellWorks.CabalCache.IO.Error+      HaskellWorks.CabalCache.IO.File+      HaskellWorks.CabalCache.IO.Lazy+      HaskellWorks.CabalCache.IO.Tar+      HaskellWorks.CabalCache.Location+      HaskellWorks.CabalCache.Metadata+      HaskellWorks.CabalCache.Options+      HaskellWorks.CabalCache.Show+      HaskellWorks.CabalCache.Text+      HaskellWorks.CabalCache.Types+      HaskellWorks.CabalCache.Version  executable cabal-cache   import:   base, config@@ -130,6 +140,7 @@           , antiope-core           , antiope-s3           , bytestring+          , containers           , filepath           , generic-lens           , hedgehog@@ -147,6 +158,7 @@   ghc-options:          -threaded -rtsopts -with-rtsopts=-N   build-tools:          hspec-discover   other-modules:-      HaskellWorks.Assist.AwsSpec-      HaskellWorks.Assist.LocationSpec-      HaskellWorks.Assist.QuerySpec+      HaskellWorks.CabalCache.AwsSpec+      HaskellWorks.CabalCache.Data.RelationSpec+      HaskellWorks.CabalCache.LocationSpec+      HaskellWorks.CabalCache.QuerySpec
src/App/Commands/Options/Parser.hs view
@@ -1,14 +1,17 @@ {-# LANGUAGE OverloadedStrings #-}+ module App.Commands.Options.Parser where -import Antiope.Core                    (FromText, Region (..), fromText)-import App.Commands.Options.Types      (SyncFromArchiveOptions (..), SyncToArchiveOptions (..), VersionOptions (..))-import App.Static                      (homeDirectory)+import Antiope.Core                     (FromText, Region (..), fromText)+import Antiope.Options.Applicative+import App.Commands.Options.Types       (SyncFromArchiveOptions (..), SyncToArchiveOptions (..), VersionOptions (..))+import App.Static                       (homeDirectory) import Control.Applicative-import HaskellWorks.Ci.Assist.Location (Location (..), toLocation, (</>))+import HaskellWorks.CabalCache.Location (Location (..), toLocation, (</>)) import Options.Applicative -import qualified Data.Text as Text+import qualified Data.Text         as Text+import qualified Network.AWS.Types as AWS  optsSyncFromArchive :: Parser SyncFromArchiveOptions optsSyncFromArchive = SyncFromArchiveOptions@@ -43,6 +46,13 @@       <>  metavar "NUM_THREADS"       <>  value 4       )+  <*> optional+      ( option autoText+        (   long "aws-log-level"+        <>  help "AWS Log Level.  One of (Error, Info, Debug, Trace)"+        <>  metavar "AWS_LOG_LEVEL"+        )+      )  optsSyncToArchive :: Parser SyncToArchiveOptions optsSyncToArchive = SyncToArchiveOptions@@ -76,6 +86,13 @@       <>  help "Number of concurrent threads"       <>  metavar "NUM_THREADS"       <>  value 4+      )+  <*> optional+      ( option autoText+        (   long "aws-log-level"+        <>  help "AWS Log Level.  One of (Error, Info, Debug, Trace)"+        <>  metavar "AWS_LOG_LEVEL"+        )       )  optsVersion :: Parser VersionOptions
src/App/Commands/Options/Types.hs view
@@ -3,19 +3,22 @@  module App.Commands.Options.Types where -import Antiope.Env                     (Region)-import Data.Text                       (Text)+import Antiope.Env                      (Region)+import Data.Text                        (Text) import GHC.Generics-import GHC.Word                        (Word8)-import HaskellWorks.Ci.Assist.Location-import Network.AWS.Types               (Region)+import GHC.Word                         (Word8)+import HaskellWorks.CabalCache.Location+import Network.AWS.Types                (Region) +import qualified Antiope.Env as AWS+ data SyncToArchiveOptions = SyncToArchiveOptions   { region        :: Region   , archiveUri    :: Location   , storePath     :: FilePath   , storePathHash :: Maybe String   , threads       :: Int+  , awsLogLevel   :: Maybe AWS.LogLevel   } deriving (Eq, Show, Generic)  data SyncFromArchiveOptions = SyncFromArchiveOptions@@ -24,6 +27,7 @@   , storePath     :: FilePath   , storePathHash :: Maybe String   , threads       :: Int+  , awsLogLevel   :: Maybe AWS.LogLevel   } deriving (Eq, Show, Generic)  data VersionOptions = VersionOptions deriving (Eq, Show, Generic)
src/App/Commands/SyncFromArchive.hs view
@@ -7,48 +7,49 @@   ( cmdSyncFromArchive   ) where -import Antiope.Core                    (runResAws, toText)-import Antiope.Env                     (LogLevel, mkEnv)-import App.Commands.Options.Parser     (optsSyncFromArchive)-import App.Static                      (homeDirectory)-import Control.Lens                    hiding ((<.>))-import Control.Monad                   (unless, void, when)+import Antiope.Core                     (runResAws, toText)+import Antiope.Env                      (LogLevel, mkEnv)+import App.Commands.Options.Parser      (optsSyncFromArchive)+import App.Static                       (homeDirectory)+import Control.Lens                     hiding ((<.>))+import Control.Monad                    (unless, void, when) import Control.Monad.Except-import Control.Monad.IO.Class          (liftIO)-import Control.Monad.Trans.Resource    (runResourceT)-import Data.ByteString.Lazy.Search     (replace)-import Data.Generics.Product.Any       (the)+import Control.Monad.IO.Class           (liftIO)+import Control.Monad.Trans.Resource     (runResourceT)+import Data.ByteString.Lazy.Search      (replace)+import Data.Generics.Product.Any        (the) import Data.Maybe-import Data.Semigroup                  ((<>))-import Data.Text                       (Text)-import HaskellWorks.Ci.Assist.Core     (PackageInfo (..), Presence (..), Tagged (..), getPackages, loadPlan)-import HaskellWorks.Ci.Assist.IO.Error (exceptWarn, maybeToExcept, maybeToExceptM)-import HaskellWorks.Ci.Assist.Location ((<.>), (</>))-import HaskellWorks.Ci.Assist.Metadata (deleteMetadata, loadMetadata)-import HaskellWorks.Ci.Assist.Show-import HaskellWorks.Ci.Assist.Version  (archiveVersion)-import Network.AWS.Types               (Region (Oregon))-import Options.Applicative             hiding (columns)-import System.Directory                (createDirectoryIfMissing, doesDirectoryExist)+import Data.Semigroup                   ((<>))+import Data.Text                        (Text)+import HaskellWorks.CabalCache.Core     (PackageInfo (..), Presence (..), Tagged (..), getPackages, loadPlan)+import HaskellWorks.CabalCache.IO.Error (exceptWarn, maybeToExcept, maybeToExceptM)+import HaskellWorks.CabalCache.Location ((<.>), (</>))+import HaskellWorks.CabalCache.Metadata (deleteMetadata, loadMetadata)+import HaskellWorks.CabalCache.Show+import HaskellWorks.CabalCache.Version  (archiveVersion)+import Network.AWS.Types                (Region (Oregon))+import Options.Applicative              hiding (columns)+import System.Directory                 (createDirectoryIfMissing, doesDirectoryExist) -import qualified App.Commands.Options.Types        as Z-import qualified Codec.Archive.Tar                 as F-import qualified Codec.Compression.GZip            as F-import qualified Data.ByteString                   as BS-import qualified Data.ByteString.Char8             as C8-import qualified Data.ByteString.Lazy              as LBS-import qualified Data.Map.Strict                   as Map-import qualified Data.Text                         as T-import qualified HaskellWorks.Ci.Assist.GhcPkg     as GhcPkg-import qualified HaskellWorks.Ci.Assist.Hash       as H-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO-import qualified HaskellWorks.Ci.Assist.IO.Lazy    as IO-import qualified HaskellWorks.Ci.Assist.IO.Tar     as IO-import qualified HaskellWorks.Ci.Assist.Types      as Z-import qualified System.Directory                  as IO-import qualified System.IO                         as IO-import qualified System.IO.Temp                    as IO-import qualified UnliftIO.Async                    as IO+import qualified App.Commands.Options.Types         as Z+import qualified Codec.Archive.Tar                  as F+import qualified Codec.Compression.GZip             as F+import qualified Data.ByteString                    as BS+import qualified Data.ByteString.Char8              as C8+import qualified Data.ByteString.Lazy               as LBS+import qualified Data.Map.Strict                    as Map+import qualified Data.Text                          as T+import qualified HaskellWorks.CabalCache.AWS.Env    as AWS+import qualified HaskellWorks.CabalCache.GhcPkg     as GhcPkg+import qualified HaskellWorks.CabalCache.Hash       as H+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified HaskellWorks.CabalCache.IO.Lazy    as IO+import qualified HaskellWorks.CabalCache.IO.Tar     as IO+import qualified HaskellWorks.CabalCache.Types      as Z+import qualified System.Directory                   as IO+import qualified System.IO                          as IO+import qualified System.IO.Temp                     as IO+import qualified UnliftIO.Async                     as IO  {-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-} {-# ANN module ("HLint: ignore Redundant do"        :: String) #-}@@ -58,6 +59,7 @@   let storePath           = opts ^. the @"storePath"   let archiveUri          = opts ^. the @"archiveUri"   let threads             = opts ^. the @"threads"+  let awsLogLevel         = opts ^. the @"awsLogLevel"   let versionedArchiveUri = archiveUri </> archiveVersion   let storePathHash       = opts ^. the @"storePathHash" & fromMaybe (H.hashStorePath storePath)   let scopedArchiveUri    = versionedArchiveUri </> T.pack storePathHash@@ -67,13 +69,14 @@   CIO.putStrLn $ "Archive URI: "      <> toText archiveUri   CIO.putStrLn $ "Archive version: "  <> archiveVersion   CIO.putStrLn $ "Threads: "          <> tshow threads+  CIO.putStrLn $ "AWS Log level: "    <> tshow awsLogLevel    GhcPkg.testAvailability    mbPlan <- loadPlan   case mbPlan of     Right planJson -> do-      envAws <- mkEnv (opts ^. the @"region") (\_ _ -> pure ())+      envAws <- mkEnv (opts ^. the @"region") (AWS.awsLogger awsLogLevel)       let compilerId                  = planJson ^. the @"compilerId"       let archivePath                 = versionedArchiveUri </> compilerId       let storeCompilerPath           = storePath </> T.unpack compilerId
src/App/Commands/SyncToArchive.hs view
@@ -7,45 +7,47 @@   ( cmdSyncToArchive   ) where -import Antiope.Core                    (toText)-import Antiope.Env                     (LogLevel, mkEnv)-import App.Commands.Options.Parser     (optsSyncToArchive)-import App.Static                      (homeDirectory)-import Control.Lens                    hiding ((<.>))-import Control.Monad                   (unless, when)+import Antiope.Core                     (toText)+import Antiope.Env                      (LogLevel (..), mkEnv)+import App.Commands.Options.Parser      (optsSyncToArchive)+import App.Static                       (homeDirectory)+import Control.Lens                     hiding ((<.>))+import Control.Monad                    (unless, when) import Control.Monad.Except-import Control.Monad.Trans.Resource    (runResourceT)-import Data.Generics.Product.Any       (the)-import Data.List                       (isSuffixOf, (\\))+import Control.Monad.Trans.Resource     (runResourceT)+import Data.Generics.Product.Any        (the)+import Data.List                        (isSuffixOf, (\\)) import Data.Maybe-import Data.Semigroup                  ((<>))-import HaskellWorks.Ci.Assist.Core     (PackageInfo (..), Presence (..), Tagged (..), getPackages, loadPlan, relativePaths)-import HaskellWorks.Ci.Assist.Location ((<.>), (</>))-import HaskellWorks.Ci.Assist.Metadata (createMetadata)-import HaskellWorks.Ci.Assist.Show-import HaskellWorks.Ci.Assist.Version  (archiveVersion)-import Options.Applicative             hiding (columns)-import System.Directory                (createDirectoryIfMissing, doesDirectoryExist)+import Data.Semigroup                   ((<>))+import HaskellWorks.CabalCache.Core     (PackageInfo (..), Presence (..), Tagged (..), getPackages, loadPlan, relativePaths)+import HaskellWorks.CabalCache.Location ((<.>), (</>))+import HaskellWorks.CabalCache.Metadata (createMetadata)+import HaskellWorks.CabalCache.Show+import HaskellWorks.CabalCache.Version  (archiveVersion)+import Options.Applicative              hiding (columns)+import System.Directory                 (createDirectoryIfMissing, doesDirectoryExist) -import qualified App.Commands.Options.Types        as Z-import qualified Codec.Archive.Tar                 as F-import qualified Codec.Compression.GZip            as F-import qualified Data.ByteString.Lazy              as LBS-import qualified Data.ByteString.Lazy.Char8        as LC8-import qualified Data.Text                         as T-import qualified HaskellWorks.Ci.Assist.GhcPkg     as GhcPkg-import qualified HaskellWorks.Ci.Assist.Hash       as H-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO-import qualified HaskellWorks.Ci.Assist.IO.Error   as IO-import qualified HaskellWorks.Ci.Assist.IO.File    as IO-import qualified HaskellWorks.Ci.Assist.IO.Lazy    as IO-import qualified HaskellWorks.Ci.Assist.IO.Tar     as IO-import qualified HaskellWorks.Ci.Assist.Types      as Z-import qualified System.Directory                  as IO-import qualified System.FilePath.Posix             as FP-import qualified System.IO                         as IO-import qualified System.IO.Temp                    as IO-import qualified UnliftIO.Async                    as IO+import qualified App.Commands.Options.Types         as Z+import qualified Codec.Archive.Tar                  as F+import qualified Codec.Compression.GZip             as F+import qualified Data.ByteString.Lazy               as LBS+import qualified Data.ByteString.Lazy.Char8         as LC8+import qualified Data.Text                          as T+import qualified Data.Text.Encoding                 as T+import qualified HaskellWorks.CabalCache.AWS.Env    as AWS+import qualified HaskellWorks.CabalCache.GhcPkg     as GhcPkg+import qualified HaskellWorks.CabalCache.Hash       as H+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified HaskellWorks.CabalCache.IO.Error   as IO+import qualified HaskellWorks.CabalCache.IO.File    as IO+import qualified HaskellWorks.CabalCache.IO.Lazy    as IO+import qualified HaskellWorks.CabalCache.IO.Tar     as IO+import qualified HaskellWorks.CabalCache.Types      as Z+import qualified System.Directory                   as IO+import qualified System.FilePath.Posix              as FP+import qualified System.IO                          as IO+import qualified System.IO.Temp                     as IO+import qualified UnliftIO.Async                     as IO  {-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-} {-# ANN module ("HLint: ignore Redundant do"        :: String) #-}@@ -55,6 +57,7 @@   let storePath           = opts ^. the @"storePath"   let archiveUri          = opts ^. the @"archiveUri"   let threads             = opts ^. the @"threads"+  let awsLogLevel         = opts ^. the @"awsLogLevel"   let versionedArchiveUri = archiveUri </> archiveVersion   let storePathHash       = opts ^. the @"storePathHash" & fromMaybe (H.hashStorePath storePath)   let scopedArchiveUri    = versionedArchiveUri </> T.pack storePathHash@@ -64,12 +67,13 @@   CIO.putStrLn $ "Archive URI: "      <> toText archiveUri   CIO.putStrLn $ "Archive version: "  <> archiveVersion   CIO.putStrLn $ "Threads: "          <> tshow threads+  CIO.putStrLn $ "AWS Log level: "    <> tshow awsLogLevel    mbPlan <- loadPlan   case mbPlan of     Right planJson -> do       let compilerId = planJson ^. the @"compilerId"-      envAws <- mkEnv (opts ^. the @"region") (\_ _ -> pure ())+      envAws <- mkEnv (opts ^. the @"region") (AWS.awsLogger awsLogLevel)       let archivePath       = versionedArchiveUri </> compilerId       let scopedArchivePath = scopedArchiveUri </> compilerId       IO.createLocalDirectoryIfMissing archivePath
src/App/Commands/Version.hs view
@@ -17,10 +17,10 @@ import Options.Applicative         hiding (columns) import Paths_cabal_cache -import qualified App.Commands.Options.Types        as Z-import qualified Data.Text                         as T-import qualified Data.Version                      as V-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO+import qualified App.Commands.Options.Types         as Z+import qualified Data.Text                          as T+import qualified Data.Version                       as V+import qualified HaskellWorks.CabalCache.IO.Console as CIO  {-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-} {-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+ src/HaskellWorks/CabalCache/AWS/Env.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE OverloadedStrings #-}++module HaskellWorks.CabalCache.AWS.Env+  ( awsLogger+  ) where++import Antiope.Env                  (LogLevel (..))+import Control.Concurrent           (myThreadId)+import Control.Monad+import HaskellWorks.CabalCache.Show++import qualified Data.ByteString.Lazy               as LBS+import qualified Data.ByteString.Lazy.Char8         as LC8+import qualified Data.Text.Encoding                 as T+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified System.IO                          as IO++awsLogger :: Maybe LogLevel -> LogLevel -> LC8.ByteString -> IO ()+awsLogger maybeConfigLogLevel msgLogLevel message =+  forM_ maybeConfigLogLevel $ \configLogLevel ->+    when (msgLogLevel <= configLogLevel) $ do+      threadId <- myThreadId+      CIO.hPutStrLn IO.stderr $ "[" <> tshow msgLogLevel <> "] [tid: " <> tshow threadId <> "]"  <> text+  where text = T.decodeUtf8 $ LBS.toStrict message
+ src/HaskellWorks/CabalCache/Concurrent/DownloadQueue.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE DataKinds       #-}+{-# LANGUAGE RecordWildCards #-}++module HaskellWorks.CabalCache.Concurrent.DownloadQueue+  ( createDownloadQueue+  , anchor+  ) where++import Control.Lens+import Control.Monad+import Control.Monad.IO.Class+import Data.Generics.Product.Any+import Data.Set                  ((\\))++import qualified Control.Concurrent.STM                  as STM+import qualified Data.Map                                as M+import qualified Data.Set                                as S+import qualified Data.Text                               as T+import qualified HaskellWorks.CabalCache.Concurrent.Type as Z+import qualified HaskellWorks.CabalCache.Data.Relation   as R++anchor :: Z.PackageId -> M.Map Z.ConsumerId Z.ProviderId -> M.Map Z.ConsumerId Z.ProviderId+anchor root dependencies = M.union dependencies $ M.singleton root (mconcat (M.elems dependencies))++createDownloadQueue :: [(Z.ProviderId, Z.ConsumerId)] -> STM.STM Z.DownloadQueue+createDownloadQueue dependencies = do+  tDependencies <- STM.newTVar (R.fromList dependencies)+  tUploading    <- STM.newTVar S.empty+  return Z.DownloadQueue {..}++takeReady :: Z.DownloadQueue -> STM.STM (Maybe Z.PackageId)+takeReady Z.DownloadQueue {..} = do+  dependencies  <- STM.readTVar tDependencies+  uploading     <- STM.readTVar tUploading++  let ready = R.range dependencies \\ R.domain dependencies \\ uploading++  case S.lookupMin ready of+    Just packageId -> do+      STM.writeTVar tUploading (S.insert packageId uploading)+      return (Just packageId)+    Nothing -> return Nothing++commit :: Z.DownloadQueue -> Z.PackageId -> STM.STM ()+commit Z.DownloadQueue {..} packageId = do+  dependencies  <- STM.readTVar tDependencies+  uploading     <- STM.readTVar tUploading++  STM.writeTVar tUploading    $ S.delete packageId uploading+  STM.writeTVar tDependencies $ R.withoutRange (S.singleton packageId) dependencies++runQueue :: MonadIO m => Z.DownloadQueue -> (Z.PackageId -> m ()) -> m ()+runQueue downloadQueue@Z.DownloadQueue {..} f = do+  maybePackageId <- liftIO $ STM.atomically $ takeReady downloadQueue++  case maybePackageId of+    Just packageId -> do+      f packageId+      liftIO $ STM.atomically $ commit downloadQueue packageId+    Nothing -> return ()
+ src/HaskellWorks/CabalCache/Concurrent/Type.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE DuplicateRecordFields #-}++module HaskellWorks.CabalCache.Concurrent.Type+  ( DownloadQueue(..)+  , ConsumerId+  , ProviderId+  , PackageId+  ) where++import Data.Text                     (Text)+import GHC.Generics+import HaskellWorks.CabalCache.Types (PackageId)++import qualified Control.Concurrent.STM                as STM+import qualified Data.Map                              as M+import qualified Data.Set                              as S+import qualified Data.Text                             as T+import qualified HaskellWorks.CabalCache.Data.Relation as R++type ConsumerId = PackageId+type ProviderId = PackageId++data DownloadQueue = DownloadQueue+  { tDependencies :: STM.TVar (R.Relation ConsumerId ProviderId)+  , tUploading    :: STM.TVar (S.Set PackageId)+  } deriving Generic
+ src/HaskellWorks/CabalCache/Core.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveAnyClass        #-}+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE TypeApplications      #-}+module HaskellWorks.CabalCache.Core+  ( PackageInfo(..)+  , Tagged(..)+  , Presence(..)+  , getPackages+  , relativePaths+  , loadPlan+  ) where++import Control.DeepSeq           (NFData)+import Control.Lens              hiding ((<.>))+import Control.Monad             (forM)+import Data.Aeson                (eitherDecode)+import Data.Bool                 (bool)+import Data.Generics.Product.Any (the)+import Data.Maybe                (maybeToList)+import Data.Semigroup            ((<>))+import Data.Text                 (Text)+import GHC.Generics              (Generic)+import System.FilePath           ((<.>), (</>))++import qualified Data.ByteString.Lazy           as LBS+import qualified Data.List                      as List+import qualified Data.Text                      as T+import qualified HaskellWorks.CabalCache.IO.Tar as IO+import qualified HaskellWorks.CabalCache.Types  as Z+import qualified System.Directory               as IO++type CompilerId = Text+type PackageId  = Text+type PackageDir = FilePath+type ConfPath   = FilePath+type Library    = FilePath++data Presence   = Present | Absent deriving (Eq, Show, NFData, Generic)++data Tagged a t = Tagged+  { value :: a+  , tag   :: t+  } deriving (Eq, Show, Generic, NFData)++data PackageInfo = PackageInfo+  { compilerId :: CompilerId+  , packageId  :: PackageId+  , packageDir :: PackageDir+  , confPath   :: Tagged ConfPath Presence+  , libs       :: [Library]+  } deriving (Show, Eq, Generic, NFData)++relativePaths :: FilePath -> PackageInfo -> [IO.TarGroup]+relativePaths basePath pInfo =+  [ IO.TarGroup basePath $ mempty+      <> (pInfo ^. the @"libs")+      <> [packageDir pInfo]+  , IO.TarGroup basePath $ mempty+      <> ([pInfo ^. the @"confPath"] & filter ((== Present) . (^. the @"tag")) <&> (^. the @"value"))+  ]++getPackages :: FilePath -> Z.PlanJson -> IO [PackageInfo]+getPackages basePath planJson = forM packages (mkPackageInfo basePath compilerId)+  where compilerId :: Text+        compilerId = planJson ^. the @"compilerId"+        packages :: [Z.Package]+        packages = planJson ^.. the @"installPlan" . each . filtered predicate+        predicate :: Z.Package -> Bool+        predicate package = package ^. the @"packageType" /= "pre-existing" && package ^. the @"style" == Just "global"++loadPlan :: IO (Either String Z.PlanJson)+loadPlan =+  eitherDecode <$> LBS.readFile ("dist-newstyle" </> "cache" </> "plan.json")++-------------------------------------------------------------------------------+mkPackageInfo :: FilePath -> CompilerId -> Z.Package -> IO PackageInfo+mkPackageInfo basePath cid pkg = do+  let pid               = pkg ^. the @"id"+  let compilerPath      = basePath </> T.unpack cid+  let relativeConfPath  = T.unpack cid </> "package.db" </> T.unpack pid <.> ".conf"+  let absoluteConfPath  = basePath </> relativeConfPath+  let libPath           = compilerPath </> "lib"+  let relativeLibPath   = T.unpack cid </> "lib"+  let libPrefix         = "libHS" <> pid+  absoluteConfPathExists <- IO.doesFileExist absoluteConfPath+  libPathExists <- IO.doesDirectoryExist libPath+  libFiles <- getLibFiles relativeLibPath libPath libPrefix+  return PackageInfo+    { compilerId  = cid+    , packageId   = pid+    , packageDir  = T.unpack cid </> T.unpack pid+    , confPath    = Tagged relativeConfPath (bool Absent Present absoluteConfPathExists)+    , libs        = libFiles+    }++getLibFiles :: FilePath -> FilePath -> Text -> IO [Library]+getLibFiles relativeLibPath libPath libPrefix =+  fmap (relativeLibPath </>) . filter (List.isPrefixOf (T.unpack libPrefix)) <$> IO.listDirectory libPath
+ src/HaskellWorks/CabalCache/Data/Relation.hs view
@@ -0,0 +1,94 @@+module HaskellWorks.CabalCache.Data.Relation+  ( Relation(Relation)+  , empty+  , null+  , fromList+  , toList+  , singleton+  , insert+  , delete+  , domain+  , range+  , restrictDomain+  , restrictRange+  , withoutDomain+  , withoutRange+  ) where++import GHC.Generics+import HaskellWorks.CabalCache.Data.Relation.Type (Relation (Relation))+import Prelude                                    hiding (null)++import qualified Data.Map                                   as M+import qualified Data.Set                                   as S+import qualified HaskellWorks.CabalCache.Data.Relation.Type as R++empty :: Relation a b+empty = Relation M.empty M.empty++null :: Relation a b -> Bool+null = M.null . R.domain++fromList :: (Ord a, Ord b) => [(a, b)] -> Relation a b+fromList rs = Relation+  { R.domain  = M.fromListWith S.union $ map (\(x, y) -> (x, S.singleton y)) rs+  , R.range   = M.fromListWith S.union $ map (\(x, y) -> (y, S.singleton x)) rs+  }++toList :: Relation a b -> [(a, b)]+toList r = concatMap+  (\(x, y) -> zip (repeat x) (S.toList y))+  (M.toList (R.domain  r))++singleton :: a -> b -> Relation a b+singleton x y = Relation+  { R.domain  = M.singleton x (S.singleton y)+  , R.range   = M.singleton y (S.singleton x)+  }++insert :: (Ord a, Ord b) => a -> b -> Relation a b -> Relation a b+insert x y r = Relation+  { R.domain  = M.insertWith S.union x (S.singleton y) (R.domain r)+  , R.range   = M.insertWith S.union y (S.singleton x) (R.range  r)+  }++delete :: (Ord a, Ord b) =>  a -> b -> Relation a b -> Relation a b+delete x y r = r+  { R.domain  = M.update (justUnlessEmpty . S.delete y) x (R.domain r)+  , R.range   = M.update (justUnlessEmpty . S.delete x) y (R.range  r)+  }++domain ::  Relation a b -> S.Set a+domain r = M.keysSet (R.domain r)++range ::  Relation a b -> S.Set b+range r = M.keysSet (R.range r)++restrictDomain :: (Ord a, Ord b) => S.Set a -> Relation a b -> Relation a b+restrictDomain s r = R.Relation+  { R.domain = M.restrictKeys (R.domain r) s+  , R.range  = M.mapMaybe (justUnlessEmpty . S.intersection s) (R.range r)+  }++restrictRange :: (Ord a, Ord b) => S.Set b -> Relation a b -> Relation a b+restrictRange s r = R.Relation+  { R.domain  = M.mapMaybe (justUnlessEmpty . S.intersection s) (R.domain r)+  , R.range   = M.restrictKeys (R.range r) s+  }++withoutDomain :: (Ord a, Ord b) => S.Set a -> Relation a b -> Relation a b+withoutDomain s r = R.Relation+  { R.domain = M.withoutKeys (R.domain r) s+  , R.range  = M.mapMaybe (justUnlessEmpty . flip S.difference s) (R.range r)+  }++withoutRange :: (Ord a, Ord b) => S.Set b -> Relation a b -> Relation a b+withoutRange s r = R.Relation+  { R.domain  = M.mapMaybe (justUnlessEmpty . flip S.difference s) (R.domain r)+  , R.range   = M.withoutKeys (R.range r) s+  }++------++justUnlessEmpty :: S.Set a -> Maybe (S.Set a)+justUnlessEmpty c = if S.null c then Nothing else Just c
+ src/HaskellWorks/CabalCache/Data/Relation/Type.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE DeriveGeneric #-}++module HaskellWorks.CabalCache.Data.Relation.Type+  ( Relation (..)+  ) where++import GHC.Generics++import qualified Data.Map as M+import qualified Data.Set as S++data Relation a b = Relation+  { domain :: M.Map a (S.Set b)+  , range  :: M.Map b (S.Set a)+  } deriving (Eq, Show, Ord, Generic)
+ src/HaskellWorks/CabalCache/GhcPkg.hs view
@@ -0,0 +1,27 @@+module HaskellWorks.CabalCache.GhcPkg where++import Data.Text      (Text)+import System.Exit    (ExitCode (..), exitWith)+import System.Process (spawnProcess, waitForProcess)++import qualified Data.Text as Text+import qualified System.IO as IO++runGhcPkg :: [String] -> IO ()+runGhcPkg params = do+  hGhcPkg2 <- spawnProcess "ghc-pkg" params+  exitCodeGhcPkg2 <- waitForProcess hGhcPkg2+  case exitCodeGhcPkg2 of+    ExitFailure _ -> do+      IO.hPutStrLn IO.stderr "ERROR: Unable to recache package db"+      exitWith (ExitFailure 1)+    _ -> return ()++testAvailability :: IO ()+testAvailability = runGhcPkg ["--version"]++recache :: FilePath -> IO ()+recache packageDb = runGhcPkg ["recache", "--package-db", packageDb]++init :: FilePath -> IO ()+init packageDb = runGhcPkg ["init", packageDb]
+ src/HaskellWorks/CabalCache/Hash.hs view
@@ -0,0 +1,10 @@+module HaskellWorks.CabalCache.Hash+  ( hashStorePath+  ) where++import qualified Crypto.Hash        as CH+import qualified Data.Text          as T+import qualified Data.Text.Encoding as T++hashStorePath :: String -> String+hashStorePath = take 10 . show . CH.hashWith CH.SHA256 . T.encodeUtf8 . T.pack
+ src/HaskellWorks/CabalCache/IO/Console.hs view
@@ -0,0 +1,36 @@+module HaskellWorks.CabalCache.IO.Console+  ( putStrLn+  , print+  , hPutStrLn+  , hPrint+  ) where++import Control.Exception      (bracket_)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Text              (Text)+import Prelude                (IO, Show (..), ($), (.))++import qualified Control.Concurrent.QSem as IO+import qualified Data.Text               as T+import qualified Data.Text.IO            as T+import qualified System.IO               as IO+import qualified System.IO.Unsafe        as IO++sem :: IO.QSem+sem = IO.unsafePerformIO $ IO.newQSem 1+{-# NOINLINE sem #-}++consoleBracket :: IO a -> IO a+consoleBracket = bracket_ (IO.waitQSem sem) (IO.signalQSem sem)++putStrLn :: MonadIO m => Text -> m ()+putStrLn = liftIO . consoleBracket . T.putStrLn++print :: (MonadIO m, Show a) => a -> m ()+print = liftIO . consoleBracket . IO.print++hPutStrLn :: MonadIO m => IO.Handle -> Text -> m ()+hPutStrLn h = liftIO . consoleBracket . T.hPutStrLn h++hPrint :: (MonadIO m, Show a) => IO.Handle -> a -> m ()+hPrint h = liftIO . consoleBracket . IO.hPrint h
+ src/HaskellWorks/CabalCache/IO/Error.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE FlexibleContexts #-}++module HaskellWorks.CabalCache.IO.Error+  ( exceptFatal+  , exceptWarn+  , maybeToExcept+  , maybeToExceptM+  ) where++import Control.Monad.Except+import Control.Monad.IO.Class++import qualified Data.Text                          as T+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified System.Exit                        as IO+import qualified System.IO                          as IO++exceptFatal :: MonadIO m => ExceptT String m a -> ExceptT String m a+exceptFatal f = catchError f handler+  where handler e = do+          liftIO . CIO.hPutStrLn IO.stderr . T.pack $ "Fatal Error: " <> e+          liftIO IO.exitFailure+          throwError e++exceptWarn :: MonadIO m => ExceptT String m a -> ExceptT String m a+exceptWarn f = catchError f handler+  where handler e = do+          liftIO . CIO.hPutStrLn IO.stderr . T.pack $ "Warning: " <> e+          throwError e++maybeToExcept :: Monad m => String -> Maybe a -> ExceptT String m a+maybeToExcept message = maybe (throwError message) pure++maybeToExceptM :: Monad m => String -> m (Maybe a) -> ExceptT String m a+maybeToExceptM message = ExceptT . fmap (maybe (Left message) Right)
+ src/HaskellWorks/CabalCache/IO/File.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE OverloadedStrings #-}++module HaskellWorks.CabalCache.IO.File+  ( copyDirectoryRecursive+  , listMaybeDirectory+  ) where++import Control.Monad.Except+import Control.Monad.IO.Class++import qualified Data.Text                          as T+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified System.Directory                   as IO+import qualified System.Exit                        as IO+import qualified System.IO                          as IO+import qualified System.Process                     as IO++copyDirectoryRecursive :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()+copyDirectoryRecursive source target = do+  CIO.putStrLn $ "Copying recursively from " <> T.pack source <> " to " <> T.pack target+  process <- liftIO $ IO.spawnProcess "cp" ["-r", source, target]+  exitCode <- liftIO $ IO.waitForProcess process+  case exitCode of+    IO.ExitSuccess   -> return ()+    IO.ExitFailure n -> throwError ""++listMaybeDirectory :: MonadIO m => FilePath -> ExceptT String m [FilePath]+listMaybeDirectory filepath = do+  exists <- liftIO $ IO.doesDirectoryExist filepath+  if exists+    then liftIO $ IO.listDirectory filepath+    else return []
+ src/HaskellWorks/CabalCache/IO/Lazy.hs view
@@ -0,0 +1,141 @@+{-# LANGUAGE LambdaCase          #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}+module HaskellWorks.CabalCache.IO.Lazy+  ( readResource+  , resourceExists+  , firstExistingResource+  , headS3Uri+  , writeResource+  , createLocalDirectoryIfMissing+  , linkOrCopyResource+  ) where++import Antiope.Core+import Antiope.S3.Lazy+import Control.Lens+import Control.Monad                    (void)+import Control.Monad.Catch+import Control.Monad.Except+import Control.Monad.IO.Class+import Control.Monad.Trans.Resource+import Data.Conduit.Lazy                (lazyConsume)+import Data.Either                      (isRight)+import Data.Text                        (Text)+import HaskellWorks.CabalCache.Location (Location (..))+import HaskellWorks.CabalCache.Show+import Network.AWS                      (MonadAWS, chunkedFile)+import Network.AWS.Data.Body            (_streamBody)++import qualified Antiope.S3.Lazy                    as AWS+import qualified Antiope.S3.Types                   as AWS+import qualified Control.Concurrent                 as IO+import qualified Data.ByteString.Lazy               as LBS+import qualified Data.Text                          as T+import qualified Data.Text.IO                       as T+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified Network.AWS                        as AWS+import qualified Network.AWS.Data                   as AWS+import qualified Network.AWS.S3.CopyObject          as AWS+import qualified Network.AWS.S3.HeadObject          as AWS+import qualified Network.AWS.S3.PutObject           as AWS+import qualified Network.HTTP.Types                 as HTTP+import qualified System.Directory                   as IO+import qualified System.FilePath.Posix              as FP+import qualified System.IO                          as IO+import qualified System.IO.Error                    as IO++{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}+{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}++readResource :: MonadResource m => AWS.Env -> Location -> m (Maybe LBS.ByteString)+readResource envAws = \case+  S3 s3Uri    -> runAws envAws $ AWS.downloadFromS3Uri s3Uri+  Local path  -> liftIO $ Just <$> LBS.readFile path++safePathIsSymbolLink :: FilePath -> IO Bool+safePathIsSymbolLink filePath = catch (IO.pathIsSymbolicLink filePath) handler+  where handler :: IOError -> IO Bool+        handler e = if IO.isDoesNotExistError e+          then return False+          else return True++resourceExists :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => AWS.Env -> Location -> m Bool+resourceExists envAws = \case+  S3 s3Uri    -> isRight <$> runResourceT (headS3Uri envAws s3Uri)+  Local path  -> do+    fileExists <- liftIO $ IO.doesFileExist path+    if fileExists+      then return True+      else do+        symbolicLinkExists <- liftIO $ safePathIsSymbolLink path+        if symbolicLinkExists+          then do+            target <- liftIO $ IO.getSymbolicLinkTarget path+            resourceExists envAws (Local target)+          else return False++firstExistingResource :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => AWS.Env -> [Location] -> m (Maybe Location)+firstExistingResource envAws [] = return Nothing+firstExistingResource envAws (a:as) = do+  exists <- resourceExists envAws a+  if exists+    then return (Just a)+    else firstExistingResource envAws as++headS3Uri :: (MonadResource m, MonadCatch m) => AWS.Env -> AWS.S3Uri -> m (Either String AWS.HeadObjectResponse)+headS3Uri envAws (AWS.S3Uri b k) =+  catch (Right <$> runAws envAws (AWS.send (AWS.headObject b k))) $ \(e :: AWS.Error) ->+    case e of+      (AWS.ServiceError (AWS.ServiceError' _ (HTTP.Status 404 _) _ _ _ _)) -> return (Left "Not found")+      _                                                                    -> throwM e++chunkSize :: AWS.ChunkSize+chunkSize = AWS.ChunkSize (1024 * 1024)++uploadToS3 :: MonadUnliftIO m => AWS.Env -> AWS.S3Uri -> LBS.ByteString -> m ()+uploadToS3 envAws (AWS.S3Uri b k) lbs = do+  let req = AWS.toBody lbs+  let po  = AWS.putObject b k req+  void $ runResAws envAws $ AWS.send po++writeResource :: MonadUnliftIO m => AWS.Env -> Location -> LBS.ByteString -> m ()+writeResource envAws loc lbs = case loc of+  S3 s3Uri   -> uploadToS3 envAws s3Uri lbs+  Local path -> liftIO $ LBS.writeFile path lbs++createLocalDirectoryIfMissing :: (MonadCatch m, MonadIO m) => Location -> m ()+createLocalDirectoryIfMissing = \case+  S3 s3Uri   -> return ()+  Local path -> liftIO $ IO.createDirectoryIfMissing True path++copyS3Uri :: MonadUnliftIO m => AWS.Env -> AWS.S3Uri -> AWS.S3Uri -> ExceptT String m ()+copyS3Uri envAws (AWS.S3Uri sourceBucket sourceObjectKey) (AWS.S3Uri targetBucket targetObjectKey) = ExceptT $ do+  response <- runResourceT $ runAws envAws $ AWS.send (AWS.copyObject targetBucket (toText sourceBucket <> "/" <> toText sourceObjectKey) targetObjectKey)+  let responseCode = response ^. AWS.corsResponseStatus+  if 200 <= responseCode && responseCode < 300+    then return (Right ())+    else do+      liftIO $ CIO.hPutStrLn IO.stderr $ "Error in S3 copy: " <> tshow response+      return (Left "")++retry :: MonadIO m => Int -> ExceptT String m () -> ExceptT String m ()+retry n f = catchError f $ \e -> if n > 0+  then do+    liftIO $ CIO.hPutStrLn IO.stderr $ "WARNING: " <> T.pack e <> " (retrying)"+    liftIO $ IO.threadDelay 1000000+    retry (n - 1) f+  else throwError e++linkOrCopyResource :: MonadUnliftIO m => AWS.Env -> Location -> Location -> ExceptT String m ()+linkOrCopyResource envAws source target = case source of+  S3 sourceS3Uri -> case target of+    S3 targetS3Uri -> retry 3 (copyS3Uri envAws sourceS3Uri targetS3Uri)+    Local _        -> throwError "Can't copy between different file backends"+  Local sourcePath -> case target of+    S3 _             -> throwError "Can't copy between different file backends"+    Local targetPath -> do+      liftIO $ IO.createDirectoryIfMissing True (FP.takeDirectory targetPath)+      targetPathExists <- liftIO $ IO.doesFileExist targetPath+      unless targetPathExists $ liftIO $ IO.createFileLink sourcePath targetPath
+ src/HaskellWorks/CabalCache/IO/Tar.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE DeriveAnyClass    #-}+{-# LANGUAGE DeriveGeneric     #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications  #-}++module HaskellWorks.CabalCache.IO.Tar+  ( TarGroup(..)+  , createTar+  , extractTar+  ) where++import Control.DeepSeq              (NFData)+import Control.Lens+import Control.Monad.Except+import Control.Monad.IO.Class       (MonadIO, liftIO)+import Data.Generics.Product.Any+import Data.List+import GHC.Generics+import HaskellWorks.CabalCache.Show++import qualified Data.Text                          as T+import qualified HaskellWorks.CabalCache.IO.Console as CIO+import qualified System.Exit                        as IO+import qualified System.IO                          as IO+import qualified System.Process                     as IO++data TarGroup = TarGroup+  { basePath   :: FilePath+  , entryPaths :: [FilePath]+  } deriving (Show, Eq, Generic, NFData)++createTar :: MonadIO m => FilePath -> [TarGroup] -> ExceptT String m ()+createTar tarFile groups = do+  let args = ["-zcf", tarFile] <> foldMap tarGroupToArgs groups+  process <- liftIO $ IO.spawnProcess "tar" args+  exitCode <- liftIO $ IO.waitForProcess process+  case exitCode of+    IO.ExitSuccess   -> return ()+    IO.ExitFailure n -> throwError ""++extractTar :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()+extractTar tarFile targetPath = do+  process <- liftIO $ IO.spawnProcess "tar" ["-C", targetPath, "-zxf", tarFile]+  exitCode <- liftIO $ IO.waitForProcess process+  case exitCode of+    IO.ExitSuccess   -> return ()+    IO.ExitFailure n -> throwError ""++tarGroupToArgs :: TarGroup -> [String]+tarGroupToArgs tarGroup = ["-C", tarGroup ^. the @"basePath"] <> tarGroup ^. the @"entryPaths"
+ src/HaskellWorks/CabalCache/Location.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE DeriveGeneric          #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiWayIf             #-}+{-# LANGUAGE OverloadedStrings      #-}+{-# LANGUAGE TypeFamilies           #-}+module HaskellWorks.CabalCache.Location+( IsPath(..)+, Location(..)+, toLocation+)+where++import Antiope.Core (ToText (..), fromText)+import Antiope.S3   (BucketName, ObjectKey (..), S3Uri (..))+import Data.Maybe   (fromMaybe)+import Data.Text    (Text)+import GHC.Generics (Generic)++import qualified Data.Text       as Text+import qualified System.FilePath as FP++class IsPath a s | a -> s where+  (</>) :: a -> s -> a+  (<.>) :: a -> s -> a++infixr 5 </>+infixr 7 <.>++data Location+  = S3 S3Uri+  | Local FilePath+  deriving (Show, Eq, Generic)++instance ToText Location where+  toText (S3 uri)   = toText uri+  toText (Local p)  = Text.pack p++instance IsPath Location Text where+  (S3 b)    </> p = S3    (b </> p)+  (Local b) </> p = Local (b </> Text.unpack p)++  (S3 b)    <.> e = S3    (b <.> e)+  (Local b) <.> e = Local (b <.> Text.unpack e)++instance IsPath Text Text where+  b </> p = Text.pack (Text.unpack b FP.</> Text.unpack p)+  b <.> e = Text.pack (Text.unpack b FP.<.> Text.unpack e)++instance (a ~ Char) => IsPath [a] [a] where+  b </> p = b FP.</> p+  b <.> e = b FP.<.> e++instance IsPath S3Uri Text where+  S3Uri b (ObjectKey k) </> p =+    S3Uri b (ObjectKey (stripEnd "/" k <> "/" <> stripStart "/" p))++  S3Uri b (ObjectKey k) <.> e =+    S3Uri b (ObjectKey (stripEnd "." k <> "." <> stripStart "." e))++toLocation :: Text -> Maybe Location+toLocation txt = if+  | Text.isPrefixOf "s3://" txt'    -> either (const Nothing) (Just . S3) (fromText txt')+  | Text.isPrefixOf "file://" txt'  -> Just (Local (Text.unpack txt'))+  | Text.isInfixOf  "://" txt'      -> Nothing+  | otherwise                       -> Just (Local (Text.unpack txt'))+  where+    txt' = Text.strip txt++-------------------------------------------------------------------------------+stripStart :: Text -> Text -> Text+stripStart what txt = fromMaybe txt (Text.stripPrefix what txt)++stripEnd :: Text -> Text -> Text+stripEnd what txt = fromMaybe txt (Text.stripSuffix what txt)
+ src/HaskellWorks/CabalCache/Metadata.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE TupleSections #-}++module HaskellWorks.CabalCache.Metadata where++import Control.Lens                   ((<&>))+import Control.Monad                  (forM_)+import Control.Monad.IO.Class         (MonadIO, liftIO)+import HaskellWorks.CabalCache.Core   (PackageInfo (..))+import HaskellWorks.CabalCache.IO.Tar (TarGroup (..))+import System.FilePath                (makeRelative, takeFileName, (<.>), (</>))++import qualified Data.ByteString.Lazy as LBS+import qualified Data.Map.Strict      as Map+import qualified Data.Text            as T+import qualified System.Directory     as IO++metaDir :: String+metaDir = "_CC_METADATA"++createMetadata :: MonadIO m => FilePath -> PackageInfo -> [(T.Text, LBS.ByteString)] -> m TarGroup+createMetadata storePath pkg values = liftIO $ do+  let pkgMetaPath = storePath </> packageDir pkg </> metaDir+  IO.createDirectoryIfMissing True pkgMetaPath+  forM_ values $ \(k, v) -> LBS.writeFile (pkgMetaPath </> T.unpack k) v+  pure $ TarGroup storePath [packageDir pkg </> metaDir]++loadMetadata :: MonadIO m => FilePath -> m (Map.Map T.Text LBS.ByteString)+loadMetadata pkgStorePath = liftIO $ do+  let pkgMetaPath = pkgStorePath </> metaDir+  exists <- IO.doesDirectoryExist pkgMetaPath+  if not exists+    then pure Map.empty+    else IO.listDirectory pkgMetaPath+          <&> fmap (pkgMetaPath </>)+          >>= traverse (\mfile -> (T.pack (takeFileName mfile),) <$> LBS.readFile mfile)+          <&> Map.fromList++deleteMetadata :: MonadIO m => FilePath -> m ()+deleteMetadata pkgStorePath =+  liftIO $ IO.removeDirectoryRecursive (pkgStorePath </> metaDir)
+ src/HaskellWorks/CabalCache/Options.hs view
@@ -0,0 +1,14 @@+module HaskellWorks.CabalCache.Options+  ( readOrFromTextOption+  ) where++import Network.AWS.Data.Text (FromText (..), fromText)+import Options.Applicative   hiding (columns)+import Text.Read             (readEither)++import qualified Data.Text as T++readOrFromTextOption :: (Read a, FromText a) => Mod OptionFields a -> Parser a+readOrFromTextOption =+  let fromStr s = readEither s <|> fromText (T.pack s)+  in option $ eitherReader fromStr
+ src/HaskellWorks/CabalCache/Show.hs view
@@ -0,0 +1,10 @@+module HaskellWorks.CabalCache.Show+  ( tshow+  ) where++import Data.Text (Text)++import qualified Data.Text as T++tshow :: Show a => a -> Text+tshow = T.pack . show
+ src/HaskellWorks/CabalCache/Text.hs view
@@ -0,0 +1,11 @@+module HaskellWorks.CabalCache.Text+  ( maybeStripPrefix+  ) where++import Data.Maybe+import Data.Text  (Text)++import qualified Data.Text as T++maybeStripPrefix :: Text -> Text -> Text+maybeStripPrefix prefix text = fromMaybe text (T.stripPrefix prefix text)
+ src/HaskellWorks/CabalCache/Types.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings     #-}++module HaskellWorks.CabalCache.Types where++import Data.Aeson+import Data.Text    (Text)+import GHC.Generics++type PackageId = Text++data PlanJson = PlanJson+  { compilerId  :: Text+  , installPlan :: [Package]+  } deriving (Eq, Show, Generic)++data Package = Package+  { packageType   :: Text+  , id            :: Text+  , name          :: Text+  , version       :: Text+  , style         :: Maybe Text+  , componentName :: Maybe Text+  , depends       :: Maybe [PackageId]+  } deriving (Eq, Show, Generic)++instance FromJSON PlanJson where+  parseJSON = withObject "PlanJson" $ \v -> PlanJson+    <$> v .: "compiler-id"+    <*> v .: "install-plan"++instance FromJSON Package where+  parseJSON = withObject "Package" $ \v -> Package+    <$> v .:  "type"+    <*> v .:  "id"+    <*> v .:  "pkg-name"+    <*> v .:  "pkg-version"+    <*> v .:? "style"+    <*> v .:? "component-name"+    <*> v .:? "depends"
+ src/HaskellWorks/CabalCache/Version.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE OverloadedStrings #-}++module HaskellWorks.CabalCache.Version where++import Data.String++archiveVersion :: IsString s => s+archiveVersion = "v1"
− src/HaskellWorks/Ci/Assist/Core.hs
@@ -1,102 +0,0 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DeriveAnyClass        #-}-{-# LANGUAGE DeriveGeneric         #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE TypeApplications      #-}-module HaskellWorks.Ci.Assist.Core-  ( PackageInfo(..)-  , Tagged(..)-  , Presence(..)-  , getPackages-  , relativePaths-  , loadPlan-  ) where--import Control.DeepSeq           (NFData)-import Control.Lens              hiding ((<.>))-import Control.Monad             (forM)-import Data.Aeson                (eitherDecode)-import Data.Bool                 (bool)-import Data.Generics.Product.Any (the)-import Data.Maybe                (maybeToList)-import Data.Semigroup            ((<>))-import Data.Text                 (Text)-import GHC.Generics              (Generic)-import System.FilePath           ((<.>), (</>))--import qualified Data.ByteString.Lazy          as LBS-import qualified Data.List                     as List-import qualified Data.Text                     as T-import qualified HaskellWorks.Ci.Assist.IO.Tar as IO-import qualified HaskellWorks.Ci.Assist.Types  as Z-import qualified System.Directory              as IO--type CompilerId = Text-type PackageId  = Text-type PackageDir = FilePath-type ConfPath   = FilePath-type Library    = FilePath--data Presence   = Present | Absent deriving (Eq, Show, NFData, Generic)--data Tagged a t = Tagged-  { value :: a-  , tag   :: t-  } deriving (Eq, Show, Generic, NFData)--data PackageInfo = PackageInfo-  { compilerId :: CompilerId-  , packageId  :: PackageId-  , packageDir :: PackageDir-  , confPath   :: Tagged ConfPath Presence-  , libs       :: [Library]-  } deriving (Show, Eq, Generic, NFData)--relativePaths :: FilePath -> PackageInfo -> [IO.TarGroup]-relativePaths basePath pInfo =-  [ IO.TarGroup basePath $ mempty-      <> (pInfo ^. the @"libs")-      <> [packageDir pInfo]-  , IO.TarGroup basePath $ mempty-      <> ([pInfo ^. the @"confPath"] & filter ((== Present) . (^. the @"tag")) <&> (^. the @"value"))-  ]--getPackages :: FilePath -> Z.PlanJson -> IO [PackageInfo]-getPackages basePath planJson = forM packages (mkPackageInfo basePath compilerId)-  where compilerId :: Text-        compilerId = planJson ^. the @"compilerId"-        packages :: [Z.Package]-        packages = planJson ^.. the @"installPlan" . each . filtered predicate-        predicate :: Z.Package -> Bool-        predicate package = package ^. the @"packageType" /= "pre-existing" && package ^. the @"style" == Just "global"--loadPlan :: IO (Either String Z.PlanJson)-loadPlan =-  eitherDecode <$> LBS.readFile ("dist-newstyle" </> "cache" </> "plan.json")----------------------------------------------------------------------------------mkPackageInfo :: FilePath -> CompilerId -> Z.Package -> IO PackageInfo-mkPackageInfo basePath cid pkg = do-  let pid               = pkg ^. the @"id"-  let compilerPath      = basePath </> T.unpack cid-  let relativeConfPath  = T.unpack cid </> "package.db" </> T.unpack pid <.> ".conf"-  let absoluteConfPath  = basePath </> relativeConfPath-  let libPath           = compilerPath </> "lib"-  let relativeLibPath   = T.unpack cid </> "lib"-  let libPrefix         = "libHS" <> pid-  absoluteConfPathExists <- IO.doesFileExist absoluteConfPath-  libPathExists <- IO.doesDirectoryExist libPath-  libFiles <- getLibFiles relativeLibPath libPath libPrefix-  return PackageInfo-    { compilerId  = cid-    , packageId   = pid-    , packageDir  = T.unpack cid </> T.unpack pid-    , confPath    = Tagged relativeConfPath (bool Absent Present absoluteConfPathExists)-    , libs        = libFiles-    }--getLibFiles :: FilePath -> FilePath -> Text -> IO [Library]-getLibFiles relativeLibPath libPath libPrefix =-  fmap (relativeLibPath </>) . filter (List.isPrefixOf (T.unpack libPrefix)) <$> IO.listDirectory libPath
− src/HaskellWorks/Ci/Assist/GhcPkg.hs
@@ -1,28 +0,0 @@-module HaskellWorks.Ci.Assist.GhcPkg-where--import Data.Text      (Text)-import System.Exit    (ExitCode (..), exitWith)-import System.Process (spawnProcess, waitForProcess)--import qualified Data.Text as Text-import qualified System.IO as IO--runGhcPkg :: [String] -> IO ()-runGhcPkg params = do-  hGhcPkg2 <- spawnProcess "ghc-pkg" params-  exitCodeGhcPkg2 <- waitForProcess hGhcPkg2-  case exitCodeGhcPkg2 of-    ExitFailure _ -> do-      IO.hPutStrLn IO.stderr "ERROR: Unable to recache package db"-      exitWith (ExitFailure 1)-    _ -> return ()--testAvailability :: IO ()-testAvailability = runGhcPkg ["--version"]--recache :: FilePath -> IO ()-recache packageDb = runGhcPkg ["recache", "--package-db", packageDb]--init :: FilePath -> IO ()-init packageDb = runGhcPkg ["init", packageDb]
− src/HaskellWorks/Ci/Assist/Hash.hs
@@ -1,10 +0,0 @@-module HaskellWorks.Ci.Assist.Hash-  ( hashStorePath-  ) where--import qualified Crypto.Hash        as CH-import qualified Data.Text          as T-import qualified Data.Text.Encoding as T--hashStorePath :: String -> String-hashStorePath = take 10 . show . CH.hashWith CH.SHA256 . T.encodeUtf8 . T.pack
− src/HaskellWorks/Ci/Assist/IO/Console.hs
@@ -1,36 +0,0 @@-module HaskellWorks.Ci.Assist.IO.Console-  ( putStrLn-  , print-  , hPutStrLn-  , hPrint-  ) where--import Control.Exception      (bracket_)-import Control.Monad.IO.Class (MonadIO, liftIO)-import Data.Text              (Text)-import Prelude                (IO, Show (..), ($), (.))--import qualified Control.Concurrent.QSem as IO-import qualified Data.Text               as T-import qualified Data.Text.IO            as T-import qualified System.IO               as IO-import qualified System.IO.Unsafe        as IO--sem :: IO.QSem-sem = IO.unsafePerformIO $ IO.newQSem 1-{-# NOINLINE sem #-}--consoleBracket :: IO a -> IO a-consoleBracket = bracket_ (IO.waitQSem sem) (IO.signalQSem sem)--putStrLn :: MonadIO m => Text -> m ()-putStrLn = liftIO . consoleBracket . T.putStrLn--print :: (MonadIO m, Show a) => a -> m ()-print = liftIO . consoleBracket . IO.print--hPutStrLn :: MonadIO m => IO.Handle -> Text -> m ()-hPutStrLn h = liftIO . consoleBracket . T.hPutStrLn h--hPrint :: (MonadIO m, Show a) => IO.Handle -> a -> m ()-hPrint h = liftIO . consoleBracket . IO.hPrint h
− src/HaskellWorks/Ci/Assist/IO/Error.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}--module HaskellWorks.Ci.Assist.IO.Error-  ( exceptFatal-  , exceptWarn-  , maybeToExcept-  , maybeToExceptM-  ) where--import Control.Monad.Except-import Control.Monad.IO.Class--import qualified Data.Text                         as T-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO-import qualified System.Exit                       as IO-import qualified System.IO                         as IO--exceptFatal :: MonadIO m => ExceptT String m a -> ExceptT String m a-exceptFatal f = catchError f handler-  where handler e = do-          liftIO . CIO.hPutStrLn IO.stderr . T.pack $ "Fatal Error: " <> e-          liftIO IO.exitFailure-          throwError e--exceptWarn :: MonadIO m => ExceptT String m a -> ExceptT String m a-exceptWarn f = catchError f handler-  where handler e = do-          liftIO . CIO.hPutStrLn IO.stderr . T.pack $ "Warning: " <> e-          throwError e--maybeToExcept :: Monad m => String -> Maybe a -> ExceptT String m a-maybeToExcept message = maybe (throwError message) pure--maybeToExceptM :: Monad m => String -> m (Maybe a) -> ExceptT String m a-maybeToExceptM message = ExceptT . fmap (maybe (Left message) Right)
− src/HaskellWorks/Ci/Assist/IO/File.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module HaskellWorks.Ci.Assist.IO.File-  ( copyDirectoryRecursive-  , listMaybeDirectory-  ) where--import Control.Monad.Except-import Control.Monad.IO.Class--import qualified Data.Text                         as T-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO-import qualified System.Directory                  as IO-import qualified System.Exit                       as IO-import qualified System.IO                         as IO-import qualified System.Process                    as IO--copyDirectoryRecursive :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()-copyDirectoryRecursive source target = do-  CIO.putStrLn $ "Copying recursively from " <> T.pack source <> " to " <> T.pack target-  process <- liftIO $ IO.spawnProcess "cp" ["-r", source, target]-  exitCode <- liftIO $ IO.waitForProcess process-  case exitCode of-    IO.ExitSuccess   -> return ()-    IO.ExitFailure n -> throwError ""--listMaybeDirectory :: MonadIO m => FilePath -> ExceptT String m [FilePath]-listMaybeDirectory filepath = do-  exists <- liftIO $ IO.doesDirectoryExist filepath-  if exists-    then liftIO $ IO.listDirectory filepath-    else return []
− src/HaskellWorks/Ci/Assist/IO/Lazy.hs
@@ -1,139 +0,0 @@-{-# LANGUAGE LambdaCase          #-}-{-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE ScopedTypeVariables #-}-module HaskellWorks.Ci.Assist.IO.Lazy-  ( readResource-  , resourceExists-  , firstExistingResource-  , headS3Uri-  , writeResource-  , createLocalDirectoryIfMissing-  , linkOrCopyResource-  ) where--import Antiope.Core-import Antiope.S3.Lazy-import Control.Lens-import Control.Monad                   (void)-import Control.Monad.Catch-import Control.Monad.Except-import Control.Monad.IO.Class-import Control.Monad.Trans.Resource-import Data.Conduit.Lazy               (lazyConsume)-import Data.Either                     (isRight)-import Data.Text                       (Text)-import HaskellWorks.Ci.Assist.Location (Location (..))-import HaskellWorks.Ci.Assist.Show-import Network.AWS                     (MonadAWS, chunkedFile)-import Network.AWS.Data.Body           (_streamBody)--import qualified Antiope.S3.Lazy                   as AWS-import qualified Antiope.S3.Types                  as AWS-import qualified Control.Concurrent                as IO-import qualified Data.ByteString.Lazy              as LBS-import qualified Data.Text                         as T-import qualified Data.Text.IO                      as T-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO-import qualified Network.AWS                       as AWS-import qualified Network.AWS.Data                  as AWS-import qualified Network.AWS.S3.CopyObject         as AWS-import qualified Network.AWS.S3.HeadObject         as AWS-import qualified Network.AWS.S3.PutObject          as AWS-import qualified Network.HTTP.Types                as HTTP-import qualified System.Directory                  as IO-import qualified System.FilePath.Posix             as FP-import qualified System.IO                         as IO-import qualified System.IO.Error                   as IO--{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}-{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}-{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}--readResource :: MonadResource m => AWS.Env -> Location -> m (Maybe LBS.ByteString)-readResource envAws = \case-  S3 s3Uri    -> runAws envAws $ AWS.downloadFromS3Uri s3Uri-  Local path  -> liftIO $ Just <$> LBS.readFile path--safePathIsSymbolLink :: FilePath -> IO Bool-safePathIsSymbolLink filePath = catch (IO.pathIsSymbolicLink filePath) handler-  where handler :: IOError -> IO Bool-        handler e = if IO.isDoesNotExistError e-          then return False-          else return True--resourceExists :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => AWS.Env -> Location -> m Bool-resourceExists envAws = \case-  S3 s3Uri    -> isRight <$> runResourceT (headS3Uri envAws s3Uri)-  Local path  -> do-    fileExists <- liftIO $ IO.doesFileExist path-    if fileExists-      then return True-      else do-        symbolicLinkExists <- liftIO $ safePathIsSymbolLink path-        if symbolicLinkExists-          then do-            target <- liftIO $ IO.getSymbolicLinkTarget path-            resourceExists envAws (Local target)-          else return False--firstExistingResource :: (MonadUnliftIO m, MonadCatch m, MonadIO m) => AWS.Env -> [Location] -> m (Maybe Location)-firstExistingResource envAws [] = return Nothing-firstExistingResource envAws (a:as) = do-  exists <- resourceExists envAws a-  if exists-    then return (Just a)-    else firstExistingResource envAws as--headS3Uri :: (MonadResource m, MonadCatch m) => AWS.Env -> AWS.S3Uri -> m (Either String AWS.HeadObjectResponse)-headS3Uri envAws (AWS.S3Uri b k) =-  catch (Right <$> runAws envAws (AWS.send (AWS.headObject b k))) $ \(e :: AWS.Error) ->-    case e of-      (AWS.ServiceError (AWS.ServiceError' _ (HTTP.Status 404 _) _ _ _ _)) -> return (Left "Not found")-      _                                                                    -> throwM e--chunkSize :: AWS.ChunkSize-chunkSize = AWS.ChunkSize (1024 * 1024)--uploadToS3 :: MonadUnliftIO m => AWS.Env -> AWS.S3Uri -> LBS.ByteString -> m ()-uploadToS3 envAws (AWS.S3Uri b k) lbs = do-  let req = AWS.toBody lbs-  let po  = AWS.putObject b k req-  void $ runResAws envAws $ AWS.send po--writeResource :: MonadUnliftIO m => AWS.Env -> Location -> LBS.ByteString -> m ()-writeResource envAws loc lbs = case loc of-  S3 s3Uri   -> uploadToS3 envAws s3Uri lbs-  Local path -> liftIO $ LBS.writeFile path lbs--createLocalDirectoryIfMissing :: (MonadCatch m, MonadIO m) => Location -> m ()-createLocalDirectoryIfMissing = \case-  S3 s3Uri   -> return ()-  Local path -> liftIO $ IO.createDirectoryIfMissing True path--copyS3Uri :: MonadUnliftIO m => AWS.Env -> AWS.S3Uri -> AWS.S3Uri -> ExceptT String m ()-copyS3Uri envAws (AWS.S3Uri sourceBucket sourceObjectKey) (AWS.S3Uri targetBucket targetObjectKey) = ExceptT $ do-  response <- runResourceT $ runAws envAws $ AWS.send (AWS.copyObject targetBucket (toText sourceBucket <> "/" <> toText sourceObjectKey) targetObjectKey)-  let responseCode = response ^. AWS.corsResponseStatus-  if 200 <= responseCode && responseCode < 300-    then return (Right ())-    else return (Left "")--retry :: MonadIO m => Int -> ExceptT String m () -> ExceptT String m ()-retry n f = catchError f $ \e -> if n > 0-  then do-    liftIO $ CIO.hPutStrLn IO.stderr $ "WARNING: " <> T.pack e <> " (retrying)"-    liftIO $ IO.threadDelay 1000000-    retry (n - 1) f-  else throwError e--linkOrCopyResource :: MonadUnliftIO m => AWS.Env -> Location -> Location -> ExceptT String m ()-linkOrCopyResource envAws source target = case source of-  S3 sourceS3Uri -> case target of-    S3 targetS3Uri -> retry 3 (copyS3Uri envAws sourceS3Uri targetS3Uri)-    Local _        -> throwError "Can't copy between different file backends"-  Local sourcePath -> case target of-    S3 _             -> throwError "Can't copy between different file backends"-    Local targetPath -> do-      liftIO $ IO.createDirectoryIfMissing True (FP.takeDirectory targetPath)-      targetPathExists <- liftIO $ IO.doesFileExist targetPath-      unless targetPathExists $ liftIO $ IO.createFileLink sourcePath targetPath
− src/HaskellWorks/Ci/Assist/IO/Tar.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE DeriveAnyClass    #-}-{-# LANGUAGE DeriveGeneric     #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications  #-}--module HaskellWorks.Ci.Assist.IO.Tar-  ( TarGroup(..)-  , createTar-  , extractTar-  ) where--import Control.DeepSeq             (NFData)-import Control.Lens-import Control.Monad.Except-import Control.Monad.IO.Class      (MonadIO, liftIO)-import Data.Generics.Product.Any-import Data.List-import GHC.Generics-import HaskellWorks.Ci.Assist.Show--import qualified Data.Text                         as T-import qualified HaskellWorks.Ci.Assist.IO.Console as CIO-import qualified System.Exit                       as IO-import qualified System.IO                         as IO-import qualified System.Process                    as IO--data TarGroup = TarGroup-  { basePath   :: FilePath-  , entryPaths :: [FilePath]-  } deriving (Show, Eq, Generic, NFData)--createTar :: MonadIO m => FilePath -> [TarGroup] -> ExceptT String m ()-createTar tarFile groups = do-  let args = ["-zcf", tarFile] <> foldMap tarGroupToArgs groups-  process <- liftIO $ IO.spawnProcess "tar" args-  exitCode <- liftIO $ IO.waitForProcess process-  case exitCode of-    IO.ExitSuccess   -> return ()-    IO.ExitFailure n -> throwError ""--extractTar :: MonadIO m => FilePath -> FilePath -> ExceptT String m ()-extractTar tarFile targetPath = do-  process <- liftIO $ IO.spawnProcess "tar" ["-C", targetPath, "-zxf", tarFile]-  exitCode <- liftIO $ IO.waitForProcess process-  case exitCode of-    IO.ExitSuccess   -> return ()-    IO.ExitFailure n -> throwError ""--tarGroupToArgs :: TarGroup -> [String]-tarGroupToArgs tarGroup = ["-C", tarGroup ^. the @"basePath"] <> tarGroup ^. the @"entryPaths"
− src/HaskellWorks/Ci/Assist/Location.hs
@@ -1,74 +0,0 @@-{-# LANGUAGE DeriveGeneric          #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiWayIf             #-}-{-# LANGUAGE OverloadedStrings      #-}-{-# LANGUAGE TypeFamilies           #-}-module HaskellWorks.Ci.Assist.Location-( IsPath(..)-, Location(..)-, toLocation-)-where--import Antiope.Core (ToText (..), fromText)-import Antiope.S3   (BucketName, ObjectKey (..), S3Uri (..))-import Data.Maybe   (fromMaybe)-import Data.Text    (Text)-import GHC.Generics (Generic)--import qualified Data.Text       as Text-import qualified System.FilePath as FP--class IsPath a s | a -> s where-  (</>) :: a -> s -> a-  (<.>) :: a -> s -> a--infixr 5 </>-infixr 7 <.>--data Location-  = S3 S3Uri-  | Local FilePath-  deriving (Show, Eq, Generic)--instance ToText Location where-  toText (S3 uri)   = toText uri-  toText (Local p)  = Text.pack p--instance IsPath Location Text where-  (S3 b)    </> p = S3    (b </> p)-  (Local b) </> p = Local (b </> Text.unpack p)--  (S3 b)    <.> e = S3    (b <.> e)-  (Local b) <.> e = Local (b <.> Text.unpack e)--instance IsPath Text Text where-  b </> p = Text.pack (Text.unpack b FP.</> Text.unpack p)-  b <.> e = Text.pack (Text.unpack b FP.<.> Text.unpack e)--instance (a ~ Char) => IsPath [a] [a] where-  b </> p = b FP.</> p-  b <.> e = b FP.<.> e--instance IsPath S3Uri Text where-  S3Uri b (ObjectKey k) </> p =-    S3Uri b (ObjectKey (stripEnd "/" k <> "/" <> stripStart "/" p))--  S3Uri b (ObjectKey k) <.> e =-    S3Uri b (ObjectKey (stripEnd "." k <> "." <> stripStart "." e))--toLocation :: Text -> Maybe Location-toLocation txt = if-  | Text.isPrefixOf "s3://" txt'    -> either (const Nothing) (Just . S3) (fromText txt')-  | Text.isPrefixOf "file://" txt'  -> Just (Local (Text.unpack txt'))-  | Text.isInfixOf  "://" txt'      -> Nothing-  | otherwise                       -> Just (Local (Text.unpack txt'))-  where-    txt' = Text.strip txt----------------------------------------------------------------------------------stripStart :: Text -> Text -> Text-stripStart what txt = fromMaybe txt (Text.stripPrefix what txt)--stripEnd :: Text -> Text -> Text-stripEnd what txt = fromMaybe txt (Text.stripSuffix what txt)
− src/HaskellWorks/Ci/Assist/Metadata.hs
@@ -1,40 +0,0 @@-{-# LANGUAGE TupleSections #-}-module HaskellWorks.Ci.Assist.Metadata-where--import Control.Lens                  ((<&>))-import Control.Monad                 (forM_)-import Control.Monad.IO.Class        (MonadIO, liftIO)-import HaskellWorks.Ci.Assist.Core   (PackageInfo (..))-import HaskellWorks.Ci.Assist.IO.Tar (TarGroup (..))-import System.FilePath               (makeRelative, takeFileName, (<.>), (</>))--import qualified Data.ByteString.Lazy as LBS-import qualified Data.Map.Strict      as Map-import qualified Data.Text            as T-import qualified System.Directory     as IO--metaDir :: String-metaDir = "_CC_METADATA"--createMetadata :: MonadIO m => FilePath -> PackageInfo -> [(T.Text, LBS.ByteString)] -> m TarGroup-createMetadata storePath pkg values = liftIO $ do-  let pkgMetaPath = storePath </> packageDir pkg </> metaDir-  IO.createDirectoryIfMissing True pkgMetaPath-  forM_ values $ \(k, v) -> LBS.writeFile (pkgMetaPath </> T.unpack k) v-  pure $ TarGroup storePath [packageDir pkg </> metaDir]--loadMetadata :: MonadIO m => FilePath -> m (Map.Map T.Text LBS.ByteString)-loadMetadata pkgStorePath = liftIO $ do-  let pkgMetaPath = pkgStorePath </> metaDir-  exists <- IO.doesDirectoryExist pkgMetaPath-  if not exists-    then pure Map.empty-    else IO.listDirectory pkgMetaPath-          <&> fmap (pkgMetaPath </>)-          >>= traverse (\mfile -> (T.pack (takeFileName mfile),) <$> LBS.readFile mfile)-          <&> Map.fromList--deleteMetadata :: MonadIO m => FilePath -> m ()-deleteMetadata pkgStorePath =-  liftIO $ IO.removeDirectoryRecursive (pkgStorePath </> metaDir)
− src/HaskellWorks/Ci/Assist/Options.hs
@@ -1,14 +0,0 @@-module HaskellWorks.Ci.Assist.Options-  ( readOrFromTextOption-  ) where--import Network.AWS.Data.Text (FromText (..), fromText)-import Options.Applicative   hiding (columns)-import Text.Read             (readEither)--import qualified Data.Text as T--readOrFromTextOption :: (Read a, FromText a) => Mod OptionFields a -> Parser a-readOrFromTextOption =-  let fromStr s = readEither s <|> fromText (T.pack s)-  in option $ eitherReader fromStr
− src/HaskellWorks/Ci/Assist/Show.hs
@@ -1,10 +0,0 @@-module HaskellWorks.Ci.Assist.Show-  ( tshow-  ) where--import Data.Text (Text)--import qualified Data.Text as T--tshow :: Show a => a -> Text-tshow = T.pack . show
− src/HaskellWorks/Ci/Assist/Text.hs
@@ -1,11 +0,0 @@-module HaskellWorks.Ci.Assist.Text-  ( maybeStripPrefix-  ) where--import Data.Maybe-import Data.Text  (Text)--import qualified Data.Text as T--maybeStripPrefix :: Text -> Text -> Text-maybeStripPrefix prefix text = fromMaybe text (T.stripPrefix prefix text)
− src/HaskellWorks/Ci/Assist/Types.hs
@@ -1,37 +0,0 @@-{-# LANGUAGE DeriveGeneric         #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}--module HaskellWorks.Ci.Assist.Types where--import Data.Aeson-import Data.Text    (Text)-import GHC.Generics--data PlanJson = PlanJson-  { compilerId  :: Text-  , installPlan :: [Package]-  } deriving (Eq, Show, Generic)--data Package = Package-  { packageType   :: Text-  , id            :: Text-  , name          :: Text-  , version       :: Text-  , style         :: Maybe Text-  , componentName :: Maybe Text-  } deriving (Eq, Show, Generic)--instance FromJSON PlanJson where-  parseJSON = withObject "PlanJson" $ \v -> PlanJson-    <$> v .: "compiler-id"-    <*> v .: "install-plan"--instance FromJSON Package where-  parseJSON = withObject "Package" $ \v -> Package-    <$> v .:  "type"-    <*> v .:  "id"-    <*> v .:  "pkg-name"-    <*> v .:  "pkg-version"-    <*> v .:? "style"-    <*> v .:? "component-name"
− src/HaskellWorks/Ci/Assist/Version.hs
@@ -1,8 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module HaskellWorks.Ci.Assist.Version where--import Data.String--archiveVersion :: IsString s => s-archiveVersion = "v1"
− test/HaskellWorks/Assist/AwsSpec.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE OverloadedStrings #-}--module HaskellWorks.Assist.AwsSpec-  ( spec-  ) where--import Antiope.Core-import Antiope.Env-import Control.Lens-import Control.Monad-import Control.Monad.IO.Class-import Data.Generics.Product.Any-import Data.Maybe                     (fromJust, isJust)-import HaskellWorks.Ci.Assist.IO.Lazy-import HaskellWorks.Hspec.Hedgehog-import Hedgehog-import System.Environment             (lookupEnv)-import Test.Hspec-import Text.RawString.QQ--import qualified Antiope.S3.Lazy              as LBS-import qualified Antiope.S3.Types             as AWS-import qualified Data.Aeson                   as A-import qualified Data.ByteString.Lazy         as LBS-import qualified Data.ByteString.Lazy.Char8   as LBSC-import qualified HaskellWorks.Ci.Assist.Types as Z-import qualified System.Environment           as IO--{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}-{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}-{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}--spec :: Spec-spec = describe "HaskellWorks.Assist.QuerySpec" $ do-  it "stub" $ requireTest $ do-    ci <- liftIO $ IO.lookupEnv "CI" <&> isJust-    unless ci $ do-      envAws <- liftIO $ mkEnv Oregon (const LBSC.putStrLn)-      result <- liftIO $ runResourceT $ headS3Uri envAws $ AWS.S3Uri "jky-mayhem" "hjddhd"-      result === Left "Not found"
− test/HaskellWorks/Assist/LocationSpec.hs
@@ -1,67 +0,0 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE OverloadedStrings #-}-module HaskellWorks.Assist.LocationSpec-( spec-) where--import Antiope.Core                    (toText)-import Antiope.S3                      (BucketName (..), ObjectKey (..), S3Uri (..))-import Data.Text                       (Text)-import HaskellWorks.Ci.Assist.Location--import HaskellWorks.Hspec.Hedgehog-import Hedgehog-import Test.Hspec--import qualified Data.List       as List-import qualified Data.Text       as Text-import qualified Hedgehog.Gen    as Gen-import qualified Hedgehog.Range  as Range-import qualified System.FilePath as FP--{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}-{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}-{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}--s3Uri :: MonadGen m => m S3Uri-s3Uri = do-  let partGen = Gen.text (Range.linear 3 10) Gen.alphaNum-  bkt <- partGen-  parts <- Gen.list (Range.linear 1 5) partGen-  ext <- Gen.text (Range.linear 2 4) Gen.alphaNum-  pure $ S3Uri (BucketName bkt) (ObjectKey (Text.intercalate "/" parts <> "." <> ext))--localPath :: MonadGen m => m FilePath-localPath = do-  let partGen = Gen.string (Range.linear 3 10) Gen.alphaNum-  parts <- Gen.list (Range.linear 1 5) partGen-  ext <- Gen.string (Range.linear 2 4) Gen.alphaNum-  pure $ "/" <> List.intercalate "/" parts <> "." <> ext--location :: MonadGen m => m Location-location =-  Gen.choice [S3 <$> s3Uri, Local <$> localPath]--spec :: Spec-spec = describe "HaskellWorks.Assist.LocationSpec" $ do-  it "S3 should roundtrip from and to text" $ require $ property $ do-    uri <- forAll s3Uri-    tripping (S3 uri) toText toLocation--  it "LocalLocation should roundtrip from and to text" $ require $ property $ do-    path <- forAll localPath-    tripping (Local path) toText toLocation--  it "Should append s3 path" $ require $ property $ do-    loc  <- S3 <$> forAll s3Uri-    part <- forAll $ Gen.text (Range.linear 3 10) Gen.alphaNum-    ext  <- forAll $ Gen.text (Range.linear 2 4)  Gen.alphaNum-    toText (loc </> part <.> ext) === (toText loc) <> "/" <> part <> "." <> ext-    toText (loc </> ("/" <> part) <.> ("." <> ext)) === (toText loc) <> "/" <> part <> "." <> ext--  it "Should append s3 path" $ require $ property $ do-    loc  <- Local <$> forAll localPath-    part <- forAll $ Gen.string (Range.linear 3 10) Gen.alphaNum-    ext  <- forAll $ Gen.string (Range.linear 2 4)  Gen.alphaNum-    toText (loc </> Text.pack part <.> Text.pack ext) === Text.pack ((Text.unpack $ toText loc) FP.</> part FP.<.> ext)-
− test/HaskellWorks/Assist/QuerySpec.hs
@@ -1,63 +0,0 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes       #-}--module HaskellWorks.Assist.QuerySpec-  ( spec-  ) where--import Control.Lens-import Data.Generics.Product.Any-import HaskellWorks.Hspec.Hedgehog-import Hedgehog-import Test.Hspec-import Text.RawString.QQ--import qualified Data.Aeson                   as A-import qualified Data.ByteString.Lazy         as LBS-import qualified HaskellWorks.Ci.Assist.Types as Z--{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}-{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}-{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}--spec :: Spec-spec = describe "HaskellWorks.Assist.QuerySpec" $ do-  it "stub" $ requireTest $ do-    let Right planJson = A.eitherDecode exampleJson-    planJson === Z.PlanJson-      { Z.compilerId  = "ghc-8.6.4"-      , Z.installPlan =-        [ Z.Package-          { Z.packageType   = "pre-existing"-          , Z.id            = "Cabal-2.4.0.1"-          , Z.name          = "Cabal"-          , Z.version       = "2.4.0.1"-          , Z.style         = Nothing-          , Z.componentName = Nothing-          }-        ]-      }--exampleJson :: LBS.ByteString-exampleJson = [r|-{-  "cabal-version": "2.4.1.0",-  "cabal-lib-version": "2.4.1.0",-  "compiler-id": "ghc-8.6.4",-  "os": "osx",-  "arch": "x86_64",-  "install-plan": [-    {-      "type": "pre-existing",-      "id": "Cabal-2.4.0.1",-      "pkg-name": "Cabal",-      "pkg-version": "2.4.0.1",-      "depends": [-        "array-0.5.3.0",-        "base-4.12.0.0"-      ]-    }-  ]-}-|]
+ test/HaskellWorks/CabalCache/AwsSpec.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE OverloadedStrings #-}++module HaskellWorks.CabalCache.AwsSpec+  ( spec+  ) where++import Antiope.Core+import Antiope.Env+import Control.Lens+import Control.Monad+import Control.Monad.IO.Class+import Data.Generics.Product.Any+import Data.Maybe                      (fromJust, isJust)+import HaskellWorks.CabalCache.IO.Lazy+import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import System.Environment              (lookupEnv)+import Test.Hspec+import Text.RawString.QQ++import qualified Antiope.S3.Lazy               as LBS+import qualified Antiope.S3.Types              as AWS+import qualified Data.Aeson                    as A+import qualified Data.ByteString.Lazy          as LBS+import qualified Data.ByteString.Lazy.Char8    as LBSC+import qualified HaskellWorks.CabalCache.Types as Z+import qualified System.Environment            as IO++{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}+{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}++spec :: Spec+spec = describe "HaskellWorks.CabalCache.QuerySpec" $ do+  it "stub" $ requireTest $ do+    ci <- liftIO $ IO.lookupEnv "CI" <&> isJust+    unless ci $ do+      envAws <- liftIO $ mkEnv Oregon (const LBSC.putStrLn)+      result <- liftIO $ runResourceT $ headS3Uri envAws $ AWS.S3Uri "jky-mayhem" "hjddhd"+      result === Left "Not found"
+ test/HaskellWorks/CabalCache/Data/RelationSpec.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellWorks.CabalCache.Data.RelationSpec+  ( spec+  ) where++import HaskellWorks.CabalCache.Data.Relation (Relation (Relation))+import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified Data.List                             as L+import qualified Data.Map                              as M+import qualified Data.Set                              as S+import qualified HaskellWorks.CabalCache.Data.Relation as R+import qualified Hedgehog.Gen                          as G+import qualified Hedgehog.Range                        as R++{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}+{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}++spec :: Spec+spec = describe "HaskellWorks.Assist.Data.RelationSpec" $ do+  it "List roundtrip" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    L.sort (R.toList (R.fromList as)) === L.sort as+  it "Full domain restriction" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha++    R.restrictDomain S.empty (R.fromList as) === R.empty+  it "Full range restriction" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha++    R.restrictRange S.empty (R.fromList as) === R.empty+  it "No domain restriction" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    let r = R.fromList as++    R.restrictDomain (R.domain r) r === r+  it "No range restriction" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    let r = R.fromList as+    R.restrictRange (R.range r) r === r+  it "Full domain without" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    let r = R.fromList as+    R.withoutDomain S.empty r === r+  it "Full range without" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    let r = R.fromList as+    R.withoutRange S.empty r === r+  it "No domain without" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    let r = R.fromList as++    R.withoutDomain (R.domain r) r === R.empty+  it "No range without" $ require $ property $ do+    as <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.int R.constantBounded+      <*> G.alpha+    let r = R.fromList as+    R.withoutRange (R.range r) r === R.empty
+ test/HaskellWorks/CabalCache/LocationSpec.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellWorks.CabalCache.LocationSpec+( spec+) where++import Antiope.Core                     (toText)+import Antiope.S3                       (BucketName (..), ObjectKey (..), S3Uri (..))+import Data.Text                        (Text)+import HaskellWorks.CabalCache.Location++import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified Data.List       as List+import qualified Data.Text       as Text+import qualified Hedgehog.Gen    as Gen+import qualified Hedgehog.Range  as Range+import qualified System.FilePath as FP++{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}+{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}++s3Uri :: MonadGen m => m S3Uri+s3Uri = do+  let partGen = Gen.text (Range.linear 3 10) Gen.alphaNum+  bkt <- partGen+  parts <- Gen.list (Range.linear 1 5) partGen+  ext <- Gen.text (Range.linear 2 4) Gen.alphaNum+  pure $ S3Uri (BucketName bkt) (ObjectKey (Text.intercalate "/" parts <> "." <> ext))++localPath :: MonadGen m => m FilePath+localPath = do+  let partGen = Gen.string (Range.linear 3 10) Gen.alphaNum+  parts <- Gen.list (Range.linear 1 5) partGen+  ext <- Gen.string (Range.linear 2 4) Gen.alphaNum+  pure $ "/" <> List.intercalate "/" parts <> "." <> ext++location :: MonadGen m => m Location+location =+  Gen.choice [S3 <$> s3Uri, Local <$> localPath]++spec :: Spec+spec = describe "HaskellWorks.Assist.LocationSpec" $ do+  it "S3 should roundtrip from and to text" $ require $ property $ do+    uri <- forAll s3Uri+    tripping (S3 uri) toText toLocation++  it "LocalLocation should roundtrip from and to text" $ require $ property $ do+    path <- forAll localPath+    tripping (Local path) toText toLocation++  it "Should append s3 path" $ require $ property $ do+    loc  <- S3 <$> forAll s3Uri+    part <- forAll $ Gen.text (Range.linear 3 10) Gen.alphaNum+    ext  <- forAll $ Gen.text (Range.linear 2 4)  Gen.alphaNum+    toText (loc </> part <.> ext) === (toText loc) <> "/" <> part <> "." <> ext+    toText (loc </> ("/" <> part) <.> ("." <> ext)) === (toText loc) <> "/" <> part <> "." <> ext++  it "Should append s3 path" $ require $ property $ do+    loc  <- Local <$> forAll localPath+    part <- forAll $ Gen.string (Range.linear 3 10) Gen.alphaNum+    ext  <- forAll $ Gen.string (Range.linear 2 4)  Gen.alphaNum+    toText (loc </> Text.pack part <.> Text.pack ext) === Text.pack ((Text.unpack $ toText loc) FP.</> part FP.<.> ext)+
+ test/HaskellWorks/CabalCache/QuerySpec.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}++module HaskellWorks.CabalCache.QuerySpec+  ( spec+  ) where++import Control.Lens+import Data.Generics.Product.Any+import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec+import Text.RawString.QQ++import qualified Data.Aeson                    as A+import qualified Data.ByteString.Lazy          as LBS+import qualified HaskellWorks.CabalCache.Types as Z++{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}+{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}++spec :: Spec+spec = describe "HaskellWorks.Assist.QuerySpec" $ do+  it "stub" $ requireTest $ do+    let Right planJson = A.eitherDecode exampleJson+    planJson === Z.PlanJson+      { Z.compilerId  = "ghc-8.6.4"+      , Z.installPlan =+        [ Z.Package+          { Z.packageType   = "pre-existing"+          , Z.id            = "Cabal-2.4.0.1"+          , Z.name          = "Cabal"+          , Z.version       = "2.4.0.1"+          , Z.style         = Nothing+          , Z.componentName = Nothing+          , Z.depends       = Just+            [ "array-0.5.3.0"+            , "base-4.12.0.0"+            ]+          }+        ]+      }++exampleJson :: LBS.ByteString+exampleJson = [r|+{+  "cabal-version": "2.4.1.0",+  "cabal-lib-version": "2.4.1.0",+  "compiler-id": "ghc-8.6.4",+  "os": "osx",+  "arch": "x86_64",+  "install-plan": [+    {+      "type": "pre-existing",+      "id": "Cabal-2.4.0.1",+      "pkg-name": "Cabal",+      "pkg-version": "2.4.0.1",+      "depends": [+        "array-0.5.3.0",+        "base-4.12.0.0"+      ]+    }+  ]+}+|]