allow use of host:port in a FROM instruction#75
allow use of host:port in a FROM instruction#75petitlapin wants to merge 1 commit intohadolint:masterfrom
Conversation
|
@lorenzo @m-ildefons , hi can you please take a look when you have some time? |
|
Hi @petitlapin ,
Let me know if you need any help with that. |
|
Hi, |
|
Hi, not sure on how much time you want to spend helping me but if you don't have, I guess we can close this PR and it can be implemented later by someone who has the knowledge. parseRegistry :: (?esc :: Char) => Parser Registry
parseRegistry = do
registry <- someUnless "a domain name" (\c -> c== '/')will give me whatever is before '/' if there is one. |
|
Hi, Regarding your question, try writing down the type signature of such a function first, it makes things somewhat easier: isDomainName :: Text -> BoolThe input is just a isDomainName dom
| isJust (find (== '.') dom) = True
| isJust (find (== ':') dom) = True
| otherwise = FalseThis is Haskell syntax expressing the equivalent of a Just as a side note, You can't call A -- This parser will succeed only if it can find something that looks like a domain name
-- at the beginning of the input. In case it also finds something that looks like a port
-- (e.g. `:5000`) it will also consume that and append it at the end of the return value.
parseRegistry :: Parser Registry
parseRegistry = do
domain <- parseDomain
port <- optional parsePort -- note the `optional` [1]
if isJust port
then return $ Registry ( domain <> ":" <> port )
else return $ Registry domain
-- This parser only succeeds if it can find something that roughly looks like a domain name
parseDomain :: Parser Text
parseDomain = do
subdomain <- someUnless "a subdomain" (/= '.')
void $ char '.' -- this ensures there is at least one dot '.' in the domain (e.g. 'docker.io')
domain <- someUnless "a domain" isIllegalChar
return $ subdomain <> "." <> domain
where
-- returns `False` as long as the given char may occur in a domain name and `True` if it is
-- illegal in the context of a domain name (e.g. ':', '/', '&')
isIllegalChar :: Char -> Bool
isIllegalChar c = (not isAlphaNum c) && (c /= '.')
parsePort :: Parser Text
parsePort = do
void $ char ':' -- needs to start with colon, but we will throw it away
some digitChar -- one or more digits, fails if there are noneI haven't tried any of these parser, but I think they should convey how the program could be structured and how combinators can be leveraged to deal with optional parts of a URI. Note however that this is still a very naive implementation and will fail horribly in edge cases like raw IPv6 addresses. [1] The I hope you are not discouraged from Haskell by this. You are working on a hard problem and these parsers are not easy to grok. If you have more questions, feel free to ask, I'm happy to help you. |
|
Hi, don't worry for the delay, 3-4 days is more than acceptable :). I have a few things to do before coming back to this PR but I'll check it as soon as I can. Thank you again for the complete explanation (and yes, there is no need to do a solution in a hurry if it is not good enough or come back to it later) |
|
Hi, I still have issues trying to understand how to make it work. A registry can either be (I added the corresponding unit test in the PR): followed by a slash. However, if there are neither a tld or a port, it is not a domain but part of image name. parseRegistry :: Parser Registry
parseRegistry = do
domain <- (Just <$> try parseUntilDotOrSemiColonAndNoSlash) <|> return Nothing -- if we find a / before a : or a ., there is no registry
port <- (Just <$> try parseUntilSlash) <|> return Nothing
return $ Registry (domain <> separator <> port) -- where 'separator' would be the first : or . foundso parseUntilDotOrSemiColonAndNoSlash would be something like: parseUntilDotOrSemiColonAndNoSlash :: Parser Text
parseUntilDotOrSemiColonAndNoSlash = do
subdomain <- someUnless "a subdomain" (\c -> c == '.' || c == '/' || c == ':')
if c == '/' -- Issue: how can we access c here or fail above if the first character is a '/'?
then return Nothing
else return $ subdomainand parseUntilSlash: parseUntilSlash :: Parser Text
parseUntilSlash = do
portOrTld <- someUnless "a subdomain" ( == '/')
return $ portOrTldI can commit the (non working) code if it is easier to debug. |
when having a FROM line like:
FROM myregistry:port/imagename:tag, there is an errorunexpected ':' expecting '@', a new line followed by the next instruction, at least one space, or the image tag.This patch proposes to simplify how the registry is computed.
fixes: hadolint/hadolint#355
Note: I don't know haskell, I tested the change by cloning the repo, and testing on a local file using the test in integration-tests