@@ -8,25 +8,31 @@
8{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TypeApplications #-}
9{-# LANGUAGE TypeApplications #-}
10module Obelisk.Command.Thunk
10module Obelisk.Command.Thunk
13+ , ReadThunkError (..)
16+ , ThunkPackConfig (..)
11− ( ThunkPtr (..)
17+ , ThunkPtr (..)
12 , ThunkRev (..)
18 , ThunkRev (..)
13 , ThunkSource (..)
19 , ThunkSource (..)
14− , ThunkData (..)
20+ , ThunkUpdateConfig (..)
15− , ReadThunkError (..)
21+ , attrCacheFileName
19− , updateThunkToLatest
20 , createThunk
22 , createThunk
21 , createThunkWithLatest
23 , createThunkWithLatest
22 , nixBuildAttrWithCache
28 , nixBuildAttrWithCache
23 , nixBuildThunkAttrWithCache
29 , nixBuildThunkAttrWithCache
25 , packThunk
30 , packThunk
26 , readThunk
32 , readThunk
27 , updateThunk
34 , updateThunk
28− , getThunkPtr
35+ , updateThunkToLatest
30 , uriThunkPtr
36 , uriThunkPtr
@@ -42,6 +48,7 @@ import qualified Data.Aeson as Aeson
42import Data.Aeson.Encode.Pretty
48import Data.Aeson.Encode.Pretty
43import qualified Data.Aeson.Types as Aeson
49import qualified Data.Aeson.Types as Aeson
44import qualified Data.ByteString.Lazy as LBS
50import qualified Data.ByteString.Lazy as LBS
51+import Data.Containers.ListUtils (nubOrd)
45import Data.Default
52import Data.Default
46import Data.Either.Combinators (fromRight', rightToMaybe)
53import Data.Either.Combinators (fromRight', rightToMaybe)
47import Data.Git.Ref (Ref)
54import Data.Git.Ref (Ref)
@@ -64,12 +71,12 @@ import GitHub
64import GitHub.Data.Name
71import GitHub.Data.Name
65import Obelisk.Command.Nix
72import Obelisk.Command.Nix
66import System.Directory
73import System.Directory
67import System.FilePath
75import System.FilePath
68import System.IO.Error
76import System.IO.Error
69import System.IO.Temp
77import System.IO.Temp
70import System.Posix (getSymbolicLinkStatus, modificationTime)
78import System.Posix (getSymbolicLinkStatus, modificationTime)
71−import System.Process (proc)
79+import qualified Text.URI as URI
74import Obelisk.App (MonadObelisk)
81import Obelisk.App (MonadObelisk)
75import Obelisk.CliApp
82import Obelisk.CliApp
@@ -111,37 +118,63 @@ data GitHubSource = GitHubSource
111 { _gitHubSource_owner :: Name Owner
118 { _gitHubSource_owner :: Name Owner
112 , _gitHubSource_repo :: Name Repo
119 , _gitHubSource_repo :: Name Repo
113 , _gitHubSource_branch :: Maybe (Name Branch)
120 , _gitHubSource_branch :: Maybe (Name Branch)
121+ , _gitHubSource_private :: Bool
115 deriving (Show, Eq, Ord)
123 deriving (Show, Eq, Ord)
125+newtype GitUri = GitUri { unGitUri :: URI.URI } deriving (Eq, Ord, Show)
127+gitUriToText :: GitUri -> Text
128+gitUriToText (GitUri uri)
129+ | (T.toLower . URI.unRText <$> URI.uriScheme uri) == Just "file"
130+ , Just (_, path) <- URI.uriPath uri
131+ = "/" <> T.intercalate "/" (map URI.unRText $ NonEmpty.toList path)
132+ | otherwise = URI.render uri
117data GitSource = GitSource
134data GitSource = GitSource
118− { _gitSource_url :: URI
135+ { _gitSource_url :: GitUri
119 , _gitSource_branch :: Maybe (Name Branch)
136 , _gitSource_branch :: Maybe (Name Branch)
120 , _gitSource_fetchSubmodules :: Bool
137 , _gitSource_fetchSubmodules :: Bool
138+ , _gitSource_private :: Bool
122 deriving (Show, Eq, Ord)
140 deriving (Show, Eq, Ord)
142+newtype ThunkConfig = ThunkConfig
143+ { _thunkConfig_private :: Maybe Bool
146+data ThunkUpdateConfig = ThunkUpdateConfig
147+ { _thunkUpdateConfig_branch :: Maybe String
148+ , _thunkUpdateConfig_config :: ThunkConfig
151+data ThunkPackConfig = ThunkPackConfig
152+ { _thunkPackConfig_force :: Bool
153+ , _thunkPackConfig_config :: ThunkConfig
124-- | Convert a GitHub source to a regular Git source. Assumes no submodules.
156-- | Convert a GitHub source to a regular Git source. Assumes no submodules.
125forgetGithub :: Bool -> GitHubSource -> GitSource
157forgetGithub :: Bool -> GitHubSource -> GitSource
126forgetGithub useSsh s = GitSource
158forgetGithub useSsh s = GitSource
127− { _gitSource_url = URI
159+ { _gitSource_url = GitUri $ URI.URI
128− { uriScheme = Just $ fromRight' $ mkScheme $ if useSsh then "ssh" else "https"
160+ { URI.uriScheme = Just $ fromRight' $ URI.mkScheme $ if useSsh then "ssh" else "https"
129− , uriAuthority = Right $ Authority
161+ , URI.uriAuthority = Right $ URI.Authority
130− { authUserInfo = UserInfo (fromRight' $ mkUsername "git") Nothing
162+ { URI.authUserInfo = URI.UserInfo (fromRight' $ URI.mkUsername "git") Nothing
131 <$ guard useSsh
163 <$ guard useSsh
132− , authHost = fromRight' $ mkHost "github.com"
164+ , URI.authHost = fromRight' $ URI.mkHost "github.com"
133− , authPort = Nothing
165+ , URI.authPort = Nothing
135− , uriPath = Just ( False
167+ , URI.uriPath = Just ( False
136− , fromRight' . mkPathPiece <$>
168+ , fromRight' . URI.mkPathPiece <$>
137 untagName (_gitHubSource_owner s)
169 untagName (_gitHubSource_owner s)
138 :| [ untagName (_gitHubSource_repo s) <> ".git" ]
170 :| [ untagName (_gitHubSource_repo s) <> ".git" ]
140− , uriQuery = []
172+ , URI.uriQuery = []
141− , uriFragment = Nothing
173+ , URI.uriFragment = Nothing
143 , _gitSource_branch = _gitHubSource_branch s
175 , _gitSource_branch = _gitHubSource_branch s
144 , _gitSource_fetchSubmodules = False
176 , _gitSource_fetchSubmodules = False
177+ , _gitSource_private = _gitHubSource_private s
147getThunkGitBranch :: ThunkPtr -> Maybe Text
180getThunkGitBranch :: ThunkPtr -> Maybe Text
@@ -155,20 +188,20 @@ commitNameToRef (N c) = Ref.fromHex $ encodeUtf8 c
155-- TODO: Use spinner here.
188-- TODO: Use spinner here.
156getNixSha256ForUriUnpacked
189getNixSha256ForUriUnpacked
157 :: MonadObelisk m
190 :: MonadObelisk m
158− => URI
191+ => GitUri
159 -> m NixSha256
192 -> m NixSha256
160getNixSha256ForUriUnpacked uri =
193getNixSha256ForUriUnpacked uri =
161− withExitFailMessage ("nix-prefetch-url: Failed to determine sha256 hash of URL " <> render uri) $ do
194+ withExitFailMessage ("nix-prefetch-url: Failed to determine sha256 hash of URL " <> gitUriToText uri) $ do
162 [hash] <- fmap T.lines $ readProcessAndLogOutput (Debug, Debug) $
195 [hash] <- fmap T.lines $ readProcessAndLogOutput (Debug, Debug) $
163− proc "nix-prefetch-url" ["--unpack" , "--type" , "sha256" , T.unpack $ render uri]
196+ proc "nix-prefetch-url" ["--unpack", "--type", "sha256", T.unpack $ gitUriToText uri]
164 pure hash
197 pure hash
166−nixPrefetchGit :: MonadObelisk m => URI -> Text -> Bool -> m NixSha256
199+nixPrefetchGit :: MonadObelisk m => GitUri -> Text -> Bool -> m NixSha256
167nixPrefetchGit uri rev fetchSubmodules =
200nixPrefetchGit uri rev fetchSubmodules =
168− withExitFailMessage ("nix-prefetch-git: Failed to determine sha256 hash of Git repo " <> render uri <> " at " <> rev) $ do
201+ withExitFailMessage ("nix-prefetch-git: Failed to determine sha256 hash of Git repo " <> gitUriToText uri <> " at " <> rev) $ do
169 out <- readProcessAndLogStderr Debug $
202 out <- readProcessAndLogStderr Debug $
170 proc "nix-prefetch-git" $ filter (/="")
203 proc "nix-prefetch-git" $ filter (/="")
171− [ "--url", T.unpack $ render uri
204+ [ "--url", T.unpack $ gitUriToText uri
172 , "--rev", T.unpack rev
205 , "--rev", T.unpack rev
173 , if fetchSubmodules then "--fetch-submodules" else ""
206 , if fetchSubmodules then "--fetch-submodules" else ""
174 , "--quiet"
207 , "--quiet"
@@ -199,6 +232,9 @@ readThunk thunkDir = do
199 False -> return $ return Nothing
232 False -> return $ return Nothing
200 False -> liftIO $ fmap ThunkData_Packed <$> readPackedThunk thunkDir
233 False -> liftIO $ fmap ThunkData_Packed <$> readPackedThunk thunkDir
235+attrCacheFileName :: FilePath
236+attrCacheFileName = ".attr-cache"
202data ThunkType = ThunkType
238data ThunkType = ThunkType
203 { _thunkType_loader :: FilePath
239 { _thunkType_loader :: FilePath
204 , _thunkType_json :: FilePath
240 , _thunkType_json :: FilePath
@@ -211,7 +247,7 @@ gitHubThunkType :: ThunkType
211gitHubThunkType = ThunkType
247gitHubThunkType = ThunkType
212 { _thunkType_loader = "default.nix"
248 { _thunkType_loader = "default.nix"
213 , _thunkType_json = "github.json"
249 , _thunkType_json = "github.json"
214− , _thunkType_optional = Set.fromList [".attr-cache"]
250+ , _thunkType_optional = Set.fromList [attrCacheFileName]
215 , _thunkType_loaderVersions = gitHubStandaloneLoaders
251 , _thunkType_loaderVersions = gitHubStandaloneLoaders
216 , _thunkType_parser = parseThunkPtr $ \v ->
252 , _thunkType_parser = parseThunkPtr $ \v ->
217 ThunkSource_GitHub <$> parseGitHubSource v <|> ThunkSource_Git <$> parseGitSource v
253 ThunkSource_GitHub <$> parseGitHubSource v <|> ThunkSource_Git <$> parseGitSource v
@@ -221,7 +257,7 @@ gitThunkType :: ThunkType
221gitThunkType = ThunkType
257gitThunkType = ThunkType
222 { _thunkType_loader = "default.nix"
258 { _thunkType_loader = "default.nix"
223 , _thunkType_json = "git.json"
259 , _thunkType_json = "git.json"
224− , _thunkType_optional = Set.fromList [".attr-cache"]
260+ , _thunkType_optional = Set.fromList [attrCacheFileName]
225 , _thunkType_loaderVersions = plainGitStandaloneLoaders
261 , _thunkType_loaderVersions = plainGitStandaloneLoaders
226 , _thunkType_parser = parseThunkPtr $ fmap ThunkSource_Git . parseGitSource
262 , _thunkType_parser = parseThunkPtr $ fmap ThunkSource_Git . parseGitSource
@@ -286,10 +322,12 @@ parseGitHubSource v = do
286 owner <- v Aeson..: "owner"
322 owner <- v Aeson..: "owner"
287 repo <- v Aeson..: "repo"
323 repo <- v Aeson..: "repo"
288 branch <- v Aeson..:! "branch"
324 branch <- v Aeson..:! "branch"
325+ private <- v Aeson..:? "private"
289 pure $ GitHubSource
326 pure $ GitHubSource
290 { _gitHubSource_owner = owner
327 { _gitHubSource_owner = owner
291 , _gitHubSource_repo = repo
328 , _gitHubSource_repo = repo
292 , _gitHubSource_branch = branch
329 , _gitHubSource_branch = branch
330+ , _gitHubSource_private = fromMaybe False private
295parseGitSource :: Aeson.Object -> Aeson.Parser GitSource
333parseGitSource :: Aeson.Object -> Aeson.Parser GitSource
@@ -297,10 +335,12 @@ parseGitSource v = do
297 Just url <- parseGitUri <$> v Aeson..: "url"
335 Just url <- parseGitUri <$> v Aeson..: "url"
298 branch <- v Aeson..:! "branch"
336 branch <- v Aeson..:! "branch"
299 fetchSubmodules <- v Aeson..:! "fetchSubmodules"
337 fetchSubmodules <- v Aeson..:! "fetchSubmodules"
338+ private <- v Aeson..:? "private"
300 pure $ GitSource
339 pure $ GitSource
301 { _gitSource_url = url
340 { _gitSource_url = url
302 , _gitSource_branch = branch
341 , _gitSource_branch = branch
303 , _gitSource_fetchSubmodules = fromMaybe False fetchSubmodules
342 , _gitSource_fetchSubmodules = fromMaybe False fetchSubmodules
343+ , _gitSource_private = fromMaybe False private
306overwriteThunk :: MonadObelisk m => FilePath -> ThunkPtr -> m ()
346overwriteThunk :: MonadObelisk m => FilePath -> ThunkPtr -> m ()
@@ -327,13 +367,15 @@ encodeThunkPtrData (ThunkPtr rev src) = case src of
327 , ("branch" .=) <$> _gitHubSource_branch s
367 , ("branch" .=) <$> _gitHubSource_branch s
328 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
368 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
329 , Just $ "sha256" .= _thunkRev_nixSha256 rev
369 , Just $ "sha256" .= _thunkRev_nixSha256 rev
370+ , Just $ "private" .= _gitHubSource_private s
331 ThunkSource_Git s -> encodePretty' plainGitCfg $ Aeson.object $ catMaybes
372 ThunkSource_Git s -> encodePretty' plainGitCfg $ Aeson.object $ catMaybes
332− [ Just $ "url" .= render (_gitSource_url s)
373+ [ Just $ "url" .= gitUriToText (_gitSource_url s)
333 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
374 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
334 , ("branch" .=) <$> _gitSource_branch s
375 , ("branch" .=) <$> _gitSource_branch s
335 , Just $ "sha256" .= _thunkRev_nixSha256 rev
376 , Just $ "sha256" .= _thunkRev_nixSha256 rev
336 , Just $ "fetchSubmodules" .= _gitSource_fetchSubmodules s
377 , Just $ "fetchSubmodules" .= _gitSource_fetchSubmodules s
378+ , Just $ "private" .= _gitSource_private s
339 githubCfg = defConfig
381 githubCfg = defConfig
@@ -354,6 +396,7 @@ encodeThunkPtrData (ThunkPtr rev src) = case src of
356 , "sha256"
398 , "sha256"
357 , "fetchSubmodules"
400 , "fetchSubmodules"
358 ] <> compare
401 ] <> compare
359 , confTrailingNewline = True
402 , confTrailingNewline = True
@@ -361,7 +404,7 @@ encodeThunkPtrData (ThunkPtr rev src) = case src of
362createThunk :: MonadIO m => FilePath -> ThunkPtr -> m ()
405createThunk :: MonadIO m => FilePath -> ThunkPtr -> m ()
363createThunk target thunk = liftIO $ do
406createThunk target thunk = liftIO $ do
364− createDirectoryIfMissing True (target </> ".attr-cache")
407+ createDirectoryIfMissing True (target </> attrCacheFileName)
365 T.writeFile (target </> "default.nix") (thunkPtrLoader thunk)
408 T.writeFile (target </> "default.nix") (thunkPtrLoader thunk)
367 jsonFileName = case _thunkPtr_source thunk of
410 jsonFileName = case _thunkPtr_source thunk of
@@ -377,8 +420,8 @@ createThunkWithLatest target s = do
377 , _thunkPtr_rev = rev
420 , _thunkPtr_rev = rev
380−updateThunkToLatest :: MonadObelisk m => FilePath -> Maybe String -> m ()
423+updateThunkToLatest :: MonadObelisk m => ThunkUpdateConfig -> FilePath -> m ()
381−updateThunkToLatest target mBranch = withSpinner' ("Updating thunk " <> T.pack target <> " to latest") (pure $ const $ "Thunk " <> T.pack target <> " updated to latest") $ do
424+updateThunkToLatest (ThunkUpdateConfig mBranch thunkConfig) target = withSpinner' ("Updating thunk " <> T.pack target <> " to latest") (pure $ const $ "Thunk " <> T.pack target <> " updated to latest") $ do
382 checkThunkDirectory "ob thunk update directory cannot be '.'" target
425 checkThunkDirectory "ob thunk update directory cannot be '.'" target
383 -- check to see if thunk should be updated to a specific branch or just update it's current branch
426 -- check to see if thunk should be updated to a specific branch or just update it's current branch
384 case mBranch of
427 case mBranch of
@@ -390,7 +433,7 @@ updateThunkToLatest target mBranch = withSpinner' ("Updating thunk " <> T.pack t
390 ThunkData_Checkout _ -> failWith "cannot update an unpacked thunk"
433 ThunkData_Checkout _ -> failWith "cannot update an unpacked thunk"
391 let src = _thunkPtr_source ptr
434 let src = _thunkPtr_source ptr
392 rev <- getLatestRev src
435 rev <- getLatestRev src
393− overwriteThunk overwrite $ ThunkPtr
436+ overwriteThunk overwrite $ modifyThunkPtrByConfig thunkConfig $ ThunkPtr
394 { _thunkPtr_source = src
437 { _thunkPtr_source = src
395 , _thunkPtr_rev = rev
438 , _thunkPtr_rev = rev
@@ -398,24 +441,25 @@ updateThunkToLatest target mBranch = withSpinner' ("Updating thunk " <> T.pack t
398 Left err -> failWith $ T.pack $ "thunk update: " <> show err
441 Left err -> failWith $ T.pack $ "thunk update: " <> show err
399 Right c -> case c of
442 Right c -> case c of
400 ThunkData_Packed t -> case _thunkPtr_source t of
443 ThunkData_Packed t -> case _thunkPtr_source t of
401− ThunkSource_Git tsg -> setThunk target tsg branch
444+ ThunkSource_Git tsg -> setThunk thunkConfig target tsg branch
402 ThunkSource_GitHub tsgh -> do
445 ThunkSource_GitHub tsgh -> do
403 let tsg = forgetGithub False tsgh
446 let tsg = forgetGithub False tsgh
404− setThunk target tsg branch
447+ setThunk thunkConfig target tsg branch
405− ThunkData_Checkout _ -> failWith $ T.pack $ "thunk located at " <> (show target) <> " is unpacked. Use ob thunk pack on the desired directory and then try ob thunk update again."
448+ ThunkData_Checkout _ -> failWith $ T.pack $ "thunk located at " <> show target <> " is unpacked. Use ob thunk pack on the desired directory and then try ob thunk update again."
407−setThunk :: MonadObelisk m => FilePath -> GitSource -> String -> m ()
450+setThunk :: MonadObelisk m => ThunkConfig -> FilePath -> GitSource -> String -> m ()
408−setThunk target gs branch = do
451+setThunk thunkConfig target gs branch = do
409− newThunkPtr <- uriThunkPtr (_gitSource_url gs) (Just $ T.pack branch) Nothing
452+ newThunkPtr <- uriThunkPtr (_gitSource_url gs) (_thunkConfig_private thunkConfig) (Just $ T.pack branch) Nothing
410 overwriteThunk target newThunkPtr
453 overwriteThunk target newThunkPtr
411− updateThunkToLatest target Nothing
454+ updateThunkToLatest (ThunkUpdateConfig Nothing thunkConfig) target
413-- | All recognized github standalone loaders, ordered from newest to oldest.
456-- | All recognized github standalone loaders, ordered from newest to oldest.
414-- This tool will only ever produce the newest one when it writes a thunk.
457-- This tool will only ever produce the newest one when it writes a thunk.
415gitHubStandaloneLoaders :: NonEmpty Text
458gitHubStandaloneLoaders :: NonEmpty Text
416gitHubStandaloneLoaders =
459gitHubStandaloneLoaders =
417− gitHubStandaloneLoaderV2 :|
460+ gitHubStandaloneLoaderV4 :|
418 [ gitHubStandaloneLoaderV3
461 [ gitHubStandaloneLoaderV3
462+ , gitHubStandaloneLoaderV2
419 , gitHubStandaloneLoaderV1
463 , gitHubStandaloneLoaderV1
@@ -455,10 +499,24 @@ gitHubStandaloneLoaderV3 = T.unlines
455 , "in import (fetch (builtins.fromJSON (builtins.readFile ./github.json)))"
499 , "in import (fetch (builtins.fromJSON (builtins.readFile ./github.json)))"
502+gitHubStandaloneLoaderV4 :: Text
503+gitHubStandaloneLoaderV4 = T.unlines
504+ [ "# DO NOT HAND-EDIT THIS FILE"
505+ , "let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }:"
506+ , " if !fetchSubmodules && !private then builtins.fetchTarball {"
507+ , " url = \"https://github.com/${owner}/${repo}/archive/${rev}.tar.gz\"; inherit sha256;"
508+ , " } else (import <nixpkgs> {}).fetchFromGitHub {"
509+ , " inherit owner repo rev sha256 fetchSubmodules private;"
511+ , "in import (fetch (builtins.fromJSON (builtins.readFile ./github.json)))"
458plainGitStandaloneLoaders :: NonEmpty Text
514plainGitStandaloneLoaders :: NonEmpty Text
459plainGitStandaloneLoaders =
515plainGitStandaloneLoaders =
460− plainGitStandaloneLoaderV1 :|
516+ plainGitStandaloneLoaderV4 :|
517+ [ plainGitStandaloneLoaderV1
461− [ plainGitStandaloneLoaderV2
518+ , plainGitStandaloneLoaderV2
519+ , plainGitStandaloneLoaderV3
464plainGitStandaloneLoaderV1 :: Text
522plainGitStandaloneLoaderV1 :: Text
@@ -479,6 +537,41 @@ plainGitStandaloneLoaderV2 = T.unlines
479 , "in import (fetchGit (builtins.fromJSON (builtins.readFile ./git.json)))"
537 , "in import (fetchGit (builtins.fromJSON (builtins.readFile ./git.json)))"
540+-- This loader has a bug because @builtins.fetchGit@ is not given a @ref@
541+-- and will fail to find commits without this because it does shallow clones.
542+plainGitStandaloneLoaderV3 :: Text
543+plainGitStandaloneLoaderV3 = T.unlines
544+ [ "# DO NOT HAND-EDIT THIS FILE"
545+ , "let fetch = {url, rev, ref ? null, sha256 ? null, fetchSubmodules ? false, private ? false, ...}:"
546+ , " let realUrl = let firstChar = builtins.substring 0 1 url; in"
547+ , " if firstChar == \"/\" then /. + url"
548+ , " else if firstChar == \".\" then ./. + url"
550+ , " in if !fetchSubmodules && private then builtins.fetchGit {"
551+ , " url = realUrl; inherit rev;"
552+ , " } else (import <nixpkgs> {}).fetchgit {"
553+ , " url = realUrl; inherit rev sha256;"
555+ , "in import (fetch (builtins.fromJSON (builtins.readFile ./git.json)))"
558+plainGitStandaloneLoaderV4 :: Text
559+plainGitStandaloneLoaderV4 = T.unlines
560+ [ "# DO NOT HAND-EDIT THIS FILE"
561+ , "let fetch = {url, rev, branch ? null, sha256 ? null, fetchSubmodules ? false, private ? false, ...}:"
562+ , " let realUrl = let firstChar = builtins.substring 0 1 url; in"
563+ , " if firstChar == \"/\" then /. + url"
564+ , " else if firstChar == \".\" then ./. + url"
566+ , " in if !fetchSubmodules && private then builtins.fetchGit {"
567+ , " url = realUrl; inherit rev;"
568+ , " ${if branch == null then null else \"ref\"} = branch;"
569+ , " } else (import <nixpkgs> {}).fetchgit {"
570+ , " url = realUrl; inherit rev sha256;"
572+ , "in import (fetch (builtins.fromJSON (builtins.readFile ./git.json)))"
482thunkFileNames :: [FilePath]
575thunkFileNames :: [FilePath]
483thunkFileNames = ["default.nix", "github.json", "git.json"]
576thunkFileNames = ["default.nix", "github.json", "git.json"]
@@ -505,7 +598,7 @@ nixBuildThunkAttrWithCache thunkDir attr = do
505 let cacheErrHandler e
598 let cacheErrHandler e
506 | isDoesNotExistError e = return Nothing -- expected from a cache miss
599 | isDoesNotExistError e = return Nothing -- expected from a cache miss
507 | otherwise = putLog Error (T.pack $ displayException e) >> return Nothing
600 | otherwise = putLog Error (T.pack $ displayException e) >> return Nothing
508− cacheDir = thunkDir </> ".attr-cache"
601+ cacheDir = thunkDir </> attrCacheFileName
509 cachePath = cacheDir </> attr <.> "out"
602 cachePath = cacheDir </> attr <.> "out"
510 latestChange <- liftIO $ do
603 latestChange <- liftIO $ do
511 createDirectoryIfMissing False cacheDir
604 createDirectoryIfMissing False cacheDir
@@ -520,7 +613,7 @@ nixBuildThunkAttrWithCache thunkDir attr = do
520 Just c -> return c
613 Just c -> return c
521 Nothing -> do
614 Nothing -> do
522 putLog Warning $ T.pack $ mconcat [thunkDir, ": ", attr, " not cached, building ..."]
615 putLog Warning $ T.pack $ mconcat [thunkDir, ": ", attr, " not cached, building ..."]
523− _ <- nixCmd $ NixCmd_Build$ def
616+ _ <- nixCmd $ NixCmd_Build $ def
524 Lens.& nixBuildConfig_outLink Lens..~ OutLink_IndirectRoot cachePath
617 Lens.& nixBuildConfig_outLink Lens..~ OutLink_IndirectRoot cachePath
525 Lens.& nixCmdConfig_target Lens..~ Target
618 Lens.& nixCmdConfig_target Lens..~ Target
526 { _target_path = Just thunkDir
619 { _target_path = Just thunkDir
@@ -568,13 +661,13 @@ updateThunk p f = withSystemTempDirectory "obelisk-thunkptr-" $ \tmpDir -> do
568 Right (ThunkData_Packed _) -> do
661 Right (ThunkData_Packed _) -> do
569 let tmpThunk = tmpDir </> "thunk"
662 let tmpThunk = tmpDir </> "thunk"
570 callProcessAndLogOutput (Notice, Error) $
663 callProcessAndLogOutput (Notice, Error) $
571− proc "cp" ["-r", "-T", thunkDir, tmpThunk]
664+ proc cp ["-r", "-T", thunkDir, tmpThunk]
572 return tmpThunk
665 return tmpThunk
573− Right _ -> failWith $ "Thunk is not packed"
666+ Right _ -> failWith "Thunk is not packed"
574 updateThunkFromTmp p' = do
667 updateThunkFromTmp p' = do
575− _ <- packThunk' True False p'
668+ _ <- packThunk' True (ThunkPackConfig False (ThunkConfig Nothing)) p'
576 callProcessAndLogOutput (Notice, Error) $
669 callProcessAndLogOutput (Notice, Error) $
577− proc "cp" ["-r", "-T", p', p]
670+ proc cp ["-r", "-T", p', p]
579finalMsg :: Bool -> (a -> Text) -> Maybe (a -> Text)
672finalMsg :: Bool -> (a -> Text) -> Maybe (a -> Text)
580finalMsg noTrail s = if noTrail then Nothing else Just s
673finalMsg noTrail s = if noTrail then Nothing else Just s
@@ -606,7 +699,7 @@ unpackThunk' noTrail thunkDir = checkThunkDirectory "Can't pack/unpack from with
606 let git = callProcessAndLogOutput (Notice, Notice) . gitProc tmpRepo
699 let git = callProcessAndLogOutput (Notice, Notice) . gitProc tmpRepo
607 git $ [ "clone" ]
700 git $ [ "clone" ]
608 ++ ("--recursive" <$ guard (_gitSource_fetchSubmodules s))
701 ++ ("--recursive" <$ guard (_gitSource_fetchSubmodules s))
609− ++ [ T.unpack $ render $ _gitSource_url s ]
702+ ++ [ T.unpack $ gitUriToText $ _gitSource_url s ]
610 ++ do branch <- maybeToList $ _gitSource_branch s
703 ++ do branch <- maybeToList $ _gitSource_branch s
611 [ "--branch", T.unpack $ untagName branch ]
704 [ "--branch", T.unpack $ untagName branch ]
612 git ["reset", "--hard", Ref.toHexString $ _thunkRev_commit $ _thunkPtr_rev tptr]
705 git ["reset", "--hard", Ref.toHexString $ _thunkRev_commit $ _thunkPtr_rev tptr]
@@ -615,31 +708,39 @@ unpackThunk' noTrail thunkDir = checkThunkDirectory "Can't pack/unpack from with
616 liftIO $ createDirectory obGitDir
709 liftIO $ createDirectory obGitDir
617 callProcessAndLogOutput (Notice, Error) $
710 callProcessAndLogOutput (Notice, Error) $
618− proc "cp" ["-r", "-T", thunkDir </> ".", obGitDir </> "orig-thunk"]
711+ proc cp ["-r", "-T", thunkDir </> ".", obGitDir </> "orig-thunk"]
619 callProcessAndLogOutput (Notice, Error) $
712 callProcessAndLogOutput (Notice, Error) $
620 proc "rm" ["-r", thunkDir]
713 proc "rm" ["-r", thunkDir]
621 callProcessAndLogOutput (Notice, Error) $
714 callProcessAndLogOutput (Notice, Error) $
622 proc "mv" ["-T", tmpRepo, thunkDir]
715 proc "mv" ["-T", tmpRepo, thunkDir]
624--TODO: add a rollback mode to pack to the original thunk
717--TODO: add a rollback mode to pack to the original thunk
625−packThunk :: MonadObelisk m => Bool -> FilePath -> m ThunkPtr
718+packThunk :: MonadObelisk m => ThunkPackConfig -> FilePath -> m ThunkPtr
626packThunk = packThunk' False
719packThunk = packThunk' False
628−packThunk' :: MonadObelisk m => Bool -> Bool -> FilePath -> m ThunkPtr
721+packThunk' :: MonadObelisk m => Bool -> ThunkPackConfig -> FilePath -> m ThunkPtr
629−packThunk' noTrail force thunkDir = checkThunkDirectory "Can't pack/unpack from within the thunk directory" thunkDir >> readThunk thunkDir >>= \case
722+packThunk' noTrail (ThunkPackConfig force thunkConfig) thunkDir = checkThunkDirectory "Can't pack/unpack from within the thunk directory" thunkDir >> readThunk thunkDir >>= \case
630 Left err -> failWith $ T.pack $ "thunk pack: " <> show err
723 Left err -> failWith $ T.pack $ "thunk pack: " <> show err
631 Right (ThunkData_Packed _) -> failWith "pack: thunk is already packed"
724 Right (ThunkData_Packed _) -> failWith "pack: thunk is already packed"
632 Right (ThunkData_Checkout _) -> do
725 Right (ThunkData_Checkout _) -> do
633 withSpinner' ("Packing thunk " <> T.pack thunkDir)
726 withSpinner' ("Packing thunk " <> T.pack thunkDir)
634 (finalMsg noTrail $ const $ "Packed thunk " <> T.pack thunkDir) $ do
727 (finalMsg noTrail $ const $ "Packed thunk " <> T.pack thunkDir) $ do
635− thunkPtr <- getThunkPtr (not force) thunkDir
728+ thunkPtr <- modifyThunkPtrByConfig thunkConfig <$> getThunkPtr (not force) thunkDir (_thunkConfig_private thunkConfig)
636 callProcessAndLogOutput (Debug, Error) $ proc "rm" ["-rf", thunkDir]
729 callProcessAndLogOutput (Debug, Error) $ proc "rm" ["-rf", thunkDir]
637 liftIO $ createThunk thunkDir thunkPtr
730 liftIO $ createThunk thunkDir thunkPtr
638 pure thunkPtr
731 pure thunkPtr
733+modifyThunkPtrByConfig :: ThunkConfig -> ThunkPtr -> ThunkPtr
734+modifyThunkPtrByConfig (ThunkConfig markPrivate') ptr = case markPrivate' of
736+ Just markPrivate -> ptr { _thunkPtr_source = case _thunkPtr_source ptr of
737+ ThunkSource_Git s -> ThunkSource_Git $ s { _gitSource_private = markPrivate }
738+ ThunkSource_GitHub s -> ThunkSource_GitHub $ s { _gitHubSource_private = markPrivate }
640−getThunkPtr :: forall m. MonadObelisk m => Bool -> FilePath -> m ThunkPtr
741+getThunkPtr :: forall m. MonadObelisk m => Bool -> FilePath -> Maybe Bool -> m ThunkPtr
641−getThunkPtr checkClean thunkDir = do
742+getThunkPtr checkClean thunkDir mPrivate = do
642− when checkClean $ ensureCleanGitRepo thunkDir True $
743+ when checkClean $ ensureCleanGitRepo thunkDir True
643 "thunk pack: thunk checkout contains unsaved modifications"
744 "thunk pack: thunk checkout contains unsaved modifications"
645 -- Check whether there are any stashes
746 -- Check whether there are any stashes
@@ -652,7 +753,7 @@ getThunkPtr checkClean thunkDir = do
652 ] ++ T.lines stashOutput
753 ] ++ T.lines stashOutput
653 True -> return ()
754 True -> return ()
655− -- Get current branch ``
756+ -- Get current branch
656 (mCurrentBranch, mCurrentCommit) <- do
757 (mCurrentBranch, mCurrentCommit) <- do
657 b <- listToMaybe
758 b <- listToMaybe
658 <$> T.lines
759 <$> T.lines
@@ -661,7 +762,7 @@ getThunkPtr checkClean thunkDir = do
661 <$> T.lines
762 <$> T.lines
662 <$> readGitProcess thunkDir ["rev-parse", "HEAD"]
763 <$> readGitProcess thunkDir ["rev-parse", "HEAD"]
663 case b of
764 case b of
664− (Just "HEAD") -> failWith $ T.unlines $
765+ (Just "HEAD") -> failWith $ T.unlines
665 [ "thunk pack: You are in 'detached HEAD' state."
766 [ "thunk pack: You are in 'detached HEAD' state."
666 , "If you want to pack at the current ref \
767 , "If you want to pack at the current ref \
667 \then please create a new branch with 'git checkout -b <new-branch-name>' and push this upstream."
768 \then please create a new branch with 'git checkout -b <new-branch-name>' and push this upstream."
@@ -733,7 +834,7 @@ getThunkPtr checkClean thunkDir = do
733 [ "thunk pack: Certain branches in the thunk have commits not yet pushed upstream:"
834 [ "thunk pack: Certain branches in the thunk have commits not yet pushed upstream:"
736− (flip map (Map.toList nonGood) $ \(branch, (upstream, (ahead, behind))) -> mconcat
837+ flip map (Map.toList nonGood) (\(branch, (upstream, (ahead, behind))) -> mconcat
737 [" ", branch, " ahead: ", T.pack (show ahead), " behind: ", T.pack (show behind), " remote branch ", upstream]) ++
838 [" ", branch, " ahead: ", T.pack (show ahead), " behind: ", T.pack (show behind), " remote branch ", upstream]) ++
739 , "Please push these upstream and try again. (Or just fetch, if they are somehow \
840 , "Please push these upstream and try again. (Or just fetch, if they are somehow \
@@ -741,7 +842,7 @@ getThunkPtr checkClean thunkDir = do
743 -- We assume it's safe to pack the thunk at this point
844 -- We assume it's safe to pack the thunk at this point
744− putLog Informational $ "All changes safe in git remotes. OK to pack thunk."
845+ putLog Informational "All changes safe in git remotes. OK to pack thunk."
746 let remote = maybe "origin" snd $ flip Map.lookup headUpstream =<< mCurrentBranch
847 let remote = maybe "origin" snd $ flip Map.lookup headUpstream =<< mCurrentBranch
@@ -754,7 +855,7 @@ getThunkPtr checkClean thunkDir = do
754 remoteUri <- case parseGitUri remoteUri' of
855 remoteUri <- case parseGitUri remoteUri' of
755 Nothing -> failWith $ "Could not identify git remote: " <> remoteUri'
856 Nothing -> failWith $ "Could not identify git remote: " <> remoteUri'
756 Just uri -> pure uri
857 Just uri -> pure uri
757− uriThunkPtr remoteUri mCurrentBranch mCurrentCommit
858+ uriThunkPtr remoteUri mPrivate mCurrentBranch mCurrentCommit
759-- | Get the latest revision available from the given source
860-- | Get the latest revision available from the given source
760getLatestRev :: MonadObelisk m => ThunkSource -> m ThunkRev
861getLatestRev :: MonadObelisk m => ThunkSource -> m ThunkRev
@@ -773,18 +874,18 @@ getLatestRev os = do
773-- performance. If that doesn't work (e.g. authentication issue), we fall back
874-- performance. If that doesn't work (e.g. authentication issue), we fall back
774-- on just doing things the normal way for git repos in general, and save it as
875-- on just doing things the normal way for git repos in general, and save it as
775-- a regular git thunk.
876-- a regular git thunk.
776−uriThunkPtr :: MonadObelisk m => URI -> Maybe Text -> Maybe Text -> m ThunkPtr
877+uriThunkPtr :: MonadObelisk m => GitUri -> Maybe Bool -> Maybe Text -> Maybe Text -> m ThunkPtr
777−uriThunkPtr uri mbranch mcommit = do
878+uriThunkPtr uri mPrivate mbranch mcommit = do
778 commit <- case mcommit of
879 commit <- case mcommit of
779 Nothing -> gitGetCommitBranch uri mbranch >>= return . snd
880 Nothing -> gitGetCommitBranch uri mbranch >>= return . snd
780 (Just c) -> return c
881 (Just c) -> return c
781− (src, rev) <- case uriToThunkSource uri mbranch of
882+ (src, rev) <- uriToThunkSource uri mPrivate mbranch >>= \case
782 ThunkSource_GitHub s -> do
883 ThunkSource_GitHub s -> do
783 rev <- runExceptT $ githubThunkRev s commit
884 rev <- runExceptT $ githubThunkRev s commit
784 case rev of
885 case rev of
785 Right r -> pure (ThunkSource_GitHub s, r)
886 Right r -> pure (ThunkSource_GitHub s, r)
786 Left e -> do
887 Left e -> do
787− putLog Warning $ "\
888+ putLog Warning "\
788\Failed to fetch archive from GitHub. This is probably a private repo. \
889\Failed to fetch archive from GitHub. This is probably a private repo. \
789\Falling back on normal fetchgit. Original failure:"
890\Falling back on normal fetchgit. Original failure:"
790 errorToWarning e
891 errorToWarning e
@@ -801,34 +902,66 @@ uriThunkPtr uri mbranch mcommit = do
801-- If the thunk is a GitHub thunk and fails, we do *not* fall back like with
902-- If the thunk is a GitHub thunk and fails, we do *not* fall back like with
802-- `uriThunkPtr`. Unlike a plain URL, a thunk src explicitly states which method
903-- `uriThunkPtr`. Unlike a plain URL, a thunk src explicitly states which method
803-- should be employed, and so we respect that.
904-- should be employed, and so we respect that.
804−uriToThunkSource :: URI -> Maybe Text -> ThunkSource
905+uriToThunkSource :: MonadObelisk m => GitUri -> Maybe Bool -> Maybe Text -> m ThunkSource
805−uriToThunkSource u
906+uriToThunkSource (GitUri u) mPrivate
806− | Right uriAuth <- uriAuthority u
907+ | Right uriAuth <- URI.uriAuthority u
807− , Just scheme <- unRText <$> uriScheme u
908+ , Just scheme <- URI.unRText <$> URI.uriScheme u
808 , case scheme of
909 , case scheme of
809− "ssh" -> uriAuth == Authority
910+ "ssh" -> uriAuth == URI.Authority
810− { authUserInfo = Just $ UserInfo (fromRight' $ mkUsername "git") Nothing
911+ { URI.authUserInfo = Just $ URI.UserInfo (fromRight' $ URI.mkUsername "git") Nothing
811− , authHost = fromRight' $ mkHost "github.com"
912+ , URI.authHost = fromRight' $ URI.mkHost "github.com"
812− , authPort = Nothing
913+ , URI.authPort = Nothing
814 s -> s `L.elem` [ "git", "https", "http" ] -- "http:" just redirects to "https:"
915 s -> s `L.elem` [ "git", "https", "http" ] -- "http:" just redirects to "https:"
815− && unRText (authHost uriAuth) == "github.com"
916+ && URI.unRText (URI.authHost uriAuth) == "github.com"
816− , Just (_, owner :| [repoish]) <- uriPath u
917+ , Just (_, owner :| [repoish]) <- URI.uriPath u
919+ isPrivate <- getIsPrivate
817− = \mbranch -> ThunkSource_GitHub $ GitHubSource
920+ pure $ ThunkSource_GitHub $ GitHubSource
818− { _gitHubSource_owner = N $ unRText owner
921+ { _gitHubSource_owner = N $ URI.unRText owner
819− , _gitHubSource_repo = N $ let
922+ , _gitHubSource_repo = N $ let
820− repoish' = unRText repoish
923+ repoish' = URI.unRText repoish
821− in case T.stripSuffix ".git" repoish' of
924+ in fromMaybe repoish' $ T.stripSuffix ".git" repoish'
824− , _gitHubSource_branch = N <$> mbranch
925+ , _gitHubSource_branch = N <$> mbranch
926+ , _gitHubSource_private = isPrivate
929+ | otherwise = \mbranch -> do
930+ isPrivate <- getIsPrivate
827− | otherwise = \mbranch -> ThunkSource_Git $ GitSource
931+ pure $ ThunkSource_Git $ GitSource
828− { _gitSource_url = u
932+ { _gitSource_url = GitUri u
829− , _gitSource_branch = N <$> mbranch
933+ , _gitSource_branch = N <$> mbranch
830− , _gitSource_fetchSubmodules = False -- TODO: How do we determine if this should be true?
934+ , _gitSource_fetchSubmodules = False -- TODO: How do we determine if this should be true?
935+ , _gitSource_private = isPrivate
938+ getIsPrivate = maybe (guessGitRepoIsPrivate $ GitUri u) pure mPrivate
940+guessGitRepoIsPrivate :: MonadObelisk m => GitUri -> m Bool
941+guessGitRepoIsPrivate uri = flip fix urisToTry $ \loop -> \case
944+ result <- readCreateProcessWithExitCode $
951+ , T.unpack $ gitUriToText uriAttempt
954+ (ExitSuccess, _, _) -> pure False -- Must be a public repo
957+ urisToTry = nubOrd $
958+ -- Include the original URI if it isn't using SSH because SSH will certainly fail.
959+ [uri | fmap URI.unRText (URI.uriScheme (unGitUri uri)) /= Just "ssh"] <>
960+ [changeScheme "https" uri, changeScheme "http" uri]
961+ changeScheme scheme (GitUri u) = GitUri $ u
962+ { URI.uriScheme = URI.mkScheme scheme
963+ , URI.uriAuthority = (\x -> x { URI.authUserInfo = Nothing }) <$> URI.uriAuthority u
833-- Funny signature indicates no effects depend on the optional branch name.
966-- Funny signature indicates no effects depend on the optional branch name.
834githubThunkRev
967githubThunkRev
@@ -840,19 +973,19 @@ githubThunkRev
840githubThunkRev s commit = do
973githubThunkRev s commit = do
841 owner <- forcePP $ _gitHubSource_owner s
974 owner <- forcePP $ _gitHubSource_owner s
842 repo <- forcePP $ _gitHubSource_repo s
975 repo <- forcePP $ _gitHubSource_repo s
843− revTarball <- mkPathPiece $ commit <> ".tar.gz"
976+ revTarball <- URI.mkPathPiece $ commit <> ".tar.gz"
844− let archiveUri = URI
977+ let archiveUri = GitUri $ URI.URI
845− { uriScheme = Just $ fromRight' $ mkScheme "https"
978+ { URI.uriScheme = Just $ fromRight' $ URI.mkScheme "https"
846− , uriAuthority = Right $ Authority
979+ , URI.uriAuthority = Right $ URI.Authority
847− { authUserInfo = Nothing
980+ { URI.authUserInfo = Nothing
848− , authHost = fromRight' $ mkHost "github.com"
981+ , URI.authHost = fromRight' $ URI.mkHost "github.com"
849− , authPort = Nothing
982+ , URI.authPort = Nothing
851− , uriPath = Just ( False
984+ , URI.uriPath = Just ( False
852− , owner :| [ repo, fromRight' $ mkPathPiece "archive", revTarball ]
985+ , owner :| [ repo, fromRight' $ URI.mkPathPiece "archive", revTarball ]
854− , uriQuery = []
987+ , URI.uriQuery = []
855− , uriFragment = Nothing
988+ , URI.uriFragment = Nothing
857 hash <- getNixSha256ForUriUnpacked archiveUri
990 hash <- getNixSha256ForUriUnpacked archiveUri
858 putLog Debug $ "Nix sha256 is " <> hash
991 putLog Debug $ "Nix sha256 is " <> hash
@@ -861,8 +994,8 @@ githubThunkRev s commit = do
861 , _thunkRev_nixSha256 = hash
994 , _thunkRev_nixSha256 = hash
864− forcePP :: Name entity -> m (RText 'PathPiece)
997+ forcePP :: Name entity -> m (URI.RText 'URI.PathPiece)
865− forcePP = mkPathPiece . untagName
998+ forcePP = URI.mkPathPiece . untagName
867gitThunkRev
1000gitThunkRev
868 :: MonadObelisk m
1001 :: MonadObelisk m
@@ -871,11 +1004,11 @@ gitThunkRev
871 -> m ThunkRev
1004 -> m ThunkRev
872gitThunkRev s commit = do
1005gitThunkRev s commit = do
873 let u = _gitSource_url s
1006 let u = _gitSource_url s
874− protocols = ["https", "ssh", "git"]
1007+ protocols = ["file", "https", "ssh", "git"]
875− Just scheme <- pure $ unRText <$> uriScheme u
1008+ scheme = maybe "file" URI.unRText $ URI.uriScheme $ (\(GitUri x) -> x) u
876 unless (T.toLower scheme `elem` protocols) $
1009 unless (T.toLower scheme `elem` protocols) $
877 failWith $ "obelisk currently only supports "
1010 failWith $ "obelisk currently only supports "
878− <> T.intercalate ", " protocols <> " protocols for non-GitHub remotes"
1011+ <> T.intercalate ", " protocols <> " protocols for plain Git remotes"
879 hash <- nixPrefetchGit u commit $ _gitSource_fetchSubmodules s
1012 hash <- nixPrefetchGit u commit $ _gitSource_fetchSubmodules s
880 putLog Informational $ "Nix sha256 is " <> hash
1013 putLog Informational $ "Nix sha256 is " <> hash
881 pure $ ThunkRev
1014 pure $ ThunkRev
@@ -888,11 +1021,12 @@ gitThunkRev s commit = do
889-- If the branch name is passed in, it is returned exactly as-is. If it is not
1022-- If the branch name is passed in, it is returned exactly as-is. If it is not
890-- passed it, the default branch of the repo is used instead.
1023-- passed it, the default branch of the repo is used instead.
891gitGetCommitBranch
1025gitGetCommitBranch
892− :: MonadObelisk m => URI -> Maybe Text -> m (Text, CommitId)
1026+ :: MonadObelisk m => GitUri -> Maybe Text -> m (Text, CommitId)
893gitGetCommitBranch uri mbranch = withExitFailMessage ("Failure for git remote " <> uriMsg) $ do
1027gitGetCommitBranch uri mbranch = withExitFailMessage ("Failure for git remote " <> uriMsg) $ do
894 (_, bothMaps) <- gitLsRemote
1028 (_, bothMaps) <- gitLsRemote
895− (T.unpack $ render uri)
1029+ (T.unpack $ gitUriToText uri)
896 (GitRef_Branch <$> mbranch)
1030 (GitRef_Branch <$> mbranch)
898 branch <- case mbranch of
1032 branch <- case mbranch of
@@ -908,18 +1042,21 @@ gitGetCommitBranch uri mbranch = withExitFailMessage ("Failure for git remote "
908 pure (branch, commit)
1042 pure (branch, commit)
910 rethrowE = either failWith pure
1044 rethrowE = either failWith pure
911− uriMsg = render uri
1045+ uriMsg = gitUriToText uri
1047+parseGitUri :: Text -> Maybe GitUri
1048+parseGitUri x = GitUri <$> (parseFileURI x <|> parseAbsoluteURI x <|> parseSshShorthand x)
913−parseGitUri :: Text -> Maybe URI
1050+parseFileURI :: Text -> Maybe URI.URI
914−parseGitUri x = parseAbsoluteURI x <|> parseSshShorthand x
1051+parseFileURI uri = if "/" `T.isPrefixOf` uri then parseAbsoluteURI ("file://" <> uri) else Nothing
916−parseAbsoluteURI :: Text -> Maybe URI
1053+parseAbsoluteURI :: Text -> Maybe URI.URI
917parseAbsoluteURI uri = do
1054parseAbsoluteURI uri = do
918− parsedUri <- mkURI uri
1055+ parsedUri <- URI.mkURI uri
919− guard $ isPathAbsolute parsedUri
1056+ guard $ URI.isPathAbsolute parsedUri
920− pure $ parsedUri
1057+ pure parsedUri
922−parseSshShorthand :: Text -> Maybe URI
1059+parseSshShorthand :: Text -> Maybe URI.URI
923parseSshShorthand uri = do
1060parseSshShorthand uri = do
924 -- This is what git does to check that the remote
1061 -- This is what git does to check that the remote
925 -- is not a local file path when parsing shorthand.
1062 -- is not a local file path when parsing shorthand.
@@ -932,4 +1069,4 @@ parseSshShorthand uri = do
932 -- This check is used to disambiguate a filepath containing a colon from shorthand
1069 -- This check is used to disambiguate a filepath containing a colon from shorthand
933 guard $ isNothing (T.findIndex (=='/') authAndHostname)
1070 guard $ isNothing (T.findIndex (=='/') authAndHostname)
934 && not (T.null colonAndPath)
1071 && not (T.null colonAndPath)
935− mkURI properUri
1072+ URI.mkURI properUri