summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2018-07-09 18:41:36 -0400
committerAndrew Cady <d@jerkface.net>2018-07-09 19:29:37 -0400
commitdb279470ddaafcafd9e9c28ef41f2eab1a904ead (patch)
treea86b102820fd9b70469a6f120a23a6b85c7380cd
parent31aa1e527dd9439f4c74a9c88347806e4d65f94e (diff)
werks purty good
-rw-r--r--fsmgr.hs66
1 files changed, 37 insertions, 29 deletions
diff --git a/fsmgr.hs b/fsmgr.hs
index 47ce03f..0c4bfe2 100644
--- a/fsmgr.hs
+++ b/fsmgr.hs
@@ -1,4 +1,4 @@
1{-# LANGUAGE ScopedTypeVariables #-} 1{-# LANGUAGE ScopedTypeVariables #-}
2{-# OPTIONS_GHC -fno-warn-type-defaults #-} 2{-# OPTIONS_GHC -fno-warn-type-defaults #-}
3{-# LANGUAGE ExtendedDefaultRules #-} 3{-# LANGUAGE ExtendedDefaultRules #-}
4{-# LANGUAGE InstanceSigs #-} 4{-# LANGUAGE InstanceSigs #-}
@@ -14,14 +14,14 @@ import Rebase.Prelude hiding (bool, hash, (<.>))
14import Crypto.Hash 14import Crypto.Hash
15import Crypto.Hash.Types.Digest.Read () 15import Crypto.Hash.Types.Digest.Read ()
16import Data.Yaml.Combinators 16import Data.Yaml.Combinators
17import qualified Rebase.Data.Set as Set
18import qualified Rebase.Data.Vector as Vector
19
20import Development.Shake 17import Development.Shake
21import Development.Shake.Command() 18import Development.Shake.Command ()
22import Development.Shake.FilePath 19import Development.Shake.FilePath
23import Rebase.Data.Text (pack, unpack) 20import qualified Rebase.Data.Set as Set
21import qualified Rebase.Data.Text as Text
22 ;import Rebase.Data.Text (pack, unpack)
24import Rebase.Data.Text.Encoding 23import Rebase.Data.Text.Encoding
24import qualified Rebase.Data.Vector as Vector
25{- 25{-
26 26
27Basic idea is to have a fs.yaml that specifies the build procedure. Analogous to 27Basic idea is to have a fs.yaml that specifies the build procedure. Analogous to
@@ -56,11 +56,11 @@ data BaseImageSpecification
56 deriving (Show, Read) 56 deriving (Show, Read)
57 57
58data DiskImageConfig = DiskImageConfig { 58data DiskImageConfig = DiskImageConfig {
59 initialImage :: BaseImageSpecification 59 initialImage :: BaseImageSpecification
60, packages :: Set Package 60, packages :: Set Package
61-- , debconfConfig :: DebconfConfig 61-- , debconfConfig :: DebconfConfig
62, unpackOnly :: Bool 62, unpackOnly :: Bool
63-- , patched :: Vector Text -- :: [Patch] 63, binaries :: Vector Text -- :: [Patch]
64} deriving (Show, Read) 64} deriving (Show, Read)
65 65
66parsePackageName :: Text -> Package 66parsePackageName :: Text -> Package
@@ -70,10 +70,10 @@ diskImageConfigParser :: Parser DiskImageConfig
70diskImageConfigParser = object $ 70diskImageConfigParser = object $
71 DiskImageConfig 71 DiskImageConfig
72 <$> field "parent" ((EmptyImageOfBytes <$> integer) <> (ParentImageConfigFile . unpack <$> string)) 72 <$> field "parent" ((EmptyImageOfBytes <$> integer) <> (ParentImageConfigFile . unpack <$> string))
73 <*> (Set.fromList . toList . fmap parsePackageName <$> (field "packages" (array string))) 73 <*> (Set.fromList . toList . fmap parsePackageName <$> defaultField "packages" Vector.empty (array string))
74 -- <*> pure (DebconfConfig "") 74 -- <*> pure (DebconfConfig "")
75 <*> defaultField "configure" True bool 75 <*> defaultField "unpack-only" False bool
76 -- <*> ((fromMaybe Vector.empty) <$> (optField "patches" (array string))) 76 <*> defaultField "binaries" Vector.empty (array string)
77 77
78diskImageFilename :: DiskImageConfig -> FilePath 78diskImageFilename :: DiskImageConfig -> FilePath
79diskImageFilename = (++ ".btrfs") . show . sha1 . show 79diskImageFilename = (++ ".btrfs") . show . sha1 . show
@@ -81,27 +81,20 @@ diskImageFilename = (++ ".btrfs") . show . sha1 . show
81 sha1 :: String -> Digest SHA1 81 sha1 :: String -> Digest SHA1
82 sha1 = hash . encodeUtf8 . pack 82 sha1 = hash . encodeUtf8 . pack
83 83
84targetConfig :: DiskImageConfig
85targetConfig = undefined
86
87targetFilename :: FilePath
88targetFilename = diskImageFilename targetConfig
89
90readCfg :: FilePath -> Action DiskImageConfig 84readCfg :: FilePath -> Action DiskImageConfig
91readCfg yaml = either error id . parse diskImageConfigParser . encodeUtf8 . pack <$> readFile' yaml 85readCfg yaml = either error id . parse diskImageConfigParser . encodeUtf8 . pack <$> readFile' yaml
92 86
93s :: String -> String
94s = id
95
96buildRoot :: DiskImageConfig -> FilePath -> Action () 87buildRoot :: DiskImageConfig -> FilePath -> Action ()
97buildRoot DiskImageConfig{..} finalOut = do 88buildRoot DiskImageConfig{..} finalOut = do
98 let out = finalOut <.> "tmp" 89 let out = finalOut <.> "tmp"
99 mountpoint = finalOut <.> "mnt" 90 mountpoint = finalOut <.> "mnt"
91 cmd_ "sh -c" ["! mountpoint -q \"$0\" || umount \"$0\" ", mountpoint]
100 case initialImage of 92 case initialImage of
101 ParentImageConfigFile f -> do 93 ParentImageConfigFile f -> do
102 let parent = f -<.> "yaml" <.> "btrfs" 94 let parent = "_build" </> f -<.> "btrfs"
103 need [parent] 95 need [parent]
104 cmd_ "cp --reflink" [parent, out] 96 cmd_ "cp --reflink" [parent, out]
97 cmd_ "mkdir -p" [mountpoint]
105 cmd_ "mount -t btrfs" [out] mountpoint 98 cmd_ "mount -t btrfs" [out] mountpoint
106 EmptyImageOfBytes n -> do 99 EmptyImageOfBytes n -> do
107 cmd_ "truncate -s" [show n] [out] 100 cmd_ "truncate -s" [show n] [out]
@@ -109,29 +102,44 @@ buildRoot DiskImageConfig{..} finalOut = do
109 cmd_ "mkdir -p" [mountpoint] 102 cmd_ "mkdir -p" [mountpoint]
110 cmd_ "mount -t btrfs" [out] mountpoint 103 cmd_ "mount -t btrfs" [out] mountpoint
111 createDefaultSubvolume mountpoint 104 createDefaultSubvolume mountpoint
105 cmd_ (Cwd mountpoint) "mkdir -p root/var/cache/apt"
112 cmd_ (Cwd mountpoint) "btrfs subvolume create root/var/cache/apt/archives" 106 cmd_ (Cwd mountpoint) "btrfs subvolume create root/var/cache/apt/archives"
113 cmd_ "selfstrap" (("--unpack" `consWhen` unpackOnly) ["-t", mountpoint]) (unpack . coerce <$> toList packages) 107 -- TODO: catch errors and umount, rmdir mountpoint
108 cmd_ "selfstrap --skip-update"
109 (("--unpack" `consWhen` unpackOnly) ["-t", mountpoint]) (unpack . coerce <$> toList packages)
110 cmd_ "mv" [out, finalOut]
114 111
115consWhen :: a -> Bool -> [a] -> [a] 112consWhen :: a -> Bool -> [a] -> [a]
116a `consWhen` c = if c then (a:) else id 113a `consWhen` c = if c then (a:) else id
117 114
115strip :: String -> String
116strip = unpack . Text.strip . pack
117
118createDefaultSubvolume :: FilePath -> Action () 118createDefaultSubvolume :: FilePath -> Action ()
119createDefaultSubvolume mountpoint = do 119createDefaultSubvolume mountpoint = do
120 cmd_ (Cwd mountpoint) "btrfs subvolume create root" 120 cmd_ (Cwd mountpoint) "btrfs subvolume create root"
121 Stdout (subvolId::String) <- cmd (Cwd mountpoint) "sh -c" 121 Stdout subvolIdLine <- cmd (Cwd mountpoint) "sh -c"
122 ["btrfs subvolume show root | sed -n -e 's/^[ \t]*Subvolume ID:[ \t]*//p; s/.*is toplevel subvolume/5/p'"] 122 ["btrfs subvolume show root | sed -n -e 's/^[ \t]*Subvolume ID:[ \t]*//p; s/.*is toplevel subvolume/5/p'"]
123 let subvolId = strip subvolIdLine
123 when (null subvolId) $ fail "could not obtain btrfs Subvolume ID" 124 when (null subvolId) $ fail "could not obtain btrfs Subvolume ID"
124 cmd_ "btrfs subvolume set-default" [subvolId, mountpoint] 125 cmd_ "btrfs subvolume set-default" [strip subvolId, mountpoint]
125 126
127defaultImageName :: String
128defaultImageName = "minbase"
126 129
130stripSuffix :: Text -> String -> String
131stripSuffix s t = fromMaybe t $ fmap unpack $ Text.stripSuffix s $ pack t
127 132
128main :: IO () 133main :: IO ()
129main = do 134main = do
135 -- TODO: Fail early on:
136 -- 1. not running as root
137 -- 2. no "selfstrap" in PATH
130 args <- getArgs 138 args <- getArgs
131 case args of 139 case args of
132 [target] -> shakeBuildOneImage target 140 [target] -> shakeBuildOneImage (stripSuffix ".yaml" target)
133 [] -> shakeBuildOneImage "image" 141 [] -> shakeBuildOneImage defaultImageName
134 _ -> error "usage" 142 _ -> error "usage"
135 143
136shakeBuildOneImage :: FilePath -> IO () 144shakeBuildOneImage :: FilePath -> IO ()
137shakeBuildOneImage target = 145shakeBuildOneImage target =