@@ -28,7 +28,7 @@ data RunMountArg
2828 | MountArgSharing CacheSharing
2929 | MountArgSource SourcePath
3030 | MountArgTarget TargetPath
31- | MountArgType Text
31+ | MountArgType MountType
3232 | MountArgUid Text
3333 | MountArgGid Text
3434 deriving (Show )
@@ -39,6 +39,7 @@ data MountType
3939 | Tmpfs
4040 | Secret
4141 | Ssh
42+ deriving (Show )
4243
4344parseRun :: (? esc :: Char ) => Parser (Instruction Text )
4445parseRun = do
@@ -83,32 +84,29 @@ runFlagNetwork = do
8384runFlagMount :: (? esc :: Char ) => Parser RunMount
8485runFlagMount = do
8586 void $ string " --mount="
86- maybeType <-
87- choice
88- [ string " type="
89- *> choice
90- [ Just Bind <$ string " bind" ,
91- Just Cache <$ string " cache" ,
92- Just Tmpfs <$ string " tmpfs" ,
93- Just Secret <$ string " secret" ,
94- Just Ssh <$ string " ssh"
95- ],
96- pure Nothing
97- ]
98- (mountType, args) <- return $
99- case maybeType of
100- Nothing -> (Bind , argsParser Bind )
101- Just Ssh -> (Ssh , choice [string " ," *> argsParser Ssh , pure [] ])
102- Just t -> (t, string " ," *> argsParser t)
103- case mountType of
104- Bind -> BindMount <$> (bindMount =<< args)
105- Cache -> CacheMount <$> (cacheMount =<< args)
106- Tmpfs -> TmpfsMount <$> (tmpfsMount =<< args)
107- Secret -> SecretMount <$> (secretMount =<< args)
108- Ssh -> SshMount <$> (secretMount =<< args)
109-
110- argsParser :: (? esc :: Char ) => MountType -> Parser [RunMountArg ]
111- argsParser mountType = mountChoices mountType `sepBy1` string " ,"
87+ args <- mountArgs `sepBy1` string " ,"
88+ mt <- parseTypeFromArgs args
89+ case mt of
90+ Bind -> BindMount <$> (bindMount $ filter (not . isMountArgType) args)
91+ Cache -> CacheMount <$> (cacheMount $ filter (not . isMountArgType) args)
92+ Tmpfs -> TmpfsMount <$> (tmpfsMount $ filter (not . isMountArgType) args)
93+ Secret -> SecretMount <$> (secretMount $ filter (not . isMountArgType) args)
94+ Ssh -> SshMount <$> (secretMount $ filter (not . isMountArgType) args)
95+
96+ parseTypeFromArgs :: [RunMountArg ] -> Parser MountType
97+ parseTypeFromArgs args =
98+ -- `notFollowedBy eof` is a trivially succeeding parser that isn't supposed to
99+ -- consume any input here. It's a hack that converts a simple type into a
100+ -- parser. This allows this function to emit parse errors after analyzing its
101+ -- input arguments and not consume any input.
102+ case filter isMountArgType args of
103+ [] -> Bind <$ notFollowedBy eof
104+ [(MountArgType t)] -> t <$ notFollowedBy eof
105+ _: _ -> fail $ " --mount with multiple `type` arguments"
106+
107+ isMountArgType :: RunMountArg -> Bool
108+ isMountArgType (MountArgType _) = True
109+ isMountArgType _ = False
112110
113111bindMount :: [RunMountArg ] -> Parser BindOpts
114112bindMount args =
@@ -188,6 +186,7 @@ validArgs typeName allowed required args =
188186 [] -> result
189187 missing -> Left $ MissingArgument missing
190188 where
189+ checkValidArg :: RunMountArg -> (Either DockerfileError [RunMountArg ], Set. Set Text ) -> (Either DockerfileError [RunMountArg ], Set. Set Text )
191190 checkValidArg _ x@ (Left _, _) = x
192191 checkValidArg a (Right as, seen) =
193192 let name = toArgName a
@@ -196,38 +195,22 @@ validArgs typeName allowed required args =
196195 (_, True ) -> (Left (DuplicateArgument name), seen)
197196 (True , False ) -> (Right (a : as), Set. insert name seen)
198197
199- mountChoices :: (? esc :: Char ) => MountType -> Parser RunMountArg
200- mountChoices mountType =
201- choice $
202- case mountType of
203- Bind ->
204- [ mountArgTarget,
205- mountArgSource,
206- mountArgFromImage,
207- mountArgReadOnly
208- ]
209- Cache ->
210- [ mountArgTarget,
211- mountArgSource,
212- mountArgFromImage,
213- mountArgReadOnly,
214- mountArgId,
215- mountArgSharing,
216- mountArgMode,
217- mountArgUid,
218- mountArgGid
219- ]
220- Tmpfs -> [mountArgTarget]
221- _ -> -- Secret and Ssh
222- [ mountArgTarget,
223- mountArgId,
224- mountArgRequired,
225- mountArgSource,
226- mountArgMode,
227- mountArgUid,
228- mountArgGid,
229- mountArgEnv
230- ]
198+ mountArgs :: (? esc :: Char ) => Parser RunMountArg
199+ mountArgs =
200+ choice
201+ [ mountArgEnv,
202+ mountArgFromImage,
203+ mountArgGid,
204+ mountArgId,
205+ mountArgMode,
206+ mountArgReadOnly,
207+ mountArgRequired,
208+ mountArgSharing,
209+ mountArgSource,
210+ mountArgTarget,
211+ mountArgType,
212+ mountArgUid
213+ ]
231214
232215stringArg :: (? esc :: Char ) => Parser Text
233216stringArg = choice [doubleQuotedString, someUnless " a string" (== ' ,' )]
@@ -319,6 +302,19 @@ mountArgTarget = do
319302 label " target=" $ choice [string " target=" , string " dst=" , string " destination=" ]
320303 MountArgTarget . TargetPath <$> stringArg
321304
305+ mountArgType :: Parser RunMountArg
306+ mountArgType = MountArgType <$> key " type" mountType
307+
308+ mountType :: Parser MountType
309+ mountType =
310+ choice
311+ [ Bind <$ string " bind" ,
312+ Cache <$ string " cache" ,
313+ Tmpfs <$ string " tmpfs" ,
314+ Secret <$ string " secret" ,
315+ Ssh <$ string " ssh"
316+ ]
317+
322318mountArgUid :: (? esc :: Char ) => Parser RunMountArg
323319mountArgUid = MountArgUid <$> key " uid" stringArg
324320
0 commit comments