diff options
| author | Joey Hess <joeyh@joeyh.name> | 2017-07-05 17:29:19 -0400 |
|---|---|---|
| committer | Joey Hess <joeyh@joeyh.name> | 2017-07-05 17:29:19 -0400 |
| commit | 9648e1797f7f08b3465f6c301404ee0555c20881 (patch) | |
| tree | 9273d7a1b1e6ae2223aac05bbb6f8afc162845ba /src | |
| parent | 9d6c50fff28ed5ba7da7fdd2989c7773e357a3c3 (diff) | |
| parent | 3451ca8beeb58a3bdd864cd1009ba9f0e314b442 (diff) | |
Merge branch 'joeyconfig'
Diffstat (limited to 'src')
| -rw-r--r-- | src/Propellor/Property.hs | 1 | ||||
| -rw-r--r-- | src/Propellor/Property/DiskImage.hs | 6 | ||||
| -rw-r--r-- | src/Propellor/Property/File.hs | 50 | ||||
| -rw-r--r-- | src/Propellor/Property/LightDM.hs | 3 | ||||
| -rw-r--r-- | src/Propellor/Property/XFCE.hs | 41 |
5 files changed, 87 insertions, 14 deletions
diff --git a/src/Propellor/Property.hs b/src/Propellor/Property.hs index 8b2a4e3d..55e688ab 100644 --- a/src/Propellor/Property.hs +++ b/src/Propellor/Property.hs @@ -50,6 +50,7 @@ import Data.Monoid import Control.Monad.IfElse import "mtl" Control.Monad.RWS.Strict import System.Posix.Files +import Data.Maybe import Data.List import Data.Hashable import Control.Applicative diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs index d5898d7c..89a8d0c6 100644 --- a/src/Propellor/Property/DiskImage.hs +++ b/src/Propellor/Property/DiskImage.hs @@ -49,7 +49,11 @@ type DiskImage = FilePath -- First the specified Chroot is set up, and its properties are satisfied. -- -- Then, the disk image is set up, and the chroot is copied into the --- appropriate partition(s) of it. +-- appropriate partition(s) of it. +-- +-- The partitions default to being sized just large enough to fit the files +-- from the chroot. You can use `addFreeSpace` to make them a bit larger +-- than that, or `setSize` to use a fixed size. -- -- Note that the disk image file is reused if it already exists, -- to avoid expensive IO to generate a new one. And, it's updated in-place, diff --git a/src/Propellor/Property/File.hs b/src/Propellor/Property/File.hs index 459fe2c7..3293599a 100644 --- a/src/Propellor/Property/File.hs +++ b/src/Propellor/Property/File.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleInstances, FlexibleContexts #-} module Propellor.Property.File where @@ -105,11 +105,11 @@ hasPrivContent' writemode source f context = -- | Replaces the content of a file with the transformed content of another file basedOn :: FilePath -> (FilePath, [Line] -> [Line]) -> Property UnixLike -f `basedOn` (f', a) = property' desc $ \o -> do - tmpl <- liftIO $ readFile f' +f `basedOn` (src, a) = property' desc $ \o -> do + tmpl <- liftIO $ readFile src ensureProperty o $ fileProperty desc (\_ -> a $ lines $ tmpl) f where - desc = f ++ " is based on " ++ f' + desc = f ++ " is based on " ++ src -- | Removes a file. Does not remove symlinks or non-plain-files. notPresent :: FilePath -> Property UnixLike @@ -150,23 +150,26 @@ link `isSymlinkedTo` (LinkTarget target) = property desc $ -- | Ensures that a file is a copy of another (regular) file. isCopyOf :: FilePath -> FilePath -> Property UnixLike -f `isCopyOf` f' = property desc $ go =<< (liftIO $ tryIO $ getFileStatus f') +f `isCopyOf` src = property desc $ go =<< (liftIO $ tryIO $ getFileStatus src) where - desc = f ++ " is copy of " ++ f' + desc = f ++ " is copy of " ++ src go (Right stat) = if isRegularFile stat - then gocmp =<< (liftIO $ cmp) - else warningMessage (f' ++ " is not a regular file") >> + then ifM (liftIO $ doesFileExist f) + ( gocmp =<< (liftIO $ cmp) + , doit + ) + else warningMessage (src ++ " is not a regular file") >> return FailedChange go (Left e) = warningMessage (show e) >> return FailedChange - cmp = safeSystem "cmp" [Param "-s", Param "--", File f, File f'] + cmp = safeSystem "cmp" [Param "-s", Param "--", File f, File src] gocmp ExitSuccess = noChange gocmp (ExitFailure 1) = doit gocmp _ = warningMessage "cmp failed" >> return FailedChange - doit = makeChange $ copy f' `viaStableTmp` f - copy src dest = unlessM (runcp src dest) $ errorMessage "cp failed" - runcp src dest = boolSystem "cp" + doit = makeChange $ copy `viaStableTmp` f + copy dest = unlessM (runcp dest) $ errorMessage "cp failed" + runcp dest = boolSystem "cp" [Param "--preserve=all", Param "--", File src, File dest] -- | Ensures that a file/dir has the specified owner and group. @@ -177,6 +180,20 @@ ownerGroup f (User owner) (Group group) = p `describe` (f ++ " owner " ++ og) `changesFile` f og = owner ++ ":" ++ group +-- | Given a base directory, and a relative path under that +-- directory, applies a property to each component of the path in turn, +-- starting with the base directory. +-- +-- For example, to make a file owned by a user, making sure their home +-- directory and the subdirectories to it are also owned by them: +-- +-- > "/home/user/program/file" `hasContent` ["foo"] +-- > `before` applyPath "/home/user" ".config/program/file" +-- > (\f -> ownerGroup f (User "user") (Group "user")) +applyPath :: Monoid (Property metatypes) => FilePath -> FilePath -> (FilePath -> Property metatypes) -> Property metatypes +applyPath basedir relpath mkp = mconcat $ + map mkp (scanl (</>) basedir (splitPath relpath)) + -- | Ensures that a file/dir has the specfied mode. mode :: FilePath -> FileMode -> Property UnixLike mode f v = p `changesFile` f @@ -290,3 +307,12 @@ readConfigFileName = readish . unescape Nothing -> '_' : ns ++ unescape cs' Just n -> chr n : unescape cs' unescape (c:cs) = c : unescape cs + +data Overwrite = OverwriteExisting | PreserveExisting + +-- | When passed PreserveExisting, only ensures the property when the file +-- does not exist. +checkOverwrite :: Overwrite -> FilePath -> (FilePath -> Property i) -> Property i +checkOverwrite OverwriteExisting f mkp = mkp f +checkOverwrite PreserveExisting f mkp = + check (not <$> doesFileExist f) (mkp f) diff --git a/src/Propellor/Property/LightDM.hs b/src/Propellor/Property/LightDM.hs index 339fa9a3..69538d89 100644 --- a/src/Propellor/Property/LightDM.hs +++ b/src/Propellor/Property/LightDM.hs @@ -10,7 +10,8 @@ installed :: Property DebianLike installed = Apt.installed ["lightdm"] -- | Configures LightDM to skip the login screen and autologin as a user. -autoLogin :: User -> Property UnixLike +autoLogin :: User -> Property DebianLike autoLogin (User u) = "/etc/lightdm/lightdm.conf" `ConfFile.containsIniSetting` ("SeatDefaults", "autologin-user", u) `describe` "lightdm autologin" + `requires` installed diff --git a/src/Propellor/Property/XFCE.hs b/src/Propellor/Property/XFCE.hs new file mode 100644 index 00000000..dc57660f --- /dev/null +++ b/src/Propellor/Property/XFCE.hs @@ -0,0 +1,41 @@ +module Propellor.Property.XFCE where + +import Propellor.Base +import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.File as File +import qualified Propellor.Property.User as User + +installed :: Property DebianLike +installed = Apt.installed ["task-xfce-desktop"] + `describe` "XFCE desktop installed" + +-- | Minimal install of XFCE, with a terminal emulator and panel, +-- and X and network-manager, but not any of the extra apps. +installedMin :: Property DebianLike +installedMin = Apt.installedMin ["xfce4", "xfce4-terminal", "task-desktop"] + `describe` "minimal XFCE desktop installed" + +-- | Installs network-manager-gnome, which is the way to get +-- network-manager to manage networking in XFCE too. +networkManager :: Property DebianLike +networkManager = Apt.installedMin ["network-manager-gnome"] + +-- | Normally at first login, XFCE asks what kind of panel the user wants. +-- This enables the default configuration noninteractively. +defaultPanelFor :: User -> File.Overwrite -> Property DebianLike +defaultPanelFor u@(User username) overwrite = property' desc $ \w -> do + home <- liftIO $ User.homedir u + ensureProperty w (go home) + where + desc = "default XFCE panel for " ++ username + basecf = ".config" </> "xfce4" </> "xfconf" + </> "xfce-perchannel-xml" </> "xfce4-panel.xml" + -- This location is probably Debian-specific. + defcf = "/etc/xdg/xfce4/panel/default.xml" + go :: FilePath -> Property DebianLike + go home = tightenTargets $ + File.checkOverwrite overwrite (home </> basecf) $ \cf -> + cf `File.isCopyOf` defcf + `before` File.applyPath home basecf + (\f -> File.ownerGroup f u (userGroup u)) + `requires` Apt.installed ["xfce4-panel"] |
