packages feed

cabal-flatpak 0.1.2 → 0.1.3

raw patch · 5 files changed

+133/−67 lines, 5 filesdep ~aesondep ~http-client-tls

Dependency ranges changed: aeson, http-client-tls

Files

cabal-flatpak.cabal view
@@ -1,6 +1,6 @@ Cabal-Version:  2.2 Name:           cabal-flatpak-Version:        0.1.2+Version:        0.1.3 License:        BSD-3-Clause License-File:   LICENSE Author:         Henning Thielemann <haskell@henning-thielemann.de>@@ -20,12 +20,14 @@ Build-Type:     Simple Extra-Source-Files:   Makefile+  flatpak.cabal.json++Extra-Doc-Files:   ReadMe.md   Changes.md-  flatpak.cabal.json  Source-Repository this-  Tag:         0.1.2+  Tag:         0.1.3   Type:        darcs   Location:    https://hub.darcs.net/thielema/cabal-flatpak/ @@ -38,20 +40,20 @@     cabal-plan >=0.5 && <0.8,     cryptohash-sha256 >=0.11 && <0.12,     zlib >=0.5.3 && <0.8,-    tar >=0.5.0.3 && <0.7,-    http-client-tls >=0.3.5.3 && <0.4,+    tar >=0.5.0.3 && <0.8,+    http-client-tls >=0.3.5.3 && <0.5,     http-client >=0.5.12 && <0.8,     http-types >=0.10 && <0.13,     aeson-pretty >=0.8.7 && <0.9,-    aeson >=2.0 && <2.3,+    aeson >=2.0 && <2.4,     yaml >=0.11 && <0.12,     shell-utility >=0.1 && <0.2,-    optparse-applicative >=0.11 && <0.19,+    optparse-applicative >=0.11 && <0.20,     pathtype >=0.8 && <0.9,     directory >=1.2.3 && <1.4,     text >=1.2 && <2.2,     bytestring >=0.9 && <0.13,-    containers >=0.5 && <0.8,+    containers >=0.5 && <0.9,     utility-ht >=0.0.12 && <0.1,     base >=4.5 && <5 
src/Flatpak.hs view
@@ -118,6 +118,7 @@       typ :: SourceType,       url :: Maybe String,       destFilename :: Maybe String,+      dest :: Maybe String,       sha256 :: Maybe Plan.Sha256    } deriving (Show) @@ -127,6 +128,7 @@          <*> (parseSourceType o =<< o .: "type")          <*> o .:? ("url", Nothing)          <*> o .:? ("dest-filename", Nothing)+         <*> o .:? ("dest", Nothing)          <*> o .:? ("sha256", Nothing)  instance ToJSON Source where@@ -134,6 +136,7 @@       (pairsFromSourceType . typ) <>       ("url" .=? (url, Nothing)) <>       ("dest-filename" .=? (destFilename, Nothing)) <>+      ("dest" .=? (dest, Nothing)) <>       ("sha256" .=? (sha256, Nothing)) <>       mempty 
src/Generate.hs view
@@ -12,6 +12,7 @@ import qualified Data.Text as Text import Data.Foldable (foldMap) import Data.Map (Map)+import Data.Maybe.HT (toMaybe) import Data.Bool.HT (if')  import Text.Printf (printf)@@ -31,6 +32,9 @@ projectMain project =    (Flatpak.mainPackage project, Flatpak.mainSources project) +projectMainExe :: Flatpak.Cabal -> String+projectMainExe = Flatpak.command . Flatpak.base+ matchName :: String -> Plan.Unit -> Bool matchName expected unit =    case Plan.uPId unit of@@ -109,13 +113,14 @@                   Just $                   ghcDirUrl compiler ++ ghcArchive compiler arch,                Flatpak.destFilename = Nothing,+               Flatpak.dest = Nothing,                Flatpak.sha256 = Just hash              }]       }  type RevisedUnit = (Plan.Unit, Package.Revision) -packageURLs :: RevisedUnit -> (String, String, String)+packageURLs :: RevisedUnit -> (String, String, String, String) packageURLs (pkg, revision) =    let pkgId@(Plan.PkgId (Plan.PkgName name) _version) = Plan.uPId pkg        pkgName = Text.unpack name@@ -124,24 +129,31 @@          pkgNameVer pkgNameVer,        printf "https://hackage.haskell.org/package/%s/revision/%d.cabal"          pkgNameVer revision,+       pkgNameVer,        printf "%s.cabal" pkgName) +reviseToSubdir :: Flatpak.SourceType -> Bool+reviseToSubdir (Flatpak.Archive n) = n == 0+reviseToSubdir _ = False+ packageSources ::    (String, [Flatpak.Source]) -> Flatpak.SourceType ->    RevisedUnit -> [Flatpak.Source] packageSources (mainPkg, mainSrcs) typ pkgRev@(pkg,_) =-   let (pkgUrl, cabalUrl, cabalPath) = packageURLs pkgRev+   let (pkgUrl, cabalUrl, cabalDest, cabalPath) = packageURLs pkgRev    in if' (matchName mainPkg pkg && not (null mainSrcs)) mainSrcs $       Flatpak.Source {          Flatpak.typ = typ,          Flatpak.url = Just pkgUrl,          Flatpak.destFilename = Nothing,+         Flatpak.dest = Nothing,          Flatpak.sha256 = Plan.uSha256 pkg       } :       Flatpak.Source {          Flatpak.typ = Flatpak.File,          Flatpak.url = Just cabalUrl,          Flatpak.destFilename = Just cabalPath,+         Flatpak.dest = toMaybe (reviseToSubdir typ) cabalDest,          Flatpak.sha256 = Plan.uCabalSha256 pkg       } :       []@@ -210,17 +222,17 @@ cabalHash arch =    case arch of       Flatpak.I386 -> Just $-         "b2da736cc27609442b10f77fc1a687aba603a7a33045b722dbf1a0066fade198"+         "c03043d5c9dfed9a1a4c795e4260221986dcdde28a68b909fcf4ccc07d7dd7b5"       Flatpak.X86_64 -> Just $-         "6136c189ffccaa39916f9cb5788f757166444a2d0c473b987856a79ecbf0c714"+         "97e61bcd143f0b8a181ea2261a1de587b58fa9f84d123b9b9cec4463ae2f41c6"       _ -> Nothing  cabalInstallModule :: Flatpak.Arch -> Flatpak.Module cabalInstallModule arch =-   let cabalVerName = "cabal-install-2.4.1.0"+   let cabalVerName = "cabal-install-3.10.3.0"        url =          printf-            "https://downloads.haskell.org/cabal/%s/%s-%s-unknown-linux.tar.xz"+            "https://downloads.haskell.org/cabal/%s/%s-%s-linux-deb9.tar.xz"                cabalVerName cabalVerName (archGHC arch)    in Flatpak.Module {          Flatpak.name = cabalVerName ++ "-" ++ Flatpak.archString arch,@@ -237,28 +249,14 @@                   Flatpak.Archive {Flatpak.stripComponents = 0},                Flatpak.url = Just url,                Flatpak.destFilename = Nothing,+               Flatpak.dest = Nothing,                Flatpak.sha256 = Plan.parseSha256 . Text.pack =<< cabalHash arch              }]       } -reviseCabalScript :: [String]-reviseCabalScript =-   "tarball=\"$1\"" :-   "pkgid=\"$(basename $tarball .tar.gz)\"" :-   "name=\"$(echo $pkgid | sed -r 's:^(.*)-(.*)$:\\1:')\"" :-   "ver=\"$(echo $pkgid | sed -r 's:^(.*)-(.*)$:\\2:')\"" :-   "echo Revising .cabal file for \"$pkgid\"" :-   "gunzip \"$tarball\"" :-   "mkdir \"$pkgid\"" :-   "mv \"$name.cabal\" \"$pkgid\"" :-   "tar rf \"$pkgid.tar\" \"$pkgid/$name.cabal\"" :-   "gzip \"$pkgid.tar\"" :-   []--allInOneModule ::-   (String, [Flatpak.Source]) -> Options -> [String] ->-   [RevisedUnit] -> Flatpak.Module-allInOneModule main (cabalCfgOptions, ghcOptions) postInstall pkgs =+allInOneModule :: Flatpak.Cabal -> [RevisedUnit] -> Flatpak.Module+allInOneModule project pkgs =+   let (cabalCfgOptions, ghcOptions) = projectOptions project in       Flatpak.Module {          Flatpak.name = "haskell-parts",          Flatpak.onlyArches = [],@@ -266,26 +264,21 @@          Flatpak.builddir = False,          Flatpak.configOpts = [],          Flatpak.buildCommands =-            "find . -name '*.tar.gz' | while read pkg; do bash revise.sh \"$pkg\"; done" :             "mkdir .cabal" :             "touch .cabal/config" :-            unwords-               ("cabal --config-file=.cabal/config install" :-                  "-j$FLATPAK_BUILDER_N_JOBS" :-                  "--offline --prefix=/app" :-                  cabalCfgOptions ++ map ghcOption ghcOptions ++-                  ["*.tar.gz"]) :+            "echo 'packages: */' > cabal.project" :+            unwords ("cabal --config-file=.cabal/config -j$FLATPAK_BUILDER_N_JOBS" :+                     "--offline --store-dir /app/cabal" :+                     "--installdir=/app/bin" :+                     ("v2-install exe:" ++ projectMainExe project) :+                     cabalCfgOptions ++ map ghcOption ghcOptions) :             [],-         Flatpak.postInstall = postInstall,+         Flatpak.postInstall =+            concatMap Flatpak.postInstallHook $ Flatpak.packageHooks project,          Flatpak.cleanupModule = [],          Flatpak.sources =-            Flatpak.Source {-               Flatpak.typ = Flatpak.Script reviseCabalScript,-               Flatpak.url = Nothing,-               Flatpak.destFilename = Just "revise.sh",-               Flatpak.sha256 = Nothing-            } :-            concatMap (packageSources main Flatpak.File) pkgs+            concatMap (packageSources (projectMain project) $+                       Flatpak.Archive {Flatpak.stripComponents = 0}) pkgs       }  manifestCabalInstall ::@@ -296,6 +289,12 @@    base {       Flatpak.cleanup =          concatMap (ghcPkgCleanup plan . fst) archs ++ Flatpak.cleanup base,+      Flatpak.cleanupCommands =+         ( "find /app/cabal/ghc-* -mindepth 1 " +++           "\\( \\( -not -path '*/" +++           (fst $ projectMain project) +++           "*' -a -path '*/bin/*' \\) -o -path '*/lib/*' \\) -delete" ) :+         Flatpak.cleanupCommands base,       Flatpak.modules =          (map ModuleEmbed $           concatMap@@ -303,9 +302,6 @@                [ghcModule plan arch ghcHash, cabalInstallModule arch])             archs) ++          Flatpak.modules base ++-         (ModuleEmbed $-          allInOneModule (projectMain project) (projectOptions project)-            (concatMap Flatpak.postInstallHook $ Flatpak.packageHooks project)-            pkgs) :+         (ModuleEmbed $ allInOneModule project pkgs) :          []    }
src/Main.hs view
@@ -21,6 +21,7 @@  import Control.Monad (when) import Control.Applicative ((<$>))+import Control.Arrow ((&&&))  import qualified Data.Aeson as Json import qualified Data.Yaml as Yaml@@ -73,7 +74,70 @@                ++                printf "%s, %s" xdgDir (Path.toString appDir) +{- |+Cabal operates on units.+A package can have multiple units,+for example a library unit and multiple executable units.+Each of those units can have its own set of library and executable dependencies. +However, when downloading packages in Flatpak+we don't differentiate between the units+and treat all units belonging to the same package as one.++The below heuristic+merges all units belonging to the same package into one package+and topologically sorts the packages.++This heuristic can be completely skipped when using the --cabal-install option,+because in this mode all we need to do is to download all necessary packages+in any order and cabal will determine the correct order of the units by itself.++The heuristic goes as follows:++1. Build a map between the unit IDs and the package ID that contains it+2. Get the dependency graph using the cabal-plan API+3. Group all units belonging to the same package+   and merge their dependencies to obtain package dependencies+4. Topologically sort the packages+5. Take one representative unit for each package+   and use them in the flatpak.json generation process.+   This is safe to do as long as the rest of the generator+   uses information that is common to all units in the same package.+   Those are: uPId, uSha256, uCabalSha256 and uType.++In certain situations+this heuristic can still fail to produce a buildable sequence.+For example, we can have two packages as such:+Pkg1@(lib1, exe1) and Pkg2@(lib2)+where the unit lib2 depends on lib1 and exe1 depends on lib2.+Unit-wise, it is possible to sequence the builds of the units+that avoids cyclical dependencies.+But package-wise, it is not possible.+In such cases and in general+it is better to enable the --cabal-install option which avoids this problem.++It is also not possible to use the qualified name of the component+for the 'configure' stage+and build a package in multiple parts in multiple Flatpak modules.+This is because the Plan.uComps is not precise enough,+as the documentation states that in certain situations+that field may contain more than one value.+In that case it is impossible to determine the precise component name.+-}+getSortedUnits :: Plan.PlanJson -> [Plan.Unit]+getSortedUnits plan =+   let+      allUnits = Plan.pjUnits plan+      -- Build a mapping from unit ID to package ID+      unitIdToPkgId unitId = Plan.uPId $ allUnits Map.! unitId+      -- Here we take one representative unit for a given package.+      pkgIdToUnit = Map.fromList $ map (Plan.uPId &&& id) $ Map.elems allUnits+   in filter ((Plan.UnitTypeBuiltin /=) . Plan.uType) $+      map (pkgIdToUnit Map.!) $ topSort $+      -- Merge unit groups into packages, merging their dependencies.+      Map.mapKeysWith Set.union unitIdToPkgId $+      Map.map (Set.map unitIdToPkgId) $ Plan.planJsonIdGraph plan+ main :: IO () main = do    opt <- OP.execParser Option.info@@ -105,17 +169,19 @@     let matchExe name comp =          case comp of Plan.CompNameExe nameExe -> name == nameExe; _ -> False+   let matchExeUnit name unit =+         any (matchExe name) $ Map.keys $ Plan.uComps unit    let mainExe = Text.pack $ Flatpak.command $ Flatpak.base projectJson    let mainPackage = Flatpak.mainPackage projectJson-   let units =-         filter-            (\unit ->-               if Generate.matchName mainPackage unit-                  then any (matchExe mainExe) $ Map.keys $ Plan.uComps unit-                  else Map.member Plan.CompNameLib $ Plan.uComps unit) $-         filter ((Plan.UnitTypeBuiltin /=) . Plan.uType) $-         map (Plan.pjUnits plan Map.!) $ topSort $ Plan.planJsonIdGraph plan +   mainUnit <-+      case filter (matchExeUnit mainExe) $ Map.elems $ Plan.pjUnits plan of+         [x] -> return x+         [] -> fail "main package not found in build plan"+         _ -> fail "main package found multiple times in build plan"++   let units = getSortedUnits plan+    archs <-       case Option.archs opt of          [] ->@@ -138,12 +204,10 @@    let hackageDir =          cabalDir </> Path.dir "packages" </> Path.dir "hackage.haskell.org" -   mainVersion <--      case filter (Generate.matchName mainPackage) units of-         [Plan.Unit{Plan.uPId = Plan.PkgId _pkg ver}] ->-            return $ Retrieve.formatVersion ver-         [] -> fail "main package not found in build plan"-         _ -> fail "main package found multiple times in build plan"+   let mainVersion = case mainUnit of+         Plan.Unit{Plan.uPId = Plan.PkgId _pkg ver} ->+            Retrieve.formatVersion ver+    (revisions, mainCabalHash) <- do       tar <- Package.readTar $ hackageDir </> Path.file "01-index.tar.gz"       either fail return $
src/Option.hs view
@@ -7,7 +7,8 @@  import qualified Shell.Utility.ParseArgument as ParseArg import qualified Options.Applicative as OP-import Options.Applicative (help, metavar, argument, option, long, value, flag)+import Options.Applicative+         (help, metavar, argument, option, long, value, switch)  import Control.Applicative (pure, (<*>)) @@ -36,7 +37,7 @@ parseFlags :: OP.Parser T parseFlags =    pure Cons-    <*> flag False True+    <*> switch             (long "cabal-install"           <> help "Build with one cabal-install (default: build module-wise using Cabal)")     <*> OP.many