    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE DeriveDataTypeable #-}

    module Propellor.Property.Apt where

    import Data.Maybe
    import Data.List
    import Data.Typeable
    import System.IO
    import Control.Monad
    import Control.Applicative
    import Prelude

    import Propellor.Base
    import qualified Propellor.Property.File as File
    import qualified Propellor.Property.Service as Service
    import Propellor.Property.File (Line)
    import Propellor.Types.Info
    import Utility.SafeCommand

    data HostMirror = HostMirror Url
    	deriving (HostMirror -> HostMirror -> Bool
    (HostMirror -> HostMirror -> Bool)
    -> (HostMirror -> HostMirror -> Bool) -> Eq HostMirror
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: HostMirror -> HostMirror -> Bool
    $c/= :: HostMirror -> HostMirror -> Bool
    == :: HostMirror -> HostMirror -> Bool
    $c== :: HostMirror -> HostMirror -> Bool
    Eq, Int -> HostMirror -> ShowS
    [HostMirror] -> ShowS
    HostMirror -> String
    (Int -> HostMirror -> ShowS)
    -> (HostMirror -> String)
    -> ([HostMirror] -> ShowS)
    -> Show HostMirror
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [HostMirror] -> ShowS
    $cshowList :: [HostMirror] -> ShowS
    show :: HostMirror -> String
    $cshow :: HostMirror -> String
    showsPrec :: Int -> HostMirror -> ShowS
    $cshowsPrec :: Int -> HostMirror -> ShowS
    Show, Typeable)

    data HostAptProxy = HostAptProxy Url
    	deriving (HostAptProxy -> HostAptProxy -> Bool
    (HostAptProxy -> HostAptProxy -> Bool)
    -> (HostAptProxy -> HostAptProxy -> Bool) -> Eq HostAptProxy
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: HostAptProxy -> HostAptProxy -> Bool
    $c/= :: HostAptProxy -> HostAptProxy -> Bool
    == :: HostAptProxy -> HostAptProxy -> Bool
    $c== :: HostAptProxy -> HostAptProxy -> Bool
    Eq, Int -> HostAptProxy -> ShowS
    [HostAptProxy] -> ShowS
    HostAptProxy -> String
    (Int -> HostAptProxy -> ShowS)
    -> (HostAptProxy -> String)
    -> ([HostAptProxy] -> ShowS)
    -> Show HostAptProxy
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [HostAptProxy] -> ShowS
    $cshowList :: [HostAptProxy] -> ShowS
    show :: HostAptProxy -> String
    $cshow :: HostAptProxy -> String
    showsPrec :: Int -> HostAptProxy -> ShowS
    $cshowsPrec :: Int -> HostAptProxy -> ShowS
    Show, Typeable)

    -- | Indicate host's preferred apt mirror
    mirror :: Url -> Property (HasInfo + UnixLike)
    mirror :: String -> Property (HasInfo + UnixLike)
    mirror u :: String
    u = String -> InfoVal HostMirror -> Property (HasInfo + UnixLike)
    forall v. IsInfo v => String -> v -> Property (HasInfo + UnixLike)
    pureInfoProperty (String
    u String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ " apt mirror selected")
    	     (HostMirror -> InfoVal HostMirror
    forall v. v -> InfoVal v
    InfoVal (String -> HostMirror
    HostMirror String
    u))

    getMirror :: Propellor Url
    getMirror :: Propellor String
    getMirror = do
    	Maybe HostMirror
    mirrorInfo <- Propellor (Maybe HostMirror)
    getMirrorInfo
    	Maybe System
    osInfo <- Propellor (Maybe System)
    getOS
    	String -> Propellor String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Propellor String) -> String -> Propellor String
    forall a b. (a -> b) -> a -> b
    $ case (Maybe System
    osInfo, Maybe HostMirror
    mirrorInfo) of
    		(_, Just (HostMirror u :: String
    u)) -> String
    u
    		(Just (System (Debian _ _) _), _) ->
    			"http://deb.debian.org/debian"
    		(Just (System (Buntish _) _), _) ->
    			"mirror://mirrors.ubuntu.com/"
    		(Just (System dist :: Distribution
    dist _), _) ->
    			ShowS
    forall a. HasCallStack => String -> a
    error ("no Apt mirror defined for " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Distribution -> String
    forall a. Show a => a -> String
    show Distribution
    dist)
    		_ -> ShowS
    forall a. HasCallStack => String -> a
    error "no Apt mirror defined for this host or OS"
      where
    	getMirrorInfo :: Propellor (Maybe HostMirror)
    	getMirrorInfo :: Propellor (Maybe HostMirror)
    getMirrorInfo = InfoVal HostMirror -> Maybe HostMirror
    forall v. InfoVal v -> Maybe v
    fromInfoVal (InfoVal HostMirror -> Maybe HostMirror)
    -> Propellor (InfoVal HostMirror) -> Propellor (Maybe HostMirror)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Propellor (InfoVal HostMirror)
    forall v. IsInfo v => Propellor v
    askInfo

    withMirror :: Desc -> (Url -> Property DebianLike) -> Property DebianLike
    withMirror :: String -> (String -> Property DebianLike) -> Property DebianLike
    withMirror desc :: String
    desc mkp :: String -> Property DebianLike
    mkp = String
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Propellor Result)
    -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' String
    desc ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
      -> Propellor Result)
     -> Property DebianLike)
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Propellor Result)
    -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ \w :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w -> do
    	String
    u <- Propellor String
    getMirror
    	OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    -> Property DebianLike -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w (String -> Property DebianLike
    mkp String
    u)

    sourcesList :: FilePath
    sourcesList :: String
    sourcesList = "/etc/apt/sources.list"

    type Url = String
    type Section = String

    type SourcesGenerator = DebianSuite -> [Line]

    showSuite :: DebianSuite -> String
    showSuite :: DebianSuite -> String
    showSuite (Stable s :: String
    s) = String
    s
    showSuite Testing = "testing"
    showSuite Unstable = "unstable"
    showSuite Experimental = "experimental"

    backportSuite :: DebianSuite -> Maybe String
    backportSuite :: DebianSuite -> Maybe String
    backportSuite (Stable s :: String
    s) = String -> Maybe String
    forall a. a -> Maybe a
    Just (String
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "-backports")
    backportSuite _ = Maybe String
    forall a. Maybe a
    Nothing

    stableUpdatesSuite :: DebianSuite -> Maybe String
    stableUpdatesSuite :: DebianSuite -> Maybe String
    stableUpdatesSuite (Stable s :: String
    s) = String -> Maybe String
    forall a. a -> Maybe a
    Just (String
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "-updates")
    stableUpdatesSuite _ = Maybe String
    forall a. Maybe a
    Nothing

    debLine :: String -> Url -> [Section] -> Line
    debLine :: String -> String -> [String] -> String
    debLine suite :: String
    suite url :: String
    url sections :: [String]
    sections = [String] -> String
    unwords ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
    	["deb", String
    url, String
    suite] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String]
    sections

    srcLine :: Line -> Line
    srcLine :: ShowS
    srcLine l :: String
    l = case String -> [String]
    words String
    l of
    	("deb":rest :: [String]
    rest) -> [String] -> String
    unwords ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ "deb-src" String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : [String]
    rest
    	_ -> ""

    stdSections :: [Section]
    stdSections :: [String]
    stdSections = ["main", "contrib", "non-free"]

    binandsrc :: String -> SourcesGenerator
    binandsrc :: String -> SourcesGenerator
    binandsrc url :: String
    url suite :: DebianSuite
    suite = [Maybe String] -> [String]
    forall a. [Maybe a] -> [a]
    catMaybes
    	[ String -> Maybe String
    forall a. a -> Maybe a
    Just String
    l
    	, String -> Maybe String
    forall a. a -> Maybe a
    Just (String -> Maybe String) -> String -> Maybe String
    forall a b. (a -> b) -> a -> b
    $ ShowS
    srcLine String
    l
    	, Maybe String
    sul
    	, ShowS
    srcLine ShowS -> Maybe String -> Maybe String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe String
    sul
    	, Maybe String
    bl
    	, ShowS
    srcLine ShowS -> Maybe String -> Maybe String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe String
    bl
    	]
      where
    	l :: String
    l = String -> String -> [String] -> String
    debLine (DebianSuite -> String
    showSuite DebianSuite
    suite) String
    url [String]
    stdSections
    	bl :: Maybe String
    bl = do
    		String
    bs <- DebianSuite -> Maybe String
    backportSuite DebianSuite
    suite
    		String -> Maybe String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Maybe String) -> String -> Maybe String
    forall a b. (a -> b) -> a -> b
    $ String -> String -> [String] -> String
    debLine String
    bs String
    url [String]
    stdSections
    	-- formerly known as 'volatile'
    	sul :: Maybe String
    sul = do
    		String
    sus <- DebianSuite -> Maybe String
    stableUpdatesSuite DebianSuite
    suite
    		String -> Maybe String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Maybe String) -> String -> Maybe String
    forall a b. (a -> b) -> a -> b
    $ String -> String -> [String] -> String
    debLine String
    sus String
    url [String]
    stdSections

    stdArchiveLines :: Propellor SourcesGenerator
    stdArchiveLines :: Propellor SourcesGenerator
    stdArchiveLines = SourcesGenerator -> Propellor SourcesGenerator
    forall (m :: * -> *) a. Monad m => a -> m a
    return (SourcesGenerator -> Propellor SourcesGenerator)
    -> (String -> SourcesGenerator)
    -> String
    -> Propellor SourcesGenerator
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> SourcesGenerator
    binandsrc (String -> Propellor SourcesGenerator)
    -> Propellor String -> Propellor SourcesGenerator
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< Propellor String
    getMirror

    -- | Only available for Stable suites, not for Testing or Unstable.
    securityUpdates :: SourcesGenerator
    securityUpdates :: SourcesGenerator
    securityUpdates suite :: DebianSuite
    suite
    	| DebianSuite -> Bool
    isStable DebianSuite
    suite =
    		let l :: String
    l = "deb http://security.debian.org/debian-security " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    securitysuite String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ " " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ [String] -> String
    unwords [String]
    stdSections
    		in [String
    l, ShowS
    srcLine String
    l]
    	| Bool
    otherwise = []
      where
    	securitysuite :: String
    securitysuite
    		| DebianSuite
    suite DebianSuite -> [DebianSuite] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` (String -> DebianSuite) -> [String] -> [DebianSuite]
    forall a b. (a -> b) -> [a] -> [b]
    map String -> DebianSuite
    Stable [String]
    releasesusingoldname =
    			DebianSuite -> String
    showSuite DebianSuite
    suite String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "/updates"
    		| Bool
    otherwise = DebianSuite -> String
    showSuite DebianSuite
    suite String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "-security"
    	releasesusingoldname :: [String]
    releasesusingoldname = ["jessie", "buster", "stretch"]

    -- | Makes sources.list have a standard content using the Debian mirror CDN
    -- (or other host specified using the `mirror` property), with the
    -- Debian suite configured by the os.
    stdSourcesList :: Property Debian
    stdSourcesList :: Property Debian
    stdSourcesList = String
    -> (OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
        -> Maybe System -> Propellor Result)
    -> Property Debian
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> (OuterMetaTypesWitness metatypes
        -> Maybe System -> Propellor Result)
    -> Property (MetaTypes metatypes)
    withOS "standard sources.list" ((OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
      -> Maybe System -> Propellor Result)
     -> Property Debian)
    -> (OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
        -> Maybe System -> Propellor Result)
    -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ \w :: OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
    w o :: Maybe System
    o -> case Maybe System
    o of
    	(Just (System (Debian _ suite :: DebianSuite
    suite) _)) ->
    		OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
    -> Property Debian -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
    w (Property Debian -> Propellor Result)
    -> Property Debian -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ DebianSuite -> Property Debian
    stdSourcesListFor DebianSuite
    suite
    	_ -> Propellor Result
    HasCallStack => Propellor Result
    unsupportedOS'

    stdSourcesListFor :: DebianSuite -> Property Debian
    stdSourcesListFor :: DebianSuite -> Property Debian
    stdSourcesListFor suite :: DebianSuite
    suite = DebianSuite -> [SourcesGenerator] -> Property Debian
    stdSourcesList' DebianSuite
    suite []

    -- | Adds additional sources.list generators.
    --
    -- Note that if a Property needs to enable an apt source, it's better
    -- to do so via a separate file in </etc/apt/sources.list.d/>
    stdSourcesList' :: DebianSuite -> [SourcesGenerator] -> Property Debian
    stdSourcesList' :: DebianSuite -> [SourcesGenerator] -> Property Debian
    stdSourcesList' suite :: DebianSuite
    suite more :: [SourcesGenerator]
    more = Property DebianLike -> Property Debian
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property DebianLike -> Property Debian)
    -> Property DebianLike -> Property Debian
    forall a b. (a -> b) -> a -> b
    $
    	String -> (String -> Property DebianLike) -> Property DebianLike
    withMirror String
    desc ((String -> Property DebianLike) -> Property DebianLike)
    -> (String -> Property DebianLike) -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ \u :: String
    u -> [String] -> Property DebianLike
    setSourcesList
    		((SourcesGenerator -> [String]) -> [SourcesGenerator] -> [String]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (\gen :: SourcesGenerator
    gen -> SourcesGenerator
    gen DebianSuite
    suite) (String -> [SourcesGenerator]
    generators String
    u))
      where
    	generators :: String -> [SourcesGenerator]
    generators u :: String
    u = [String -> SourcesGenerator
    binandsrc String
    u, SourcesGenerator
    securityUpdates] [SourcesGenerator] -> [SourcesGenerator] -> [SourcesGenerator]
    forall a. [a] -> [a] -> [a]
    ++ [SourcesGenerator]
    more
    	desc :: String
    desc = ("standard sources.list for " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    forall a. Show a => a -> String
    show DebianSuite
    suite)

    type PinPriority = Int

    -- | Adds an apt source for a suite, and pins that suite to a given pin value
    -- (see apt_preferences(5)).  Revert to drop the source and unpin the suite.
    --
    -- If the requested suite is the host's OS suite, the suite is pinned, but no
    -- source is added.  That apt source should already be available, or you can use
    -- a property like 'Apt.stdSourcesList'.
    suiteAvailablePinned
    	:: DebianSuite
    	-> PinPriority
    	-> RevertableProperty Debian Debian
    suiteAvailablePinned :: DebianSuite -> Int -> RevertableProperty Debian Debian
    suiteAvailablePinned s :: DebianSuite
    s pin :: Int
    pin = Property Debian
    available Property Debian
    -> Property Debian -> RevertableProperty Debian Debian
    forall setupmetatypes undometatypes.
    Property setupmetatypes
    -> Property undometatypes
    -> RevertableProperty setupmetatypes undometatypes
    <!> Property Debian
    unavailable
      where
    	available :: Property Debian
    	available :: Property Debian
    available = Property Debian -> Property Debian
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property Debian -> Property Debian)
    -> Property Debian -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ String -> Props Debian -> Property Debian
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties (Bool -> String
    desc Bool
    True) (Props Debian -> Property Debian)
    -> Props Debian -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ Props UnixLike
    props
    		Props UnixLike
    -> Property UnixLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & String -> [String] -> Property UnixLike
    File.hasContent String
    prefFile (String -> DebianSuite -> Int -> [String]
    suitePinBlock "*" DebianSuite
    s Int
    pin)
    		Props UnixLike
    -> Property Debian
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property Debian
    setSourcesFile

    	unavailable :: Property Debian
    	unavailable :: Property Debian
    unavailable = Property DebianLike -> Property Debian
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property DebianLike -> Property Debian)
    -> Property DebianLike -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ String -> Props DebianLike -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties (Bool -> String
    desc Bool
    False) (Props DebianLike -> Property DebianLike)
    -> Props DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ Props UnixLike
    props
    		Props UnixLike
    -> Property DebianLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & String -> Property UnixLike
    File.notPresent String
    sourcesFile
    			Property UnixLike
    -> Property DebianLike
    -> CombinedType (Property UnixLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    update
    		Props DebianLike
    -> Property UnixLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & String -> Property UnixLike
    File.notPresent String
    prefFile

    	setSourcesFile :: Property Debian
    	setSourcesFile :: Property Debian
    setSourcesFile = Property DebianLike -> Property Debian
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property DebianLike -> Property Debian)
    -> Property DebianLike -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ String -> (String -> Property DebianLike) -> Property DebianLike
    withMirror (Bool -> String
    desc Bool
    True) ((String -> Property DebianLike) -> Property DebianLike)
    -> (String -> Property DebianLike) -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ \u :: String
    u ->
    		String
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Maybe System -> Propellor Result)
    -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> (OuterMetaTypesWitness metatypes
        -> Maybe System -> Propellor Result)
    -> Property (MetaTypes metatypes)
    withOS (Bool -> String
    desc Bool
    True) ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
      -> Maybe System -> Propellor Result)
     -> Property DebianLike)
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Maybe System -> Propellor Result)
    -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ \w :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w o :: Maybe System
    o -> case Maybe System
    o of
    			(Just (System (Debian _ hostSuite :: DebianSuite
    hostSuite) _))
    				| DebianSuite
    s DebianSuite -> DebianSuite -> Bool
    forall a. Eq a => a -> a -> Bool
    /= DebianSuite
    hostSuite -> OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    -> Property DebianLike -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w (Property DebianLike -> Propellor Result)
    -> Property DebianLike -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    					String -> [String] -> Property UnixLike
    File.hasContent String
    sourcesFile (String -> [String]
    sources String
    u)
    					Property UnixLike
    -> Property DebianLike
    -> CombinedType (Property UnixLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    update
    			_ -> Propellor Result
    noChange

    	-- Unless we are pinning a backports suite, filter out any backports
    	-- sources that were added by our generators.  The user probably doesn't
    	-- want those to be pinned to the same value
    	sources :: String -> [String]
    sources u :: String
    u = [String] -> [String]
    dropBackports ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ (SourcesGenerator -> [String]) -> [SourcesGenerator] -> [String]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (\gen :: SourcesGenerator
    gen -> SourcesGenerator
    gen DebianSuite
    s) (String -> [SourcesGenerator]
    generators String
    u)
    	  where
    		dropBackports :: [String] -> [String]
    dropBackports
    			| "-backports" String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isSuffixOf` (DebianSuite -> String
    showSuite DebianSuite
    s) = [String] -> [String]
    forall a. a -> a
    id
    			| Bool
    otherwise = (String -> Bool) -> [String] -> [String]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    isInfixOf "-backports")

    	generators :: String -> [SourcesGenerator]
    generators u :: String
    u = [String -> SourcesGenerator
    binandsrc String
    u, SourcesGenerator
    securityUpdates]
    	prefFile :: String
    prefFile = "/etc/apt/preferences.d/20" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    showSuite DebianSuite
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ".pref"
    	sourcesFile :: String
    sourcesFile = "/etc/apt/sources.list.d/" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    showSuite DebianSuite
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ".list"

    	desc :: Bool -> String
    desc True = "Debian " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    showSuite DebianSuite
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ " pinned, priority " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall a. Show a => a -> String
    show Int
    pin
    	desc False = "Debian " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    showSuite DebianSuite
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ " not pinned"

    setSourcesList :: [Line] -> Property DebianLike
    setSourcesList :: [String] -> Property DebianLike
    setSourcesList ls :: [String]
    ls = String
    sourcesList String -> [String] -> Property UnixLike
    `File.hasContent` [String]
    ls Property UnixLike
    -> Property DebianLike
    -> CombinedType (Property UnixLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    update

    setSourcesListD :: [Line] -> FilePath -> Property DebianLike
    setSourcesListD :: [String] -> String -> Property DebianLike
    setSourcesListD ls :: [String]
    ls basename :: String
    basename = String
    f String -> [String] -> Property UnixLike
    `File.hasContent` [String]
    ls Property UnixLike
    -> Property DebianLike
    -> CombinedType (Property UnixLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    update
      where
    	f :: String
    f = "/etc/apt/sources.list.d/" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    basename String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ".list"

    runApt :: [String] -> UncheckedProperty DebianLike
    runApt :: [String] -> UncheckedProperty DebianLike
    runApt ps :: [String]
    ps = UncheckedProperty UnixLike -> UncheckedProperty DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (UncheckedProperty UnixLike -> UncheckedProperty DebianLike)
    -> UncheckedProperty UnixLike -> UncheckedProperty DebianLike
    forall a b. (a -> b) -> a -> b
    $ String
    -> [String] -> [(String, String)] -> UncheckedProperty UnixLike
    cmdPropertyEnv "apt-get" [String]
    ps [(String, String)]
    noninteractiveEnv

    noninteractiveEnv :: [(String, String)]
    noninteractiveEnv :: [(String, String)]
    noninteractiveEnv =
    		[ ("DEBIAN_FRONTEND", "noninteractive")
    		, ("APT_LISTCHANGES_FRONTEND", "none")
    		]

    -- | Have apt update its lists of packages, but without upgrading anything.
    update :: Property DebianLike
    update :: Property DebianLike
    update = String -> Props DebianLike -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties String
    desc (Props DebianLike -> Property DebianLike)
    -> Props DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ Props UnixLike
    props
    	Props UnixLike
    -> Property DebianLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property DebianLike
    pendingConfigured
    	Props DebianLike
    -> Property DebianLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property DebianLike
    aptupdate
      where
    	desc :: String
    desc = "apt update"
    	aptupdate :: Property DebianLike
    	aptupdate :: Property DebianLike
    aptupdate = String
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Maybe System -> Propellor Result)
    -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> (OuterMetaTypesWitness metatypes
        -> Maybe System -> Propellor Result)
    -> Property (MetaTypes metatypes)
    withOS String
    desc ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
      -> Maybe System -> Propellor Result)
     -> Property DebianLike)
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Maybe System -> Propellor Result)
    -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ \w :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w o :: Maybe System
    o -> case Maybe System
    o of
    		(Just (System (Debian _ suite :: DebianSuite
    suite) _))
    			| Bool -> Bool
    not (DebianSuite -> Bool
    isStable DebianSuite
    suite) -> OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    -> Property DebianLike -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w (Property DebianLike -> Propellor Result)
    -> Property DebianLike -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    				-- rolling suites' release info can change
    				[String] -> UncheckedProperty DebianLike
    runApt ["update", "--allow-releaseinfo-change"]
    					UncheckedProperty DebianLike -> Result -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange
    		_ -> OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    -> Property DebianLike -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w (Property DebianLike -> Propellor Result)
    -> Property DebianLike -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    			[String] -> UncheckedProperty DebianLike
    runApt ["update"]
    				UncheckedProperty DebianLike -> Result -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange

    -- | Have apt upgrade packages, adding new packages and removing old as
    -- necessary. Often used in combination with the `update` property.
    upgrade :: Property DebianLike
    upgrade :: Property DebianLike
    upgrade = String -> Property DebianLike
    upgrade' "dist-upgrade"

    upgrade' :: String -> Property DebianLike
    upgrade' :: String -> Property DebianLike
    upgrade' p :: String
    p = String -> Props DebianLike -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties ("apt " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    p) (Props DebianLike -> Property DebianLike)
    -> Props DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ Props UnixLike
    props
    	Props UnixLike
    -> Property DebianLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property DebianLike
    pendingConfigured
    	Props DebianLike
    -> Property DebianLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & [String] -> UncheckedProperty DebianLike
    runApt ["-y", String
    p]
    		UncheckedProperty DebianLike -> Result -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange

    -- | Have apt upgrade packages, but never add new packages or remove
    -- old packages. Not suitable for upgrading acrocess major versions
    -- of the distribution.
    safeUpgrade :: Property DebianLike
    safeUpgrade :: Property DebianLike
    safeUpgrade = String -> Property DebianLike
    upgrade' "upgrade"

    -- | Have dpkg try to configure any packages that are not fully configured.
    pendingConfigured :: Property DebianLike
    pendingConfigured :: Property DebianLike
    pendingConfigured = Property UnixLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property DebianLike)
    -> Property UnixLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $
    	String
    -> [String] -> [(String, String)] -> UncheckedProperty UnixLike
    cmdPropertyEnv "dpkg" ["--configure", "--pending"] [(String, String)]
    noninteractiveEnv
    		UncheckedProperty UnixLike -> Result -> Property UnixLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange
    		Property UnixLike -> String -> Property UnixLike
    forall p. IsProp p => p -> String -> p
    `describe` "dpkg configured pending"

    type Package = String

    installed :: [Package] -> Property DebianLike
    installed :: [String] -> Property DebianLike
    installed = [String] -> [String] -> Property DebianLike
    installed' ["-y"]

    -- | Minimal install of package, without recommends.
    installedMin :: [Package] -> Property DebianLike
    installedMin :: [String] -> Property DebianLike
    installedMin = [String] -> [String] -> Property DebianLike
    installed' ["--no-install-recommends", "-y"]

    installed' :: [String] -> [Package] -> Property DebianLike
    installed' :: [String] -> [String] -> Property DebianLike
    installed' params :: [String]
    params ps :: [String]
    ps = Property DebianLike -> Property DebianLike
    robustly (Property DebianLike -> Property DebianLike)
    -> Property DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ IO Bool -> UncheckedProperty DebianLike -> Property DebianLike
    forall (p :: * -> *) i (m :: * -> *).
    (Checkable p i, LiftPropellor m) =>
    m Bool -> p i -> Property i
    check (Bool -> Bool
    not (Bool -> Bool) -> IO Bool -> IO Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [String] -> IO Bool
    isInstalled' [String]
    ps) UncheckedProperty DebianLike
    go
    	Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` [String] -> String
    unwords ("apt installed"String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    ps)
      where
    	go :: UncheckedProperty DebianLike
    go = [String] -> UncheckedProperty DebianLike
    runApt ([String]
    params [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ ["install"] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String]
    ps)

    -- | Install packages from the stable-backports suite.
    --
    -- If installing the backport requires installing versions of a package's
    -- dependencies from stable-backports too, you will need to include those
    -- dependencies in the list of packages passed to this function.
    backportInstalled :: [Package] -> Property Debian
    backportInstalled :: [String] -> Property Debian
    backportInstalled = [String] -> [String] -> Property Debian
    backportInstalled' ["-y"]

    -- | Minimal install from the stable-backports suite, without recommends.
    backportInstalledMin :: [Package] -> Property Debian
    backportInstalledMin :: [String] -> Property Debian
    backportInstalledMin = [String] -> [String] -> Property Debian
    backportInstalled' ["--no-install-recommends", "-y"]

    backportInstalled' :: [String] -> [Package] -> Property Debian
    backportInstalled' :: [String] -> [String] -> Property Debian
    backportInstalled' params :: [String]
    params ps :: [String]
    ps = String
    -> (OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
        -> Maybe System -> Propellor Result)
    -> Property Debian
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> (OuterMetaTypesWitness metatypes
        -> Maybe System -> Propellor Result)
    -> Property (MetaTypes metatypes)
    withOS String
    desc ((OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
      -> Maybe System -> Propellor Result)
     -> Property Debian)
    -> (OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
        -> Maybe System -> Propellor Result)
    -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ \w :: OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
    w o :: Maybe System
    o -> case Maybe System
    o of
    	(Just (System (Debian _ suite :: DebianSuite
    suite) _)) -> case DebianSuite -> Maybe String
    backportSuite DebianSuite
    suite of
    		Nothing -> Propellor Result
    HasCallStack => Propellor Result
    unsupportedOS'
    		Just bs :: String
    bs -> OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
    -> Property DebianLike -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness '[ 'Targeting 'OSDebian]
    w (Property DebianLike -> Propellor Result)
    -> Property DebianLike -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    			[String] -> UncheckedProperty DebianLike
    runApt (("install"String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    params) [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ ((String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ '/'Char -> ShowS
    forall a. a -> [a] -> [a]
    :String
    bs) ShowS -> [String] -> [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [String]
    ps))
    				UncheckedProperty DebianLike -> String -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> String -> Property i
    `changesFile` String
    dpkgStatus
    	_ -> Propellor Result
    HasCallStack => Propellor Result
    unsupportedOS'
      where
    	desc :: String
    desc = [String] -> String
    unwords ("apt installed backport"String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    ps)

    removed :: [Package] -> Property DebianLike
    removed :: [String] -> Property DebianLike
    removed ps :: [String]
    ps = IO Bool -> UncheckedProperty DebianLike -> Property DebianLike
    forall (p :: * -> *) i (m :: * -> *).
    (Checkable p i, LiftPropellor m) =>
    m Bool -> p i -> Property i
    check ((InstallStatus -> Bool) -> [InstallStatus] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (InstallStatus -> InstallStatus -> Bool
    forall a. Eq a => a -> a -> Bool
    == InstallStatus
    IsInstalled) ([InstallStatus] -> Bool) -> IO [InstallStatus] -> IO Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [String] -> IO [InstallStatus]
    getInstallStatus [String]
    ps)
    	([String] -> UncheckedProperty DebianLike
    runApt (["-y", "remove"] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String]
    ps))
    	Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` [String] -> String
    unwords ("apt removed"String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    ps)

    buildDep :: [Package] -> Property DebianLike
    buildDep :: [String] -> Property DebianLike
    buildDep ps :: [String]
    ps = Property DebianLike -> Property DebianLike
    robustly (Property DebianLike -> Property DebianLike)
    -> Property DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ UncheckedProperty DebianLike
    go
    	UncheckedProperty DebianLike -> String -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> String -> Property i
    `changesFile` String
    dpkgStatus
    	Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` [String] -> String
    unwords ("apt build-dep"String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    ps)
      where
    	go :: UncheckedProperty DebianLike
    go = [String] -> UncheckedProperty DebianLike
    runApt ([String] -> UncheckedProperty DebianLike)
    -> [String] -> UncheckedProperty DebianLike
    forall a b. (a -> b) -> a -> b
    $ ["-y", "build-dep"] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String]
    ps

    -- | Installs the build deps for the source package unpacked
    -- in the specifed directory, with a dummy package also
    -- installed so that autoRemove won't remove them.
    buildDepIn :: FilePath -> Property DebianLike
    buildDepIn :: String -> Property DebianLike
    buildDepIn dir :: String
    dir = UncheckedProperty DebianLike
    go
    	UncheckedProperty DebianLike -> String -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> String -> Property i
    `changesFile` String
    dpkgStatus
    	Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `requires` [String] -> Property DebianLike
    installedMin ["devscripts", "equivs"]
      where
    	-- mk-build-deps may leave files behind sometimes, eg on failure,
    	-- so run it in a temp directory, passing the path to the control
    	-- file
    	go :: UncheckedProperty DebianLike
    	go :: UncheckedProperty DebianLike
    go = Property DebianLike -> UncheckedProperty DebianLike
    forall i. Property i -> UncheckedProperty i
    unchecked (Property DebianLike -> UncheckedProperty DebianLike)
    -> Property DebianLike -> UncheckedProperty DebianLike
    forall a b. (a -> b) -> a -> b
    $ String -> Propellor Result -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String -> Propellor Result -> Property (MetaTypes metatypes)
    property ("build-dep in " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    dir) (Propellor Result -> Property DebianLike)
    -> Propellor Result -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ IO Result -> Propellor Result
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Result -> Propellor Result) -> IO Result -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    		String -> (String -> IO Result) -> IO Result
    forall (m :: * -> *) a.
    (MonadMask m, MonadIO m) =>
    String -> (String -> m a) -> m a
    withTmpDir "build-dep" ((String -> IO Result) -> IO Result)
    -> (String -> IO Result) -> IO Result
    forall a b. (a -> b) -> a -> b
    $ \tmpdir :: String
    tmpdir -> do
    			Bool -> Result
    cmdResult (Bool -> Result) -> IO Bool -> IO Result
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String
    -> [CommandParam] -> (CreateProcess -> CreateProcess) -> IO Bool
    boolSystem' "mk-build-deps"
    				[ String -> CommandParam
    File (String -> CommandParam) -> String -> CommandParam
    forall a b. (a -> b) -> a -> b
    $ String
    dir String -> ShowS
    </> "debian" String -> ShowS
    </> "control"
    				, String -> CommandParam
    Param "--install"
    				, String -> CommandParam
    Param "--tool"
    				, String -> CommandParam
    Param "apt-get -y --no-install-recommends"
    				] (\p :: CreateProcess
    p -> CreateProcess
    p { cwd :: Maybe String
    cwd = String -> Maybe String
    forall a. a -> Maybe a
    Just String
    tmpdir })

    -- | The name of a package, a glob to match the names of packages, or a regexp
    -- surrounded by slashes to match the names of packages.  See
    -- apt_preferences(5), "Regular expressions and glob(7) syntax"
    type AptPackagePref = String

    -- | Pins a list of packages, package wildcards and/or regular expressions to a
    -- list of suites and corresponding pin priorities (see apt_preferences(5)).
    -- Revert to unpin.
    --
    -- Each package, package wildcard or regular expression will be pinned to all of
    -- the specified suites.
    --
    -- Note that this will have no effect unless there is an apt source for each of
    -- the suites.  One way to add an apt source is 'Apt.suiteAvailablePinned'.
    --
    -- For example, to obtain Emacs Lisp addon packages not present in your release
    -- of Debian from testing, falling back to sid if they're not available in
    -- testing, you could use
    --
    --  > & Apt.suiteAvailablePinned Testing (-10)
    --  > & Apt.suiteAvailablePinned Unstable (-10)
    --  > & ["elpa-*"] `Apt.pinnedTo` [(Testing, 100), (Unstable, 50)]
    pinnedTo
    	:: [AptPackagePref]
    	-> [(DebianSuite, PinPriority)]
    	-> RevertableProperty Debian Debian
    pinnedTo :: [String]
    -> [(DebianSuite, Int)] -> RevertableProperty Debian Debian
    pinnedTo ps :: [String]
    ps pins :: [(DebianSuite, Int)]
    pins = [RevertableProperty Debian Debian]
    -> RevertableProperty Debian Debian
    forall a. Monoid a => [a] -> a
    mconcat ((String -> RevertableProperty Debian Debian)
    -> [String] -> [RevertableProperty Debian Debian]
    forall a b. (a -> b) -> [a] -> [b]
    map (\p :: String
    p -> String -> [(DebianSuite, Int)] -> RevertableProperty Debian Debian
    pinnedTo' String
    p [(DebianSuite, Int)]
    pins) [String]
    ps)
    	RevertableProperty Debian Debian
    -> String -> RevertableProperty Debian Debian
    forall p. IsProp p => p -> String -> p
    `describe` [String] -> String
    unwords (("pinned to " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    showSuites)String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    ps)
      where
    	showSuites :: String
    showSuites = String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ DebianSuite -> String
    showSuite (DebianSuite -> String)
    -> ((DebianSuite, Int) -> DebianSuite)
    -> (DebianSuite, Int)
    -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (DebianSuite, Int) -> DebianSuite
    forall a b. (a, b) -> a
    fst ((DebianSuite, Int) -> String) -> [(DebianSuite, Int)] -> [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [(DebianSuite, Int)]
    pins

    pinnedTo'
    	:: AptPackagePref
    	-> [(DebianSuite, PinPriority)]
    	-> RevertableProperty Debian Debian
    pinnedTo' :: String -> [(DebianSuite, Int)] -> RevertableProperty Debian Debian
    pinnedTo' p :: String
    p pins :: [(DebianSuite, Int)]
    pins =
    	(Property UnixLike -> Property Debian
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property Debian)
    -> Property UnixLike -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ String
    prefFile String -> [String] -> Property UnixLike
    `File.hasContent` [String]
    prefs)
    	Property Debian
    -> Property Debian -> RevertableProperty Debian Debian
    forall setupmetatypes undometatypes.
    Property setupmetatypes
    -> Property undometatypes
    -> RevertableProperty setupmetatypes undometatypes
    <!> (Property UnixLike -> Property Debian
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property Debian)
    -> Property UnixLike -> Property Debian
    forall a b. (a -> b) -> a -> b
    $ String -> Property UnixLike
    File.notPresent String
    prefFile)
      where
    	prefs :: [String]
    prefs = ((DebianSuite, Int) -> [String] -> [String])
    -> [String] -> [(DebianSuite, Int)] -> [String]
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr (DebianSuite, Int) -> [String] -> [String]
    step [] [(DebianSuite, Int)]
    pins
    	step :: (DebianSuite, Int) -> [String] -> [String]
    step (suite :: DebianSuite
    suite, pin :: Int
    pin) ls :: [String]
    ls = [String]
    ls [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ String -> DebianSuite -> Int -> [String]
    suitePinBlock String
    p DebianSuite
    suite Int
    pin [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [""]
    	prefFile :: String
    prefFile = "/etc/apt/preferences.d/10propellor_"
    		String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ShowS
    File.configFileName String
    p String -> ShowS
    <.> "pref"

    -- | Package installation may fail becuse the archive has changed.
    -- Run an update in that case and retry.
    robustly :: Property DebianLike -> Property DebianLike
    robustly :: Property DebianLike -> Property DebianLike
    robustly p :: Property DebianLike
    p = Property DebianLike
    p Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `fallback` (Property DebianLike
    update Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` Property DebianLike
    p)

    isInstalled :: Package -> IO Bool
    isInstalled :: String -> IO Bool
    isInstalled p :: String
    p = [String] -> IO Bool
    isInstalled' [String
    p]

    isInstalled' :: [Package] -> IO Bool
    isInstalled' :: [String] -> IO Bool
    isInstalled' ps :: [String]
    ps = do
    	[InstallStatus]
    is <- [String] -> IO [InstallStatus]
    getInstallStatus [String]
    ps
    	Bool -> IO Bool
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Bool -> IO Bool) -> Bool -> IO Bool
    forall a b. (a -> b) -> a -> b
    $ (InstallStatus -> Bool) -> [InstallStatus] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (InstallStatus -> InstallStatus -> Bool
    forall a. Eq a => a -> a -> Bool
    == InstallStatus
    IsInstalled) [InstallStatus]
    is Bool -> Bool -> Bool
    && [InstallStatus] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [InstallStatus]
    is Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == [String] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [String]
    ps

    data InstallStatus = IsInstalled | NotInstalled
    	deriving (Int -> InstallStatus -> ShowS
    [InstallStatus] -> ShowS
    InstallStatus -> String
    (Int -> InstallStatus -> ShowS)
    -> (InstallStatus -> String)
    -> ([InstallStatus] -> ShowS)
    -> Show InstallStatus
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [InstallStatus] -> ShowS
    $cshowList :: [InstallStatus] -> ShowS
    show :: InstallStatus -> String
    $cshow :: InstallStatus -> String
    showsPrec :: Int -> InstallStatus -> ShowS
    $cshowsPrec :: Int -> InstallStatus -> ShowS
    Show, InstallStatus -> InstallStatus -> Bool
    (InstallStatus -> InstallStatus -> Bool)
    -> (InstallStatus -> InstallStatus -> Bool) -> Eq InstallStatus
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: InstallStatus -> InstallStatus -> Bool
    $c/= :: InstallStatus -> InstallStatus -> Bool
    == :: InstallStatus -> InstallStatus -> Bool
    $c== :: InstallStatus -> InstallStatus -> Bool
    Eq)

    {- Returns the InstallStatus of packages that are installed
     - or known and not installed. If a package is not known at all to apt
     - or dpkg, it is not included in the list. -}
    getInstallStatus :: [Package] -> IO [InstallStatus]
    getInstallStatus :: [String] -> IO [InstallStatus]
    getInstallStatus ps :: [String]
    ps = (String -> Maybe InstallStatus) -> [String] -> [InstallStatus]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe String -> Maybe InstallStatus
    parse ([String] -> [InstallStatus])
    -> (String -> [String]) -> String -> [InstallStatus]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    lines (String -> [InstallStatus]) -> IO String -> IO [InstallStatus]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO String
    policy
      where
    	parse :: String -> Maybe InstallStatus
    parse l :: String
    l
    		| "Installed: (none)" String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isInfixOf` String
    l = InstallStatus -> Maybe InstallStatus
    forall a. a -> Maybe a
    Just InstallStatus
    NotInstalled
    		| "Installed: " String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isInfixOf` String
    l = InstallStatus -> Maybe InstallStatus
    forall a. a -> Maybe a
    Just InstallStatus
    IsInstalled
    		| Bool
    otherwise = Maybe InstallStatus
    forall a. Maybe a
    Nothing
    	policy :: IO String
    policy = do
    		[(String, String)]
    environ <- String -> String -> [(String, String)] -> [(String, String)]
    forall k v. Eq k => k -> v -> [(k, v)] -> [(k, v)]
    addEntry "LANG" "C" ([(String, String)] -> [(String, String)])
    -> IO [(String, String)] -> IO [(String, String)]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO [(String, String)]
    getEnvironment
    		String -> [String] -> Maybe [(String, String)] -> IO String
    readProcessEnv "apt-cache" ("policy"String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    ps) ([(String, String)] -> Maybe [(String, String)]
    forall a. a -> Maybe a
    Just [(String, String)]
    environ)

    autoRemove :: Property DebianLike
    autoRemove :: Property DebianLike
    autoRemove = [String] -> UncheckedProperty DebianLike
    runApt ["-y", "autoremove"]
    	UncheckedProperty DebianLike -> String -> Property DebianLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> String -> Property i
    `changesFile` String
    dpkgStatus
    	Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` "apt autoremove"

    -- | Enables unattended upgrades. Revert to disable.
    unattendedUpgrades :: RevertableProperty DebianLike DebianLike
    unattendedUpgrades :: RevertableProperty DebianLike DebianLike
    unattendedUpgrades = Property DebianLike
    enable Property DebianLike
    -> Property DebianLike -> RevertableProperty DebianLike DebianLike
    forall setupmetatypes undometatypes.
    Property setupmetatypes
    -> Property undometatypes
    -> RevertableProperty setupmetatypes undometatypes
    <!> Property DebianLike
    disable
      where
    	enable :: CombinedType (Property DebianLike) (Property UnixLike)
    enable = Bool -> Property DebianLike
    setup Bool
    True
    		Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` String -> Property DebianLike
    Service.running "cron"
    		Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` Property DebianLike
    configure
    		-- work around http://bugs.debian.org/812380
    		Property DebianLike
    -> Property UnixLike
    -> CombinedType (Property DebianLike) (Property UnixLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` String -> Property UnixLike
    File.notPresent "/etc/apt/apt.conf.d/50unattended-upgrades.ucf-dist"
    	disable :: Property DebianLike
    disable = Bool -> Property DebianLike
    setup Bool
    False

    	setup :: Bool -> Property DebianLike
    setup enabled :: Bool
    enabled = (if Bool
    enabled then [String] -> Property DebianLike
    installed else [String] -> Property DebianLike
    removed) ["unattended-upgrades"]
    		Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` String -> [(String, String, String)] -> Property DebianLike
    reConfigure "unattended-upgrades"
    			[("unattended-upgrades/enable_auto_updates" , "boolean", String
    v)]
    		Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` ("unattended upgrades " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    v)
    	  where
    		v :: String
    v
    			| Bool
    enabled = "true"
    			| Bool
    otherwise = "false"

    	configure :: Property DebianLike
    	configure :: Property DebianLike
    configure = String -> Props DebianLike -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    propertyList "unattended upgrades configured" (Props DebianLike -> Property DebianLike)
    -> Props DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ Props UnixLike
    props
    		Props UnixLike
    -> Property DebianLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property DebianLike
    enableupgrading
    		Props DebianLike
    -> Property UnixLike
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall a p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & String
    unattendedconfig String -> String -> Property UnixLike
    `File.containsLine` "Unattended-Upgrade::Mail \"root\";"
    	  where
    		enableupgrading :: Property DebianLike
    		enableupgrading :: Property DebianLike
    enableupgrading = String
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Maybe System -> Propellor Result)
    -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String
    -> (OuterMetaTypesWitness metatypes
        -> Maybe System -> Propellor Result)
    -> Property (MetaTypes metatypes)
    withOS "unattended upgrades configured" ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
      -> Maybe System -> Propellor Result)
     -> Property DebianLike)
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
        -> Maybe System -> Propellor Result)
    -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ \w :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w o :: Maybe System
    o ->
    			case Maybe System
    o of
    				-- the package defaults to only upgrading stable
    				(Just (System (Debian _ suite :: DebianSuite
    suite) _))
    					| Bool -> Bool
    not (DebianSuite -> Bool
    isStable DebianSuite
    suite) -> OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    -> Property UnixLike -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
    w (Property UnixLike -> Propellor Result)
    -> Property UnixLike -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    						String
    unattendedconfig
    							String -> String -> Property UnixLike
    `File.containsLine`
    						("Unattended-Upgrade::Origins-Pattern { \"o=Debian,a="String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++DebianSuite -> String
    showSuite DebianSuite
    suiteString -> ShowS
    forall a. [a] -> [a] -> [a]
    ++"\"; };")
    				_ -> Propellor Result
    noChange
    		unattendedconfig :: String
    unattendedconfig = "/etc/apt/apt.conf.d/50unattended-upgrades"

    -- | Enable periodic updates (but not upgrades), including download
    -- of packages.
    periodicUpdates :: Property DebianLike
    periodicUpdates :: Property DebianLike
    periodicUpdates = Property UnixLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property DebianLike)
    -> Property UnixLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ "/etc/apt/apt.conf.d/02periodic" String -> [String] -> Property UnixLike
    `File.hasContent`
    	[ "APT::Periodic::Enable \"1\";"
    	, "APT::Periodic::Update-Package-Lists \"1\";"
    	, "APT::Periodic::Download-Upgradeable-Packages \"1\";"
    	, "APT::Periodic::Verbose \"1\";"
    	]

    type DebconfTemplate = String
    type DebconfTemplateType = String
    type DebconfTemplateValue = String

    -- | Preseeds debconf values and reconfigures the package so it takes
    -- effect.
    reConfigure :: Package -> [(DebconfTemplate, DebconfTemplateType, DebconfTemplateValue)] -> Property DebianLike
    reConfigure :: String -> [(String, String, String)] -> Property DebianLike
    reConfigure package :: String
    package vals :: [(String, String, String)]
    vals = Property DebianLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property DebianLike -> Property DebianLike)
    -> Property DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $
    	Property UnixLike
    reconfigure
    		Property UnixLike
    -> Property DebianLike
    -> CombinedType (Property UnixLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `requires` Property DebianLike
    setselections
    		Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` ("reconfigure " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    package)
      where
    	setselections :: Property DebianLike
    	setselections :: Property DebianLike
    setselections = String -> Propellor Result -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String -> Propellor Result -> Property (MetaTypes metatypes)
    property "preseed" (Propellor Result -> Property DebianLike)
    -> Propellor Result -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $
    		if [(String, String, String)] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [(String, String, String)]
    vals
    			then Propellor Result
    noChange
    			else IO () -> Propellor Result
    makeChange (IO () -> Propellor Result) -> IO () -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    				StdHandle
    -> CreateProcessRunner
    -> CreateProcess
    -> (Handle -> IO ())
    -> IO ()
    forall a.
    StdHandle
    -> CreateProcessRunner -> CreateProcess -> (Handle -> IO a) -> IO a
    withHandle StdHandle
    StdinHandle CreateProcessRunner
    createProcessSuccess
    					(String -> [String] -> CreateProcess
    proc "debconf-set-selections" []) ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \h :: Handle
    h -> do
    						[(String, String, String)]
    -> ((String, String, String) -> IO ()) -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ [(String, String, String)]
    vals (((String, String, String) -> IO ()) -> IO ())
    -> ((String, String, String) -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \(tmpl :: String
    tmpl, tmpltype :: String
    tmpltype, value :: String
    value) ->
    							Handle -> String -> IO ()
    hPutStrLn Handle
    h (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unwords [String
    package, String
    tmpl, String
    tmpltype, String
    value]
    						Handle -> IO ()
    hClose Handle
    h
    	reconfigure :: Property UnixLike
    reconfigure = String
    -> [String] -> [(String, String)] -> UncheckedProperty UnixLike
    cmdPropertyEnv "dpkg-reconfigure" ["-fnone", String
    package] [(String, String)]
    noninteractiveEnv
    		UncheckedProperty UnixLike -> Result -> Property UnixLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange

    -- | Ensures that a service is installed and running.
    --
    -- Assumes that there is a 1:1 mapping between service names and apt
    -- package names.
    serviceInstalledRunning :: Package -> Property DebianLike
    serviceInstalledRunning :: String -> Property DebianLike
    serviceInstalledRunning svc :: String
    svc = String -> Property DebianLike
    Service.running String
    svc Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `requires` [String] -> Property DebianLike
    installed [String
    svc]

    data AptKey = AptKey
    	{ AptKey -> String
    keyname :: String
    	, AptKey -> String
    pubkey :: String
    	}

    trustsKey :: AptKey -> RevertableProperty DebianLike DebianLike
    trustsKey :: AptKey -> RevertableProperty DebianLike DebianLike
    trustsKey k :: AptKey
    k = AptKey -> Property DebianLike
    trustsKey' AptKey
    k Property DebianLike
    -> Property DebianLike -> RevertableProperty DebianLike DebianLike
    forall setupmetatypes undometatypes.
    Property setupmetatypes
    -> Property undometatypes
    -> RevertableProperty setupmetatypes undometatypes
    <!> AptKey -> Property DebianLike
    untrustKey AptKey
    k

    trustsKey' :: AptKey -> Property DebianLike
    trustsKey' :: AptKey -> Property DebianLike
    trustsKey' k :: AptKey
    k = IO Bool -> Property DebianLike -> Property DebianLike
    forall (p :: * -> *) i (m :: * -> *).
    (Checkable p i, LiftPropellor m) =>
    m Bool -> p i -> Property i
    check (Bool -> Bool
    not (Bool -> Bool) -> IO Bool -> IO Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> IO Bool
    doesFileExist String
    f) (Property DebianLike -> Property DebianLike)
    -> Property DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ String -> Propellor Result -> Property DebianLike
    forall k (metatypes :: k).
    SingI metatypes =>
    String -> Propellor Result -> Property (MetaTypes metatypes)
    property String
    desc (Propellor Result -> Property DebianLike)
    -> Propellor Result -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ IO () -> Propellor Result
    makeChange (IO () -> Propellor Result) -> IO () -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ do
    	StdHandle
    -> CreateProcessRunner
    -> CreateProcess
    -> (Handle -> IO ())
    -> IO ()
    forall a.
    StdHandle
    -> CreateProcessRunner -> CreateProcess -> (Handle -> IO a) -> IO a
    withHandle StdHandle
    StdinHandle CreateProcessRunner
    createProcessSuccess
    		(String -> [String] -> CreateProcess
    proc "apt-key" ["--keyring", String
    f, "add", "-"]) ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \h :: Handle
    h -> do
    			Handle -> String -> IO ()
    hPutStr Handle
    h (AptKey -> String
    pubkey AptKey
    k)
    			Handle -> IO ()
    hClose Handle
    h
    	String -> IO ()
    nukeFile (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    f String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "~" -- gpg dropping
      where
    	desc :: String
    desc = "apt trusts key " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ AptKey -> String
    keyname AptKey
    k
    	f :: String
    f = AptKey -> String
    aptKeyFile AptKey
    k

    untrustKey :: AptKey -> Property DebianLike
    untrustKey :: AptKey -> Property DebianLike
    untrustKey = Property UnixLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property DebianLike)
    -> (AptKey -> Property UnixLike) -> AptKey -> Property DebianLike
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Property UnixLike
    File.notPresent (String -> Property UnixLike)
    -> (AptKey -> String) -> AptKey -> Property UnixLike
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . AptKey -> String
    aptKeyFile

    aptKeyFile :: AptKey -> FilePath
    aptKeyFile :: AptKey -> String
    aptKeyFile k :: AptKey
    k = "/etc/apt/trusted.gpg.d" String -> ShowS
    </> AptKey -> String
    keyname AptKey
    k String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ".gpg"

    -- | Cleans apt's cache of downloaded packages to avoid using up disk
    -- space.
    cacheCleaned :: Property DebianLike
    cacheCleaned :: Property DebianLike
    cacheCleaned = Property UnixLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property DebianLike)
    -> Property UnixLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ String -> [String] -> UncheckedProperty UnixLike
    cmdProperty "apt-get" ["clean"]
    	UncheckedProperty UnixLike -> Result -> Property UnixLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    NoChange
    	Property UnixLike -> String -> Property UnixLike
    forall p. IsProp p => p -> String -> p
    `describe` "apt cache cleaned"

    -- | Add a foreign architecture to dpkg and apt.
    hasForeignArch :: String -> Property DebianLike
    hasForeignArch :: String -> Property DebianLike
    hasForeignArch arch :: String
    arch = IO Bool -> Property DebianLike -> Property DebianLike
    forall (p :: * -> *) i (m :: * -> *).
    (Checkable p i, LiftPropellor m) =>
    m Bool -> p i -> Property i
    check IO Bool
    notAdded (Property UnixLike
    add Property UnixLike
    -> Property DebianLike
    -> CombinedType (Property UnixLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` Property DebianLike
    update)
    	Property DebianLike -> String -> Property DebianLike
    forall p. IsProp p => p -> String -> p
    `describe` ("dpkg has foreign architecture " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    arch)
      where
    	notAdded :: IO Bool
    notAdded = (String -> [String] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    notElem String
    arch ([String] -> Bool) -> (String -> [String]) -> String -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    lines) (String -> Bool) -> IO String -> IO Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> [String] -> IO String
    readProcess "dpkg" ["--print-foreign-architectures"]
    	add :: Property UnixLike
    add = String -> [String] -> UncheckedProperty UnixLike
    cmdProperty "dpkg" ["--add-architecture", String
    arch]
    		UncheckedProperty UnixLike -> Result -> Property UnixLike
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange

    -- | Disable the use of PDiffs for machines with high-bandwidth connections.
    noPDiffs :: Property DebianLike
    noPDiffs :: Property DebianLike
    noPDiffs = Property UnixLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property DebianLike)
    -> Property UnixLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $ "/etc/apt/apt.conf.d/20pdiffs" String -> [String] -> Property UnixLike
    `File.hasContent`
    	[ "Acquire::PDiffs \"false\";" ]

    suitePin :: DebianSuite -> String
    suitePin :: DebianSuite -> String
    suitePin s :: DebianSuite
    s = DebianSuite -> String
    prefix DebianSuite
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    showSuite DebianSuite
    s
      where
    	prefix :: DebianSuite -> String
    prefix (Stable _) = "n="
    	prefix _ = "a="

    suitePinBlock :: AptPackagePref -> DebianSuite -> PinPriority -> [Line]
    suitePinBlock :: String -> DebianSuite -> Int -> [String]
    suitePinBlock p :: String
    p suite :: DebianSuite
    suite pin :: Int
    pin =
    	[ "Explanation: This file added by propellor"
    	, "Package: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    p
    	, "Pin: release " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ DebianSuite -> String
    suitePin DebianSuite
    suite
    	, "Pin-Priority: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall t. ConfigurableValue t => t -> String
    val Int
    pin
    	]

    dpkgStatus :: FilePath
    dpkgStatus :: String
    dpkgStatus = "/var/lib/dpkg/status"

    -- | Set apt's proxy
    proxy :: Url -> Property (HasInfo + DebianLike)
    proxy :: String -> Property (HasInfo + DebianLike)
    proxy u :: String
    u = Property DebianLike
    -> Info
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    forall k (metatypes' :: k) metatypes.
    (MetaTypes metatypes' ~ (HasInfo + metatypes), SingI metatypes') =>
    Property metatypes -> Info -> Property (MetaTypes metatypes')
    setInfoProperty (String -> Property DebianLike
    proxy' String
    u) (String -> Info
    proxyInfo String
    u)
      where
    	proxyInfo :: String -> Info
    proxyInfo = InfoVal HostAptProxy -> Info
    forall v. IsInfo v => v -> Info
    toInfo (InfoVal HostAptProxy -> Info)
    -> (String -> InfoVal HostAptProxy) -> String -> Info
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HostAptProxy -> InfoVal HostAptProxy
    forall v. v -> InfoVal v
    InfoVal (HostAptProxy -> InfoVal HostAptProxy)
    -> (String -> HostAptProxy) -> String -> InfoVal HostAptProxy
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> HostAptProxy
    HostAptProxy

    proxy' :: Url -> Property DebianLike
    proxy' :: String -> Property DebianLike
    proxy' u :: String
    u = Property UnixLike -> Property DebianLike
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property UnixLike -> Property DebianLike)
    -> Property UnixLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $
    	"/etc/apt/apt.conf.d/20proxy" String -> [String] -> Property UnixLike
    `File.hasContent`
    		[ "Acquire::HTTP::Proxy \"" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    u String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "\";" ]
    		Property UnixLike -> String -> Property UnixLike
    forall p. IsProp p => p -> String -> p
    `describe` String
    desc
      where
    	desc :: String
    desc = (String
    u String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ " apt proxy selected")

    -- | Cause apt to proxy downloads via an apt cacher on localhost
    useLocalCacher :: Property (HasInfo + DebianLike)
    useLocalCacher :: Property (HasInfo + DebianLike)
    useLocalCacher = String -> Property (HasInfo + DebianLike)
    proxy "http://localhost:3142"
    	Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `requires` String -> Property DebianLike
    serviceInstalledRunning "apt-cacher-ng"
    	Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    -> String
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    forall p. IsProp p => p -> String -> p
    `describe` "apt uses local apt cacher"